robotcode-language-server 0.92.0__tar.gz → 0.93.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/.gitignore +2 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/PKG-INFO +5 -5
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/pyproject.toml +4 -4
- robotcode_language_server-0.93.0/src/robotcode/language_server/__version__.py +1 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/cli.py +7 -1
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/diagnostics.py +133 -129
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/hover.py +15 -1
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/inlay_hint.py +2 -4
- robotcode_language_server-0.93.0/src/robotcode/language_server/robotframework/parts/robot_workspace.py +128 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/semantic_tokens.py +73 -24
- robotcode_language_server-0.92.0/src/robotcode/language_server/__version__.py +0 -1
- robotcode_language_server-0.92.0/src/robotcode/language_server/robotframework/parts/robot_workspace.py +0 -125
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/LICENSE.txt +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/README.md +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/__init__.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/__init__.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/decorators.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/__init__.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/code_action.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/code_lens.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/commands.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/completion.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/declaration.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/definition.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/document_highlight.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/document_symbols.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/documents.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/folding_range.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/formatting.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/hover.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/implementation.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/inlay_hint.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/inline_value.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/linked_editing_ranges.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/protocol_part.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/references.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/rename.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/selection_range.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/semantic_tokens.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/signature_help.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/window.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/parts/workspace.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/protocol.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/common/server.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/hooks.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/py.typed +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/__init__.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/configuration.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/__init__.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/code_action_documentation.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/code_action_helper_mixin.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/code_action_quick_fixes.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/code_action_refactor.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/code_lens.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/completion.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/debugging_utils.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/diagnostics.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/document_highlight.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/document_symbols.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/documents_cache.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/folding_range.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/formatting.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/goto.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/http_server.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/inline_value.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/keywords_treeview.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/project_info.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/protocol_part.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/references.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/rename.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/robocop_diagnostics.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/selection_range.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/parts/signature_help.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/protocol.py +0 -0
- {robotcode_language_server-0.92.0 → robotcode_language_server-0.93.0}/src/robotcode/language_server/robotframework/server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: robotcode-language-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.93.0
|
|
4
4
|
Summary: RobotCode Language Server for Robot Framework
|
|
5
5
|
Project-URL: Homepage, https://robotcode.io
|
|
6
6
|
Project-URL: Donate, https://opencollective.com/robotcode
|
|
@@ -25,10 +25,10 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
|
25
25
|
Classifier: Topic :: Utilities
|
|
26
26
|
Classifier: Typing :: Typed
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
|
-
Requires-Dist: robotcode-analyze==0.
|
|
29
|
-
Requires-Dist: robotcode-jsonrpc2==0.
|
|
30
|
-
Requires-Dist: robotcode-robot==0.
|
|
31
|
-
Requires-Dist: robotcode==0.
|
|
28
|
+
Requires-Dist: robotcode-analyze==0.93.0
|
|
29
|
+
Requires-Dist: robotcode-jsonrpc2==0.93.0
|
|
30
|
+
Requires-Dist: robotcode-robot==0.93.0
|
|
31
|
+
Requires-Dist: robotcode==0.93.0
|
|
32
32
|
Requires-Dist: robotframework>=4.1.0
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
|
|
@@ -27,10 +27,10 @@ classifiers = [
|
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
29
|
"robotframework>=4.1.0",
|
|
30
|
-
"robotcode-jsonrpc2==0.
|
|
31
|
-
"robotcode-robot==0.
|
|
32
|
-
"robotcode-analyze==0.
|
|
33
|
-
"robotcode==0.
|
|
30
|
+
"robotcode-jsonrpc2==0.93.0",
|
|
31
|
+
"robotcode-robot==0.93.0",
|
|
32
|
+
"robotcode-analyze==0.93.0",
|
|
33
|
+
"robotcode==0.93.0",
|
|
34
34
|
]
|
|
35
35
|
dynamic = ["version"]
|
|
36
36
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.93.0"
|
|
@@ -82,7 +82,13 @@ def language_server(
|
|
|
82
82
|
profile: Optional[RobotBaseProfile] = None
|
|
83
83
|
analysis_config: Optional[WorkspaceAnalysisConfig] = None
|
|
84
84
|
|
|
85
|
-
config_files, root_folder, _ = get_config_files(
|
|
85
|
+
config_files, root_folder, _ = get_config_files(
|
|
86
|
+
paths,
|
|
87
|
+
app.config.config_files,
|
|
88
|
+
root_folder=app.config.root,
|
|
89
|
+
no_vcs=app.config.no_vcs,
|
|
90
|
+
verbose_callback=app.verbose,
|
|
91
|
+
)
|
|
86
92
|
if root_folder:
|
|
87
93
|
os.chdir(root_folder)
|
|
88
94
|
|
|
@@ -65,12 +65,6 @@ class DiagnosticsResult:
|
|
|
65
65
|
skipped: bool = False
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
@dataclass
|
|
69
|
-
class WorkspaceDocumentsResult:
|
|
70
|
-
name: Optional[str]
|
|
71
|
-
document: TextDocument
|
|
72
|
-
|
|
73
|
-
|
|
74
68
|
@dataclass
|
|
75
69
|
class DiagnosticsData:
|
|
76
70
|
lock: RLock
|
|
@@ -158,7 +152,7 @@ class DiagnosticsProtocolPart(LanguageServerProtocolPart):
|
|
|
158
152
|
@event
|
|
159
153
|
def load_workspace_documents(
|
|
160
154
|
sender,
|
|
161
|
-
) ->
|
|
155
|
+
) -> None: ...
|
|
162
156
|
|
|
163
157
|
@event
|
|
164
158
|
def on_workspace_loaded(sender: Any) -> None: ...
|
|
@@ -362,72 +356,74 @@ class DiagnosticsProtocolPart(LanguageServerProtocolPart):
|
|
|
362
356
|
check_current_task_canceled(1)
|
|
363
357
|
continue
|
|
364
358
|
|
|
365
|
-
self._logger.
|
|
359
|
+
with self._logger.measure_time(
|
|
360
|
+
lambda: f"analyzing workspace for {len(documents)} documents",
|
|
361
|
+
context_name="workspace_diagnostics",
|
|
362
|
+
):
|
|
366
363
|
|
|
367
|
-
|
|
364
|
+
self.on_workspace_diagnostics_analyze(self)
|
|
368
365
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
366
|
+
if self._break_diagnostics_loop_event.is_set():
|
|
367
|
+
self._logger.debug("break workspace diagnostics loop 1", context_name="workspace_diagnostics")
|
|
368
|
+
self.on_workspace_diagnostics_break(self)
|
|
369
|
+
continue
|
|
373
370
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
371
|
+
with self.parent.window.progress(
|
|
372
|
+
"Analyze Workspace",
|
|
373
|
+
cancellable=False,
|
|
374
|
+
current=0,
|
|
375
|
+
max=len(documents),
|
|
376
|
+
start=False,
|
|
377
|
+
) as progress:
|
|
378
|
+
for i, document in enumerate(documents):
|
|
379
|
+
check_current_task_canceled()
|
|
380
|
+
|
|
381
|
+
if self._break_diagnostics_loop_event.is_set():
|
|
382
|
+
self._logger.debug(
|
|
383
|
+
"break workspace diagnostics loop 2", context_name="workspace_diagnostics"
|
|
384
|
+
)
|
|
385
|
+
self.on_workspace_diagnostics_break(self)
|
|
386
|
+
break
|
|
385
387
|
|
|
386
|
-
|
|
387
|
-
self._logger.debug("break workspace diagnostics loop 2")
|
|
388
|
-
self.on_workspace_diagnostics_break(self)
|
|
389
|
-
break
|
|
388
|
+
done_something = True
|
|
390
389
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
analysis_mode = self.get_analysis_progress_mode(document.uri)
|
|
394
|
-
|
|
395
|
-
if analysis_mode == AnalysisProgressMode.DETAILED:
|
|
396
|
-
progress.begin()
|
|
397
|
-
path = document.uri.to_path()
|
|
398
|
-
folder = self.parent.workspace.get_workspace_folder(document.uri)
|
|
399
|
-
name = path if folder is None else path.relative_to(folder.uri.to_path())
|
|
400
|
-
|
|
401
|
-
progress.report(f"Analyze {i+1}/{len(documents)}: {name}", current=i + 1)
|
|
402
|
-
elif analysis_mode == AnalysisProgressMode.SIMPLE:
|
|
403
|
-
progress.begin()
|
|
404
|
-
progress.report(f"Analyze {i+1}/{len(documents)}", current=i + 1)
|
|
405
|
-
|
|
406
|
-
try:
|
|
407
|
-
with self._current_diagnostics_task_lock:
|
|
408
|
-
self._current_diagnostics_task = run_as_task(self._analyse_document, document)
|
|
409
|
-
self._current_diagnostics_task.result(self._diagnostics_task_timeout)
|
|
410
|
-
|
|
411
|
-
except CancelledError:
|
|
412
|
-
self._logger.debug(lambda: f"Analyzing {document} cancelled")
|
|
413
|
-
except BaseException as e:
|
|
414
|
-
ex = e
|
|
415
|
-
self._logger.exception(
|
|
416
|
-
lambda: f"Error in analyzing ${document}: {ex}",
|
|
417
|
-
exc_info=ex,
|
|
418
|
-
)
|
|
419
|
-
finally:
|
|
420
|
-
with self._current_diagnostics_task_lock:
|
|
421
|
-
self._current_diagnostics_task = None
|
|
390
|
+
analysis_mode = self.get_analysis_progress_mode(document.uri)
|
|
422
391
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
392
|
+
if analysis_mode == AnalysisProgressMode.DETAILED:
|
|
393
|
+
progress.begin()
|
|
394
|
+
path = document.uri.to_path()
|
|
395
|
+
folder = self.parent.workspace.get_workspace_folder(document.uri)
|
|
396
|
+
name = path if folder is None else path.relative_to(folder.uri.to_path())
|
|
426
397
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
398
|
+
progress.report(f"Analyze {i+1}/{len(documents)}: {name}", current=i + 1)
|
|
399
|
+
elif analysis_mode == AnalysisProgressMode.SIMPLE:
|
|
400
|
+
progress.begin()
|
|
401
|
+
progress.report(f"Analyze {i+1}/{len(documents)}", current=i + 1)
|
|
402
|
+
|
|
403
|
+
try:
|
|
404
|
+
with self._current_diagnostics_task_lock:
|
|
405
|
+
self._current_diagnostics_task = run_as_task(self._analyse_document, document)
|
|
406
|
+
self._current_diagnostics_task.result(self._diagnostics_task_timeout)
|
|
407
|
+
|
|
408
|
+
except CancelledError:
|
|
409
|
+
self._logger.debug(
|
|
410
|
+
lambda: f"Analyzing {document.uri} cancelled", context_name="workspace_diagnostics"
|
|
411
|
+
)
|
|
412
|
+
except BaseException as e:
|
|
413
|
+
ex = e
|
|
414
|
+
self._logger.exception(
|
|
415
|
+
lambda: f"Error in analyzing ${document.uri}: {ex}",
|
|
416
|
+
exc_info=ex,
|
|
417
|
+
context_name="workspace_diagnostics",
|
|
418
|
+
)
|
|
419
|
+
finally:
|
|
420
|
+
with self._current_diagnostics_task_lock:
|
|
421
|
+
self._current_diagnostics_task = None
|
|
422
|
+
|
|
423
|
+
if self._break_diagnostics_loop_event.is_set():
|
|
424
|
+
self._logger.debug("break workspace diagnostics loop 3", context_name="workspace_diagnostics")
|
|
425
|
+
self.on_workspace_diagnostics_break(self)
|
|
426
|
+
continue
|
|
431
427
|
|
|
432
428
|
self.on_workspace_diagnostics_collect(self)
|
|
433
429
|
|
|
@@ -437,78 +433,86 @@ class DiagnosticsProtocolPart(LanguageServerProtocolPart):
|
|
|
437
433
|
if doc.opened_in_editor or self.get_diagnostics_mode(document.uri) == DiagnosticsMode.WORKSPACE
|
|
438
434
|
]
|
|
439
435
|
|
|
440
|
-
|
|
441
|
-
|
|
436
|
+
with self._logger.measure_time(
|
|
437
|
+
lambda: f"collect workspace diagnostic for {len(documents_to_collect)} documents",
|
|
438
|
+
context_name="collect_workspace_diagnostics",
|
|
439
|
+
):
|
|
442
440
|
|
|
443
|
-
|
|
444
|
-
self._logger.debug("break workspace diagnostics loop 4")
|
|
445
|
-
self.on_workspace_diagnostics_break(self)
|
|
446
|
-
break
|
|
447
|
-
|
|
448
|
-
self.reset_document_diagnostics_data(document)
|
|
449
|
-
|
|
450
|
-
start = time.monotonic()
|
|
451
|
-
with self.parent.window.progress(
|
|
452
|
-
"Collect Diagnostics",
|
|
453
|
-
cancellable=False,
|
|
454
|
-
current=0,
|
|
455
|
-
max=len(documents_to_collect),
|
|
456
|
-
start=False,
|
|
457
|
-
) as progress:
|
|
458
|
-
for i, document in enumerate(documents_to_collect):
|
|
459
|
-
self._logger.debug(lambda: f"Collect diagnostics for {document}")
|
|
441
|
+
for document in set(documents) - set(documents_to_collect):
|
|
460
442
|
check_current_task_canceled()
|
|
461
443
|
|
|
462
444
|
if self._break_diagnostics_loop_event.is_set():
|
|
463
|
-
self._logger.debug("break workspace diagnostics loop
|
|
445
|
+
self._logger.debug("break workspace diagnostics loop 4")
|
|
464
446
|
self.on_workspace_diagnostics_break(self)
|
|
465
447
|
break
|
|
466
448
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
name = path if folder is None else path.relative_to(folder.uri.to_path())
|
|
481
|
-
|
|
482
|
-
progress.report(f"Collect {i+1}/{len(documents_to_collect)}: {name}", current=i + 1)
|
|
483
|
-
elif analysis_mode == AnalysisProgressMode.SIMPLE:
|
|
484
|
-
progress.begin()
|
|
485
|
-
progress.report(f"Collect {i+1}/{len(documents_to_collect)}", current=i + 1)
|
|
486
|
-
|
|
487
|
-
try:
|
|
488
|
-
with self._current_diagnostics_task_lock:
|
|
489
|
-
self._current_diagnostics_task = self.create_document_diagnostics_task(
|
|
490
|
-
document,
|
|
491
|
-
False,
|
|
492
|
-
mode == DiagnosticsMode.WORKSPACE or document.opened_in_editor,
|
|
493
|
-
)
|
|
494
|
-
if self._current_diagnostics_task is not None:
|
|
495
|
-
self._current_diagnostics_task.result(self._diagnostics_task_timeout)
|
|
496
|
-
except CancelledError:
|
|
497
|
-
self._logger.debug(lambda: f"Collecting diagnostics for {document} cancelled")
|
|
498
|
-
except BaseException as e:
|
|
499
|
-
ex = e
|
|
500
|
-
self._logger.exception(
|
|
501
|
-
lambda: f"Error getting diagnostics for ${document}: {ex}",
|
|
502
|
-
exc_info=ex,
|
|
449
|
+
self.reset_document_diagnostics_data(document)
|
|
450
|
+
|
|
451
|
+
with self.parent.window.progress(
|
|
452
|
+
"Collect Diagnostics",
|
|
453
|
+
cancellable=False,
|
|
454
|
+
current=0,
|
|
455
|
+
max=len(documents_to_collect),
|
|
456
|
+
start=False,
|
|
457
|
+
) as progress:
|
|
458
|
+
for i, document in enumerate(documents_to_collect):
|
|
459
|
+
self._logger.debug(
|
|
460
|
+
lambda: f"collect diagnostics for {document.uri}",
|
|
461
|
+
context_name="collect_workspace_diagnostics",
|
|
503
462
|
)
|
|
504
|
-
|
|
505
|
-
with self._current_diagnostics_task_lock:
|
|
506
|
-
self._current_diagnostics_task = None
|
|
463
|
+
check_current_task_canceled()
|
|
507
464
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
465
|
+
if self._break_diagnostics_loop_event.is_set():
|
|
466
|
+
self._logger.debug(
|
|
467
|
+
"break workspace diagnostics loop 5", context_name="collect_workspace_diagnostics"
|
|
468
|
+
)
|
|
469
|
+
self.on_workspace_diagnostics_break(self)
|
|
470
|
+
break
|
|
471
|
+
|
|
472
|
+
mode = self.get_diagnostics_mode(document.uri)
|
|
473
|
+
if mode == DiagnosticsMode.OFF:
|
|
474
|
+
self.reset_document_diagnostics_data(document)
|
|
475
|
+
continue
|
|
476
|
+
|
|
477
|
+
done_something = True
|
|
478
|
+
|
|
479
|
+
analysis_mode = self.get_analysis_progress_mode(document.uri)
|
|
480
|
+
|
|
481
|
+
if analysis_mode == AnalysisProgressMode.DETAILED:
|
|
482
|
+
progress.begin()
|
|
483
|
+
path = document.uri.to_path()
|
|
484
|
+
folder = self.parent.workspace.get_workspace_folder(document.uri)
|
|
485
|
+
name = path if folder is None else path.relative_to(folder.uri.to_path())
|
|
486
|
+
|
|
487
|
+
progress.report(f"Collect {i+1}/{len(documents_to_collect)}: {name}", current=i + 1)
|
|
488
|
+
elif analysis_mode == AnalysisProgressMode.SIMPLE:
|
|
489
|
+
progress.begin()
|
|
490
|
+
progress.report(f"Collect {i+1}/{len(documents_to_collect)}", current=i + 1)
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
with self._current_diagnostics_task_lock:
|
|
494
|
+
self._current_diagnostics_task = self.create_document_diagnostics_task(
|
|
495
|
+
document,
|
|
496
|
+
False,
|
|
497
|
+
mode == DiagnosticsMode.WORKSPACE or document.opened_in_editor,
|
|
498
|
+
)
|
|
499
|
+
if self._current_diagnostics_task is not None:
|
|
500
|
+
self._current_diagnostics_task.result(self._diagnostics_task_timeout)
|
|
501
|
+
except CancelledError:
|
|
502
|
+
self._logger.debug(
|
|
503
|
+
lambda: f"Collecting diagnostics for {document.uri} cancelled",
|
|
504
|
+
context_name="collect_workspace_diagnostics",
|
|
505
|
+
)
|
|
506
|
+
except BaseException as e:
|
|
507
|
+
ex = e
|
|
508
|
+
self._logger.exception(
|
|
509
|
+
lambda: f"Error getting diagnostics for ${document.uri}: {ex}",
|
|
510
|
+
exc_info=ex,
|
|
511
|
+
context_name="collect_workspace_diagnostics",
|
|
512
|
+
)
|
|
513
|
+
finally:
|
|
514
|
+
with self._current_diagnostics_task_lock:
|
|
515
|
+
self._current_diagnostics_task = None
|
|
512
516
|
|
|
513
517
|
except (SystemExit, KeyboardInterrupt, CancelledError):
|
|
514
518
|
raise
|
|
@@ -184,11 +184,19 @@ class RobotHoverProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
184
184
|
)
|
|
185
185
|
|
|
186
186
|
if found_range is not None:
|
|
187
|
-
|
|
187
|
+
txt = kw.to_markdown()
|
|
188
|
+
if kw.libtype == "RESOURCE":
|
|
189
|
+
txt = namespace.imports_manager.replace_variables_scalar(
|
|
190
|
+
txt,
|
|
191
|
+
str(document.uri.to_path().parent),
|
|
192
|
+
namespace.get_resolvable_variables(nodes, position),
|
|
193
|
+
)
|
|
194
|
+
result.append((found_range, txt))
|
|
188
195
|
if result:
|
|
189
196
|
r = result[0][0]
|
|
190
197
|
if all(r == i[0] for i in result):
|
|
191
198
|
doc = "\n\n---\n\n".join(i[1] for i in result)
|
|
199
|
+
|
|
192
200
|
return Hover(
|
|
193
201
|
contents=MarkupContent(kind=MarkupKind.MARKDOWN, value=doc),
|
|
194
202
|
range=r,
|
|
@@ -233,6 +241,7 @@ class RobotHoverProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
233
241
|
document: TextDocument,
|
|
234
242
|
position: Position,
|
|
235
243
|
) -> Optional[Hover]:
|
|
244
|
+
namespace = self.parent.documents_cache.get_namespace(document)
|
|
236
245
|
test_case = cast(TestCase, node)
|
|
237
246
|
|
|
238
247
|
if not position.is_in_range(range_from_node(test_case.header)):
|
|
@@ -259,6 +268,11 @@ class RobotHoverProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
259
268
|
txt += "\n*Tags*: "
|
|
260
269
|
txt += f"{', '.join(tags.values)}\n"
|
|
261
270
|
|
|
271
|
+
txt = namespace.imports_manager.replace_variables_scalar(
|
|
272
|
+
txt,
|
|
273
|
+
str(document.uri.to_path().parent),
|
|
274
|
+
namespace.get_resolvable_variables(nodes, position),
|
|
275
|
+
)
|
|
262
276
|
return Hover(
|
|
263
277
|
contents=MarkupContent(kind=MarkupKind.MARKDOWN, value=MarkDownFormatter().format(txt)),
|
|
264
278
|
range=range_from_token(name_token),
|
|
@@ -329,8 +329,7 @@ class RobotInlayHintProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
329
329
|
|
|
330
330
|
except (SystemExit, KeyboardInterrupt):
|
|
331
331
|
raise
|
|
332
|
-
except BaseException
|
|
333
|
-
self._logger.exception(e)
|
|
332
|
+
except BaseException:
|
|
334
333
|
return None
|
|
335
334
|
|
|
336
335
|
arguments = library_node.get_tokens(RobotToken.ARGUMENT)
|
|
@@ -373,8 +372,7 @@ class RobotInlayHintProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
373
372
|
|
|
374
373
|
except (SystemExit, KeyboardInterrupt):
|
|
375
374
|
raise
|
|
376
|
-
except BaseException
|
|
377
|
-
self._logger.exception(e)
|
|
375
|
+
except BaseException:
|
|
378
376
|
return None
|
|
379
377
|
|
|
380
378
|
arguments = library_node.get_tokens(RobotToken.ARGUMENT)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from concurrent.futures import CancelledError
|
|
2
|
+
from logging import CRITICAL
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from threading import Event
|
|
5
|
+
from typing import TYPE_CHECKING, Any, List, Optional
|
|
6
|
+
|
|
7
|
+
from robotcode.core.ignore_spec import DEFAULT_SPEC_RULES, GIT_IGNORE_FILE, ROBOT_IGNORE_FILE, IgnoreSpec, iter_files
|
|
8
|
+
from robotcode.core.language import language_id
|
|
9
|
+
from robotcode.core.uri import Uri
|
|
10
|
+
from robotcode.core.utils.logging import LoggingDescriptor
|
|
11
|
+
from robotcode.jsonrpc2.protocol import rpc_method
|
|
12
|
+
from robotcode.language_server.common.parts.diagnostics import (
|
|
13
|
+
AnalysisProgressMode,
|
|
14
|
+
DiagnosticsMode,
|
|
15
|
+
)
|
|
16
|
+
from robotcode.language_server.robotframework.configuration import AnalysisConfig
|
|
17
|
+
from robotcode.robot.diagnostics.library_doc import (
|
|
18
|
+
RESOURCE_FILE_EXTENSION,
|
|
19
|
+
ROBOT_FILE_EXTENSION,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from ..configuration import RobotCodeConfig
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from ..protocol import RobotLanguageServerProtocol
|
|
26
|
+
|
|
27
|
+
from .protocol_part import RobotLanguageServerProtocolPart
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CantReadDocumentError(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RobotWorkspaceProtocolPart(RobotLanguageServerProtocolPart):
|
|
35
|
+
_logger = LoggingDescriptor()
|
|
36
|
+
|
|
37
|
+
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
38
|
+
super().__init__(parent)
|
|
39
|
+
self.parent.documents.on_read_document_text.add(self.on_read_document_text)
|
|
40
|
+
self.parent.diagnostics.load_workspace_documents.add(self.load_workspace_documents)
|
|
41
|
+
self.parent.diagnostics.on_get_diagnostics_mode.add(self.on_get_diagnostics_mode)
|
|
42
|
+
self.parent.diagnostics.on_get_analysis_progress_mode.add(self.on_get_analysis_progress_mode)
|
|
43
|
+
self.documents_loaded = Event()
|
|
44
|
+
|
|
45
|
+
@language_id("robotframework")
|
|
46
|
+
def on_read_document_text(self, sender: Any, uri: Uri) -> Optional[str]:
|
|
47
|
+
from robot.utils import FileReader
|
|
48
|
+
|
|
49
|
+
with FileReader(uri.to_path()) as reader:
|
|
50
|
+
return str(reader.read())
|
|
51
|
+
|
|
52
|
+
def on_get_diagnostics_mode(self, sender: Any, uri: Uri) -> Optional[DiagnosticsMode]:
|
|
53
|
+
config = self.parent.workspace.get_configuration(AnalysisConfig, uri)
|
|
54
|
+
return config.diagnostic_mode
|
|
55
|
+
|
|
56
|
+
def on_get_analysis_progress_mode(self, sender: Any, uri: Uri) -> Optional[AnalysisProgressMode]:
|
|
57
|
+
config = self.parent.workspace.get_configuration(AnalysisConfig, uri)
|
|
58
|
+
return config.progress_mode
|
|
59
|
+
|
|
60
|
+
def load_workspace_documents(self, sender: Any) -> None:
|
|
61
|
+
with self._logger.measure_time(lambda: "loading workspace documents", context_name="load_workspace_documents"):
|
|
62
|
+
try:
|
|
63
|
+
result: List[Path] = []
|
|
64
|
+
|
|
65
|
+
for folder in self.parent.workspace.workspace_folders:
|
|
66
|
+
config = self.parent.workspace.get_configuration(RobotCodeConfig, folder.uri)
|
|
67
|
+
|
|
68
|
+
extensions = [ROBOT_FILE_EXTENSION, RESOURCE_FILE_EXTENSION]
|
|
69
|
+
with self.parent.window.progress("Collect sources", cancellable=False):
|
|
70
|
+
files = list(
|
|
71
|
+
filter(
|
|
72
|
+
lambda f: f.suffix in extensions,
|
|
73
|
+
iter_files(
|
|
74
|
+
folder.uri.to_path(),
|
|
75
|
+
ignore_files=[ROBOT_IGNORE_FILE, GIT_IGNORE_FILE],
|
|
76
|
+
include_hidden=False,
|
|
77
|
+
parent_spec=IgnoreSpec.from_list(
|
|
78
|
+
[*DEFAULT_SPEC_RULES, *(config.workspace.exclude_patterns or [])],
|
|
79
|
+
folder.uri.to_path(),
|
|
80
|
+
),
|
|
81
|
+
verbose_callback=self._logger.debug,
|
|
82
|
+
verbose_trace=False,
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
result.extend(files)
|
|
88
|
+
|
|
89
|
+
canceled = False
|
|
90
|
+
with self.parent.window.progress(
|
|
91
|
+
"Load workspace", current=0, max=len(files), start=False, cancellable=False
|
|
92
|
+
) as progress:
|
|
93
|
+
for i, f in enumerate(files):
|
|
94
|
+
try:
|
|
95
|
+
self.parent.documents.get_or_open_document(f)
|
|
96
|
+
|
|
97
|
+
if config.analysis.progress_mode != AnalysisProgressMode.OFF:
|
|
98
|
+
name = f.relative_to(folder.uri.to_path())
|
|
99
|
+
|
|
100
|
+
progress.begin()
|
|
101
|
+
progress.report(
|
|
102
|
+
(
|
|
103
|
+
f"Load {name!s}"
|
|
104
|
+
if config.analysis.progress_mode == AnalysisProgressMode.DETAILED
|
|
105
|
+
else None
|
|
106
|
+
),
|
|
107
|
+
current=i,
|
|
108
|
+
)
|
|
109
|
+
except (SystemExit, KeyboardInterrupt):
|
|
110
|
+
raise
|
|
111
|
+
except CancelledError:
|
|
112
|
+
canceled = True
|
|
113
|
+
break
|
|
114
|
+
except BaseException as e:
|
|
115
|
+
ex = e
|
|
116
|
+
self._logger.exception(
|
|
117
|
+
lambda: f"Can't load document {f}: {ex}",
|
|
118
|
+
level=CRITICAL,
|
|
119
|
+
context_name="load_workspace_documents",
|
|
120
|
+
)
|
|
121
|
+
finally:
|
|
122
|
+
if canceled:
|
|
123
|
+
self._logger.info(lambda: "Workspace loading canceled")
|
|
124
|
+
|
|
125
|
+
@rpc_method(name="robot/cache/clear", threaded=True)
|
|
126
|
+
def robot_cache_clear(self) -> None:
|
|
127
|
+
for folder in self.parent.workspace.workspace_folders:
|
|
128
|
+
self.parent.documents_cache.get_imports_manager_for_workspace_folder(folder).clear_cache()
|
|
@@ -21,8 +21,10 @@ from typing import (
|
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
from robot.parsing.lexer.tokens import Token
|
|
24
|
+
from robot.parsing.model.blocks import Section
|
|
24
25
|
from robot.parsing.model.statements import (
|
|
25
26
|
Arguments,
|
|
27
|
+
Documentation,
|
|
26
28
|
Fixture,
|
|
27
29
|
KeywordCall,
|
|
28
30
|
LibraryImport,
|
|
@@ -62,6 +64,7 @@ from robotcode.robot.diagnostics.model_helper import ModelHelper
|
|
|
62
64
|
from robotcode.robot.diagnostics.namespace import DEFAULT_BDD_PREFIXES, Namespace
|
|
63
65
|
from robotcode.robot.utils import get_robot_version
|
|
64
66
|
from robotcode.robot.utils.ast import (
|
|
67
|
+
cached_isinstance,
|
|
65
68
|
iter_nodes,
|
|
66
69
|
iter_over_keyword_names_and_owners,
|
|
67
70
|
token_in_range,
|
|
@@ -72,6 +75,9 @@ from .protocol_part import RobotLanguageServerProtocolPart
|
|
|
72
75
|
if get_robot_version() >= (5, 0):
|
|
73
76
|
from robot.parsing.model.statements import ExceptHeader, WhileHeader
|
|
74
77
|
|
|
78
|
+
if get_robot_version() >= (7, 0):
|
|
79
|
+
from robot.parsing.model.blocks import InvalidSection
|
|
80
|
+
|
|
75
81
|
if TYPE_CHECKING:
|
|
76
82
|
from ..protocol import RobotLanguageServerProtocol
|
|
77
83
|
|
|
@@ -120,6 +126,7 @@ class RobotSemTokenTypes(Enum):
|
|
|
120
126
|
|
|
121
127
|
class RobotSemTokenModifiers(Enum):
|
|
122
128
|
BUILTIN = "builtin"
|
|
129
|
+
EMBEDDED = "embedded"
|
|
123
130
|
|
|
124
131
|
|
|
125
132
|
@dataclass
|
|
@@ -340,6 +347,7 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
340
347
|
node: ast.AST,
|
|
341
348
|
col_offset: Optional[int] = None,
|
|
342
349
|
length: Optional[int] = None,
|
|
350
|
+
yield_arguments: bool = False,
|
|
343
351
|
) -> Iterator[SemTokenInfo]:
|
|
344
352
|
sem_info = cls.mapping().get(token.type, None) if token.type is not None else None
|
|
345
353
|
if sem_info is not None:
|
|
@@ -391,7 +399,7 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
391
399
|
yield SemTokenInfo.from_token(token, sem_type, sem_mod)
|
|
392
400
|
|
|
393
401
|
elif token.type in [Token.KEYWORD, ROBOT_KEYWORD_INNER] or (
|
|
394
|
-
token.type == Token.NAME and
|
|
402
|
+
token.type == Token.NAME and cached_isinstance(node, Fixture, Template, TestTemplate)
|
|
395
403
|
):
|
|
396
404
|
if (
|
|
397
405
|
namespace.find_keyword(
|
|
@@ -461,6 +469,9 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
461
469
|
|
|
462
470
|
kw_index = len(kw_namespace) + 1 if kw_namespace else 0
|
|
463
471
|
|
|
472
|
+
if token.type == Token.NAME and kw_doc is not None:
|
|
473
|
+
sem_type = RobotSemTokenTypes.KEYWORD
|
|
474
|
+
|
|
464
475
|
if kw_namespace:
|
|
465
476
|
kw = token.value[kw_index:]
|
|
466
477
|
|
|
@@ -501,13 +512,25 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
501
512
|
col_offset + kw_index + start,
|
|
502
513
|
arg_start - start,
|
|
503
514
|
)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
515
|
+
|
|
516
|
+
embedded_token = Token(
|
|
517
|
+
Token.ARGUMENT,
|
|
518
|
+
token.value[arg_start:arg_end],
|
|
519
|
+
token.lineno,
|
|
520
|
+
token.col_offset + arg_start,
|
|
510
521
|
)
|
|
522
|
+
|
|
523
|
+
for sub_token in ModelHelper.tokenize_variables(
|
|
524
|
+
embedded_token,
|
|
525
|
+
ignore_errors=True,
|
|
526
|
+
identifiers="$@&%",
|
|
527
|
+
):
|
|
528
|
+
for e in cls.generate_sem_sub_tokens(
|
|
529
|
+
namespace, builtin_library_doc, sub_token, node, yield_arguments=True
|
|
530
|
+
):
|
|
531
|
+
e.sem_modifiers = {RobotSemTokenModifiers.EMBEDDED}
|
|
532
|
+
yield e
|
|
533
|
+
|
|
511
534
|
start = arg_end + 1
|
|
512
535
|
|
|
513
536
|
if start < end:
|
|
@@ -521,7 +544,7 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
521
544
|
|
|
522
545
|
else:
|
|
523
546
|
yield SemTokenInfo.from_token(token, sem_type, sem_mod, col_offset + kw_index, len(kw))
|
|
524
|
-
elif token.type == Token.NAME and
|
|
547
|
+
elif token.type == Token.NAME and cached_isinstance(node, LibraryImport, ResourceImport, VariablesImport):
|
|
525
548
|
if "\\" in token.value:
|
|
526
549
|
if col_offset is None:
|
|
527
550
|
col_offset = token.col_offset
|
|
@@ -543,7 +566,9 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
543
566
|
length,
|
|
544
567
|
)
|
|
545
568
|
elif get_robot_version() >= (5, 0) and token.type == Token.OPTION:
|
|
546
|
-
if (
|
|
569
|
+
if (
|
|
570
|
+
cached_isinstance(node, ExceptHeader) or cached_isinstance(node, WhileHeader)
|
|
571
|
+
) and "=" in token.value:
|
|
547
572
|
if col_offset is None:
|
|
548
573
|
col_offset = token.col_offset
|
|
549
574
|
|
|
@@ -589,7 +614,12 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
589
614
|
1,
|
|
590
615
|
)
|
|
591
616
|
else:
|
|
592
|
-
if
|
|
617
|
+
if (
|
|
618
|
+
yield_arguments
|
|
619
|
+
or token.type != Token.ARGUMENT
|
|
620
|
+
or token.type != Token.NAME
|
|
621
|
+
and cached_isinstance(node, Metadata)
|
|
622
|
+
):
|
|
593
623
|
yield SemTokenInfo.from_token(token, sem_type, sem_mod, col_offset, length)
|
|
594
624
|
|
|
595
625
|
def generate_sem_tokens(
|
|
@@ -602,25 +632,25 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
602
632
|
if (
|
|
603
633
|
token.type in {Token.ARGUMENT, Token.TESTCASE_NAME, Token.KEYWORD_NAME}
|
|
604
634
|
or token.type == Token.NAME
|
|
605
|
-
and
|
|
635
|
+
and cached_isinstance(node, VariablesImport, LibraryImport, ResourceImport)
|
|
606
636
|
):
|
|
607
|
-
if (
|
|
608
|
-
|
|
609
|
-
):
|
|
637
|
+
if (
|
|
638
|
+
cached_isinstance(node, Variable) and token.type == Token.ARGUMENT and node.name and node.name[0] == "&"
|
|
639
|
+
) or (cached_isinstance(node, Arguments)):
|
|
610
640
|
name, value = split_from_equals(token.value)
|
|
611
641
|
if value is not None:
|
|
612
642
|
length = len(name)
|
|
613
643
|
|
|
614
644
|
yield SemTokenInfo.from_token(
|
|
615
645
|
Token(
|
|
616
|
-
ROBOT_NAMED_ARGUMENT if
|
|
646
|
+
ROBOT_NAMED_ARGUMENT if cached_isinstance(node, Variable) else SemanticTokenTypes.PARAMETER,
|
|
617
647
|
name,
|
|
618
648
|
token.lineno,
|
|
619
649
|
token.col_offset,
|
|
620
650
|
),
|
|
621
651
|
(
|
|
622
652
|
RobotSemTokenTypes.NAMED_ARGUMENT
|
|
623
|
-
if
|
|
653
|
+
if cached_isinstance(node, Variable)
|
|
624
654
|
else SemanticTokenTypes.PARAMETER
|
|
625
655
|
),
|
|
626
656
|
)
|
|
@@ -640,7 +670,7 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
640
670
|
token.col_offset + length + 1,
|
|
641
671
|
token.error,
|
|
642
672
|
)
|
|
643
|
-
elif
|
|
673
|
+
elif cached_isinstance(node, Arguments) and name:
|
|
644
674
|
yield SemTokenInfo.from_token(
|
|
645
675
|
Token(
|
|
646
676
|
ROBOT_NAMED_ARGUMENT,
|
|
@@ -663,11 +693,13 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
663
693
|
ignore_errors=True,
|
|
664
694
|
identifiers="$" if token.type == Token.KEYWORD_NAME else "$@&%",
|
|
665
695
|
):
|
|
666
|
-
for e in self.generate_sem_sub_tokens(
|
|
696
|
+
for e in self.generate_sem_sub_tokens(
|
|
697
|
+
namespace, builtin_library_doc, sub_token, node, yield_arguments=True
|
|
698
|
+
):
|
|
667
699
|
yield e
|
|
668
700
|
|
|
669
701
|
else:
|
|
670
|
-
for e in self.generate_sem_sub_tokens(namespace, builtin_library_doc, token, node):
|
|
702
|
+
for e in self.generate_sem_sub_tokens(namespace, builtin_library_doc, token, node, yield_arguments=True):
|
|
671
703
|
yield e
|
|
672
704
|
|
|
673
705
|
def generate_run_kw_tokens(
|
|
@@ -953,11 +985,19 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
953
985
|
last_col = 0
|
|
954
986
|
|
|
955
987
|
def get_tokens() -> Iterator[Tuple[Token, ast.AST]]:
|
|
988
|
+
current_section: Optional[Section] = None
|
|
989
|
+
in_invalid_section = False
|
|
990
|
+
|
|
956
991
|
for node in iter_nodes(model):
|
|
992
|
+
if cached_isinstance(node, Section):
|
|
993
|
+
current_section = node
|
|
994
|
+
if get_robot_version() >= (7, 0):
|
|
995
|
+
in_invalid_section = cached_isinstance(current_section, InvalidSection)
|
|
996
|
+
|
|
957
997
|
check_current_task_canceled()
|
|
958
998
|
|
|
959
|
-
if
|
|
960
|
-
if
|
|
999
|
+
if cached_isinstance(node, Statement):
|
|
1000
|
+
if cached_isinstance(node, LibraryImport) and node.name:
|
|
961
1001
|
lib_doc = namespace.get_imported_library_libdoc(node.name, node.args, node.alias)
|
|
962
1002
|
kw_doc = lib_doc.inits.keywords[0] if lib_doc and lib_doc.inits else None
|
|
963
1003
|
if lib_doc is not None:
|
|
@@ -1009,7 +1049,7 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
1009
1049
|
|
|
1010
1050
|
yield token, node
|
|
1011
1051
|
continue
|
|
1012
|
-
if
|
|
1052
|
+
if cached_isinstance(node, VariablesImport) and node.name:
|
|
1013
1053
|
lib_doc = namespace.get_imported_variables_libdoc(node.name, node.args)
|
|
1014
1054
|
kw_doc = lib_doc.inits.keywords[0] if lib_doc and lib_doc.inits else None
|
|
1015
1055
|
if lib_doc is not None:
|
|
@@ -1061,12 +1101,12 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
1061
1101
|
|
|
1062
1102
|
yield token, node
|
|
1063
1103
|
continue
|
|
1064
|
-
if
|
|
1104
|
+
if cached_isinstance(node, KeywordCall, Fixture):
|
|
1065
1105
|
kw_token = cast(
|
|
1066
1106
|
Token,
|
|
1067
1107
|
(
|
|
1068
1108
|
node.get_token(Token.KEYWORD)
|
|
1069
|
-
if
|
|
1109
|
+
if cached_isinstance(node, KeywordCall)
|
|
1070
1110
|
else node.get_token(Token.NAME)
|
|
1071
1111
|
),
|
|
1072
1112
|
)
|
|
@@ -1109,8 +1149,16 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
1109
1149
|
yield kw_res
|
|
1110
1150
|
|
|
1111
1151
|
continue
|
|
1152
|
+
if cached_isinstance(node, Documentation):
|
|
1153
|
+
for token in node.tokens:
|
|
1154
|
+
if token.type == Token.ARGUMENT:
|
|
1155
|
+
continue
|
|
1156
|
+
yield token, node
|
|
1157
|
+
continue
|
|
1112
1158
|
|
|
1113
1159
|
for token in node.tokens:
|
|
1160
|
+
if not in_invalid_section and token.type == Token.COMMENT:
|
|
1161
|
+
continue
|
|
1114
1162
|
yield token, node
|
|
1115
1163
|
|
|
1116
1164
|
lines = document.get_lines()
|
|
@@ -1136,6 +1184,7 @@ class RobotSemanticTokenProtocolPart(RobotLanguageServerProtocolPart):
|
|
|
1136
1184
|
),
|
|
1137
1185
|
),
|
|
1138
1186
|
)
|
|
1187
|
+
|
|
1139
1188
|
token_col_offset = token_range.start.character
|
|
1140
1189
|
token_length = token_range.end.character - token_range.start.character
|
|
1141
1190
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.92.0"
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from concurrent.futures import CancelledError
|
|
3
|
-
from logging import CRITICAL
|
|
4
|
-
from threading import Event
|
|
5
|
-
from typing import TYPE_CHECKING, Any, List, Optional
|
|
6
|
-
|
|
7
|
-
from robotcode.core.ignore_spec import DEFAULT_SPEC_RULES, GIT_IGNORE_FILE, ROBOT_IGNORE_FILE, IgnoreSpec, iter_files
|
|
8
|
-
from robotcode.core.language import language_id
|
|
9
|
-
from robotcode.core.uri import Uri
|
|
10
|
-
from robotcode.core.utils.logging import LoggingDescriptor
|
|
11
|
-
from robotcode.jsonrpc2.protocol import rpc_method
|
|
12
|
-
from robotcode.language_server.common.parts.diagnostics import (
|
|
13
|
-
AnalysisProgressMode,
|
|
14
|
-
DiagnosticsMode,
|
|
15
|
-
WorkspaceDocumentsResult,
|
|
16
|
-
)
|
|
17
|
-
from robotcode.language_server.robotframework.configuration import AnalysisConfig
|
|
18
|
-
from robotcode.robot.diagnostics.library_doc import (
|
|
19
|
-
RESOURCE_FILE_EXTENSION,
|
|
20
|
-
ROBOT_FILE_EXTENSION,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
from ..configuration import RobotCodeConfig
|
|
24
|
-
|
|
25
|
-
if TYPE_CHECKING:
|
|
26
|
-
from ..protocol import RobotLanguageServerProtocol
|
|
27
|
-
|
|
28
|
-
from .protocol_part import RobotLanguageServerProtocolPart
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class CantReadDocumentError(Exception):
|
|
32
|
-
pass
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class RobotWorkspaceProtocolPart(RobotLanguageServerProtocolPart):
|
|
36
|
-
_logger = LoggingDescriptor()
|
|
37
|
-
|
|
38
|
-
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
39
|
-
super().__init__(parent)
|
|
40
|
-
self.parent.documents.on_read_document_text.add(self.on_read_document_text)
|
|
41
|
-
self.parent.diagnostics.load_workspace_documents.add(self.load_workspace_documents)
|
|
42
|
-
self.parent.diagnostics.on_get_diagnostics_mode.add(self.on_get_diagnostics_mode)
|
|
43
|
-
self.parent.diagnostics.on_get_analysis_progress_mode.add(self.on_get_analysis_progress_mode)
|
|
44
|
-
self.documents_loaded = Event()
|
|
45
|
-
|
|
46
|
-
@language_id("robotframework")
|
|
47
|
-
def on_read_document_text(self, sender: Any, uri: Uri) -> Optional[str]:
|
|
48
|
-
from robot.utils import FileReader
|
|
49
|
-
|
|
50
|
-
with FileReader(uri.to_path()) as reader:
|
|
51
|
-
return str(reader.read())
|
|
52
|
-
|
|
53
|
-
def on_get_diagnostics_mode(self, sender: Any, uri: Uri) -> Optional[DiagnosticsMode]:
|
|
54
|
-
config = self.parent.workspace.get_configuration(AnalysisConfig, uri)
|
|
55
|
-
return config.diagnostic_mode
|
|
56
|
-
|
|
57
|
-
def on_get_analysis_progress_mode(self, sender: Any, uri: Uri) -> Optional[AnalysisProgressMode]:
|
|
58
|
-
config = self.parent.workspace.get_configuration(AnalysisConfig, uri)
|
|
59
|
-
return config.progress_mode
|
|
60
|
-
|
|
61
|
-
def load_workspace_documents(self, sender: Any) -> List[WorkspaceDocumentsResult]:
|
|
62
|
-
start = time.monotonic()
|
|
63
|
-
try:
|
|
64
|
-
result: List[WorkspaceDocumentsResult] = []
|
|
65
|
-
|
|
66
|
-
for folder in self.parent.workspace.workspace_folders:
|
|
67
|
-
config = self.parent.workspace.get_configuration(RobotCodeConfig, folder.uri)
|
|
68
|
-
|
|
69
|
-
extensions = [ROBOT_FILE_EXTENSION, RESOURCE_FILE_EXTENSION]
|
|
70
|
-
with self.parent.window.progress("Collect sources", cancellable=False):
|
|
71
|
-
files = list(
|
|
72
|
-
filter(
|
|
73
|
-
lambda f: f.suffix in extensions,
|
|
74
|
-
iter_files(
|
|
75
|
-
folder.uri.to_path(),
|
|
76
|
-
ignore_files=[ROBOT_IGNORE_FILE, GIT_IGNORE_FILE],
|
|
77
|
-
include_hidden=False,
|
|
78
|
-
parent_spec=IgnoreSpec.from_list(
|
|
79
|
-
[*DEFAULT_SPEC_RULES, *(config.workspace.exclude_patterns or [])],
|
|
80
|
-
folder.uri.to_path(),
|
|
81
|
-
),
|
|
82
|
-
),
|
|
83
|
-
)
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
canceled = False
|
|
87
|
-
with self.parent.window.progress(
|
|
88
|
-
"Load workspace", current=0, max=len(files), start=False, cancellable=False
|
|
89
|
-
) as progress:
|
|
90
|
-
for i, f in enumerate(files):
|
|
91
|
-
try:
|
|
92
|
-
self.parent.documents.get_or_open_document(f)
|
|
93
|
-
|
|
94
|
-
if config.analysis.progress_mode != AnalysisProgressMode.OFF:
|
|
95
|
-
name = f.relative_to(folder.uri.to_path())
|
|
96
|
-
|
|
97
|
-
progress.begin()
|
|
98
|
-
progress.report(
|
|
99
|
-
(
|
|
100
|
-
f"Load {name!s}"
|
|
101
|
-
if config.analysis.progress_mode == AnalysisProgressMode.DETAILED
|
|
102
|
-
else None
|
|
103
|
-
),
|
|
104
|
-
current=i,
|
|
105
|
-
)
|
|
106
|
-
except (SystemExit, KeyboardInterrupt):
|
|
107
|
-
raise
|
|
108
|
-
except CancelledError:
|
|
109
|
-
canceled = True
|
|
110
|
-
break
|
|
111
|
-
except BaseException as e:
|
|
112
|
-
ex = e
|
|
113
|
-
self._logger.exception(lambda: f"Can't load document {f}: {ex}", level=CRITICAL)
|
|
114
|
-
|
|
115
|
-
if canceled:
|
|
116
|
-
return []
|
|
117
|
-
|
|
118
|
-
return result
|
|
119
|
-
finally:
|
|
120
|
-
self._logger.info(lambda: f"Workspace loaded {len(result)} documents in {time.monotonic() - start}s")
|
|
121
|
-
|
|
122
|
-
@rpc_method(name="robot/cache/clear", threaded=True)
|
|
123
|
-
def robot_cache_clear(self) -> None:
|
|
124
|
-
for folder in self.parent.workspace.workspace_folders:
|
|
125
|
-
self.parent.documents_cache.get_imports_manager_for_workspace_folder(folder).clear_cache()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|