Skip to content

Commit dee570b

Browse files
committed
feat(langserver): better signature help and completion of keyword arguments and library import arguments, including completions for type converters like Enums, bools, TypedDict, ...
1 parent ed7b186 commit dee570b

File tree

25 files changed

+275
-194
lines changed

25 files changed

+275
-194
lines changed

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

+8-5
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ def resolve(
439439
resolve_variables_until: Any = None,
440440
dict_to_kwargs: bool = False,
441441
validate: bool = True,
442-
) -> Tuple[List[Any], Dict[str, Any]]:
442+
) -> Tuple[List[Any], List[Tuple[str, Any]]]:
443443
from robot.running.arguments.argumentresolver import (
444444
ArgumentResolver,
445445
DictToKwargs,
@@ -470,7 +470,7 @@ def resolve(
470470
resolve_variables_until=resolve_variables_until,
471471
dict_to_kwargs=dict_to_kwargs,
472472
)
473-
return cast(Tuple[List[Any], Dict[str, Any]], resolver.resolve(arguments, variables))
473+
return cast(Tuple[List[Any], List[Tuple[str, Any]]], resolver.resolve(arguments, variables))
474474

475475
positional, named = NamedArgumentResolver(self.__robot_arguments).resolve(arguments, variables)
476476
positional, named = VariableReplacer(resolve_variables_until).replace(positional, named, variables)
@@ -626,7 +626,10 @@ def to_markdown(self, add_signature: bool = True, header_level: int = 2, add_typ
626626

627627
def _get_signature(self, header_level: int, add_type: bool = True) -> str:
628628
if add_type:
629-
result = f"#{'#'*header_level} {'Library' if self.is_initializer else 'Keyword'} *{self.name}*\n"
629+
result = (
630+
f"#{'#'*header_level} "
631+
f"{(self.libtype or 'Library').capitalize() if self.is_initializer else 'Keyword'} *{self.name}*\n"
632+
)
630633
else:
631634
if not self.is_initializer:
632635
result = f"\n\n#{'#'*header_level} {self.name}\n"
@@ -1971,7 +1974,7 @@ def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any:
19711974
col_offset=-1,
19721975
end_col_offset=-1,
19731976
end_line_no=-1,
1974-
type="library",
1977+
type="variables",
19751978
libname=libdoc.name,
19761979
libtype=libdoc.type,
19771980
longname=f"{libdoc.name}.{kw[0].name}",
@@ -2008,7 +2011,7 @@ def _get_initial_handler(self, library: Any, name: Any, method: Any) -> Any:
20082011
col_offset=-1,
20092012
end_col_offset=-1,
20102013
end_line_no=-1,
2011-
type="library",
2014+
type="variables",
20122015
libname=libdoc.name,
20132016
libtype=libdoc.type,
20142017
longname=f"{libdoc.name}.{kw[0].name}",

packages/language_server/src/robotcode/language_server/robotframework/languages.py

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class Languages(Protocol):
77
headers: Dict[str, str]
88
settings: Dict[str, str]
99
bdd_prefixes: Set[str]
10+
true_strings: Set[str]
11+
false_strings: Set[str]
1012

1113
def add_language(self, name: str) -> None:
1214
...

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

+169-120
Large diffs are not rendered by default.

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

+47-27
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ def get_argument_info_at_position(
645645
tokens: Tuple[Token, ...],
646646
token_at_position: Token,
647647
position: Position,
648-
) -> Tuple[int, List[ArgumentInfo], Optional[Token]]:
648+
) -> Tuple[int, Optional[List[ArgumentInfo]], Optional[Token]]:
649649
from robot.parsing.lexer.tokens import Token as RobotToken
650650
from robot.utils.escaping import split_from_equals
651651

@@ -670,7 +670,7 @@ def get_argument_info_at_position(
670670
and tokens[token_at_position_index - 1].type == RobotToken.CONTINUATION
671671
and position.character < range_from_token(tokens[token_at_position_index - 1]).end.character + 2
672672
):
673-
return -1, kw_arguments, None
673+
return -1, None, None
674674

675675
token_at_position_index = tokens.index(token_at_position)
676676

@@ -723,35 +723,55 @@ def get_argument_info_at_position(
723723
if argument_token is not None and argument_token.type == RobotToken.ARGUMENT:
724724
arg_name_or_value, arg_value = split_from_equals(argument_token.value)
725725
if arg_value is not None:
726-
arg_name = arg_name_or_value
727-
named_arg = True
728-
argument_index = next((i for i, v in enumerate(kw_arguments) if v.name == arg_name), -1)
726+
old_argument_index = argument_index
727+
argument_index = next(
728+
(
729+
i
730+
for i, v in enumerate(kw_arguments)
731+
if v.name == arg_name_or_value or v.kind == KeywordArgumentKind.VAR_NAMED
732+
),
733+
-1,
734+
)
735+
729736
if argument_index == -1:
737+
argument_index = old_argument_index
738+
else:
739+
named_arg = True
740+
741+
if not named_arg and argument_index >= 0:
742+
need_named = False
743+
for i, a in enumerate(arguments):
744+
if i == argument_index:
745+
break
746+
arg_name_or_value, arg_value = split_from_equals(a.value)
747+
if arg_value is not None and any(
748+
(i for i, v in enumerate(kw_arguments) if v.name == arg_name_or_value)
749+
):
750+
need_named = True
751+
break
752+
753+
a_index = next(
754+
(
755+
i
756+
for i, v in enumerate(kw_arguments)
757+
if v.kind in [KeywordArgumentKind.POSITIONAL_ONLY, KeywordArgumentKind.POSITIONAL_OR_NAMED]
758+
and i == argument_index
759+
),
760+
-1,
761+
)
762+
if a_index >= 0 and not need_named:
763+
argument_index = a_index
764+
else:
765+
if need_named:
730766
argument_index = next(
731767
(i for i, v in enumerate(kw_arguments) if v.kind == KeywordArgumentKind.VAR_NAMED), -1
732768
)
769+
else:
770+
argument_index = next(
771+
(i for i, v in enumerate(kw_arguments) if v.kind == KeywordArgumentKind.VAR_POSITIONAL), -1
772+
)
733773

734-
if (
735-
argument_index >= len(kw_arguments)
736-
and len(kw_arguments) > 0
737-
and kw_arguments[-1].kind in [KeywordArgumentKind.VAR_POSITIONAL, KeywordArgumentKind.VAR_NAMED]
738-
):
739-
argument_index = len(kw_arguments) - 1
740-
741-
if not named_arg and argument_index >= 0 and argument_index < len(kw_arguments) and argument_token is not None:
742-
while (
743-
argument_index >= 0
744-
and argument_index < len(kw_arguments)
745-
and kw_arguments[argument_index].kind in [KeywordArgumentKind.NAMED_ONLY]
746-
):
747-
argument_index -= 1
748-
749-
if argument_index >= 0 and argument_index < len(kw_arguments):
750-
args = arguments[:argument_index]
751-
for a in args:
752-
arg_name_or_value, arg_value = split_from_equals(a.value)
753-
if arg_value is not None:
754-
argument_index = -1
755-
break
774+
if argument_index >= len(kw_arguments):
775+
argument_index = -1
756776

757777
return argument_index, kw_arguments, argument_token

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,15 @@ async def _signature_help_KeywordCall_or_Fixture( # noqa: N802
122122
analyse_run_keywords=False,
123123
)
124124

125-
if keyword_doc_and_token is None or keyword_doc_and_token[0] is None:
125+
if keyword_doc_and_token is None:
126126
return None
127127

128-
keyword_doc = keyword_doc_and_token[0]
128+
keyword_doc, keyword_token = keyword_doc_and_token
129+
if keyword_doc is None:
130+
return None
131+
132+
if keyword_token is not None and position < range_from_token(keyword_token).extend(end_character=2).end:
133+
return None
129134

130135
if keyword_doc.is_any_run_keyword():
131136
# TODO
@@ -143,6 +148,8 @@ def _get_signature_help(
143148
argument_index, kw_arguments, _ = self.get_argument_info_at_position(
144149
keyword_doc, tokens, token_at_position, position
145150
)
151+
if kw_arguments is None:
152+
return None
146153

147154
signature = SignatureInformation(
148155
label=keyword_doc.parameter_signature(),

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_signature_help.test[signature_help.robot-012-059-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_signature_help.test[signature_help.robot-012-062-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_signature_help.test[signature_help.robot-012-065-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_signature_help.test[signature_help.robot-024-046-no_params].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 24
44
name: no params
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: '(i: int, b: bool, l: TestEnum = A)'
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf41/test_signature_help.test[signature_help.robot-033-018-BuiltIn_no_params].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 33
44
name: BuiltIn no params
55
result: !SignatureHelp
6-
active_parameter: 0
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 0
9+
- activeParameter: -1
1010
documentation: null
1111
label: ()
1212
parameters: []

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_signature_help.test[signature_help.robot-012-059-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_signature_help.test[signature_help.robot-012-062-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_signature_help.test[signature_help.robot-012-065-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_signature_help.test[signature_help.robot-024-046-no_params].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 24
44
name: no params
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: '(i: int, b: bool, l: TestEnum = A)'
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf50/test_signature_help.test[signature_help.robot-033-018-BuiltIn_no_params].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 33
44
name: BuiltIn no params
55
result: !SignatureHelp
6-
active_parameter: 0
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 0
9+
- activeParameter: -1
1010
documentation: null
1111
label: ()
1212
parameters: []

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf60/test_signature_help.test[signature_help.robot-012-059-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf60/test_signature_help.test[signature_help.robot-012-062-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf60/test_signature_help.test[signature_help.robot-012-065-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf60/test_signature_help.test[signature_help.robot-024-046-no_params].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 24
44
name: no params
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: '(i: int, b: bool, l: TestEnum = A)'
1212
parameters:

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf60/test_signature_help.test[signature_help.robot-033-018-BuiltIn_no_params].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 33
44
name: BuiltIn no params
55
result: !SignatureHelp
6-
active_parameter: 0
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 0
9+
- activeParameter: -1
1010
documentation: null
1111
label: ()
1212
parameters: []

tests/robotcode/language_server/robotframework/parts/_regtest_outputs/rf61/test_signature_help.test[signature_help.robot-012-059-no_param_resource].out

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ data: !GeneratedTestData
33
line: 12
44
name: no param resource
55
result: !SignatureHelp
6-
active_parameter: 3
6+
active_parameter: -1
77
active_signature: 0
88
signatures:
9-
- activeParameter: 3
9+
- activeParameter: -1
1010
documentation: null
1111
label: (message, level = INFO, html = ${False})
1212
parameters:

0 commit comments

Comments
 (0)