@@ -467,17 +467,48 @@ async def create_keyword_settings_completion_items(self, range: Optional[Range])
467
467
for setting in KEYWORD_SETTINGS
468
468
]
469
469
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
+
470
497
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 ,
472
505
) -> List [CompletionItem ]:
473
506
result : List [CompletionItem ] = []
474
507
if self .document is None :
475
508
return []
476
509
477
510
r : Optional [Range ] = None
478
511
479
- # TODO: create Snippet for embedded keywords?
480
-
481
512
if token is not None :
482
513
r = range_from_token (token )
483
514
@@ -516,8 +547,17 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
516
547
detail = f"{ CompleteResultKind .KEYWORD .value } "
517
548
f"{ f'({ kw .libname } )' if kw .libname is not None else '' } " ,
518
549
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 ,
521
561
data = {
522
562
"document_uri" : str (self .document .uri ),
523
563
"type" : CompleteResultKind .KEYWORD .name ,
@@ -540,15 +580,23 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
540
580
for kw in res .library_doc .keywords .values ():
541
581
if kw .is_error_handler :
542
582
continue
583
+
543
584
result .append (
544
585
CompletionItem (
545
586
label = kw .name ,
546
587
kind = CompletionItemKind .FUNCTION ,
547
588
detail = f"{ CompleteResultKind .KEYWORD .value } "
548
589
f"{ f'({ kw .libname } )' if kw .libname is not None else '' } " ,
549
590
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
+ ),
552
600
data = {
553
601
"document_uri" : str (self .document .uri ),
554
602
"type" : CompleteResultKind .KEYWORD .name ,
@@ -561,6 +609,9 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
561
609
562
610
return result
563
611
612
+ if r is None :
613
+ r = Range (position , position )
614
+
564
615
for kw in await self .namespace .get_keywords ():
565
616
if kw .is_error_handler :
566
617
continue
@@ -572,8 +623,11 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
572
623
detail = f"{ CompleteResultKind .KEYWORD .value } { f'({ kw .libname } )' if kw .libname is not None else '' } " ,
573
624
deprecated = kw .is_deprecated ,
574
625
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
+ ),
577
631
data = {
578
632
"document_uri" : str (self .document .uri ),
579
633
"type" : CompleteResultKind .KEYWORD .name ,
@@ -593,7 +647,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
593
647
sort_text = f"030_{ v .name } " ,
594
648
deprecated = v .library_doc .is_deprecated ,
595
649
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 ),
597
651
data = {
598
652
"document_uri" : str (self .document .uri ),
599
653
"type" : CompleteResultKind .MODULE .name ,
@@ -614,7 +668,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
614
668
deprecated = v .library_doc .is_deprecated ,
615
669
sort_text = f"030_{ v .name } " ,
616
670
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 ),
618
672
data = {
619
673
"document_uri" : str (self .document .uri ),
620
674
"type" : CompleteResultKind .RESOURCE .name ,
@@ -631,7 +685,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
631
685
kind = CompletionItemKind .KEYWORD ,
632
686
sort_text = "998_NONE" ,
633
687
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" ),
635
689
)
636
690
)
637
691
@@ -643,7 +697,7 @@ def enumerate_indexes(s: str, c: str) -> Iterator[int]:
643
697
kind = CompletionItemKind .KEYWORD ,
644
698
sort_text = f"999_{ k } " ,
645
699
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 ),
647
701
)
648
702
)
649
703
@@ -965,7 +1019,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
965
1019
position : Position ,
966
1020
context : Optional [CompletionContext ],
967
1021
) -> Union [List [CompletionItem ], CompletionList , None ]:
968
- from robot .parsing .model .statements import Statement
1022
+ from robot .parsing .model .statements import Statement , TestTemplate
969
1023
970
1024
# TODO should this be configurable?
971
1025
if (
@@ -992,6 +1046,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
992
1046
position ,
993
1047
add_reserverd = False ,
994
1048
add_none = True ,
1049
+ in_template = isinstance (node , TestTemplate ),
995
1050
)
996
1051
997
1052
if len (statement_node .tokens ) > 2 :
@@ -1006,6 +1061,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
1006
1061
position ,
1007
1062
add_reserverd = False ,
1008
1063
add_none = True ,
1064
+ in_template = isinstance (node , TestTemplate ),
1009
1065
)
1010
1066
1011
1067
if len (statement_node .tokens ) > 3 :
@@ -1021,6 +1077,7 @@ async def _complete_SuiteSetup_or_SuiteTeardown_or_TestTemplate( # noqa: N802
1021
1077
position ,
1022
1078
add_reserverd = False ,
1023
1079
add_none = True ,
1080
+ in_template = isinstance (node , TestTemplate ),
1024
1081
)
1025
1082
1026
1083
return None
@@ -1092,7 +1149,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
1092
1149
position : Position ,
1093
1150
context : Optional [CompletionContext ],
1094
1151
) -> Union [List [CompletionItem ], CompletionList , None ]:
1095
- from robot .parsing .model .statements import Statement
1152
+ from robot .parsing .model .statements import Statement , Template
1096
1153
1097
1154
# TODO should this be configurable?
1098
1155
if (
@@ -1120,6 +1177,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
1120
1177
position ,
1121
1178
add_reserverd = False ,
1122
1179
add_none = True ,
1180
+ in_template = isinstance (node , Template ),
1123
1181
)
1124
1182
1125
1183
if len (statement_node .tokens ) > 3 :
@@ -1130,10 +1188,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
1130
1188
r = range_from_token (token )
1131
1189
if position .is_in_range (r ):
1132
1190
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 )
1137
1192
)
1138
1193
1139
1194
if len (statement_node .tokens ) > 4 :
@@ -1149,6 +1204,7 @@ async def complete_Setup_or_Teardown_or_Template( # noqa: N802
1149
1204
position ,
1150
1205
add_reserverd = False ,
1151
1206
add_none = True ,
1207
+ in_template = isinstance (node , Template ),
1152
1208
)
1153
1209
1154
1210
return None
0 commit comments