robotcode-language-server 2.6.2__py3-none-any.whl → 2.8.0.dev548__py3-none-any.whl
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/__version__.py +1 -1
- robotcode/language_server/common/parts/diagnostics.py +50 -17
- robotcode/language_server/common/parts/documents.py +34 -31
- robotcode/language_server/common/parts/workspace.py +57 -55
- robotcode/language_server/common/protocol.py +3 -1
- robotcode/language_server/robotframework/configuration.py +3 -0
- robotcode/language_server/robotframework/parts/code_action_documentation.py +440 -129
- robotcode/language_server/robotframework/parts/code_action_helper_mixin.py +17 -2
- robotcode/language_server/robotframework/parts/code_action_quick_fixes.py +6 -25
- robotcode/language_server/robotframework/parts/code_action_refactor.py +8 -6
- robotcode/language_server/robotframework/parts/code_lens.py +3 -4
- robotcode/language_server/robotframework/parts/completion.py +193 -21
- robotcode/language_server/robotframework/parts/debugging_utils.py +75 -6
- robotcode/language_server/robotframework/parts/diagnostics.py +15 -3
- robotcode/language_server/robotframework/parts/documents_cache.py +5 -1
- robotcode/language_server/robotframework/parts/hover.py +103 -21
- robotcode/language_server/robotframework/parts/http_server.py +17 -7
- robotcode/language_server/robotframework/parts/inline_value.py +69 -7
- robotcode/language_server/robotframework/parts/keywords_treeview.py +151 -53
- robotcode/language_server/robotframework/parts/model_variables.py +331 -0
- robotcode/language_server/robotframework/parts/references.py +47 -31
- robotcode/language_server/robotframework/parts/rename.py +1 -2
- robotcode/language_server/robotframework/parts/robot_workspace.py +229 -25
- robotcode/language_server/robotframework/parts/selection_range.py +26 -13
- robotcode/language_server/robotframework/parts/semantic_tokens.py +414 -113
- robotcode/language_server/robotframework/parts/signature_help.py +162 -70
- robotcode/language_server/robotframework/protocol.py +1 -0
- {robotcode_language_server-2.6.2.dist-info → robotcode_language_server-2.8.0.dev548.dist-info}/METADATA +7 -6
- {robotcode_language_server-2.6.2.dist-info → robotcode_language_server-2.8.0.dev548.dist-info}/RECORD +31 -30
- {robotcode_language_server-2.6.2.dist-info → robotcode_language_server-2.8.0.dev548.dist-info}/WHEEL +1 -1
- {robotcode_language_server-2.6.2.dist-info → robotcode_language_server-2.8.0.dev548.dist-info}/entry_points.txt +0 -0
|
@@ -2,9 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import List, Optional, Tuple
|
|
5
|
+
from typing import List, Optional, Tuple, Union
|
|
6
6
|
|
|
7
|
-
from robotcode.core.lsp.types import DocumentUri, Position, Range
|
|
7
|
+
from robotcode.core.lsp.types import CodeActionContext, CodeActionKind, DocumentUri, Position, Range
|
|
8
8
|
from robotcode.core.text_document import TextDocument
|
|
9
9
|
from robotcode.robot.diagnostics.namespace import Namespace
|
|
10
10
|
from robotcode.robot.utils.ast import range_from_node
|
|
@@ -13,6 +13,21 @@ from robotcode.robot.utils.visitor import Visitor
|
|
|
13
13
|
SHOW_DOCUMENT_SELECT_AND_RENAME_COMMAND = "_robotcode.codeActionShowDocumentSelectAndRename"
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def code_action_kind_requested(context: CodeActionContext, kind: Union[CodeActionKind, str]) -> bool:
|
|
17
|
+
"""Whether a code action request with `context` asks for code actions of `kind`.
|
|
18
|
+
|
|
19
|
+
Without `only` it asks for every kind. With `only` it asks for the listed kinds and the kinds below them, since
|
|
20
|
+
the LSP defines kinds hierarchically: `refactor` also takes `refactor.extract.function`.
|
|
21
|
+
"""
|
|
22
|
+
if not context.only:
|
|
23
|
+
return True
|
|
24
|
+
value = kind.value if isinstance(kind, CodeActionKind) else kind
|
|
25
|
+
return any(
|
|
26
|
+
value == requested or value.startswith(f"{requested}.")
|
|
27
|
+
for requested in (o.value if isinstance(o, CodeActionKind) else o for o in context.only)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
16
31
|
@dataclass
|
|
17
32
|
class CodeActionDataBase:
|
|
18
33
|
type: str
|
|
@@ -38,7 +38,6 @@ from robotcode.core.lsp.types import (
|
|
|
38
38
|
CodeActionContext,
|
|
39
39
|
CodeActionDisabledType,
|
|
40
40
|
CodeActionKind,
|
|
41
|
-
CodeActionTriggerKind,
|
|
42
41
|
Command,
|
|
43
42
|
OptionalVersionedTextDocumentIdentifier,
|
|
44
43
|
Position,
|
|
@@ -73,6 +72,7 @@ from .code_action_helper_mixin import (
|
|
|
73
72
|
CodeActionDataBase,
|
|
74
73
|
CodeActionHelperMixin,
|
|
75
74
|
FindSectionsVisitor,
|
|
75
|
+
code_action_kind_requested,
|
|
76
76
|
)
|
|
77
77
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
78
78
|
|
|
@@ -177,10 +177,7 @@ class RobotCodeActionQuickFixesProtocolPart(RobotLanguageServerProtocolPart, Mod
|
|
|
177
177
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
178
178
|
result: List[Union[Command, CodeAction]] = []
|
|
179
179
|
|
|
180
|
-
if (context
|
|
181
|
-
CodeActionTriggerKind.INVOKED,
|
|
182
|
-
CodeActionTriggerKind.AUTOMATIC,
|
|
183
|
-
]:
|
|
180
|
+
if code_action_kind_requested(context, CodeActionKind.QUICK_FIX):
|
|
184
181
|
namespace = self.parent.documents_cache.get_namespace(document)
|
|
185
182
|
|
|
186
183
|
for diagnostic in (
|
|
@@ -388,14 +385,7 @@ class RobotCodeActionQuickFixesProtocolPart(RobotLanguageServerProtocolPart, Mod
|
|
|
388
385
|
if (
|
|
389
386
|
range.start.line == range.end.line
|
|
390
387
|
and range.start.character <= range.end.character
|
|
391
|
-
and (
|
|
392
|
-
(context.only and CodeActionKind.QUICK_FIX in context.only)
|
|
393
|
-
or context.trigger_kind
|
|
394
|
-
in [
|
|
395
|
-
CodeActionTriggerKind.INVOKED,
|
|
396
|
-
CodeActionTriggerKind.AUTOMATIC,
|
|
397
|
-
]
|
|
398
|
-
)
|
|
388
|
+
and code_action_kind_requested(context, CodeActionKind.QUICK_FIX)
|
|
399
389
|
):
|
|
400
390
|
all_diagnostics = [d for d in context.diagnostics if d.source and d.source.startswith("robotcode.")]
|
|
401
391
|
if all_diagnostics:
|
|
@@ -471,10 +461,7 @@ class RobotCodeActionQuickFixesProtocolPart(RobotLanguageServerProtocolPart, Mod
|
|
|
471
461
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
472
462
|
result: List[Union[Command, CodeAction]] = []
|
|
473
463
|
|
|
474
|
-
if (context
|
|
475
|
-
CodeActionTriggerKind.INVOKED,
|
|
476
|
-
CodeActionTriggerKind.AUTOMATIC,
|
|
477
|
-
]:
|
|
464
|
+
if code_action_kind_requested(context, CodeActionKind.QUICK_FIX):
|
|
478
465
|
for diagnostic in (
|
|
479
466
|
d
|
|
480
467
|
for d in context.diagnostics
|
|
@@ -587,10 +574,7 @@ class RobotCodeActionQuickFixesProtocolPart(RobotLanguageServerProtocolPart, Mod
|
|
|
587
574
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
588
575
|
result: List[Union[Command, CodeAction]] = []
|
|
589
576
|
|
|
590
|
-
if (context
|
|
591
|
-
CodeActionTriggerKind.INVOKED,
|
|
592
|
-
CodeActionTriggerKind.AUTOMATIC,
|
|
593
|
-
]:
|
|
577
|
+
if code_action_kind_requested(context, CodeActionKind.QUICK_FIX):
|
|
594
578
|
for diagnostic in (
|
|
595
579
|
d
|
|
596
580
|
for d in context.diagnostics
|
|
@@ -737,10 +721,7 @@ class RobotCodeActionQuickFixesProtocolPart(RobotLanguageServerProtocolPart, Mod
|
|
|
737
721
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
738
722
|
result: List[Union[Command, CodeAction]] = []
|
|
739
723
|
|
|
740
|
-
if (context
|
|
741
|
-
CodeActionTriggerKind.INVOKED,
|
|
742
|
-
CodeActionTriggerKind.AUTOMATIC,
|
|
743
|
-
]:
|
|
724
|
+
if code_action_kind_requested(context, CodeActionKind.QUICK_FIX):
|
|
744
725
|
for diagnostic in (
|
|
745
726
|
d
|
|
746
727
|
for d in context.diagnostics
|
|
@@ -13,7 +13,6 @@ from robotcode.core.lsp.types import (
|
|
|
13
13
|
CodeActionContext,
|
|
14
14
|
CodeActionDisabledType,
|
|
15
15
|
CodeActionKind,
|
|
16
|
-
CodeActionTriggerKind,
|
|
17
16
|
Command,
|
|
18
17
|
OptionalVersionedTextDocumentIdentifier,
|
|
19
18
|
Position,
|
|
@@ -41,6 +40,7 @@ from .code_action_helper_mixin import (
|
|
|
41
40
|
SHOW_DOCUMENT_SELECT_AND_RENAME_COMMAND,
|
|
42
41
|
CodeActionDataBase,
|
|
43
42
|
CodeActionHelperMixin,
|
|
43
|
+
code_action_kind_requested,
|
|
44
44
|
)
|
|
45
45
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
46
46
|
|
|
@@ -111,6 +111,7 @@ class RobotCodeActionRefactorProtocolPart(RobotLanguageServerProtocolPart, CodeA
|
|
|
111
111
|
@code_action_kinds(
|
|
112
112
|
[
|
|
113
113
|
CODE_ACTION_KIND_REFACTOR_EXTRACT_FUNCTION,
|
|
114
|
+
CODE_ACTION_KIND_REFACTOR_EXTRACT_VARIABLE,
|
|
114
115
|
CODE_ACTION_KIND_SURROUND_WITH,
|
|
115
116
|
]
|
|
116
117
|
)
|
|
@@ -259,7 +260,7 @@ class RobotCodeActionRefactorProtocolPart(RobotLanguageServerProtocolPart, CodeA
|
|
|
259
260
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
260
261
|
from robot.parsing.model.blocks import Keyword, TestCase
|
|
261
262
|
|
|
262
|
-
if range.start == range.end:
|
|
263
|
+
if range.start == range.end or not code_action_kind_requested(context, CODE_ACTION_KIND_SURROUND_WITH):
|
|
263
264
|
return None
|
|
264
265
|
|
|
265
266
|
model = self.parent.documents_cache.get_model(document)
|
|
@@ -491,9 +492,8 @@ class RobotCodeActionRefactorProtocolPart(RobotLanguageServerProtocolPart, CodeA
|
|
|
491
492
|
def code_action_assign_result_to_variable(
|
|
492
493
|
self, document: TextDocument, range: Range, context: CodeActionContext
|
|
493
494
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
494
|
-
if range.start.line != range.end.line or not (
|
|
495
|
-
|
|
496
|
-
or context.trigger_kind in [CodeActionTriggerKind.INVOKED, CodeActionTriggerKind.AUTOMATIC]
|
|
495
|
+
if range.start.line != range.end.line or not code_action_kind_requested(
|
|
496
|
+
context, CODE_ACTION_KIND_REFACTOR_EXTRACT_VARIABLE
|
|
497
497
|
):
|
|
498
498
|
return None
|
|
499
499
|
|
|
@@ -575,7 +575,9 @@ class RobotCodeActionRefactorProtocolPart(RobotLanguageServerProtocolPart, CodeA
|
|
|
575
575
|
) -> Optional[List[Union[Command, CodeAction]]]:
|
|
576
576
|
from robot.parsing.model.blocks import Keyword, TestCase
|
|
577
577
|
|
|
578
|
-
if range.start == range.end
|
|
578
|
+
if range.start == range.end or not code_action_kind_requested(
|
|
579
|
+
context, CODE_ACTION_KIND_REFACTOR_EXTRACT_FUNCTION
|
|
580
|
+
):
|
|
579
581
|
return None
|
|
580
582
|
|
|
581
583
|
model = self.parent.documents_cache.get_model(document)
|
|
@@ -8,7 +8,6 @@ from robotcode.core.text_document import TextDocument
|
|
|
8
8
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
9
9
|
from robotcode.language_server.robotframework.configuration import AnalysisConfig
|
|
10
10
|
from robotcode.robot.diagnostics.library_doc import KeywordDoc
|
|
11
|
-
from robotcode.robot.diagnostics.model_helper import ModelHelper
|
|
12
11
|
from robotcode.robot.utils.ast import range_from_token
|
|
13
12
|
from robotcode.robot.utils.visitor import Visitor
|
|
14
13
|
|
|
@@ -18,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
18
17
|
from ..protocol import RobotLanguageServerProtocol
|
|
19
18
|
|
|
20
19
|
|
|
21
|
-
class RobotCodeLensProtocolPart(RobotLanguageServerProtocolPart
|
|
20
|
+
class RobotCodeLensProtocolPart(RobotLanguageServerProtocolPart):
|
|
22
21
|
_logger = LoggingDescriptor()
|
|
23
22
|
|
|
24
23
|
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
@@ -73,7 +72,7 @@ class RobotCodeLensProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
73
72
|
line = code_lens.data["line"]
|
|
74
73
|
|
|
75
74
|
if self.parent.diagnostics.workspace_loaded_event.is_set():
|
|
76
|
-
kw_doc =
|
|
75
|
+
kw_doc = next((k for k in namespace.library_doc.keywords.keywords if k.line_no == line), None)
|
|
77
76
|
|
|
78
77
|
if kw_doc is not None and not kw_doc.is_error_handler:
|
|
79
78
|
if not self.parent.robot_references.has_cached_keyword_references(
|
|
@@ -111,7 +110,7 @@ class RobotCodeLensProtocolPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
111
110
|
document, kw_doc, include_declaration=False
|
|
112
111
|
)
|
|
113
112
|
code_lens.command = Command(
|
|
114
|
-
f"{len(references)} references",
|
|
113
|
+
f"{len(references)} {'reference' if len(references) == 1 else 'references'}",
|
|
115
114
|
"editor.action.showReferences",
|
|
116
115
|
[str(document.uri), code_lens.range.start, references],
|
|
117
116
|
)
|
|
@@ -52,6 +52,7 @@ from robotcode.core.lsp.types import (
|
|
|
52
52
|
CompletionContext,
|
|
53
53
|
CompletionItem,
|
|
54
54
|
CompletionItemKind,
|
|
55
|
+
CompletionItemLabelDetails,
|
|
55
56
|
CompletionList,
|
|
56
57
|
InsertTextFormat,
|
|
57
58
|
MarkupContent,
|
|
@@ -62,12 +63,15 @@ from robotcode.core.lsp.types import (
|
|
|
62
63
|
)
|
|
63
64
|
from robotcode.core.text_document import TextDocument
|
|
64
65
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
66
|
+
from robotcode.robot.diagnostics.diagnostic_rules import private_keyword_call_message
|
|
65
67
|
from robotcode.robot.diagnostics.entities import VariableDefinitionType
|
|
66
68
|
from robotcode.robot.diagnostics.library_doc import (
|
|
69
|
+
ArgumentInfo,
|
|
67
70
|
CompleteResultKind,
|
|
68
71
|
KeywordArgumentKind,
|
|
69
72
|
KeywordDoc,
|
|
70
73
|
KeywordMatcher,
|
|
74
|
+
LibraryDoc,
|
|
71
75
|
)
|
|
72
76
|
from robotcode.robot.diagnostics.model_helper import ModelHelper
|
|
73
77
|
from robotcode.robot.diagnostics.namespace import DocumentType, Namespace
|
|
@@ -80,9 +84,11 @@ from robotcode.robot.utils.ast import (
|
|
|
80
84
|
whitespace_at_begin_of_token,
|
|
81
85
|
whitespace_from_begin_of_token,
|
|
82
86
|
)
|
|
87
|
+
from robotcode.robot.utils.markdown_docs import LinkResolver
|
|
83
88
|
|
|
84
89
|
from ...common.decorators import trigger_characters
|
|
85
90
|
from ..configuration import CompletionConfig
|
|
91
|
+
from .code_action_documentation import DocumentationTarget, keyword_reference_targets, link_documentation
|
|
86
92
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
87
93
|
|
|
88
94
|
if RF_VERSION >= (6, 1):
|
|
@@ -94,6 +100,7 @@ else:
|
|
|
94
100
|
|
|
95
101
|
if TYPE_CHECKING:
|
|
96
102
|
from ..protocol import RobotLanguageServerProtocol
|
|
103
|
+
from .code_action_documentation import RobotCodeActionDocumentationProtocolPart
|
|
97
104
|
|
|
98
105
|
if RF_VERSION < (7, 0):
|
|
99
106
|
from robot.variables.search import VariableIterator
|
|
@@ -319,6 +326,14 @@ class CompletionItemImportData(CompletionItemData):
|
|
|
319
326
|
id: str
|
|
320
327
|
|
|
321
328
|
|
|
329
|
+
# a file of a Variables import is resolved like a library, but has no page in the Documentation Viewer
|
|
330
|
+
VARIABLES_IMPORT = "VARIABLES"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class CompletionItemVariablesImportData(CompletionItemData):
|
|
334
|
+
import_type: str
|
|
335
|
+
|
|
336
|
+
|
|
322
337
|
class CompletionCollector(ModelHelper):
|
|
323
338
|
_logger = LoggingDescriptor()
|
|
324
339
|
|
|
@@ -409,18 +424,25 @@ class CompletionCollector(ModelHelper):
|
|
|
409
424
|
]:
|
|
410
425
|
if (lib_id := data.get("id", None)) is not None:
|
|
411
426
|
try:
|
|
412
|
-
|
|
427
|
+
lib_entry = next(
|
|
413
428
|
(
|
|
414
|
-
ld
|
|
429
|
+
ld
|
|
415
430
|
for ld in self.namespace.libraries.values()
|
|
416
431
|
if str(id(ld.library_doc)) == lib_id
|
|
417
432
|
),
|
|
418
433
|
None,
|
|
419
434
|
)
|
|
420
|
-
if
|
|
435
|
+
if lib_entry is not None:
|
|
436
|
+
entry = lib_entry
|
|
421
437
|
completion_item.documentation = MarkupContent(
|
|
422
438
|
kind=MarkupKind.MARKDOWN,
|
|
423
|
-
value=
|
|
439
|
+
value=self._documentation(
|
|
440
|
+
lambda r: entry.library_doc.to_markdown(False, link_resolver=r),
|
|
441
|
+
lambda: self._code_action_documentation.entry_target(
|
|
442
|
+
entry, True, document, self.namespace
|
|
443
|
+
),
|
|
444
|
+
entry.library_doc,
|
|
445
|
+
),
|
|
424
446
|
)
|
|
425
447
|
|
|
426
448
|
except (
|
|
@@ -444,9 +466,22 @@ class CompletionCollector(ModelHelper):
|
|
|
444
466
|
)
|
|
445
467
|
|
|
446
468
|
if lib_doc is not None:
|
|
469
|
+
library_doc = lib_doc
|
|
470
|
+
library_name = name
|
|
471
|
+
is_variables = cast(Dict[str, Any], data).get("import_type") == VARIABLES_IMPORT
|
|
447
472
|
completion_item.documentation = MarkupContent(
|
|
448
473
|
kind=MarkupKind.MARKDOWN,
|
|
449
|
-
value=
|
|
474
|
+
value=self._documentation(
|
|
475
|
+
lambda r: library_doc.to_markdown(False, link_resolver=r),
|
|
476
|
+
lambda: (
|
|
477
|
+
None
|
|
478
|
+
if is_variables
|
|
479
|
+
else self._code_action_documentation.import_target(
|
|
480
|
+
library_name, (), True, document, self.namespace
|
|
481
|
+
)
|
|
482
|
+
),
|
|
483
|
+
library_doc,
|
|
484
|
+
),
|
|
450
485
|
)
|
|
451
486
|
|
|
452
487
|
except (SystemExit, KeyboardInterrupt):
|
|
@@ -457,19 +492,26 @@ class CompletionCollector(ModelHelper):
|
|
|
457
492
|
elif comp_type == CompleteResultKind.RESOURCE.name:
|
|
458
493
|
if (res_id := data.get("id", None)) is not None:
|
|
459
494
|
try:
|
|
460
|
-
|
|
495
|
+
res_entry = next(
|
|
461
496
|
(
|
|
462
|
-
ld
|
|
497
|
+
ld
|
|
463
498
|
for ld in self.namespace.resources.values()
|
|
464
499
|
if str(id(ld.library_doc)) == res_id
|
|
465
500
|
),
|
|
466
501
|
None,
|
|
467
502
|
)
|
|
468
503
|
|
|
469
|
-
if
|
|
504
|
+
if res_entry is not None:
|
|
505
|
+
resource_entry = res_entry
|
|
470
506
|
completion_item.documentation = MarkupContent(
|
|
471
507
|
kind=MarkupKind.MARKDOWN,
|
|
472
|
-
value=
|
|
508
|
+
value=self._documentation(
|
|
509
|
+
lambda r: resource_entry.library_doc.to_markdown(False, link_resolver=r),
|
|
510
|
+
lambda: self._code_action_documentation.entry_target(
|
|
511
|
+
resource_entry, False, document, self.namespace
|
|
512
|
+
),
|
|
513
|
+
resource_entry.library_doc,
|
|
514
|
+
),
|
|
473
515
|
)
|
|
474
516
|
|
|
475
517
|
except (
|
|
@@ -493,9 +535,17 @@ class CompletionCollector(ModelHelper):
|
|
|
493
535
|
)
|
|
494
536
|
|
|
495
537
|
if lib_doc is not None:
|
|
538
|
+
resource_doc = lib_doc
|
|
539
|
+
resource_name = name
|
|
496
540
|
completion_item.documentation = MarkupContent(
|
|
497
541
|
kind=MarkupKind.MARKDOWN,
|
|
498
|
-
value=
|
|
542
|
+
value=self._documentation(
|
|
543
|
+
lambda r: resource_doc.to_markdown(False, link_resolver=r),
|
|
544
|
+
lambda: self._code_action_documentation.import_target(
|
|
545
|
+
resource_name, (), False, document, self.namespace
|
|
546
|
+
),
|
|
547
|
+
resource_doc,
|
|
548
|
+
),
|
|
499
549
|
)
|
|
500
550
|
|
|
501
551
|
except (SystemExit, KeyboardInterrupt):
|
|
@@ -512,9 +562,19 @@ class CompletionCollector(ModelHelper):
|
|
|
512
562
|
)
|
|
513
563
|
|
|
514
564
|
if kw_doc is not None:
|
|
565
|
+
keyword_doc = kw_doc
|
|
515
566
|
completion_item.documentation = MarkupContent(
|
|
516
567
|
kind=MarkupKind.MARKDOWN,
|
|
517
|
-
value=
|
|
568
|
+
value=self._documentation(
|
|
569
|
+
lambda r: keyword_doc.to_markdown(
|
|
570
|
+
link_resolver=r,
|
|
571
|
+
reference_targets=keyword_reference_targets(keyword_doc, r is not None),
|
|
572
|
+
),
|
|
573
|
+
lambda: self._code_action_documentation.keyword_target(
|
|
574
|
+
keyword_doc, None, document, self.namespace
|
|
575
|
+
),
|
|
576
|
+
keyword_doc.parent,
|
|
577
|
+
),
|
|
518
578
|
)
|
|
519
579
|
|
|
520
580
|
except (
|
|
@@ -532,6 +592,37 @@ class CompletionCollector(ModelHelper):
|
|
|
532
592
|
|
|
533
593
|
return completion_item
|
|
534
594
|
|
|
595
|
+
@property
|
|
596
|
+
def _links(self) -> bool:
|
|
597
|
+
return self.parent.parent.robot_initialization_options.documentation_viewer_links
|
|
598
|
+
|
|
599
|
+
@property
|
|
600
|
+
def _code_action_documentation(self) -> "RobotCodeActionDocumentationProtocolPart":
|
|
601
|
+
return self.parent.parent.robot_code_action_documentation
|
|
602
|
+
|
|
603
|
+
def _documentation(
|
|
604
|
+
self,
|
|
605
|
+
render: Callable[[Optional[LinkResolver]], str],
|
|
606
|
+
target: Callable[[], Optional[DocumentationTarget]],
|
|
607
|
+
library_doc: Optional[LibraryDoc],
|
|
608
|
+
*,
|
|
609
|
+
heading: bool = True,
|
|
610
|
+
) -> str:
|
|
611
|
+
"""The documentation of an item; with links, linked into the Documentation Viewer at the page of `target`."""
|
|
612
|
+
if not self._links:
|
|
613
|
+
return render(None)
|
|
614
|
+
documentation_target = target()
|
|
615
|
+
link_resolver = (
|
|
616
|
+
self._code_action_documentation.link_resolver(
|
|
617
|
+
self.document, self.namespace, documentation_target, library_doc
|
|
618
|
+
)
|
|
619
|
+
if documentation_target is not None and library_doc is not None
|
|
620
|
+
else None
|
|
621
|
+
)
|
|
622
|
+
return link_documentation(
|
|
623
|
+
render, documentation_target, library_doc, heading=heading, link_resolver=link_resolver
|
|
624
|
+
)
|
|
625
|
+
|
|
535
626
|
def create_headers_completion_items(self, range: Optional[Range]) -> List[CompletionItem]:
|
|
536
627
|
doc_type = self.parent.parent.documents_cache.get_document_type(self.document)
|
|
537
628
|
|
|
@@ -810,6 +901,24 @@ class CompletionCollector(ModelHelper):
|
|
|
810
901
|
|
|
811
902
|
return result
|
|
812
903
|
|
|
904
|
+
def _is_foreign_private(self, kw: KeywordDoc) -> bool:
|
|
905
|
+
return private_keyword_call_message(kw, self.namespace.source) is not None
|
|
906
|
+
|
|
907
|
+
def _is_hidden(self, kw: KeywordDoc, private: bool) -> bool:
|
|
908
|
+
return (private and self.config.hide_private_keywords) or (
|
|
909
|
+
kw.is_deprecated and self.config.hide_deprecated_keywords
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
@staticmethod
|
|
913
|
+
def _private_label_details(private: bool) -> Optional[CompletionItemLabelDetails]:
|
|
914
|
+
return CompletionItemLabelDetails(description="private") if private else None
|
|
915
|
+
|
|
916
|
+
@staticmethod
|
|
917
|
+
def _keyword_sort_text(prefix: str, kw: KeywordDoc, private: bool) -> str:
|
|
918
|
+
"""Other keywords first, then deprecated ones, then the shown private keywords of other files."""
|
|
919
|
+
rank = 2 if private else 1 if kw.is_deprecated else 0
|
|
920
|
+
return f"{prefix}{rank}_{kw.name}"
|
|
921
|
+
|
|
813
922
|
def create_keyword_completion_items(
|
|
814
923
|
self,
|
|
815
924
|
token: Optional[Token],
|
|
@@ -889,13 +998,18 @@ class CompletionCollector(ModelHelper):
|
|
|
889
998
|
for kw in libraries[namespace_name].library_doc.keywords.values():
|
|
890
999
|
if kw.is_error_handler:
|
|
891
1000
|
continue
|
|
1001
|
+
private = self._is_foreign_private(kw)
|
|
1002
|
+
if self._is_hidden(kw, private):
|
|
1003
|
+
continue
|
|
892
1004
|
result.append(
|
|
893
1005
|
CompletionItem(
|
|
894
1006
|
label=kw.name,
|
|
1007
|
+
label_details=self._private_label_details(private),
|
|
895
1008
|
kind=CompletionItemKind.FUNCTION,
|
|
896
1009
|
detail=f"{CompleteResultKind.KEYWORD.value} "
|
|
897
1010
|
f"{f'({kw.libname})' if kw.libname is not None else ''}",
|
|
898
|
-
|
|
1011
|
+
deprecated=kw.is_deprecated,
|
|
1012
|
+
sort_text=self._keyword_sort_text("019_", kw, private),
|
|
899
1013
|
insert_text_format=(
|
|
900
1014
|
InsertTextFormat.PLAIN_TEXT if not kw.is_embedded else InsertTextFormat.SNIPPET
|
|
901
1015
|
),
|
|
@@ -935,14 +1049,19 @@ class CompletionCollector(ModelHelper):
|
|
|
935
1049
|
for kw in res.library_doc.keywords.values():
|
|
936
1050
|
if kw.is_error_handler:
|
|
937
1051
|
continue
|
|
1052
|
+
private = self._is_foreign_private(kw)
|
|
1053
|
+
if self._is_hidden(kw, private):
|
|
1054
|
+
continue
|
|
938
1055
|
|
|
939
1056
|
result.append(
|
|
940
1057
|
CompletionItem(
|
|
941
1058
|
label=kw.name,
|
|
1059
|
+
label_details=self._private_label_details(private),
|
|
942
1060
|
kind=CompletionItemKind.FUNCTION,
|
|
943
1061
|
detail=f"{CompleteResultKind.KEYWORD.value} "
|
|
944
1062
|
f"{f'({kw.libname})' if kw.libname is not None else ''}",
|
|
945
|
-
|
|
1063
|
+
deprecated=kw.is_deprecated,
|
|
1064
|
+
sort_text=self._keyword_sort_text("019_", kw, private),
|
|
946
1065
|
insert_text_format=(
|
|
947
1066
|
InsertTextFormat.PLAIN_TEXT
|
|
948
1067
|
if not kw.is_embedded
|
|
@@ -985,14 +1104,18 @@ class CompletionCollector(ModelHelper):
|
|
|
985
1104
|
and not kw.matcher.normalized_name.startswith(namespace_matcher.normalized_name)
|
|
986
1105
|
):
|
|
987
1106
|
continue
|
|
1107
|
+
private = self._is_foreign_private(kw)
|
|
1108
|
+
if self._is_hidden(kw, private):
|
|
1109
|
+
continue
|
|
988
1110
|
|
|
989
1111
|
result.append(
|
|
990
1112
|
CompletionItem(
|
|
991
1113
|
label=kw.name,
|
|
1114
|
+
label_details=self._private_label_details(private),
|
|
992
1115
|
kind=CompletionItemKind.FUNCTION,
|
|
993
1116
|
detail=f"{CompleteResultKind.KEYWORD.value} {f'({kw.libname})' if kw.libname is not None else ''}",
|
|
994
1117
|
deprecated=kw.is_deprecated,
|
|
995
|
-
sort_text=
|
|
1118
|
+
sort_text=self._keyword_sort_text("020_", kw, private),
|
|
996
1119
|
insert_text_format=InsertTextFormat.PLAIN_TEXT if not kw.is_embedded else InsertTextFormat.SNIPPET,
|
|
997
1120
|
text_edit=TextEdit(
|
|
998
1121
|
range=r,
|
|
@@ -1783,6 +1906,13 @@ class CompletionCollector(ModelHelper):
|
|
|
1783
1906
|
kw_node.tokens[name_token_index:],
|
|
1784
1907
|
token_at_position,
|
|
1785
1908
|
position,
|
|
1909
|
+
(
|
|
1910
|
+
self._code_action_documentation.import_target(
|
|
1911
|
+
import_node.name, import_node.args, True, self.document, self.namespace, libdoc
|
|
1912
|
+
)
|
|
1913
|
+
if self._links
|
|
1914
|
+
else None
|
|
1915
|
+
),
|
|
1786
1916
|
)
|
|
1787
1917
|
|
|
1788
1918
|
except (SystemExit, KeyboardInterrupt, CancelledError):
|
|
@@ -2056,10 +2186,11 @@ class CompletionCollector(ModelHelper):
|
|
|
2056
2186
|
sort_text=f"030_{e.label}",
|
|
2057
2187
|
insert_text_format=InsertTextFormat.PLAIN_TEXT,
|
|
2058
2188
|
text_edit=TextEdit(range=r, new_text=e.label) if r is not None else None,
|
|
2059
|
-
data=
|
|
2189
|
+
data=CompletionItemVariablesImportData(
|
|
2060
2190
|
document_uri=str(self.document.uri),
|
|
2061
2191
|
type=e.kind.name,
|
|
2062
2192
|
name=((first_part) if first_part is not None else "") + e.label,
|
|
2193
|
+
import_type=VARIABLES_IMPORT,
|
|
2063
2194
|
),
|
|
2064
2195
|
)
|
|
2065
2196
|
for e in complete_list
|
|
@@ -2175,11 +2306,19 @@ class CompletionCollector(ModelHelper):
|
|
|
2175
2306
|
|
|
2176
2307
|
keyword_token_index = kw_node.tokens.index(keyword_token)
|
|
2177
2308
|
|
|
2309
|
+
target = None
|
|
2310
|
+
if self._links:
|
|
2311
|
+
prefix_entry, _ = self.get_namespace_info_from_keyword_token(self.namespace, keyword_doc_and_token[1])
|
|
2312
|
+
target = self._code_action_documentation.keyword_target(
|
|
2313
|
+
keyword_doc, prefix_entry, self.document, self.namespace
|
|
2314
|
+
)
|
|
2315
|
+
|
|
2178
2316
|
return self._complete_keyword_arguments_at_position(
|
|
2179
2317
|
keyword_doc,
|
|
2180
2318
|
kw_node.tokens[keyword_token_index:],
|
|
2181
2319
|
token_at_position,
|
|
2182
2320
|
position,
|
|
2321
|
+
target,
|
|
2183
2322
|
)
|
|
2184
2323
|
|
|
2185
2324
|
TRUE_STRINGS = {"TRUE", "YES", "ON", "1"}
|
|
@@ -2191,10 +2330,15 @@ class CompletionCollector(ModelHelper):
|
|
|
2191
2330
|
tokens: Tuple[Token, ...],
|
|
2192
2331
|
token_at_position: Token,
|
|
2193
2332
|
position: Position,
|
|
2333
|
+
target: Optional[DocumentationTarget] = None,
|
|
2194
2334
|
) -> Optional[List[CompletionItem]]:
|
|
2195
2335
|
if keyword_doc.is_any_run_keyword():
|
|
2196
2336
|
return None
|
|
2197
2337
|
|
|
2338
|
+
def type_documentation(markdown: str) -> str:
|
|
2339
|
+
# the documentation of a type links no names, only its links to a place in the documentation
|
|
2340
|
+
return self._documentation(lambda _: markdown, lambda: target, None, heading=False)
|
|
2341
|
+
|
|
2198
2342
|
(
|
|
2199
2343
|
argument_index,
|
|
2200
2344
|
kw_arguments,
|
|
@@ -2260,7 +2404,7 @@ class CompletionCollector(ModelHelper):
|
|
|
2260
2404
|
or has_name
|
|
2261
2405
|
)
|
|
2262
2406
|
):
|
|
2263
|
-
type_infos = keyword_doc.parent.
|
|
2407
|
+
type_infos = keyword_doc.parent.get_types_for_argument(kw_arguments[argument_index])
|
|
2264
2408
|
for i, type_info in enumerate(type_infos):
|
|
2265
2409
|
if type_info.name == "boolean":
|
|
2266
2410
|
if RF_VERSION >= (6, 0) and self.namespace.languages:
|
|
@@ -2287,7 +2431,7 @@ class CompletionCollector(ModelHelper):
|
|
|
2287
2431
|
for i, b_snippet in enumerate(bool_snippets):
|
|
2288
2432
|
if b_snippet[0]:
|
|
2289
2433
|
cache_name = f"BOOL{id(type_info)}_{i}"
|
|
2290
|
-
self.parent.doc_cache[cache_name] = type_info.to_markdown()
|
|
2434
|
+
self.parent.doc_cache[cache_name] = type_documentation(type_info.to_markdown())
|
|
2291
2435
|
result.append(
|
|
2292
2436
|
CompletionItem(
|
|
2293
2437
|
label=b_snippet[0],
|
|
@@ -2312,7 +2456,9 @@ class CompletionCollector(ModelHelper):
|
|
|
2312
2456
|
label="None",
|
|
2313
2457
|
kind=CompletionItemKind.CONSTANT,
|
|
2314
2458
|
detail=f"{type_info.name}",
|
|
2315
|
-
documentation=MarkupContent(
|
|
2459
|
+
documentation=MarkupContent(
|
|
2460
|
+
MarkupKind.MARKDOWN, type_documentation(type_info.to_markdown())
|
|
2461
|
+
),
|
|
2316
2462
|
sort_text="50_000_None",
|
|
2317
2463
|
insert_text_format=InsertTextFormat.PLAIN_TEXT,
|
|
2318
2464
|
text_edit=TextEdit(range=completion_range, new_text="None"),
|
|
@@ -2323,7 +2469,9 @@ class CompletionCollector(ModelHelper):
|
|
|
2323
2469
|
label="${None}",
|
|
2324
2470
|
kind=CompletionItemKind.VARIABLE,
|
|
2325
2471
|
detail=f"{type_info.name}",
|
|
2326
|
-
documentation=MarkupContent(
|
|
2472
|
+
documentation=MarkupContent(
|
|
2473
|
+
MarkupKind.MARKDOWN, type_documentation(type_info.to_markdown())
|
|
2474
|
+
),
|
|
2327
2475
|
sort_text="50_001_None",
|
|
2328
2476
|
insert_text_format=InsertTextFormat.PLAIN_TEXT,
|
|
2329
2477
|
text_edit=TextEdit(range=completion_range, new_text="${None}"),
|
|
@@ -2332,7 +2480,7 @@ class CompletionCollector(ModelHelper):
|
|
|
2332
2480
|
if type_info.members:
|
|
2333
2481
|
for member_index, member in enumerate(type_info.members):
|
|
2334
2482
|
cache_name = f"TYPE_MEMBER{id(type_info)}_{member_index}"
|
|
2335
|
-
self.parent.doc_cache[cache_name] = (
|
|
2483
|
+
self.parent.doc_cache[cache_name] = type_documentation(
|
|
2336
2484
|
f"```python\n{member.name} = {member.value}\n```"
|
|
2337
2485
|
"\n\n---"
|
|
2338
2486
|
f"\n{type_info.to_markdown(only_doc=True)}"
|
|
@@ -2375,7 +2523,7 @@ class CompletionCollector(ModelHelper):
|
|
|
2375
2523
|
]
|
|
2376
2524
|
for i, snippet in enumerate(snippets):
|
|
2377
2525
|
cache_name = f"TYPE_ITEMS{id(type_info)}_{i}"
|
|
2378
|
-
self.parent.doc_cache[cache_name] = type_info.to_markdown()
|
|
2526
|
+
self.parent.doc_cache[cache_name] = type_documentation(type_info.to_markdown())
|
|
2379
2527
|
if snippet:
|
|
2380
2528
|
result.append(
|
|
2381
2529
|
CompletionItem(
|
|
@@ -2449,6 +2597,29 @@ class CompletionCollector(ModelHelper):
|
|
|
2449
2597
|
- 1
|
|
2450
2598
|
)
|
|
2451
2599
|
|
|
2600
|
+
# once for all arguments of the keyword
|
|
2601
|
+
targets = keyword_reference_targets(keyword_doc, self._links)
|
|
2602
|
+
|
|
2603
|
+
def documentation_data(argument: ArgumentInfo) -> Optional[CompletionItemData]:
|
|
2604
|
+
# the description of the argument and the documentation of its types, sent when the item is resolved
|
|
2605
|
+
doc = self._documentation(
|
|
2606
|
+
lambda r: (
|
|
2607
|
+
keyword_doc.argument_to_markdown(argument, link_resolver=r, reference_targets=targets) or ""
|
|
2608
|
+
),
|
|
2609
|
+
lambda: target,
|
|
2610
|
+
keyword_doc.parent,
|
|
2611
|
+
heading=False,
|
|
2612
|
+
)
|
|
2613
|
+
if not doc:
|
|
2614
|
+
return None
|
|
2615
|
+
cache_name = f"ARG{id(keyword_doc)}_{argument.name}"
|
|
2616
|
+
self.parent.doc_cache[cache_name] = doc
|
|
2617
|
+
return CompletionItemData(
|
|
2618
|
+
document_uri=str(self.document.uri),
|
|
2619
|
+
type=CompleteResultKind.DOC_CACHE.name,
|
|
2620
|
+
name=cache_name,
|
|
2621
|
+
)
|
|
2622
|
+
|
|
2452
2623
|
result += [
|
|
2453
2624
|
CompletionItem(
|
|
2454
2625
|
label=f"{e.signature(False)}=",
|
|
@@ -2460,6 +2631,7 @@ class CompletionCollector(ModelHelper):
|
|
|
2460
2631
|
text_edit=TextEdit(range=completion_range, new_text=f"{e.name}="),
|
|
2461
2632
|
command=Command("", "editor.action.triggerSuggest", []),
|
|
2462
2633
|
preselect=True if i == preselected else None,
|
|
2634
|
+
data=documentation_data(e),
|
|
2463
2635
|
)
|
|
2464
2636
|
for i, e in enumerate(kw_arguments)
|
|
2465
2637
|
if e.name not in known_names
|