Skip to content

Commit 930517f

Browse files
authored
Merge pull request #1651 from puremourning/inlay-hints
Inlay hints
2 parents 70a74dc + 6ed8628 commit 930517f

25 files changed

+1124
-161
lines changed

build.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def Exit( self ):
9595
'09650af5c9dc39f0b40981bcdaa2170cbbc5bb003ac90cdb07fbb57381ac47b2'
9696
)
9797

98-
RUST_TOOLCHAIN = 'nightly-2021-10-26'
98+
RUST_TOOLCHAIN = 'nightly-2022-08-17'
9999
RUST_ANALYZER_DIR = p.join( DIR_OF_THIRD_PARTY, 'rust-analyzer' )
100100

101101
BUILD_ERROR_MESSAGE = (
@@ -868,7 +868,7 @@ def EnableGoCompleter( args ):
868868
new_env.pop( 'GOROOT', None )
869869
new_env[ 'GOBIN' ] = p.join( new_env[ 'GOPATH' ], 'bin' )
870870

871-
gopls = 'golang.org/x/tools/gopls@v0.7.1'
871+
gopls = 'golang.org/x/tools/gopls@v0.9.4'
872872
CheckCall( [ go, 'install', gopls ],
873873
env = new_env,
874874
quiet = args.quiet,

docs/index.html

Lines changed: 633 additions & 58 deletions
Large diffs are not rendered by default.

docs/openapi.yml

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,57 @@ definitions:
682682
items:
683683
$ref: "#/definitions/DiagnosticData"
684684

685+
SemanticToken:
686+
type: object
687+
description: |-
688+
A item describing the type of token covered by the supplied range.
689+
required:
690+
- range
691+
- type
692+
- modifiers
693+
properties:
694+
range:
695+
$ref: '#/definitions/Range'
696+
type:
697+
type: string
698+
description: |-
699+
One of the token types supported by LSP, or custom ones provided by
700+
the semantic engine. Should be mapped to some syntax group understood
701+
by the client.
702+
modifiers:
703+
type: array
704+
description: List of token modifiers, provided by the sematnic engine
705+
items: string
706+
707+
InlayHint:
708+
type: object
709+
description: |-
710+
An inlay hint to be rendered in the docuemnt body but not part of the
711+
text. Includes optional padding before and after and a kind, which is one
712+
of the LSP or tsserver kinds.
713+
required:
714+
- kind
715+
- position
716+
- label
717+
- paddingLeft
718+
- paddingRight
719+
properties:
720+
kind:
721+
type: string
722+
enum:
723+
- Type
724+
- Parameter
725+
- Enum
726+
position:
727+
$ref: '#/definitions/Location'
728+
label:
729+
type: string
730+
description: Text to display
731+
paddingLeft:
732+
type: boolean
733+
paddingRight:
734+
type: boolean
735+
685736
paths:
686737
/event_notification:
687738
post:
@@ -1708,3 +1759,102 @@ paths:
17081759
description: An error occurred
17091760
schema:
17101761
$ref: "#/definitions/ExceptionResponse"
1762+
/semantic_tokens:
1763+
post:
1764+
summary: Compute semantic tokens for a range, or the whole document
1765+
description: |-
1766+
Compute and return semantic tokens
1767+
produces:
1768+
application/json
1769+
parameters:
1770+
- name: request_data
1771+
in: body
1772+
description: |-
1773+
The context data, including the current cursor position, and details
1774+
of dirty buffers.
1775+
required: true
1776+
schema:
1777+
type: object
1778+
required:
1779+
- filepath
1780+
- file_data
1781+
properties:
1782+
filepath:
1783+
$ref: "#/definitions/FilePath"
1784+
file_data:
1785+
$ref: "#/definitions/FileDataMap"
1786+
range:
1787+
$ref: "#/definitions/Range"
1788+
responses:
1789+
200:
1790+
description: |-
1791+
Hints created, or not supported (emtpy list)
1792+
schema:
1793+
type: object
1794+
required:
1795+
- semantic_tokens
1796+
- errors
1797+
properties:
1798+
semantic_tokens:
1799+
type: object
1800+
properties:
1801+
tokens:
1802+
$ref: "#/definitions/SemanticToken"
1803+
errors:
1804+
type: array
1805+
items:
1806+
$ref: "#/definitions/Exception"
1807+
500:
1808+
description: An error occurred
1809+
schema:
1810+
$ref: "#/definitions/ExceptionResponse"
1811+
/inlay_hints:
1812+
post:
1813+
summary: Compute inlay hints for a range
1814+
description: |-
1815+
Compute and return inlay hints for a document range.
1816+
produces:
1817+
application/json
1818+
parameters:
1819+
- name: request_data
1820+
in: body
1821+
description: |-
1822+
The context data, including the current cursor position, and details
1823+
of dirty buffers.
1824+
required: true
1825+
schema:
1826+
type: object
1827+
required:
1828+
- filepath
1829+
- file_data
1830+
- range
1831+
properties:
1832+
filepath:
1833+
$ref: "#/definitions/FilePath"
1834+
file_data:
1835+
$ref: "#/definitions/FileDataMap"
1836+
range:
1837+
$ref: "#/definitions/Range"
1838+
responses:
1839+
200:
1840+
description: |-
1841+
Hints created, or not supported (emtpy list)
1842+
schema:
1843+
type: object
1844+
required:
1845+
- inlay_hints
1846+
- errors
1847+
properties:
1848+
inlay_hints:
1849+
type: array
1850+
items:
1851+
$ref: "#/definitions/InlayHint"
1852+
errors:
1853+
type: array
1854+
items:
1855+
$ref: "#/definitions/Exception"
1856+
1857+
500:
1858+
description: An error occurred
1859+
schema:
1860+
$ref: "#/definitions/ExceptionResponse"

third_party/tsserver/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"description": "ycmd tern runtime area with required typescript version and plugins",
33
"dependencies": {
4-
"typescript": "4.5.2"
4+
"typescript": "4.7.4"
55
}
66
}

ycmd/completers/completer.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ def ComputeSemanticTokens( self, request_data ):
373373
return {}
374374

375375

376+
def ComputeInlayHints( self, request_data ):
377+
return []
378+
379+
376380
def DefinedSubcommands( self ):
377381
subcommands = sorted( self.GetSubcommandsMap().keys() )
378382
try:

ycmd/completers/go/go_completer.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ def SupportedFiletypes( self ):
7878
return [ 'go' ]
7979

8080

81+
def _SetUpSemanticTokenAtlas( self, capabilities: dict ):
82+
if 'semanticTokensProvider' not in capabilities:
83+
# gopls is broken and doesn't provide a legend, instead assuming the
84+
# tokens specified by the client are the legend. This is broken, but
85+
# easily worked around:
86+
#
87+
# https://github.com/golang/go/issues/54531
88+
import ycmd.completers.language_server.language_server_protocol as lsp
89+
capabilities[ 'semanticTokensProvider' ] = {
90+
'full': True,
91+
'legend': {
92+
'tokenTypes': lsp.TOKEN_TYPES,
93+
'tokenModifiers': lsp.TOKEN_MODIFIERS
94+
}
95+
}
96+
97+
return super()._SetUpSemanticTokenAtlas( capabilities )
98+
99+
81100
def GetDoc( self, request_data ):
82101
assert self._settings[ 'ls' ][ 'hoverKind' ] == 'Structured'
83102
try:
@@ -98,7 +117,20 @@ def GetType( self, request_data ):
98117

99118

100119
def DefaultSettings( self, request_data ):
101-
return { 'hoverKind': 'Structured' }
120+
return {
121+
'hoverKind': 'Structured',
122+
'hints': {
123+
'assignVariableTypes': True,
124+
'compositeLiteralFields': True,
125+
'compositeLiteralTypes': True,
126+
'constantValues': True,
127+
'functionTypeParameters': True,
128+
'parameterNames': True,
129+
'rangeVariableTypes': True,
130+
},
131+
'semanticTokens': True
132+
}
133+
102134

103135

104136
def ExtraCapabilities( self ):

ycmd/completers/javascript/hook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323

2424
def GetCompleter( user_options ):
25-
if ShouldEnableTernCompleter():
25+
if ShouldEnableTernCompleter( user_options ):
2626
return TernCompleter( user_options )
2727
if ShouldEnableTypeScriptCompleter( user_options ):
2828
return TypeScriptCompleter( user_options )

ycmd/completers/javascript/tern_completer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@
5454
LOGFILE_FORMAT = 'tern_{port}_{std}_'
5555

5656

57-
def ShouldEnableTernCompleter():
57+
def ShouldEnableTernCompleter( user_options ):
5858
"""Returns whether or not the tern completer is 'installed'. That is whether
5959
or not the tern submodule has a 'node_modules' directory. This is pretty much
6060
the only way we can know if the user added '--js-completer' on
6161
install or manually ran 'npm install' in the tern submodule directory."""
6262

63+
if user_options.get( 'disable_tern' ):
64+
LOGGER.info( 'Not using Tern completer: disabled by user' )
65+
return False
66+
6367
if not PATH_TO_NODE:
6468
LOGGER.warning( 'Not using Tern completer: unable to find node' )
6569
return False

ycmd/completers/language_server/language_server_completer.py

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,10 +1551,13 @@ def ComputeSemanticTokens( self, request_data ):
15511551
if not self._semantic_token_atlas:
15521552
return {}
15531553

1554+
range_supported = self._server_capabilities[ 'semanticTokensProvider' ].get(
1555+
'range', False )
1556+
15541557
self._UpdateServerWithCurrentFileContents( request_data )
15551558

15561559
request_id = self.GetConnection().NextRequestId()
1557-
body = lsp.SemanticTokens( request_id, request_data )
1560+
body = lsp.SemanticTokens( request_id, range_supported, request_data )
15581561

15591562
for _ in RetryOnFailure( [ lsp.Errors.ContentModified ] ):
15601563
response = self._connection.GetResponse(
@@ -1578,6 +1581,53 @@ def ComputeSemanticTokens( self, request_data ):
15781581
}
15791582

15801583

1584+
def ComputeInlayHints( self, request_data ):
1585+
if not self._initialize_event.wait( REQUEST_TIMEOUT_COMPLETION ):
1586+
return []
1587+
1588+
if not self._ServerIsInitialized():
1589+
return []
1590+
1591+
if 'inlayHintProvider' not in self._server_capabilities:
1592+
return []
1593+
1594+
self._UpdateServerWithCurrentFileContents( request_data )
1595+
request_id = self.GetConnection().NextRequestId()
1596+
body = lsp.InlayHints( request_id, request_data )
1597+
1598+
for _ in RetryOnFailure( [ lsp.Errors.ContentModified ] ):
1599+
response = self._connection.GetResponse(
1600+
request_id,
1601+
body,
1602+
3 * REQUEST_TIMEOUT_COMPLETION )
1603+
1604+
if response is None:
1605+
return []
1606+
1607+
file_contents = GetFileLines( request_data, request_data[ 'filepath' ] )
1608+
1609+
def BuildLabel( label_or_labels ):
1610+
if isinstance( label_or_labels, list ):
1611+
return ' '.join( label[ 'value' ] for label in label_or_labels )
1612+
return label_or_labels
1613+
1614+
def BuildInlayHint( inlay_hint: dict ):
1615+
return {
1616+
'kind': lsp.INLAY_HINT_KIND[ inlay_hint[ 'kind' ] ],
1617+
'position': responses.BuildLocationData(
1618+
_BuildLocationAndDescription(
1619+
request_data[ 'filepath' ],
1620+
file_contents,
1621+
inlay_hint[ 'position' ] )[ 0 ]
1622+
),
1623+
'label': BuildLabel( inlay_hint[ 'label' ] ),
1624+
'paddingLeft': inlay_hint.get( 'paddingLeft', False ),
1625+
'paddingRight': inlay_hint.get( 'paddingRight', False ),
1626+
}
1627+
1628+
return [ BuildInlayHint( h ) for h in response.get( 'result' ) or [] ]
1629+
1630+
15811631
def GetDetailedDiagnostic( self, request_data ):
15821632
self._UpdateServerWithFileContents( request_data )
15831633

@@ -3117,11 +3167,11 @@ def _LocationListToGoTo( request_data, positions ):
31173167
if len( positions ) > 1:
31183168
return [
31193169
responses.BuildGoToResponseFromLocation(
3120-
*_PositionToLocationAndDescription( request_data, position ) )
3170+
*_LspLocationToLocationAndDescription( request_data, position ) )
31213171
for position in positions
31223172
]
31233173
return responses.BuildGoToResponseFromLocation(
3124-
*_PositionToLocationAndDescription( request_data, positions[ 0 ] ) )
3174+
*_LspLocationToLocationAndDescription( request_data, positions[ 0 ] ) )
31253175
except ( IndexError, KeyError ):
31263176
raise RuntimeError( 'Cannot jump to location' )
31273177

@@ -3130,7 +3180,7 @@ def _SymbolInfoListToGoTo( request_data, symbols ):
31303180
"""Convert a list of LSP SymbolInformation into a YCM GoTo response"""
31313181

31323182
def BuildGoToLocationFromSymbol( symbol ):
3133-
location, line_value = _PositionToLocationAndDescription(
3183+
location, line_value = _LspLocationToLocationAndDescription(
31343184
request_data,
31353185
symbol[ 'location' ] )
31363186

@@ -3157,10 +3207,10 @@ def BuildGoToLocationFromSymbol( symbol ):
31573207
return locations
31583208

31593209

3160-
def _PositionToLocationAndDescription( request_data, position ):
3161-
"""Convert a LSP position to a ycmd location."""
3210+
def _LspLocationToLocationAndDescription( request_data, location ):
3211+
"""Convert a LSP Location to a ycmd location."""
31623212
try:
3163-
filename = lsp.UriToFilePath( position[ 'uri' ] )
3213+
filename = lsp.UriToFilePath( location[ 'uri' ] )
31643214
file_contents = GetFileLines( request_data, filename )
31653215
except lsp.InvalidUriException:
31663216
LOGGER.debug( 'Invalid URI, file contents not available in GoTo' )
@@ -3176,7 +3226,7 @@ def _PositionToLocationAndDescription( request_data, position ):
31763226

31773227
return _BuildLocationAndDescription( filename,
31783228
file_contents,
3179-
position[ 'range' ][ 'start' ] )
3229+
location[ 'range' ][ 'start' ] )
31803230

31813231

31823232
def _LspToYcmdLocation( file_contents, location ):

0 commit comments

Comments
 (0)