@@ -576,6 +576,73 @@ function convert_from_raw(x, _, conn)
576
576
return nothing
577
577
end
578
578
579
+ # Checks if parent is a parent/grandparent/... of child
580
+ function is_parent_of (parent:: EXPR , child:: EXPR )
581
+ while child isa EXPR
582
+ if child == parent
583
+ return true
584
+ end
585
+ child = child. parent
586
+ end
587
+ return false
588
+ end
589
+
590
+ function is_in_function_signature (x:: EXPR , params; with_docstring= false )
591
+ # TODO : Perhaps also allow this if the cursor is inside a docstring?
592
+ func = _get_parent_fexpr (x, CSTParser. defines_function)
593
+ func === nothing && return false
594
+ sig = func. args[1 ]
595
+ if x. head === :FUNCTION || is_parent_of (sig, x)
596
+ hasdoc = func. parent isa EXPR && func. parent. head === :macrocall && func. parent. args[1 ] isa EXPR &&
597
+ func. parent. args[1 ]. head === :globalrefdoc
598
+ return with_docstring == hasdoc
599
+ end
600
+ return false
601
+ end
602
+
603
+ function add_docstring_template (x, _, conn)
604
+ is_in_function_signature (x, nothing ) || return
605
+ func = _get_parent_fexpr (x, CSTParser. defines_function)
606
+ func === nothing && return
607
+ file, func_offset = get_file_loc (func)
608
+ sig = func. args[1 ]
609
+ _, sig_offset = get_file_loc (sig)
610
+ docstr = " \"\"\"\n " * get_text (file)[sig_offset .+ (1 : sig. span)] * " \n\n TBW\n\"\"\"\n "
611
+ tde = TextDocumentEdit (VersionedTextDocumentIdentifier (get_uri (file), get_version (file)), TextEdit[
612
+ TextEdit (Range (file, func_offset: func_offset), docstr)
613
+ ])
614
+ JSONRPC. send (conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams (missing , WorkspaceEdit (missing , TextDocumentEdit[tde])))
615
+ return
616
+ end
617
+
618
+ function update_docstring_sig (x, _, conn)
619
+ is_in_function_signature (x, nothing ; with_docstring= true ) || return
620
+ func = _get_parent_fexpr (x, CSTParser. defines_function)
621
+ # Current docstring
622
+ docstr_expr = func. parent. args[3 ]
623
+ docstr = valof (docstr_expr)
624
+ file, docstr_offset = get_file_loc (docstr_expr)
625
+ # New signature in the code
626
+ sig = func. args[1 ]
627
+ _, sig_offset = get_file_loc (sig)
628
+ sig_str = get_text (file)[sig_offset .+ (1 : sig. span)]
629
+ # Heuristic for finding a signature in the current docstring
630
+ reg = r" \A .*$" m
631
+ if (m = match (reg, valof (docstr_expr)); m != = nothing )
632
+ docstr = replace (docstr, reg => string (" " , sig_str))
633
+ else
634
+ docstr = string (" " , sig_str, " \n\n " , docstr)
635
+ end
636
+ newline = endswith (docstr, " \n " ) ? " " : " \n "
637
+ # Rewrap in """"
638
+ docstr = string (" \"\"\"\n " , docstr, newline, " \"\"\" " )
639
+ tde = TextDocumentEdit (VersionedTextDocumentIdentifier (get_uri (file), get_version (file)), TextEdit[
640
+ TextEdit (Range (file, docstr_offset .+ (0 : docstr_expr. span)), docstr)
641
+ ])
642
+ JSONRPC. send (conn, workspace_applyEdit_request_type, ApplyWorkspaceEditParams (missing , WorkspaceEdit (missing , TextDocumentEdit[tde])))
643
+ return
644
+ end
645
+
579
646
# Adding a CodeAction requires defining:
580
647
# * a unique id
581
648
# * a description
@@ -682,3 +749,21 @@ LSActions["RewriteAsRegularString"] = ServerAction(
682
749
(x, _) -> is_string_literal (x; inraw= true ),
683
750
convert_from_raw,
684
751
)
752
+
753
+ LSActions[" AddDocstringTemplate" ] = ServerAction (
754
+ " AddDocstringTemplate" ,
755
+ " Add docstring template for this method" ,
756
+ missing ,
757
+ missing ,
758
+ is_in_function_signature,
759
+ add_docstring_template,
760
+ )
761
+
762
+ LSActions[" UpdateDocstringSignature" ] = ServerAction (
763
+ " UpdateDocstringSignature" ,
764
+ " Update method signature in docstring" ,
765
+ missing ,
766
+ missing ,
767
+ (args... ) -> is_in_function_signature (args... ; with_docstring= true ),
768
+ update_docstring_sig,
769
+ )
0 commit comments