Skip to content

Commit 84bfa36

Browse files
committed
feat: implement textDocument/inlayHint and workspace/inlayHint/refresh capabilities
1 parent 38bb3d2 commit 84bfa36

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

src/lsp_client/capability/request/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .document_symbol import WithRequestDocumentSymbol
99
from .hover import WithRequestHover
1010
from .implementation import WithRequestImplementation
11+
from .inlay_hint import WithRequestInlayHint
1112
from .inline_value import WithRequestInlineValue
1213
from .reference import WithRequestReferences
1314
from .type_definition import WithRequestTypeDefinition
@@ -21,6 +22,7 @@
2122
WithRequestDocumentSymbol,
2223
WithRequestHover,
2324
WithRequestImplementation,
25+
WithRequestInlayHint,
2426
WithRequestInlineValue,
2527
WithRequestReferences,
2628
WithRequestTypeDefinition,
@@ -35,6 +37,7 @@
3537
"WithRequestDocumentSymbol",
3638
"WithRequestHover",
3739
"WithRequestImplementation",
40+
"WithRequestInlayHint",
3841
"WithRequestInlineValue",
3942
"WithRequestReferences",
4043
"WithRequestTypeDefinition",
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Sequence
4+
from typing import Protocol, override, runtime_checkable
5+
6+
import asyncer
7+
8+
from lsp_client.jsonrpc.id import jsonrpc_uuid
9+
from lsp_client.protocol import (
10+
CapabilityClientProtocol,
11+
TextDocumentCapabilityProtocol,
12+
)
13+
from lsp_client.utils.types import AnyPath, lsp_type
14+
15+
16+
@runtime_checkable
17+
class WithRequestInlayHint(
18+
TextDocumentCapabilityProtocol,
19+
CapabilityClientProtocol,
20+
Protocol,
21+
):
22+
"""
23+
`textDocument/inlayHint` - https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_inlayHint
24+
"""
25+
26+
@override
27+
@classmethod
28+
def methods(cls) -> Sequence[str]:
29+
return (
30+
lsp_type.TEXT_DOCUMENT_INLAY_HINT,
31+
lsp_type.INLAY_HINT_RESOLVE,
32+
)
33+
34+
@override
35+
@classmethod
36+
def register_text_document_capability(
37+
cls, cap: lsp_type.TextDocumentClientCapabilities
38+
) -> None:
39+
cap.inlay_hint = lsp_type.InlayHintClientCapabilities(
40+
dynamic_registration=True,
41+
resolve_support=lsp_type.ClientInlayHintResolveOptions(
42+
properties=[
43+
"tooltip",
44+
"location",
45+
"label.tooltip",
46+
"label.location",
47+
"textEdits",
48+
]
49+
),
50+
)
51+
52+
@override
53+
@classmethod
54+
def check_server_capability(
55+
cls,
56+
cap: lsp_type.ServerCapabilities,
57+
info: lsp_type.ServerInfo | None,
58+
) -> None:
59+
super().check_server_capability(cap, info)
60+
assert cap.inlay_hint_provider
61+
62+
def get_inlay_hint_label(
63+
self, hint: lsp_type.InlayHint | lsp_type.InlayHintLabelPart
64+
) -> str:
65+
"""Extract the text label from an InlayHint or InlayHintLabelPart."""
66+
match hint:
67+
case lsp_type.InlayHintLabelPart(value=value):
68+
return value
69+
case lsp_type.InlayHint(label=str() as label):
70+
return label
71+
case lsp_type.InlayHint(label=parts):
72+
return "".join(part.value for part in parts)
73+
case _:
74+
raise TypeError(f"Unexpected type for inlay hint label: {type(hint)}")
75+
76+
async def request_inlay_hint(
77+
self,
78+
file_path: AnyPath,
79+
range: lsp_type.Range,
80+
resolve: bool = False,
81+
) -> Sequence[lsp_type.InlayHint] | None:
82+
hints = await self.file_request(
83+
lsp_type.InlayHintRequest(
84+
id=jsonrpc_uuid(),
85+
params=lsp_type.InlayHintParams(
86+
text_document=lsp_type.TextDocumentIdentifier(
87+
uri=self.as_uri(file_path)
88+
),
89+
range=range,
90+
),
91+
),
92+
schema=lsp_type.InlayHintResponse,
93+
file_paths=[file_path],
94+
)
95+
96+
if resolve and hints:
97+
async with asyncer.create_task_group() as tg:
98+
tasks = [
99+
tg.soonify(self.request_inlay_hint_resolve)(hint) for hint in hints
100+
]
101+
return [task.value for task in tasks]
102+
103+
return hints
104+
105+
async def request_inlay_hint_resolve(
106+
self,
107+
hint: lsp_type.InlayHint,
108+
) -> lsp_type.InlayHint:
109+
return await self.request(
110+
lsp_type.InlayHintResolveRequest(
111+
id=jsonrpc_uuid(),
112+
params=hint,
113+
),
114+
schema=lsp_type.InlayHintResolveResponse,
115+
)

src/lsp_client/capability/server_request/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,23 @@
22

33
from typing import Final
44

5+
from .inlay_hint_refresh import WithRespondInlayHintRefresh
56
from .show_document_request import WithRespondShowDocumentRequest
67
from .show_message_request import WithRespondShowMessageRequest
78
from .workspace_configuration import WithRespondConfigurationRequest
89
from .workspace_folders import WithRespondWorkspaceFoldersRequest
910

1011
capabilities: Final = (
1112
WithRespondConfigurationRequest,
13+
WithRespondInlayHintRefresh,
1214
WithRespondShowDocumentRequest,
1315
WithRespondShowMessageRequest,
1416
WithRespondWorkspaceFoldersRequest,
1517
)
1618

1719
__all__ = [
1820
"WithRespondConfigurationRequest",
21+
"WithRespondInlayHintRefresh",
1922
"WithRespondShowDocumentRequest",
2023
"WithRespondShowMessageRequest",
2124
"WithRespondWorkspaceFoldersRequest",
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Sequence
4+
from typing import Protocol, override, runtime_checkable
5+
6+
from lsp_client.protocol import (
7+
CapabilityClientProtocol,
8+
ServerRequestHook,
9+
ServerRequestHookProtocol,
10+
ServerRequestHookRegistry,
11+
WorkspaceCapabilityProtocol,
12+
)
13+
from lsp_client.utils.types import lsp_type
14+
15+
16+
@runtime_checkable
17+
class WithRespondInlayHintRefresh(
18+
WorkspaceCapabilityProtocol,
19+
ServerRequestHookProtocol,
20+
CapabilityClientProtocol,
21+
Protocol,
22+
):
23+
"""
24+
`workspace/inlayHint/refresh` - https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_inlayHint_refresh
25+
"""
26+
27+
@override
28+
@classmethod
29+
def methods(cls) -> Sequence[str]:
30+
return (lsp_type.WORKSPACE_INLAY_HINT_REFRESH,)
31+
32+
@override
33+
@classmethod
34+
def register_workspace_capability(
35+
cls, cap: lsp_type.WorkspaceClientCapabilities
36+
) -> None:
37+
super().register_workspace_capability(cap)
38+
cap.inlay_hint = lsp_type.InlayHintWorkspaceClientCapabilities(
39+
refresh_support=True
40+
)
41+
42+
@override
43+
@classmethod
44+
def check_server_capability(
45+
cls,
46+
cap: lsp_type.ServerCapabilities,
47+
info: lsp_type.ServerInfo | None,
48+
) -> None:
49+
super().check_server_capability(cap, info)
50+
51+
async def respond_inlay_hint_refresh(
52+
self, req: lsp_type.InlayHintRefreshRequest
53+
) -> lsp_type.InlayHintRefreshResponse:
54+
return lsp_type.InlayHintRefreshResponse(
55+
id=req.id,
56+
result=None,
57+
)
58+
59+
@override
60+
def register_server_request_hooks(
61+
self, registry: ServerRequestHookRegistry
62+
) -> None:
63+
super().register_server_request_hooks(registry)
64+
registry.register(
65+
lsp_type.WORKSPACE_INLAY_HINT_REFRESH,
66+
ServerRequestHook(
67+
cls=lsp_type.InlayHintRefreshRequest,
68+
execute=self.respond_inlay_hint_refresh,
69+
),
70+
)

0 commit comments

Comments
 (0)