@@ -128,7 +128,7 @@ async def collect(
128
128
) -> Optional [List [Union [Command , CodeAction ]]]:
129
129
result = []
130
130
for method in iter_methods (self , lambda m : m .__name__ .startswith ("code_action_" )):
131
- code_actions = await method (self , document , range , context )
131
+ code_actions = await method (document , range , context )
132
132
if code_actions :
133
133
result .extend (code_actions )
134
134
@@ -138,11 +138,15 @@ async def collect(
138
138
return None
139
139
140
140
async def code_action_create_keyword (
141
- self , sender : Any , document : TextDocument , range : Range , context : CodeActionContext
141
+ self , document : TextDocument , range : Range , context : CodeActionContext
142
142
) -> Optional [List [Union [Command , CodeAction ]]]:
143
- if range .start == range .end and (
144
- (context .only and CodeActionKind .QUICK_FIX in context .only )
145
- or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
143
+ if (
144
+ range .start .line == range .end .line
145
+ and range .start .character <= range .end .character
146
+ and (
147
+ (context .only and CodeActionKind .QUICK_FIX in context .only )
148
+ or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
149
+ )
146
150
):
147
151
diagnostics = next (
148
152
(
@@ -265,7 +269,7 @@ async def create_keyword_command(self, document_uri: DocumentUri, range: Range)
265
269
await self .parent .window .show_document (str (document .uri ), take_focus = True , selection = insert_range )
266
270
267
271
async def code_action_assign_result_to_variable (
268
- self , sender : Any , document : TextDocument , range : Range , context : CodeActionContext
272
+ self , document : TextDocument , range : Range , context : CodeActionContext
269
273
) -> Optional [List [Union [Command , CodeAction ]]]:
270
274
from robot .parsing .lexer import Token as RobotToken
271
275
from robot .parsing .model .statements import (
@@ -275,9 +279,13 @@ async def code_action_assign_result_to_variable(
275
279
TestTemplate ,
276
280
)
277
281
278
- if range .start == range .end and (
279
- (context .only and "other" in context .only )
280
- or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
282
+ if (
283
+ range .start .line == range .end .line
284
+ and range .start .character <= range .end .character
285
+ and (
286
+ (context .only and "other" in context .only )
287
+ or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
288
+ )
281
289
):
282
290
model = await self .parent .documents_cache .get_model (document , False )
283
291
node = await get_node_at_position (model , range .start )
@@ -318,7 +326,7 @@ async def assign_result_to_variable_command(self, document_uri: DocumentUri, ran
318
326
TestTemplate ,
319
327
)
320
328
321
- if range .start == range .end :
329
+ if range .start . line == range .end . line and range . start . character <= range . end . character :
322
330
document = await self .parent .documents .get (document_uri )
323
331
if document is None :
324
332
return
@@ -355,14 +363,18 @@ async def assign_result_to_variable_command(self, document_uri: DocumentUri, ran
355
363
await self .parent .window .show_document (str (document .uri ), take_focus = True , selection = insert_range )
356
364
357
365
async def code_action_create_local_variable (
358
- self , sender : Any , document : TextDocument , range : Range , context : CodeActionContext
366
+ self , document : TextDocument , range : Range , context : CodeActionContext
359
367
) -> Optional [List [Union [Command , CodeAction ]]]:
360
368
from robot .parsing .model .blocks import Keyword , TestCase
361
369
from robot .parsing .model .statements import Documentation , Fixture , Statement , Template
362
370
363
- if range .start == range .end and (
364
- (context .only and CodeActionKind .QUICK_FIX in context .only )
365
- or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
371
+ if (
372
+ range .start .line == range .end .line
373
+ and range .start .character <= range .end .character
374
+ and (
375
+ (context .only and CodeActionKind .QUICK_FIX in context .only )
376
+ or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
377
+ )
366
378
):
367
379
diagnostics = next (
368
380
(
@@ -409,7 +421,7 @@ async def create_local_variable_command(self, document_uri: DocumentUri, range:
409
421
from robot .parsing .model .blocks import Keyword , TestCase
410
422
from robot .parsing .model .statements import Documentation , Fixture , Statement , Template
411
423
412
- if range .start .line == range .end .line and range .start .character < range .end .character :
424
+ if range .start .line == range .end .line and range .start .character <= range .end .character :
413
425
document = await self .parent .documents .get (document_uri )
414
426
if document is None :
415
427
return
@@ -447,17 +459,21 @@ async def create_local_variable_command(self, document_uri: DocumentUri, range:
447
459
)
448
460
449
461
if (await self .parent .workspace .apply_edit (we )).applied :
450
- insert_range .start .character += insert_text .index ("value" )
462
+ insert_range .start .character += insert_text .rindex ("value" )
451
463
insert_range .end .character = insert_range .start .character + len ("value" )
452
464
453
465
await self .parent .window .show_document (str (document .uri ), take_focus = False , selection = insert_range )
454
466
455
467
async def code_action_disable_robotcode_diagnostics_for_line (
456
- self , sender : Any , document : TextDocument , range : Range , context : CodeActionContext
468
+ self , document : TextDocument , range : Range , context : CodeActionContext
457
469
) -> Optional [List [Union [Command , CodeAction ]]]:
458
- if range .start == range .end and (
459
- (context .only and CodeActionKind .QUICK_FIX in context .only )
460
- or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
470
+ if (
471
+ range .start .line == range .end .line
472
+ and range .start .character <= range .end .character
473
+ and (
474
+ (context .only and CodeActionKind .QUICK_FIX in context .only )
475
+ or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
476
+ )
461
477
):
462
478
diagnostics = next ((d for d in context .diagnostics if d .source and d .source .startswith ("robotcode." )), None )
463
479
@@ -479,7 +495,7 @@ async def code_action_disable_robotcode_diagnostics_for_line(
479
495
480
496
@command ("robotcode.disableRobotcodeDiagnosticsForLine" )
481
497
async def disable_robotcode_diagnostics_for_line_command (self , document_uri : DocumentUri , range : Range ) -> None :
482
- if range .start .line == range .end .line :
498
+ if range .start .line == range .end .line and range . start . character <= range . end . character :
483
499
document = await self .parent .documents .get (document_uri )
484
500
if document is None :
485
501
return
@@ -509,11 +525,15 @@ async def disable_robotcode_diagnostics_for_line_command(self, document_uri: Doc
509
525
await self .parent .workspace .apply_edit (we )
510
526
511
527
async def code_action_create_suite_variable (
512
- self , sender : Any , document : TextDocument , range : Range , context : CodeActionContext
528
+ self , document : TextDocument , range : Range , context : CodeActionContext
513
529
) -> Optional [List [Union [Command , CodeAction ]]]:
514
- if range .start == range .end and (
515
- (context .only and CodeActionKind .QUICK_FIX in context .only )
516
- or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
530
+ if (
531
+ range .start .line == range .end .line
532
+ and range .start .character <= range .end .character
533
+ and (
534
+ (context .only and CodeActionKind .QUICK_FIX in context .only )
535
+ or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
536
+ )
517
537
):
518
538
diagnostics = next (
519
539
(
@@ -548,7 +568,7 @@ async def create_suite_variable_command(self, document_uri: DocumentUri, range:
548
568
from robot .parsing .model .blocks import VariableSection
549
569
from robot .parsing .model .statements import Variable
550
570
551
- if range .start .line == range .end .line and range .start .character < range .end .character :
571
+ if range .start .line == range .end .line and range .start .character <= range .end .character :
552
572
document = await self .parent .documents .get (document_uri )
553
573
if document is None :
554
574
return
@@ -622,7 +642,127 @@ async def create_suite_variable_command(self, document_uri: DocumentUri, range:
622
642
start_line = next ((i for i , l in enumerate (splitted ) if "value" in l ), 0 )
623
643
insert_range .start .line = insert_range .start .line + start_line
624
644
insert_range .end .line = insert_range .start .line
625
- insert_range .start .character = splitted [start_line ].index ("value" )
645
+ insert_range .start .character = splitted [start_line ].rindex ("value" )
626
646
insert_range .end .character = insert_range .start .character + len ("value" )
627
647
628
648
await self .parent .window .show_document (str (document .uri ), take_focus = False , selection = insert_range )
649
+
650
+ async def code_action_add_argument (
651
+ self , document : TextDocument , range : Range , context : CodeActionContext
652
+ ) -> Optional [List [Union [Command , CodeAction ]]]:
653
+ from robot .parsing .model .blocks import Keyword
654
+
655
+ if (
656
+ range .start .line == range .end .line
657
+ and range .start .character <= range .end .character
658
+ and (
659
+ (context .only and CodeActionKind .QUICK_FIX in context .only )
660
+ or context .trigger_kind in [CodeActionTriggerKind .INVOKED , CodeActionTriggerKind .AUTOMATIC ]
661
+ )
662
+ ):
663
+ diagnostics = next (
664
+ (
665
+ d
666
+ for d in context .diagnostics
667
+ if d .source == DIAGNOSTICS_SOURCE_NAME and d .code == Error .VARIABLE_NOT_FOUND
668
+ ),
669
+ None ,
670
+ )
671
+ if (
672
+ diagnostics is not None
673
+ and diagnostics .range .start .line == diagnostics .range .end .line
674
+ and diagnostics .range .start .character < diagnostics .range .end .character
675
+ ):
676
+ text = document .get_lines ()[range .start .line ][range .start .character : range .end .character ]
677
+ if not text :
678
+ return None
679
+
680
+ model = await self .parent .documents_cache .get_model (document , False )
681
+ nodes = await get_nodes_at_position (model , range .start )
682
+
683
+ if not any (n for n in nodes if isinstance (n , Keyword )):
684
+ return None
685
+
686
+ return [
687
+ CodeAction (
688
+ "Add argument" ,
689
+ kind = CodeActionKind .QUICK_FIX ,
690
+ command = Command (
691
+ self .parent .commands .get_command_name (self .action_add_argument_command ),
692
+ self .parent .commands .get_command_name (self .action_add_argument_command ),
693
+ [document .document_uri , diagnostics .range ],
694
+ ),
695
+ diagnostics = [diagnostics ],
696
+ )
697
+ ]
698
+
699
+ return None
700
+
701
+ @command ("robotcode.actionAddArgument" )
702
+ async def action_add_argument_command (self , document_uri : DocumentUri , range : Range ) -> None :
703
+ from robot .parsing .lexer .tokens import Token
704
+ from robot .parsing .model .blocks import Keyword
705
+ from robot .parsing .model .statements import Arguments , Documentation
706
+
707
+ if range .start .line == range .end .line and range .start .character <= range .end .character :
708
+ document = await self .parent .documents .get (document_uri )
709
+ if document is None :
710
+ return
711
+
712
+ text = document .get_lines ()[range .start .line ][range .start .character : range .end .character ]
713
+ if not text :
714
+ return
715
+
716
+ model = await self .parent .documents_cache .get_model (document , False )
717
+ nodes = await get_nodes_at_position (model , range .start )
718
+
719
+ keyword = next ((n for n in nodes if isinstance (n , Keyword )), None )
720
+ if keyword is None :
721
+ return
722
+
723
+ arguments = next ((n for n in keyword .body if isinstance (n , Arguments )), None )
724
+
725
+ if arguments is None :
726
+ i = 0
727
+ first_stmt = keyword .body [i ]
728
+
729
+ while isinstance (first_stmt , Documentation ) and i < len (keyword .body ):
730
+ i += 1
731
+ first_stmt = keyword .body [i ]
732
+
733
+ if i >= len (keyword .body ):
734
+ return
735
+
736
+ spaces = (
737
+ first_stmt .tokens [0 ].value
738
+ if first_stmt is not None and first_stmt .tokens and first_stmt .tokens [0 ].type == "SEPARATOR"
739
+ else " "
740
+ )
741
+
742
+ insert_text = f"{ spaces } [Arguments] ${{{ text } }}=\n "
743
+ node_range = range_from_node (first_stmt )
744
+ insert_range = Range (start = Position (node_range .start .line , 0 ), end = Position (node_range .start .line , 0 ))
745
+ else :
746
+ insert_text = f" ${{{ text } }}="
747
+ argument_tokens = arguments .get_tokens (Token .ARGUMENT )
748
+ if argument_tokens :
749
+ token_range = range_from_token (argument_tokens [- 1 ])
750
+ else :
751
+ token_range = range_from_token (arguments .get_token (Token .ARGUMENTS ))
752
+ insert_range = Range (start = token_range .end , end = token_range .end )
753
+
754
+ we = WorkspaceEdit (
755
+ document_changes = [
756
+ TextDocumentEdit (
757
+ OptionalVersionedTextDocumentIdentifier (str (document .uri ), document .version ),
758
+ [AnnotatedTextEdit ("add_argument" , insert_range , insert_text )],
759
+ )
760
+ ],
761
+ change_annotations = {"add_argument" : ChangeAnnotation ("Add Argument" , False )},
762
+ )
763
+
764
+ if (await self .parent .workspace .apply_edit (we )).applied :
765
+ insert_range .start .character += len (insert_text )
766
+ insert_range .end .character = insert_range .start .character
767
+
768
+ await self .parent .window .show_document (str (document .uri ), take_focus = False , selection = insert_range )
0 commit comments