robotcode-language-server 2.7.0__py3-none-any.whl → 2.8.0.dev8__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/cli.py +30 -5
- robotcode/language_server/common/parts/diagnostics.py +50 -17
- robotcode/language_server/common/parts/documents.py +32 -26
- 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 +437 -146
- 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/documentation_viewer.py +127 -0
- 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 +107 -45
- 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 +446 -113
- robotcode/language_server/robotframework/parts/signature_help.py +162 -70
- robotcode/language_server/robotframework/protocol.py +12 -1
- robotcode/language_server/robotframework/server.py +4 -2
- {robotcode_language_server-2.7.0.dist-info → robotcode_language_server-2.8.0.dev8.dist-info}/METADATA +7 -6
- {robotcode_language_server-2.7.0.dist-info → robotcode_language_server-2.8.0.dev8.dist-info}/RECORD +34 -32
- {robotcode_language_server-2.7.0.dist-info → robotcode_language_server-2.8.0.dev8.dist-info}/WHEEL +1 -1
- {robotcode_language_server-2.7.0.dist-info → robotcode_language_server-2.8.0.dev8.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
|
-
from itertools import dropwhile, takewhile
|
|
2
|
+
from itertools import chain, dropwhile, takewhile
|
|
3
3
|
from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple
|
|
4
4
|
|
|
5
5
|
from robot.parsing.lexer.tokens import Token
|
|
@@ -10,24 +10,33 @@ from robotcode.core.lsp.types import (
|
|
|
10
10
|
InlineValue,
|
|
11
11
|
InlineValueContext,
|
|
12
12
|
InlineValueEvaluatableExpression,
|
|
13
|
+
Position,
|
|
13
14
|
Range,
|
|
14
15
|
)
|
|
15
16
|
from robotcode.core.text_document import TextDocument
|
|
16
17
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
17
18
|
from robotcode.robot.diagnostics.model_helper import ModelHelper
|
|
19
|
+
from robotcode.robot.diagnostics.semantic_analyzer.enums import NodeKind
|
|
20
|
+
from robotcode.robot.diagnostics.semantic_analyzer.model import SemanticModel
|
|
21
|
+
from robotcode.robot.diagnostics.semantic_analyzer.nodes import SemanticToken
|
|
18
22
|
from robotcode.robot.utils.ast import (
|
|
19
23
|
iter_nodes,
|
|
20
24
|
range_from_node,
|
|
21
25
|
range_from_token,
|
|
22
26
|
)
|
|
23
27
|
|
|
28
|
+
from .model_variables import (
|
|
29
|
+
iter_condition_ref_candidates,
|
|
30
|
+
iter_model_variable_candidates,
|
|
31
|
+
scannable_statement_tokens,
|
|
32
|
+
)
|
|
24
33
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
25
34
|
|
|
26
35
|
if TYPE_CHECKING:
|
|
27
36
|
from ..protocol import RobotLanguageServerProtocol
|
|
28
37
|
|
|
29
38
|
|
|
30
|
-
class RobotInlineValueProtocolPart(RobotLanguageServerProtocolPart
|
|
39
|
+
class RobotInlineValueProtocolPart(RobotLanguageServerProtocolPart):
|
|
31
40
|
_logger = LoggingDescriptor()
|
|
32
41
|
|
|
33
42
|
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
@@ -50,10 +59,14 @@ class RobotInlineValueProtocolPart(RobotLanguageServerProtocolPart, ModelHelper)
|
|
|
50
59
|
|
|
51
60
|
namespace = self.parent.documents_cache.get_namespace(document)
|
|
52
61
|
|
|
53
|
-
model = self.parent.documents_cache.get_model(document)
|
|
54
|
-
|
|
55
62
|
real_range = Range(range.start, min(range.end, context.stopped_location.end))
|
|
56
63
|
|
|
64
|
+
semantic_model = namespace.semantic_model
|
|
65
|
+
if semantic_model is not None:
|
|
66
|
+
return self._collect_from_model(semantic_model, real_range, context)
|
|
67
|
+
|
|
68
|
+
model = self.parent.documents_cache.get_model(document)
|
|
69
|
+
|
|
57
70
|
def get_tokens() -> Iterator[Tuple[Token, ast.AST]]:
|
|
58
71
|
for n in iter_nodes(model):
|
|
59
72
|
r = range_from_node(n)
|
|
@@ -71,15 +84,64 @@ class RobotInlineValueProtocolPart(RobotLanguageServerProtocolPart, ModelHelper)
|
|
|
71
84
|
get_tokens(),
|
|
72
85
|
),
|
|
73
86
|
):
|
|
74
|
-
if token.type == RobotToken.ARGUMENT and isinstance(node,
|
|
75
|
-
for t, var in
|
|
87
|
+
if token.type == RobotToken.ARGUMENT and isinstance(node, ModelHelper.get_expression_statement_types()):
|
|
88
|
+
for t, var in ModelHelper.iter_expression_variables_from_token(
|
|
76
89
|
token, namespace, context.stopped_location.start
|
|
77
90
|
):
|
|
78
91
|
if var.name != "${CURDIR}":
|
|
79
92
|
result.append(InlineValueEvaluatableExpression(range_from_token(t), var.name))
|
|
80
93
|
|
|
81
|
-
for t, var in
|
|
94
|
+
for t, var in ModelHelper.iter_variables_from_token(token, namespace, context.stopped_location.start):
|
|
82
95
|
if var.name != "${CURDIR}":
|
|
83
96
|
result.append(InlineValueEvaluatableExpression(range_from_token(t), var.name))
|
|
84
97
|
|
|
85
98
|
return result
|
|
99
|
+
|
|
100
|
+
def _collect_from_model(
|
|
101
|
+
self,
|
|
102
|
+
semantic_model: SemanticModel,
|
|
103
|
+
real_range: Range,
|
|
104
|
+
context: InlineValueContext,
|
|
105
|
+
) -> List[InlineValue]:
|
|
106
|
+
"""Model path: variable occurrences from the pre-built statement
|
|
107
|
+
tokens, resolved at the debugger's stopped location."""
|
|
108
|
+
resolve_line = context.stopped_location.start.line + 1
|
|
109
|
+
resolve_col = context.stopped_location.start.character
|
|
110
|
+
|
|
111
|
+
def get_model_tokens() -> Iterator[Tuple[NodeKind, SemanticToken]]:
|
|
112
|
+
for stmt in semantic_model.statements:
|
|
113
|
+
if not stmt.tokens:
|
|
114
|
+
continue
|
|
115
|
+
first = stmt.tokens[0]
|
|
116
|
+
last = stmt.tokens[-1]
|
|
117
|
+
start = Position(line=first.line - 1, character=first.col_offset)
|
|
118
|
+
end = Position(line=last.line - 1, character=last.col_offset + last.length)
|
|
119
|
+
if start in real_range or end in real_range:
|
|
120
|
+
for token in scannable_statement_tokens(stmt):
|
|
121
|
+
yield stmt.kind, token
|
|
122
|
+
if start > real_range.end:
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
result: List[InlineValue] = []
|
|
126
|
+
for stmt_kind, token in takewhile(
|
|
127
|
+
lambda t: t[1].line - 1 <= real_range.end.line,
|
|
128
|
+
dropwhile(
|
|
129
|
+
lambda t: Position(line=t[1].line - 1, character=t[1].col_offset) < real_range.start,
|
|
130
|
+
get_model_tokens(),
|
|
131
|
+
),
|
|
132
|
+
):
|
|
133
|
+
# Legacy per-token order: the condition cell's bare-`$var`
|
|
134
|
+
# expression refs first, then the regular variables.
|
|
135
|
+
for candidate in chain(
|
|
136
|
+
iter_condition_ref_candidates(token),
|
|
137
|
+
iter_model_variable_candidates(token, semantic_model, resolve_line, resolve_col, stmt_kind),
|
|
138
|
+
):
|
|
139
|
+
if not candidate.primary:
|
|
140
|
+
continue
|
|
141
|
+
# `extended=False`: the extended-syntax fallback is already
|
|
142
|
+
# encoded in the candidates' lookup names.
|
|
143
|
+
var = semantic_model.find_variable(candidate.lookup_name, resolve_line, resolve_col, extended=False)
|
|
144
|
+
if var is not None and var.name != "${CURDIR}":
|
|
145
|
+
result.append(InlineValueEvaluatableExpression(candidate.range, var.name))
|
|
146
|
+
|
|
147
|
+
return result
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import TYPE_CHECKING, Any, List, Optional
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Callable, List, Mapping, Optional, Tuple
|
|
3
3
|
|
|
4
4
|
from robotcode.core.lsp.types import TextDocumentIdentifier
|
|
5
|
+
from robotcode.core.text_document import TextDocument
|
|
5
6
|
from robotcode.core.uri import Uri
|
|
6
7
|
from robotcode.core.utils.dataclasses import CamelSnakeMixin
|
|
7
8
|
from robotcode.core.utils.logging import LoggingDescriptor
|
|
8
9
|
from robotcode.jsonrpc2.protocol import rpc_method
|
|
9
|
-
from robotcode.robot.diagnostics.
|
|
10
|
+
from robotcode.robot.diagnostics.entities import LibraryEntry
|
|
11
|
+
from robotcode.robot.diagnostics.library_doc import KeywordDoc, LibraryDoc
|
|
12
|
+
from robotcode.robot.diagnostics.namespace import Namespace
|
|
13
|
+
from robotcode.robot.utils.markdown_docs import LinkResolver, ReferenceTarget
|
|
10
14
|
|
|
15
|
+
from .code_action_documentation import DocumentationTarget, keyword_reference_targets, link_documentation
|
|
11
16
|
from .protocol_part import RobotLanguageServerProtocolPart
|
|
12
17
|
|
|
13
18
|
if TYPE_CHECKING:
|
|
@@ -72,7 +77,7 @@ class GetDocumentationUrl(CamelSnakeMixin):
|
|
|
72
77
|
keyword_id: Optional[str] = None
|
|
73
78
|
|
|
74
79
|
|
|
75
|
-
class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart
|
|
80
|
+
class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart):
|
|
76
81
|
_logger = LoggingDescriptor()
|
|
77
82
|
|
|
78
83
|
def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
|
|
@@ -96,50 +101,117 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
96
101
|
result = []
|
|
97
102
|
|
|
98
103
|
for _k, v in namespace.libraries.items():
|
|
104
|
+
documentation, keywords = (
|
|
105
|
+
self._import_documentation(v, True, document, namespace) if not no_documentation else (None, None)
|
|
106
|
+
)
|
|
99
107
|
result.append(
|
|
100
108
|
DocumentImport(
|
|
101
109
|
name=v.name,
|
|
102
110
|
alias=v.alias,
|
|
103
111
|
id=str(hash(v)),
|
|
104
112
|
type="library",
|
|
105
|
-
documentation=
|
|
106
|
-
keywords=
|
|
107
|
-
Keyword(
|
|
108
|
-
l.name,
|
|
109
|
-
str(hash(l)),
|
|
110
|
-
l.parameter_signature(),
|
|
111
|
-
l.to_markdown(add_signature=False) if not no_documentation else None,
|
|
112
|
-
)
|
|
113
|
-
for l in v.library_doc.keywords.values()
|
|
114
|
-
]
|
|
115
|
-
if not no_documentation
|
|
116
|
-
else None,
|
|
113
|
+
documentation=documentation,
|
|
114
|
+
keywords=keywords,
|
|
117
115
|
)
|
|
118
116
|
)
|
|
119
117
|
for _k, v in namespace.resources.items():
|
|
118
|
+
documentation, keywords = (
|
|
119
|
+
self._import_documentation(v, False, document, namespace) if not no_documentation else (None, None)
|
|
120
|
+
)
|
|
120
121
|
result.append(
|
|
121
122
|
DocumentImport(
|
|
122
123
|
name=v.name,
|
|
123
124
|
alias=None,
|
|
124
125
|
id=str(hash(v)),
|
|
125
126
|
type="resource",
|
|
126
|
-
documentation=
|
|
127
|
-
keywords=
|
|
128
|
-
Keyword(
|
|
129
|
-
l.name,
|
|
130
|
-
str(hash(l)),
|
|
131
|
-
l.parameter_signature(),
|
|
132
|
-
l.to_markdown(add_signature=False) if not no_documentation else None,
|
|
133
|
-
)
|
|
134
|
-
for l in v.library_doc.keywords.values()
|
|
135
|
-
]
|
|
136
|
-
if not no_documentation
|
|
137
|
-
else None,
|
|
127
|
+
documentation=documentation,
|
|
128
|
+
keywords=keywords,
|
|
138
129
|
)
|
|
139
130
|
)
|
|
140
131
|
|
|
141
132
|
return result
|
|
142
133
|
|
|
134
|
+
@property
|
|
135
|
+
def _links(self) -> bool:
|
|
136
|
+
return self.parent.robot_initialization_options.documentation_viewer_links
|
|
137
|
+
|
|
138
|
+
def _import_documentation(
|
|
139
|
+
self, entry: LibraryEntry, is_library: bool, document: TextDocument, namespace: Namespace
|
|
140
|
+
) -> Tuple[str, List[Keyword]]:
|
|
141
|
+
"""The tooltips of an import and of its keywords."""
|
|
142
|
+
library_doc = entry.library_doc
|
|
143
|
+
target = (
|
|
144
|
+
self.parent.robot_code_action_documentation.entry_target(entry, is_library, document, namespace)
|
|
145
|
+
if self._links
|
|
146
|
+
else None
|
|
147
|
+
)
|
|
148
|
+
link_resolver = self._link_resolver(document, namespace, target, library_doc)
|
|
149
|
+
return (
|
|
150
|
+
self._documentation(
|
|
151
|
+
lambda link_resolver: library_doc.to_markdown(add_signature=False, link_resolver=link_resolver),
|
|
152
|
+
target,
|
|
153
|
+
link_resolver,
|
|
154
|
+
),
|
|
155
|
+
self._keywords(list(library_doc.keywords.values()), target, link_resolver),
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def _link_resolver(
|
|
159
|
+
self,
|
|
160
|
+
document: TextDocument,
|
|
161
|
+
namespace: Namespace,
|
|
162
|
+
target: Optional[DocumentationTarget],
|
|
163
|
+
library_doc: LibraryDoc,
|
|
164
|
+
) -> Optional[LinkResolver]:
|
|
165
|
+
# one for the tooltips of an import and all of its keywords
|
|
166
|
+
if target is None:
|
|
167
|
+
return None
|
|
168
|
+
return self.parent.robot_code_action_documentation.link_resolver(document, namespace, target, library_doc)
|
|
169
|
+
|
|
170
|
+
def _keywords(
|
|
171
|
+
self,
|
|
172
|
+
keywords: List[KeywordDoc],
|
|
173
|
+
target: Optional[DocumentationTarget],
|
|
174
|
+
link_resolver: Optional[LinkResolver],
|
|
175
|
+
) -> List[Keyword]:
|
|
176
|
+
"""The keywords of a library, a resource file or the document with their tooltips."""
|
|
177
|
+
# once for all keywords, they share their library and its documentation format
|
|
178
|
+
targets = keyword_reference_targets(keywords[0], self._links) if keywords else None
|
|
179
|
+
return [self._keyword(kw, target, link_resolver, targets) for kw in keywords]
|
|
180
|
+
|
|
181
|
+
def _keyword(
|
|
182
|
+
self,
|
|
183
|
+
kw: KeywordDoc,
|
|
184
|
+
target: Optional[DocumentationTarget],
|
|
185
|
+
link_resolver: Optional[LinkResolver],
|
|
186
|
+
targets: Optional[Mapping[str, ReferenceTarget]],
|
|
187
|
+
) -> Keyword:
|
|
188
|
+
return Keyword(
|
|
189
|
+
kw.name,
|
|
190
|
+
str(hash(kw)),
|
|
191
|
+
kw.parameter_signature(),
|
|
192
|
+
self._documentation(
|
|
193
|
+
lambda link_resolver: kw.to_markdown(
|
|
194
|
+
add_signature=False, link_resolver=link_resolver, reference_targets=targets
|
|
195
|
+
),
|
|
196
|
+
target,
|
|
197
|
+
link_resolver,
|
|
198
|
+
heading=False,
|
|
199
|
+
),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
def _documentation(
|
|
203
|
+
self,
|
|
204
|
+
render: Callable[[Optional[LinkResolver]], str],
|
|
205
|
+
target: Optional[DocumentationTarget],
|
|
206
|
+
link_resolver: Optional[LinkResolver],
|
|
207
|
+
*,
|
|
208
|
+
heading: bool = True,
|
|
209
|
+
) -> str:
|
|
210
|
+
"""A tooltip; with links, linked into the Documentation Viewer at the page of `target`."""
|
|
211
|
+
if not self._links:
|
|
212
|
+
return render(None)
|
|
213
|
+
return link_documentation(render, target, None, heading=heading, link_resolver=link_resolver)
|
|
214
|
+
|
|
143
215
|
@rpc_method(name="robot/keywordsview/getDocumentKeywords", param_type=GetDocumentKeywordsParams, threaded=True)
|
|
144
216
|
@_logger.call
|
|
145
217
|
def _get_document_keywords(
|
|
@@ -155,31 +227,27 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
155
227
|
|
|
156
228
|
namespace = self.parent.documents_cache.get_namespace(document)
|
|
157
229
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
str(hash(l)),
|
|
162
|
-
l.parameter_signature(),
|
|
163
|
-
l.to_markdown(add_signature=False) if not no_documentation else None,
|
|
164
|
-
)
|
|
165
|
-
for l in namespace.library_doc.keywords.values()
|
|
166
|
-
]
|
|
230
|
+
keywords = list(namespace.library_doc.keywords.values())
|
|
231
|
+
if no_documentation:
|
|
232
|
+
return [Keyword(l.name, str(hash(l)), l.parameter_signature(), None) for l in keywords]
|
|
167
233
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
234
|
+
target = (
|
|
235
|
+
self.parent.robot_code_action_documentation.document_target(document, namespace) if self._links else None
|
|
236
|
+
)
|
|
237
|
+
return self._keywords(keywords, target, self._link_resolver(document, namespace, target, namespace.library_doc))
|
|
238
|
+
|
|
239
|
+
def _documentation_target(
|
|
171
240
|
self,
|
|
172
241
|
text_document: TextDocumentIdentifier,
|
|
173
|
-
import_id: Optional[str]
|
|
174
|
-
keyword_id: Optional[str]
|
|
175
|
-
|
|
176
|
-
**kwargs: Any,
|
|
177
|
-
) -> Optional[str]:
|
|
242
|
+
import_id: Optional[str],
|
|
243
|
+
keyword_id: Optional[str],
|
|
244
|
+
) -> Optional[DocumentationTarget]:
|
|
178
245
|
document = self.parent.documents.get(text_document.uri)
|
|
179
246
|
if document is None:
|
|
180
247
|
return None
|
|
181
248
|
|
|
182
249
|
namespace = self.parent.documents_cache.get_namespace(document)
|
|
250
|
+
documentation = self.parent.robot_code_action_documentation
|
|
183
251
|
|
|
184
252
|
keyword_name = None
|
|
185
253
|
|
|
@@ -189,25 +257,55 @@ class RobotKeywordsTreeViewPart(RobotLanguageServerProtocolPart, ModelHelper):
|
|
|
189
257
|
if keyword is not None:
|
|
190
258
|
keyword_name = keyword.name
|
|
191
259
|
|
|
192
|
-
return
|
|
193
|
-
str(document.uri.to_path().name), (), document, namespace, keyword_name
|
|
194
|
-
)
|
|
260
|
+
return documentation.document_target(document, namespace, keyword_name)
|
|
195
261
|
|
|
262
|
+
is_library = True
|
|
196
263
|
entry = next((l for l in namespace.libraries.values() if str(hash(l)) == import_id), None)
|
|
197
264
|
if entry is None:
|
|
265
|
+
is_library = False
|
|
198
266
|
entry = next((l for l in namespace.resources.values() if str(hash(l)) == import_id), None)
|
|
199
267
|
|
|
200
|
-
if
|
|
268
|
+
if entry is None:
|
|
269
|
+
return None
|
|
270
|
+
|
|
271
|
+
if keyword_id:
|
|
201
272
|
keyword = next((l for l in entry.library_doc.keywords.values() if str(hash(l)) == keyword_id), None)
|
|
202
273
|
if keyword is not None:
|
|
203
274
|
keyword_name = keyword.name
|
|
204
275
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
276
|
+
return documentation.entry_target(entry, is_library, document, namespace, keyword_name)
|
|
277
|
+
|
|
278
|
+
@rpc_method(name="robot/keywordsview/getDocumentationTarget", param_type=GetDocumentationUrl, threaded=True)
|
|
279
|
+
@_logger.call
|
|
280
|
+
def _get_documentation_target(
|
|
281
|
+
self,
|
|
282
|
+
text_document: TextDocumentIdentifier,
|
|
283
|
+
import_id: Optional[str] = None,
|
|
284
|
+
keyword_id: Optional[str] = None,
|
|
285
|
+
*args: Any,
|
|
286
|
+
**kwargs: Any,
|
|
287
|
+
) -> Optional[DocumentationTarget]:
|
|
288
|
+
return self._documentation_target(text_document, import_id, keyword_id)
|
|
289
|
+
|
|
290
|
+
@rpc_method(name="robot/keywordsview/getDocumentationUrl", param_type=GetDocumentationUrl, threaded=True)
|
|
291
|
+
@_logger.call
|
|
292
|
+
def _get_documentation_url(
|
|
293
|
+
self,
|
|
294
|
+
text_document: TextDocumentIdentifier,
|
|
295
|
+
import_id: Optional[str] = None,
|
|
296
|
+
keyword_id: Optional[str] = None,
|
|
297
|
+
*args: Any,
|
|
298
|
+
**kwargs: Any,
|
|
299
|
+
) -> Optional[str]:
|
|
300
|
+
target = self._documentation_target(text_document, import_id, keyword_id)
|
|
301
|
+
if target is None:
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
document = self.parent.documents.get(text_document.uri)
|
|
305
|
+
if document is None:
|
|
306
|
+
return None
|
|
209
307
|
|
|
210
|
-
return
|
|
308
|
+
return self.parent.robot_code_action_documentation.build_url(target, document)
|
|
211
309
|
|
|
212
310
|
@rpc_method(
|
|
213
311
|
name="robot/keywordsview/getLibraryDocumentation", param_type=GetLibraryDocumentationParams, threaded=True
|