Skip to content

Commit 755daf7

Browse files
committed
refactor(langserver): remove async code from document_highlight and document_symbols, add regression tests for document_symbols
1 parent b76eb0f commit 755daf7

File tree

292 files changed

+6737
-52
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

292 files changed

+6737
-52
lines changed

packages/language_server/src/robotcode/language_server/common/parts/document_highlight.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
from __future__ import annotations
2-
3-
from asyncio import CancelledError
1+
from concurrent.futures import CancelledError
42
from typing import TYPE_CHECKING, Any, Final, List, Optional
53

6-
from robotcode.core.async_tools import async_tasking_event
4+
from robotcode.core.event import event
75
from robotcode.core.lsp.types import (
86
DocumentHighlight,
97
DocumentHighlightOptions,
@@ -26,22 +24,20 @@
2624
class DocumentHighlightProtocolPart(LanguageServerProtocolPart):
2725
_logger: Final = LoggingDescriptor()
2826

29-
def __init__(self, parent: LanguageServerProtocol) -> None:
27+
def __init__(self, parent: "LanguageServerProtocol") -> None:
3028
super().__init__(parent)
3129

3230
def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
3331
if len(self.collect):
3432
capabilities.document_highlight_provider = DocumentHighlightOptions(work_done_progress=True)
3533

36-
@async_tasking_event
37-
async def collect(
38-
sender, document: TextDocument, position: Position # NOSONAR
39-
) -> Optional[List[DocumentHighlight]]:
34+
@event
35+
def collect(sender, document: TextDocument, position: Position) -> Optional[List[DocumentHighlight]]: # NOSONAR
4036
...
4137

4238
@rpc_method(name="textDocument/documentHighlight", param_type=DocumentHighlightParams)
4339
@threaded
44-
async def _text_document_document_highlight(
40+
def _text_document_document_highlight(
4541
self,
4642
text_document: TextDocumentIdentifier,
4743
position: Position,
@@ -54,7 +50,7 @@ async def _text_document_document_highlight(
5450
if document is None:
5551
return None
5652

57-
for result in await self.collect(
53+
for result in self.collect(
5854
self, document, document.position_from_utf16(position), callback_filter=language_id_filter(document)
5955
):
6056
if isinstance(result, BaseException):

packages/language_server/src/robotcode/language_server/common/parts/document_symbols.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
from __future__ import annotations
2-
3-
from asyncio import CancelledError
1+
from concurrent.futures import CancelledError
42
from typing import (
53
TYPE_CHECKING,
64
Any,
75
Callable,
86
Final,
7+
Iterable,
98
List,
109
Optional,
1110
Protocol,
@@ -15,7 +14,7 @@
1514
runtime_checkable,
1615
)
1716

18-
from robotcode.core.async_tools import async_tasking_event
17+
from robotcode.core.event import event
1918
from robotcode.core.lsp.types import (
2019
DocumentSymbol,
2120
DocumentSymbolClientCapabilitiesSymbolKindType,
@@ -56,14 +55,14 @@ def decorator(func: _F) -> _F:
5655
class DocumentSymbolsProtocolPart(LanguageServerProtocolPart):
5756
_logger: Final = LoggingDescriptor()
5857

59-
def __init__(self, parent: LanguageServerProtocol) -> None:
58+
def __init__(self, parent: "LanguageServerProtocol") -> None:
6059
super().__init__(parent)
6160
self.hierarchical_document_symbol_support = False
6261
self.symbol_kind: Optional[DocumentSymbolClientCapabilitiesSymbolKindType] = None
6362
self.tag_support: Optional[DocumentSymbolClientCapabilitiesTagSupportType] = None
6463

65-
@async_tasking_event
66-
async def collect(
64+
@event
65+
def collect(
6766
sender, document: TextDocument # NOSONAR
6867
) -> Optional[Union[List[DocumentSymbol], List[SymbolInformation], None]]:
6968
...
@@ -97,7 +96,7 @@ def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
9796

9897
@rpc_method(name="textDocument/documentSymbol", param_type=DocumentSymbolParams)
9998
@threaded
100-
async def _text_document_symbol(
99+
def _text_document_symbol(
101100
self, text_document: TextDocumentIdentifier, *args: Any, **kwargs: Any
102101
) -> Optional[Union[List[DocumentSymbol], List[SymbolInformation], None]]:
103102
document_symbols: List[DocumentSymbol] = []
@@ -107,16 +106,16 @@ async def _text_document_symbol(
107106
if document is None:
108107
return None
109108

110-
for result in await self.collect(self, document, callback_filter=language_id_filter(document)):
109+
for result in self.collect(self, document, callback_filter=language_id_filter(document)):
111110
if isinstance(result, BaseException):
112111
if not isinstance(result, CancelledError):
113112
self._logger.exception(result, exc_info=result)
114113
else:
115114
if result is not None:
116115
if all(isinstance(e, DocumentSymbol) for e in result):
117-
document_symbols.extend(result)
116+
document_symbols.extend(cast(Iterable[DocumentSymbol], result))
118117
elif all(isinstance(e, SymbolInformation) for e in result):
119-
symbol_informations.extend(result)
118+
symbol_informations.extend(cast(Iterable[SymbolInformation], result))
120119
else:
121120
self._logger.warning(
122121
"Result contains DocumentSymbol and SymbolInformation results, result is skipped."

packages/language_server/src/robotcode/language_server/robotframework/parts/document_highlight.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
from __future__ import annotations
2-
31
from typing import TYPE_CHECKING, Any, List, Optional, cast
42

53
from robotcode.core.lsp.types import DocumentHighlight, DocumentHighlightKind, Position, Range
64
from robotcode.core.utils.logging import LoggingDescriptor
5+
from robotcode.core.utils.threading import check_thread_canceled
76
from robotcode.language_server.common.decorators import language_id
87
from robotcode.language_server.common.text_document import TextDocument
98

@@ -16,14 +15,14 @@
1615
class RobotDocumentHighlightProtocolPart(RobotLanguageServerProtocolPart):
1716
_logger = LoggingDescriptor()
1817

19-
def __init__(self, parent: RobotLanguageServerProtocol) -> None:
18+
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
2019
super().__init__(parent)
2120

2221
parent.document_highlight.collect.add(self.collect)
2322

2423
@language_id("robotframework")
2524
@_logger.call
26-
async def collect(
25+
def collect(
2726
self,
2827
sender: Any,
2928
document: TextDocument,
@@ -34,6 +33,8 @@ async def collect(
3433
all_variable_refs = namespace.get_variable_references()
3534
if all_variable_refs:
3635
for var, var_refs in all_variable_refs.items():
36+
check_thread_canceled()
37+
3738
for r in var_refs:
3839
if (var.source == namespace.source and position in var.name_range) or position in r.range:
3940
return [
@@ -48,6 +49,8 @@ async def collect(
4849
all_kw_refs = namespace.get_keyword_references()
4950
if all_kw_refs:
5051
for kw, kw_refs in all_kw_refs.items():
52+
check_thread_canceled()
53+
5154
for r in kw_refs:
5255
if (kw.source == namespace.source and position in kw.range) or position in r.range:
5356
return [
@@ -62,6 +65,7 @@ async def collect(
6265
all_namespace_refs = namespace.get_namespace_references()
6366
if all_namespace_refs:
6467
for ns, ns_refs in all_namespace_refs.items():
68+
check_thread_canceled()
6569
found_range = (
6670
ns.import_range
6771
if ns.import_source == namespace.source

packages/language_server/src/robotcode/language_server/robotframework/parts/document_symbols.py

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from __future__ import annotations
2-
31
import ast
42
import itertools
53
from typing import TYPE_CHECKING, Any, List, Optional, Union, cast
@@ -18,6 +16,22 @@
1816
from ..protocol import RobotLanguageServerProtocol
1917

2018

19+
class RobotDocumentSymbolsProtocolPart(RobotLanguageServerProtocolPart):
20+
_logger = LoggingDescriptor()
21+
22+
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
23+
super().__init__(parent)
24+
25+
parent.document_symbols.collect.add(self.collect)
26+
27+
@language_id("robotframework")
28+
@_logger.call
29+
def collect(
30+
self, sender: Any, document: TextDocument
31+
) -> Optional[Union[List[DocumentSymbol], List[SymbolInformation], None]]:
32+
return _Visitor.find_from(self.parent.documents_cache.get_model(document), self)
33+
34+
2135
class _Visitor(Visitor):
2236
def __init__(self, parent: RobotDocumentSymbolsProtocolPart) -> None:
2337
super().__init__()
@@ -179,6 +193,42 @@ def visit_ForHeader(self, node: ast.AST) -> None: # noqa: N802
179193
if symbol.name not in map(lambda v: v.name, self.current_symbol.children):
180194
self.current_symbol.children.append(symbol)
181195

196+
def visit_ExceptHeader(self, node: ast.AST) -> None: # noqa: N802
197+
from robot.parsing.lexer.tokens import Token as RobotToken
198+
from robot.parsing.model.statements import ExceptHeader
199+
200+
n = cast(ExceptHeader, node)
201+
variables = n.get_tokens(RobotToken.VARIABLE)
202+
203+
if self.current_symbol is not None and self.current_symbol.children is not None:
204+
for variable in variables:
205+
variable_token = self.get_variable_token(variable)
206+
if variable_token is not None:
207+
r = range_from_token(variable_token)
208+
symbol = DocumentSymbol(
209+
name=variable_token.value, kind=SymbolKind.VARIABLE, range=r, selection_range=r
210+
)
211+
if symbol.name not in map(lambda v: v.name, self.current_symbol.children):
212+
self.current_symbol.children.append(symbol)
213+
214+
def visit_Var(self, node: ast.AST) -> None: # noqa: N802
215+
from robot.parsing.lexer.tokens import Token as RobotToken
216+
from robot.parsing.model.statements import Var
217+
218+
n = cast(Var, node)
219+
variables = n.get_tokens(RobotToken.VARIABLE)
220+
221+
if self.current_symbol is not None and self.current_symbol.children is not None:
222+
for variable in variables:
223+
variable_token = self.get_variable_token(variable)
224+
if variable_token is not None:
225+
r = range_from_token(variable_token)
226+
symbol = DocumentSymbol(
227+
name=variable_token.value, kind=SymbolKind.VARIABLE, range=r, selection_range=r
228+
)
229+
if symbol.name not in map(lambda v: v.name, self.current_symbol.children):
230+
self.current_symbol.children.append(symbol)
231+
182232
def visit_KeywordName(self, node: ast.AST) -> None: # noqa: N802
183233
from robot.parsing.lexer.tokens import Token as RobotToken
184234
from robot.parsing.model.statements import KeywordName
@@ -226,19 +276,3 @@ def visit_Variable(self, node: ast.AST) -> None: # noqa: N802
226276
r = range_from_node(variable)
227277
symbol = DocumentSymbol(name=name, kind=SymbolKind.VARIABLE, range=r, selection_range=r)
228278
self.current_symbol.children.append(symbol)
229-
230-
231-
class RobotDocumentSymbolsProtocolPart(RobotLanguageServerProtocolPart):
232-
_logger = LoggingDescriptor()
233-
234-
def __init__(self, parent: RobotLanguageServerProtocol) -> None:
235-
super().__init__(parent)
236-
237-
parent.document_symbols.collect.add(self.collect)
238-
239-
@language_id("robotframework")
240-
@_logger.call
241-
async def collect(
242-
self, sender: Any, document: TextDocument
243-
) -> Optional[Union[List[DocumentSymbol], List[SymbolInformation], None]]:
244-
return _Visitor.find_from(self.parent.documents_cache.get_model(document), self)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
data: !GeneratedTestData
2+
character: 1
3+
line: 0
4+
name: settings section
5+
result: !DocumentSymbol
6+
children: []
7+
deprecated: null
8+
detail: null
9+
kind: 3
10+
name: Settings
11+
range:
12+
end:
13+
character: 22
14+
line: 2
15+
start:
16+
character: 0
17+
line: 0
18+
selection_range:
19+
end:
20+
character: 22
21+
line: 2
22+
start:
23+
character: 0
24+
line: 0
25+
tags: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
data: !GeneratedTestData
2+
character: 8
3+
line: 0
4+
name: settings section
5+
result: !DocumentSymbol
6+
children: []
7+
deprecated: null
8+
detail: null
9+
kind: 3
10+
name: Settings
11+
range:
12+
end:
13+
character: 22
14+
line: 2
15+
start:
16+
character: 0
17+
line: 0
18+
selection_range:
19+
end:
20+
character: 22
21+
line: 2
22+
start:
23+
character: 0
24+
line: 0
25+
tags: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
data: !GeneratedTestData
2+
character: 15
3+
line: 0
4+
name: settings section
5+
result: !DocumentSymbol
6+
children: []
7+
deprecated: null
8+
detail: null
9+
kind: 3
10+
name: Settings
11+
range:
12+
end:
13+
character: 22
14+
line: 2
15+
start:
16+
character: 0
17+
line: 0
18+
selection_range:
19+
end:
20+
character: 22
21+
line: 2
22+
start:
23+
character: 0
24+
line: 0
25+
tags: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
data: !GeneratedTestData
2+
character: 1
3+
line: 4
4+
name: variables section
5+
result: !DocumentSymbol
6+
children: []
7+
deprecated: null
8+
detail: null
9+
kind: 3
10+
name: Variables
11+
range:
12+
end:
13+
character: 13
14+
line: 6
15+
start:
16+
character: 0
17+
line: 4
18+
selection_range:
19+
end:
20+
character: 13
21+
line: 6
22+
start:
23+
character: 0
24+
line: 4
25+
tags: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
data: !GeneratedTestData
2+
character: 8
3+
line: 4
4+
name: variables section
5+
result: !DocumentSymbol
6+
children: []
7+
deprecated: null
8+
detail: null
9+
kind: 3
10+
name: Variables
11+
range:
12+
end:
13+
character: 13
14+
line: 6
15+
start:
16+
character: 0
17+
line: 4
18+
selection_range:
19+
end:
20+
character: 13
21+
line: 6
22+
start:
23+
character: 0
24+
line: 4
25+
tags: null

0 commit comments

Comments
 (0)