Skip to content

Commit cd4f72d

Browse files
committed
implement semantic tokens
1 parent f684bb7 commit cd4f72d

File tree

8 files changed

+454
-181
lines changed

8 files changed

+454
-181
lines changed

package.json

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,81 @@
3939
"onDebugResolve:robotframework",
4040
"onLanguage:robotframework"
4141
],
42-
"preview": true,
4342
"galleryBanner": {
4443
"theme": "dark",
45-
"color": "#000000"
44+
"color": "#111111"
4645
},
4746
"main": "./out/extension.js",
4847
"contributes": {
48+
"configurationDefaults": {
49+
"[robotframework]": {
50+
"editor.semanticHighlighting.enabled": true
51+
}
52+
},
53+
"semanticTokenScopes": [
54+
{
55+
"language": "robotframework",
56+
"scopes": {
57+
"header": [
58+
"keyword.other.header.robotframework"
59+
],
60+
"headerComment": [
61+
"keyword.other.header.comment.robotframework"
62+
],
63+
"headerKeyword": [
64+
"keyword.other.header.keyword.robotframework"
65+
],
66+
"headerSetting": [
67+
"keyword.other.header.setting.robotframework"
68+
],
69+
"headerVariable": [
70+
"keyword.other.header.variable.robotframework"
71+
],
72+
"headerTestcase": [
73+
"keyword.other.header.testcase.robotframework"
74+
],
75+
"setting": [
76+
"keyword.control.settings.robotframework"
77+
],
78+
"settingImport": [
79+
"keyword.control.import.robotframework"
80+
],
81+
"testcaseName": [
82+
"entity.name.function.testcase.name.robotframework"
83+
],
84+
"keywordName": [
85+
"entity.name.function.keyword.name.robotframework"
86+
],
87+
"controlFlow": [
88+
"keyword.control.flow.robotframework"
89+
],
90+
"forSeparator": [
91+
"keyword.operator.for.robotframework"
92+
],
93+
"argument": [
94+
"string.unquoted.argument.robotframework"
95+
],
96+
"variable": [
97+
"variable.other.readwrite.robotframework"
98+
],
99+
"keywordCall": [
100+
"meta.function-call.keyword.robotframework"
101+
],
102+
"nameCall": [
103+
"meta.function-call.name.robotframework"
104+
],
105+
"continuation": [
106+
"punctuation.separator.continuation.robotframework"
107+
],
108+
"separator": [
109+
"punctuation.separator.robotframework"
110+
],
111+
"terminator": [
112+
"punctuation.terminator.robotframework"
113+
]
114+
}
115+
}
116+
],
49117
"languages": [
50118
{
51119
"id": "robotframework",
@@ -418,7 +486,7 @@
418486
"devDependencies": {
419487
"@types/glob": "^7.1.4",
420488
"@types/mocha": "^9.0.0",
421-
"@types/node": "^16.9.4",
489+
"@types/node": "^16.9.6",
422490
"@types/vscode": "^1.60.0",
423491
"@typescript-eslint/eslint-plugin": "^4.31.2",
424492
"@typescript-eslint/parser": "^4.31.2",
@@ -434,13 +502,13 @@
434502
"eslint-plugin-promise": "^5.1.0",
435503
"eslint-plugin-react": "^7.26.0",
436504
"eslint-plugin-react-hooks": "^4.2.0",
437-
"glob": "^7.1.7",
505+
"glob": "^7.2.0",
438506
"mocha": "^9.1.1",
439507
"prettier": "^2.4.1",
440508
"replace-in-file": "^6.2.0",
441509
"ts-loader": "^9.2.6",
442510
"typescript": "^4.4.3",
443-
"vsce": "^1.99.0",
511+
"vsce": "^1.100.0",
444512
"vscode-debugadapter-testsupport": "^1.49.0",
445513
"vscode-dts": "^0.3.1",
446514
"vscode-test": "^1.6.1",

robotcode/language_server/common/parts/semantic_tokens.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
7070
token_types=[e.value for e in self.token_types],
7171
token_modifiers=[e.value for e in self.token_modifiers],
7272
),
73-
full=SemanticTokensOptionsFull(delta=len(self.collect_full_delta) > 0)
73+
full=SemanticTokensOptionsFull(delta=True if len(self.collect_full_delta) > 0 else False)
7474
if len(self.collect_full)
75-
else None,
76-
range=SemanticTokensOptionsRange() if len(self.collect_range) else None,
75+
else False,
76+
range=SemanticTokensOptionsRange() if len(self.collect_range) else False,
7777
)
7878

7979
@rpc_method(name="textDocument/semanticTokens/full", param_type=SemanticTokensParams)

robotcode/language_server/common/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,7 @@ class SemanticTokensRangeParams(WorkDoneProgressParams, PartialResultParams):
14221422

14231423

14241424
class SemanticTokenTypes(Enum):
1425+
NAMESPACE = "namespace"
14251426
TYPE = "type"
14261427
CLASS = "class"
14271428
ENUM = "enum"

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@
3333
Position,
3434
Range,
3535
)
36-
from ..utils.ast import Token as AstToken
37-
from ..utils.ast import is_non_variable_token, range_from_token_or_node
36+
from ..utils.ast import Token, is_non_variable_token, range_from_token_or_node
3837
from ..utils.async_ast import AsyncVisitor
3938
from .imports_manager import ImportsManager
4039
from .library_doc import (
@@ -61,13 +60,6 @@ class ImportError(DiagnosticsError):
6160
pass
6261

6362

64-
@dataclass
65-
class Token:
66-
line_no: int
67-
col_offset: int
68-
end_col_offset: int
69-
70-
7163
@dataclass
7264
class Import:
7365
name: Optional[str]
@@ -81,11 +73,11 @@ class Import:
8173
def range(self) -> Range:
8274
return Range(
8375
start=Position(
84-
line=self.name_token.line_no - 1 if self.name_token is not None else self.line_no - 1,
76+
line=self.name_token.lineno - 1 if self.name_token is not None else self.line_no - 1,
8577
character=self.name_token.col_offset if self.name_token is not None else self.col_offset,
8678
),
8779
end=Position(
88-
line=self.name_token.line_no - 1 if self.name_token is not None else self.end_line_no - 1,
80+
line=self.name_token.lineno - 1 if self.name_token is not None else self.end_line_no - 1,
8981
character=self.name_token.end_col_offset if self.name_token is not None else self.end_col_offset,
9082
),
9183
)
@@ -171,9 +163,7 @@ async def visit_LibraryImport(self, node: ast.AST) -> None: # noqa: N802
171163
self._results.append(
172164
LibraryImport(
173165
name=n.name,
174-
name_token=Token(line_no=name.lineno, col_offset=name.col_offset, end_col_offset=name.end_col_offset)
175-
if name is not None
176-
else None,
166+
name_token=name if name is not None else None,
177167
args=n.args,
178168
alias=n.alias,
179169
line_no=node.lineno,
@@ -194,9 +184,7 @@ async def visit_ResourceImport(self, node: ast.AST) -> None: # noqa: N802
194184
self._results.append(
195185
ResourceImport(
196186
name=n.name,
197-
name_token=Token(line_no=name.lineno, col_offset=name.col_offset, end_col_offset=name.end_col_offset)
198-
if name is not None
199-
else None,
187+
name_token=name if name is not None else None,
200188
line_no=node.lineno,
201189
col_offset=node.col_offset,
202190
end_line_no=node.end_lineno if node.end_lineno is not None else -1,
@@ -217,9 +205,7 @@ async def visit_VariablesImport(self, node: ast.AST) -> None: # noqa: N802
217205
self._results.append(
218206
VariablesImport(
219207
name=n.name,
220-
name_token=Token(line_no=name.lineno, col_offset=name.col_offset, end_col_offset=name.end_col_offset)
221-
if name is not None
222-
else None,
208+
name_token=name if name is not None else None,
223209
args=n.args,
224210
line_no=node.lineno,
225211
col_offset=node.col_offset,
@@ -244,8 +230,8 @@ async def _analyze_keyword_call(
244230
self,
245231
keyword: Optional[str],
246232
value: ast.AST,
247-
keyword_token: AstToken,
248-
argument_tokens: List[AstToken],
233+
keyword_token: Token,
234+
argument_tokens: List[Token],
249235
analyse_run_keywords: bool = True,
250236
) -> Optional[KeywordDoc]:
251237
result: Optional[KeywordDoc] = None
@@ -351,8 +337,8 @@ async def _analyze_keyword_call(
351337
return result
352338

353339
async def _analyse_run_keyword(
354-
self, keyword_doc: Optional[KeywordDoc], node: ast.AST, argument_tokens: List[AstToken]
355-
) -> List[AstToken]:
340+
self, keyword_doc: Optional[KeywordDoc], node: ast.AST, argument_tokens: List[Token]
341+
) -> List[Token]:
356342

357343
if keyword_doc is None or not keyword_doc.is_any_run_keyword():
358344
return argument_tokens
@@ -445,11 +431,13 @@ async def visit_Fixture(self, node: ast.AST) -> None: # noqa: N802
445431
from robot.parsing.model.statements import Fixture
446432

447433
value = cast(Fixture, node)
448-
keyword_token = cast(AstToken, value.get_token(RobotToken.NAME))
434+
keyword_token = cast(Token, value.get_token(RobotToken.NAME))
435+
436+
# TODO: calculate possible variables in NAME
449437

450-
if keyword_token is not None:
438+
if keyword_token is not None and is_non_variable_token(keyword_token):
451439
await self._analyze_keyword_call(
452-
value.name, value, keyword_token, [cast(AstToken, e) for e in value.get_tokens(RobotToken.ARGUMENT)]
440+
value.name, value, keyword_token, [cast(Token, e) for e in value.get_tokens(RobotToken.ARGUMENT)]
453441
)
454442

455443
await self.generic_visit(node)
@@ -459,9 +447,11 @@ async def visit_TestTemplate(self, node: ast.AST) -> None: # noqa: N802
459447
from robot.parsing.model.statements import TestTemplate
460448

461449
value = cast(TestTemplate, node)
462-
keyword_token = cast(AstToken, value.get_token(RobotToken.NAME))
450+
keyword_token = cast(Token, value.get_token(RobotToken.NAME))
463451

464-
if keyword_token is not None:
452+
# TODO: calculate possible variables in NAME
453+
454+
if keyword_token is not None and is_non_variable_token(keyword_token):
465455
await self._analyze_keyword_call(value.value, value, keyword_token, [])
466456

467457
await self.generic_visit(node)
@@ -471,9 +461,11 @@ async def visit_Template(self, node: ast.AST) -> None: # noqa: N802
471461
from robot.parsing.model.statements import Template
472462

473463
value = cast(Template, node)
474-
keyword_token = cast(AstToken, value.get_token(RobotToken.NAME))
464+
keyword_token = cast(Token, value.get_token(RobotToken.NAME))
465+
466+
# TODO: calculate possible variables in NAME
475467

476-
if keyword_token is not None:
468+
if keyword_token is not None and is_non_variable_token(keyword_token):
477469
await self._analyze_keyword_call(value.value, value, keyword_token, [])
478470

479471
await self.generic_visit(node)
@@ -497,7 +489,7 @@ async def visit_KeywordCall(self, node: ast.AST) -> None: # noqa: N802
497489
)
498490
else:
499491
await self._analyze_keyword_call(
500-
value.keyword, value, keyword_token, [cast(AstToken, e) for e in value.get_tokens(RobotToken.ARGUMENT)]
492+
value.keyword, value, keyword_token, [cast(Token, e) for e in value.get_tokens(RobotToken.ARGUMENT)]
501493
)
502494

503495
if not self.current_testcase_or_keyword_name:

0 commit comments

Comments
 (0)