Skip to content

Commit 1602b71

Browse files
committed
feat(langserver): better completion for variable imports
1 parent 92b41e0 commit 1602b71

File tree

2 files changed

+41
-93
lines changed

2 files changed

+41
-93
lines changed

packages/language_server/src/robotcode/language_server/robotframework/diagnostics/library_doc.py

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,28 +1928,10 @@ def is_dynamic(self) -> bool:
19281928
if importer.is_dynamic():
19291929
get_variables = getattr(libcode, "get_variables", None) or getattr(libcode, "getVariables", None)
19301930

1931-
# TODO: add type information of the value including dict key names and member names
1932-
vars: List[ImportedVariableDefinition] = [
1933-
ImportedVariableDefinition(
1934-
1,
1935-
0,
1936-
1,
1937-
0,
1938-
source or (module_spec.origin if module_spec is not None else None) or "",
1939-
name,
1940-
None,
1941-
value=NativeValue(value) if value is None or isinstance(value, (int, float, bool, str)) else None,
1942-
has_value=value is None or isinstance(value, (int, float, bool, str)),
1943-
value_is_native=value is None or isinstance(value, (int, float, bool, str)),
1944-
)
1945-
for name, value in importer.import_variables(import_name, args)
1946-
]
1947-
19481931
libdoc = VariablesDoc(
19491932
name=stem,
19501933
source=source or module_spec.origin if module_spec is not None else import_name,
19511934
module_spec=module_spec,
1952-
variables=vars,
19531935
stdout=std_capturer.getvalue(),
19541936
python_path=sys.path,
19551937
)
@@ -2026,6 +2008,39 @@ def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any:
20262008
]
20272009
]
20282010
)
2011+
try:
2012+
# TODO: add type information of the value including dict key names and member names
2013+
libdoc.variables = [
2014+
ImportedVariableDefinition(
2015+
1,
2016+
0,
2017+
1,
2018+
0,
2019+
source or (module_spec.origin if module_spec is not None else None) or "",
2020+
name,
2021+
None,
2022+
value=NativeValue(value)
2023+
if value is None or isinstance(value, (int, float, bool, str))
2024+
else None,
2025+
has_value=value is None or isinstance(value, (int, float, bool, str)),
2026+
value_is_native=value is None or isinstance(value, (int, float, bool, str)),
2027+
)
2028+
for name, value in importer.import_variables(import_name, args)
2029+
]
2030+
except (SystemExit, KeyboardInterrupt):
2031+
raise
2032+
except BaseException as e:
2033+
libdoc.errors = [
2034+
error_from_exception(
2035+
e,
2036+
source or module_spec.origin
2037+
if module_spec is not None and module_spec.origin
2038+
else import_name
2039+
if is_variables_by_path(import_name)
2040+
else None,
2041+
1 if source is not None or module_spec is not None and module_spec.origin is not None else None,
2042+
)
2043+
]
20292044

20302045
return libdoc
20312046
except (SystemExit, KeyboardInterrupt, IgnoreEasterEggLibraryWarning):

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

Lines changed: 8 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,13 +1850,6 @@ async def complete_arguments() -> Optional[List[CompletionItem]]:
18501850
):
18511851
return None
18521852

1853-
with_name_token = next((v for v in import_node.tokens if v.value == "WITH NAME"), None)
1854-
if with_name_token is not None and position >= range_from_token(with_name_token).start:
1855-
return None
1856-
1857-
if context is None or context.trigger_kind != CompletionTriggerKind.INVOKED:
1858-
return []
1859-
18601853
kw_node = cast(Statement, node)
18611854

18621855
tokens_at_position = get_tokens_at_position(kw_node, position)
@@ -1866,87 +1859,27 @@ async def complete_arguments() -> Optional[List[CompletionItem]]:
18661859

18671860
token_at_position = tokens_at_position[-1]
18681861

1869-
if token_at_position.type not in [RobotToken.ARGUMENT, RobotToken.EOL, RobotToken.SEPARATOR]:
1870-
return None
1871-
1872-
if (
1873-
token_at_position.type == RobotToken.EOL
1874-
and len(tokens_at_position) > 1
1875-
and tokens_at_position[-2].type == RobotToken.KEYWORD
1876-
):
1877-
return None
1878-
1879-
token_at_position_index = kw_node.tokens.index(token_at_position)
1880-
1881-
argument_token_index = token_at_position_index
1882-
while argument_token_index >= 0 and kw_node.tokens[argument_token_index].type != RobotToken.ARGUMENT:
1883-
argument_token_index -= 1
1884-
1885-
argument_token: Optional[RobotToken] = None
1886-
if argument_token_index >= 0:
1887-
argument_token = kw_node.tokens[argument_token_index]
1888-
1889-
completion_range = range_from_token(argument_token or token_at_position)
1890-
completion_range.end = range_from_token(token_at_position).end
1891-
if (w := whitespace_at_begin_of_token(token_at_position)) > 0:
1892-
if w > 1 and range_from_token(token_at_position).start.character + 1 < position.character:
1893-
completion_range.start = position
1894-
elif completion_range.start != position:
1895-
return None
1896-
else:
1897-
if "=" in (argument_token or token_at_position).value:
1898-
equal_index = (argument_token or token_at_position).value.index("=")
1899-
if completion_range.start.character + equal_index < position.character:
1900-
return None
1901-
1902-
completion_range.end.character = completion_range.start.character + equal_index + 1
1903-
else:
1904-
completion_range.end = position
1905-
19061862
try:
19071863
libdoc = await self.namespace.get_imported_variables_libdoc(import_node.name, import_node.args)
1864+
if libdoc is not None:
1865+
init = next((v for v in libdoc.inits.values()), None)
1866+
if init:
1867+
return self._complete_keyword_arguments_at_position(
1868+
init, kw_node.tokens, token_at_position, position
1869+
)
19081870

19091871
except (SystemExit, KeyboardInterrupt, asyncio.CancelledError):
19101872
raise
19111873
except BaseException as e:
19121874
self._logger.exception(e)
1913-
return None
1914-
1915-
if libdoc is not None:
1916-
init = next((v for v in libdoc.inits.values()), None)
1917-
1918-
if init:
1919-
return [
1920-
CompletionItem(
1921-
label=f"{e.name}=",
1922-
kind=CompletionItemKind.VARIABLE,
1923-
sort_text=f"010{i}_{e.name}",
1924-
filter_text=e.name,
1925-
insert_text_format=InsertTextFormat.PLAIN_TEXT,
1926-
text_edit=TextEdit(range=completion_range, new_text=f"{e.name}="),
1927-
data=CompletionItemData(
1928-
document_uri=str(self.document.uri),
1929-
type="Argument",
1930-
name=e.name,
1931-
),
1932-
)
1933-
for i, e in enumerate(init.arguments)
1934-
if e.kind
1935-
not in [
1936-
KeywordArgumentKind.VAR_POSITIONAL,
1937-
KeywordArgumentKind.VAR_NAMED,
1938-
KeywordArgumentKind.NAMED_ONLY_MARKER,
1939-
KeywordArgumentKind.POSITIONAL_ONLY_MARKER,
1940-
]
1941-
]
19421875

19431876
return None
19441877

19451878
result = await complete_import() or []
19461879
# TODO this is not supported in robotframework, but it would be nice to have
1947-
# result.extend(await complete_arguments() or [])
1880+
result.extend(await complete_arguments() or [])
19481881

1949-
return result # noqa: RET504
1882+
return result
19501883

19511884
async def _complete_KeywordCall_or_Fixture( # noqa: N802
19521885
self,

0 commit comments

Comments
 (0)