@@ -467,17 +467,48 @@ async def create_keyword_settings_completion_items(self, range: Optional[Range])
467467 for setting in KEYWORD_SETTINGS
468468 ]
469469
470+ def get_keyword_snipped_text (self , kw : KeywordDoc , in_template : bool ) -> str :
471+ from robot .variables .search import VariableIterator
472+
473+ if not kw .is_embedded :
474+ return kw .name
475+
476+ result = ""
477+ for index , (before , variable , after ) in enumerate (
478+ VariableIterator (kw .name , identifiers = "$" , ignore_errors = True )
479+ ):
480+ var_name = variable [2 :- 1 ].split (":" , 1 )[0 ]
481+ result += before
482+ result += "${" + str (index + 1 ) + ":"
483+ if in_template :
484+ result += "\\ ${"
485+
486+ result += var_name
487+
488+ if in_template :
489+ result += "\\ }"
490+
491+ result += "}"
492+
493+ result += after
494+
495+ return result
496+
470497 async def create_keyword_completion_items (
471- self , token : Optional [Token ], position : Position , * , add_reserverd : bool = True , add_none : bool = False
498+ self ,
499+ token : Optional [Token ],
500+ position : Position ,
501+ * ,
502+ add_reserverd : bool = True ,
503+ add_none : bool = False ,
504+ in_template : bool = False ,
472505 ) -> List [CompletionItem ]:
473506 result : List [CompletionItem ] = []
474507 if self .document is None :
475508 return []
476509
477510 r : Optional [Range ] = None
478511
479- # TODO: create Snippet for embedded keywords?
480-
481512 if token is not None :
482513 r = range_from_token (token )
483514
@@ -516,8 +547,17 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
516547 detail = f"{ CompleteResultKind .KEYWORD .value } "
517548 f"{ f'({ kw .libname } )' if kw .libname is not None else '' } " ,
518549 sort_text = f"020_{ kw .name } " ,
519- insert_text_format = InsertTextFormat .PLAINTEXT ,
520- text_edit = TextEdit (range = r , new_text = kw .name ) if r is not None else None ,
550+ insert_text_format = InsertTextFormat .PLAINTEXT
551+ if not kw .is_embedded
552+ else InsertTextFormat .SNIPPET ,
553+ text_edit = TextEdit (
554+ range = r ,
555+ new_text = kw .name
556+ if not kw .is_embedded
557+ else self .get_keyword_snipped_text (kw , in_template ),
558+ )
559+ if r is not None
560+ else None ,
521561 data = {
522562 "document_uri" : str (self .document .uri ),
523563 "type" : CompleteResultKind .KEYWORD .name ,
@@ -540,15 +580,23 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
540580 for kw in res .library_doc .keywords .values ():
541581 if kw .is_error_handler :
542582 continue
583+
543584 result .append (
544585 CompletionItem (
545586 label = kw .name ,
546587 kind = CompletionItemKind .FUNCTION ,
547588 detail = f"{ CompleteResultKind .KEYWORD .value } "
548589 f"{ f'({ kw .libname } )' if kw .libname is not None else '' } " ,
549590 sort_text = f"020_{ kw .name } " ,
550- insert_text_format = InsertTextFormat .PLAINTEXT ,
551- text_edit = TextEdit (range = r , new_text = kw .name ) if r is not None else None ,
591+ insert_text_format = InsertTextFormat .PLAINTEXT
592+ if not kw .is_embedded
593+ else InsertTextFormat .SNIPPET ,
594+ text_edit = TextEdit (
595+ range = r ,
596+ new_text = kw .name
597+ if not kw .is_embedded
598+ else self .get_keyword_snipped_text (kw , in_template ),
599+ ),
552600 data = {
553601 "document_uri" : str (self .document .uri ),
554602 "type" : CompleteResultKind .KEYWORD .name ,
@@ -561,6 +609,9 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
561609
562610 return result
563611
612+ if r is None :
613+ r = Range (position , position )
614+
564615 for kw in await self .namespace .get_keywords ():
565616 if kw .is_error_handler :
566617 continue
@@ -572,8 +623,11 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
572623 detail = f"{ CompleteResultKind .KEYWORD .value } { f'({ kw .libname } )' if kw .libname is not None else '' } " ,
573624 deprecated = kw .is_deprecated ,
574625 sort_text = f"020_{ kw .name } " ,
575- insert_text_format = InsertTextFormat .PLAINTEXT ,
576- text_edit = TextEdit (range = r , new_text = kw .name ) if r is not None else None ,
626+ insert_text_format = InsertTextFormat .PLAINTEXT if not kw .is_embedded else InsertTextFormat .SNIPPET ,
627+ text_edit = TextEdit (
628+ range = r ,
629+ new_text = kw .name if not kw .is_embedded else self .get_keyword_snipped_text (kw , in_template ),
630+ ),
577631 data = {
578632 "document_uri" : str (self .document .uri ),
579633 "type" : CompleteResultKind .KEYWORD .name ,
@@ -593,7 +647,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
593647 sort_text = f"030_{ v .name } " ,
594648 deprecated = v .library_doc .is_deprecated ,
595649 insert_text_format = InsertTextFormat .PLAINTEXT ,
596- text_edit = TextEdit (range = r , new_text = k ) if r is not None else None ,
650+ text_edit = TextEdit (range = r , new_text = k ),
597651 data = {
598652 "document_uri" : str (self .document .uri ),
599653 "type" : CompleteResultKind .MODULE .name ,
@@ -614,7 +668,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
614668 deprecated = v .library_doc .is_deprecated ,
615669 sort_text = f"030_{ v .name } " ,
616670 insert_text_format = InsertTextFormat .PLAINTEXT ,
617- text_edit = TextEdit (range = r , new_text = v .name ) if r is not None else None ,
671+ text_edit = TextEdit (range = r , new_text = v .name ),
618672 data = {
619673 "document_uri" : str (self .document .uri ),
620674 "type" : CompleteResultKind .RESOURCE .name ,
@@ -631,7 +685,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
631685 kind = CompletionItemKind .KEYWORD ,
632686 sort_text = "998_NONE" ,
633687 insert_text_format = InsertTextFormat .PLAINTEXT ,
634- text_edit = TextEdit (range = r , new_text = "NONE" ) if r is not None else None ,
688+ text_edit = TextEdit (range = r , new_text = "NONE" ),
635689 )
636690 )
637691
@@ -643,7 +697,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
643697 kind = CompletionItemKind .KEYWORD ,
644698 sort_text = f"999_{ k } " ,
645699 insert_text_format = InsertTextFormat .PLAINTEXT ,
646- text_edit = TextEdit (range = r , new_text = k ) if r is not None else None ,
700+ text_edit = TextEdit (range = r , new_text = k ),
647701 )
648702 )
649703
@@ -965,7 +1019,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
9651019 position : Position ,
9661020 context : Optional [CompletionContext ],
9671021 ) -> Union [List [CompletionItem ], CompletionList , None ]:
968- from robot .parsing .model .statements import Statement
1022+ from robot .parsing .model .statements import Statement , TestTemplate
9691023
9701024 # TODO should this be configurable?
9711025 if (
@@ -992,6 +1046,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
9921046 position ,
9931047 add_reserverd = False ,
9941048 add_none = True ,
1049+ in_template = isinstance (node , TestTemplate ),
9951050 )
9961051
9971052 if len (statement_node .tokens ) > 2 :
@@ -1006,6 +1061,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
10061061 position ,
10071062 add_reserverd = False ,
10081063 add_none = True ,
1064+ in_template = isinstance (node , TestTemplate ),
10091065 )
10101066
10111067 if len (statement_node .tokens ) > 3 :
@@ -1021,6 +1077,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
10211077 position ,
10221078 add_reserverd = False ,
10231079 add_none = True ,
1080+ in_template = isinstance (node , TestTemplate ),
10241081 )
10251082
10261083 return None
@@ -1092,7 +1149,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
10921149 position : Position ,
10931150 context : Optional [CompletionContext ],
10941151 ) -> Union [List [CompletionItem ], CompletionList , None ]:
1095- from robot .parsing .model .statements import Statement
1152+ from robot .parsing .model .statements import Statement , Template
10961153
10971154 # TODO should this be configurable?
10981155 if (
@@ -1120,6 +1177,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
11201177 position ,
11211178 add_reserverd = False ,
11221179 add_none = True ,
1180+ in_template = isinstance (node , Template ),
11231181 )
11241182
11251183 if len (statement_node .tokens ) > 3 :
@@ -1130,10 +1188,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
11301188 r = range_from_token (token )
11311189 if position .is_in_range (r ):
11321190 return await self .create_keyword_completion_items (
1133- token ,
1134- position ,
1135- add_reserverd = False ,
1136- add_none = True ,
1191+ token , position , add_reserverd = False , add_none = True , in_template = isinstance (node , Template )
11371192 )
11381193
11391194 if len (statement_node .tokens ) > 4 :
@@ -1149,6 +1204,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
11491204 position ,
11501205 add_reserverd = False ,
11511206 add_none = True ,
1207+ in_template = isinstance (node , Template ),
11521208 )
11531209
11541210 return None
0 commit comments