27
27
from robotcode .core .async_itertools import async_chain , async_chain_iterator
28
28
from robotcode .core .logging import LoggingDescriptor
29
29
from robotcode .core .lsp .types import (
30
+ Command ,
30
31
CompletionContext ,
31
32
CompletionItem ,
32
33
CompletionItemKind ,
@@ -104,6 +105,7 @@ async def get_header_style(self, config: CompletionConfig) -> str:
104
105
"." ,
105
106
"/" ,
106
107
"{" ,
108
+ "=" ,
107
109
os .sep ,
108
110
],
109
111
)
@@ -2021,8 +2023,8 @@ async def _complete_KeywordCall_or_Fixture( # noqa: N802
2021
2023
from robot .parsing .lexer .tokens import Token as RobotToken
2022
2024
from robot .parsing .model .statements import Statement
2023
2025
2024
- if context is None or context .trigger_kind != CompletionTriggerKind .INVOKED :
2025
- return []
2026
+ # if context is None or context.trigger_kind != CompletionTriggerKind.INVOKED:
2027
+ # return []
2026
2028
2027
2029
kw_node = cast (Statement , node )
2028
2030
@@ -2040,24 +2042,35 @@ async def _complete_KeywordCall_or_Fixture( # noqa: N802
2040
2042
if token_at_position .type not in [RobotToken .ARGUMENT , RobotToken .EOL , RobotToken .SEPARATOR ]:
2041
2043
return None
2042
2044
2043
- if (
2044
- token_at_position .type in [RobotToken .EOL , RobotToken .SEPARATOR ]
2045
- and len (tokens_at_position ) > 1
2046
- and tokens_at_position [- 2 ].type == RobotToken .KEYWORD
2047
- ):
2045
+ keyword_doc_and_token : Optional [Tuple [Optional [KeywordDoc ], Token ]] = None
2046
+
2047
+ keyword_token = kw_node .get_token (keyword_name_token_type )
2048
+ if keyword_token is None :
2049
+ return None
2050
+
2051
+ keyword_doc_and_token = await self .get_keyworddoc_and_token_from_position (
2052
+ keyword_token .value ,
2053
+ keyword_token ,
2054
+ [t for t in kw_node .get_tokens (RobotToken .ARGUMENT )],
2055
+ self .namespace ,
2056
+ range_from_token (keyword_token ).start ,
2057
+ analyse_run_keywords = False ,
2058
+ )
2059
+
2060
+ if keyword_doc_and_token is None or keyword_doc_and_token [0 ] is None :
2048
2061
return None
2049
2062
2050
- token_at_position_index = kw_node . tokens . index ( token_at_position )
2063
+ keyword_doc = keyword_doc_and_token [ 0 ]
2051
2064
2052
- argument_token_index = token_at_position_index
2053
- while argument_token_index >= 0 and kw_node . tokens [ argument_token_index ]. type != RobotToken . ARGUMENT :
2054
- argument_token_index -= 1
2065
+ if keyword_doc . is_any_run_keyword ():
2066
+ # TODO
2067
+ pass
2055
2068
2056
- argument_token : Optional [ RobotToken ] = None
2057
- if argument_token_index >= 0 :
2058
- argument_token = kw_node . tokens [ argument_token_index ]
2069
+ argument_index , kw_arguments , argument_token = self . get_argument_info_at_position (
2070
+ keyword_doc , kw_node . tokens , token_at_position , position
2071
+ )
2059
2072
2060
- result : Optional [ Tuple [ Optional [ KeywordDoc ], Token ]]
2073
+ complete_argument_names = True
2061
2074
2062
2075
completion_range = range_from_token (argument_token or token_at_position )
2063
2076
completion_range .end = range_from_token (token_at_position ).end
@@ -2069,56 +2082,107 @@ async def _complete_KeywordCall_or_Fixture( # noqa: N802
2069
2082
else :
2070
2083
if "=" in (argument_token or token_at_position ).value :
2071
2084
equal_index = (argument_token or token_at_position ).value .index ("=" )
2072
- if completion_range .start .character + equal_index < position . character :
2073
- return None
2074
-
2075
- completion_range . end . character = completion_range . start . character + equal_index + 1
2076
- else :
2077
- completion_range .end = position
2085
+ if position . character < completion_range .start .character + equal_index :
2086
+ completion_range . end . character = completion_range . start . character + equal_index + 1
2087
+ else :
2088
+ complete_argument_names = False
2089
+ completion_range . start . character = completion_range . start . character + equal_index + 1
2090
+ completion_range .end = position
2078
2091
2079
- result = await self .get_keyworddoc_and_token_from_position (
2080
- keyword_token .value ,
2081
- keyword_token ,
2082
- [cast (Token , t ) for t in kw_node .get_tokens (RobotToken .ARGUMENT )],
2083
- self .namespace ,
2084
- range_from_token (keyword_token ).start ,
2085
- analyse_run_keywords = False ,
2086
- )
2092
+ result = []
2087
2093
2088
- if result is None or result [0 ] is None :
2089
- return None
2094
+ if argument_index >= 0 and keyword_doc .parent is not None and argument_index < len (kw_arguments ):
2095
+ type_infos = keyword_doc .parent .get_types (kw_arguments [argument_index ].types )
2096
+ for i , type_info in enumerate (type_infos ):
2097
+ if type_info .name == "boolean" :
2098
+ snippets = [
2099
+ "True" ,
2100
+ "False" ,
2101
+ ]
2102
+ for i , snippet in enumerate (snippets ):
2103
+ result .append (
2104
+ CompletionItem (
2105
+ label = snippet ,
2106
+ kind = CompletionItemKind .VALUE ,
2107
+ detail = type_info .name ,
2108
+ documentation = MarkupContent (MarkupKind .MARKDOWN , type_info .to_markdown ()),
2109
+ sort_text = f"02{ i :03} _{ snippet } " ,
2110
+ insert_text_format = InsertTextFormat .PLAIN_TEXT ,
2111
+ text_edit = TextEdit (
2112
+ range = completion_range ,
2113
+ new_text = snippet ,
2114
+ ),
2115
+ )
2116
+ )
2090
2117
2091
- if result [0 ].is_any_run_keyword ():
2092
- # TODO: complete run keyword
2093
- # ks = await self.get_keyworddoc_and_token_from_position(
2094
- # keyword_token.value,
2095
- # keyword_token,
2096
- # [cast(Token, t) for t in kw_node.get_tokens(RobotToken.ARGUMENT)],
2097
- # namespace,
2098
- # position,
2099
- # analyse_run_keywords=True,
2100
- # )
2101
- pass
2118
+ if type_info .members :
2119
+ for member in type_info .members :
2120
+ result .append (
2121
+ CompletionItem (
2122
+ label = member .name ,
2123
+ kind = CompletionItemKind .ENUM_MEMBER ,
2124
+ detail = type_info .name ,
2125
+ documentation = MarkupContent (
2126
+ MarkupKind .MARKDOWN , f"```python\n { member .name } = { member .value } \n ```"
2127
+ ),
2128
+ sort_text = f"01{ i } _{ member .name } " ,
2129
+ insert_text_format = InsertTextFormat .PLAIN_TEXT ,
2130
+ text_edit = TextEdit (
2131
+ range = completion_range ,
2132
+ new_text = member .name ,
2133
+ ),
2134
+ )
2135
+ )
2136
+ if type_info .items :
2137
+ snippets = [
2138
+ "{"
2139
+ + ", " .join (
2140
+ (str (m .key ) + ": ${" + str (i + 1 ) + "}" )
2141
+ for i , m in enumerate (type_info .items )
2142
+ if m .required
2143
+ )
2144
+ + "}" ,
2145
+ f"{{{ ', ' .join ((str (m .key )+ ': ${' + str (i + 1 )+ '}' ) for i , m in enumerate (type_info .items ))} }}" ,
2146
+ ]
2147
+ for i , snippet in enumerate (snippets ):
2148
+ result .append (
2149
+ CompletionItem (
2150
+ label = snippet ,
2151
+ kind = CompletionItemKind .STRUCT ,
2152
+ detail = type_info .name ,
2153
+ documentation = MarkupContent (MarkupKind .MARKDOWN , type_info .to_markdown ()),
2154
+ sort_text = f"02{ i :03} _{ snippet } " ,
2155
+ insert_text_format = InsertTextFormat .SNIPPET ,
2156
+ text_edit = TextEdit (
2157
+ range = completion_range ,
2158
+ new_text = snippet ,
2159
+ ),
2160
+ )
2161
+ )
2102
2162
2103
- return [
2104
- CompletionItem (
2105
- label = f"{ e .name } =" ,
2106
- kind = CompletionItemKind .VARIABLE ,
2107
- detail = "Argument" ,
2108
- filter_text = e .name ,
2109
- sort_text = f"02{ i } _{ e .name } =" ,
2110
- insert_text_format = InsertTextFormat .PLAIN_TEXT ,
2111
- text_edit = TextEdit (range = completion_range , new_text = f"{ e .name } =" ),
2112
- )
2113
- for i , e in enumerate (result [0 ].arguments )
2114
- if e .kind
2115
- not in [
2116
- KeywordArgumentKind .VAR_POSITIONAL ,
2117
- KeywordArgumentKind .VAR_NAMED ,
2118
- KeywordArgumentKind .NAMED_ONLY_MARKER ,
2119
- KeywordArgumentKind .POSITIONAL_ONLY_MARKER ,
2163
+ if complete_argument_names :
2164
+ result += [
2165
+ CompletionItem (
2166
+ label = f"{ e .name } =" ,
2167
+ kind = CompletionItemKind .VARIABLE ,
2168
+ detail = "Argument" ,
2169
+ filter_text = e .name ,
2170
+ sort_text = f"03{ i :03} _{ e .name } =" ,
2171
+ insert_text_format = InsertTextFormat .PLAIN_TEXT ,
2172
+ text_edit = TextEdit (range = completion_range , new_text = f"{ e .name } =" ),
2173
+ command = Command ("" , "editor.action.triggerSuggest" , []),
2174
+ )
2175
+ for i , e in enumerate (kw_arguments )
2176
+ if e .kind
2177
+ not in [
2178
+ KeywordArgumentKind .VAR_POSITIONAL ,
2179
+ KeywordArgumentKind .VAR_NAMED ,
2180
+ KeywordArgumentKind .NAMED_ONLY_MARKER ,
2181
+ KeywordArgumentKind .POSITIONAL_ONLY_MARKER ,
2182
+ ]
2120
2183
]
2121
- ]
2184
+
2185
+ return result
2122
2186
2123
2187
async def complete_KeywordCall ( # noqa: N802
2124
2188
self ,
0 commit comments