11use crate :: handlers:: completion:: { completion_builder:: CompletionBuilder , data:: DOC_TAGS } ;
22use crate :: meta_text:: meta_doc_tag;
3- use emmylua_parser:: LuaTokenKind ;
3+ use emmylua_parser:: {
4+ LuaAst , LuaAstToken , LuaComment , LuaDocTag , LuaExpr , LuaGeneralToken , LuaTokenKind ,
5+ } ;
46use lsp_types:: { CompletionItem , MarkupContent } ;
57
68pub fn add_completion ( builder : & mut CompletionBuilder ) -> Option < ( ) > {
@@ -9,8 +11,9 @@ pub fn add_completion(builder: &mut CompletionBuilder) -> Option<()> {
911 }
1012
1113 let trigger_token = & builder. trigger_token ;
14+ let trigger_token_kind: LuaTokenKind = trigger_token. kind ( ) . into ( ) ;
1215 if !matches ! (
13- trigger_token . kind ( ) . into ( ) ,
16+ trigger_token_kind ,
1417 LuaTokenKind :: TkDocStart | LuaTokenKind :: TkDocLongStart | LuaTokenKind :: TkTagOther
1518 ) {
1619 return None ;
@@ -23,8 +26,15 @@ pub fn add_completion(builder: &mut CompletionBuilder) -> Option<()> {
2326 add_tag_completion ( builder, sorted_index, tag) ;
2427 }
2528
26- builder. stop_here ( ) ;
29+ if matches ! (
30+ trigger_token_kind,
31+ LuaTokenKind :: TkDocStart | LuaTokenKind :: TkTagOther
32+ ) {
33+ let last_index = DOC_TAGS . len ( ) + emmyrc. doc . known_tags . len ( ) ;
34+ add_tag_param_return_completion ( builder, last_index) ;
35+ }
2736
37+ builder. stop_here ( ) ;
2838 Some ( ( ) )
2939}
3040
@@ -42,3 +52,117 @@ fn add_tag_completion(builder: &mut CompletionBuilder, sorted_index: usize, tag:
4252
4353 builder. add_completion_item ( completion_item) ;
4454}
55+
56+ fn add_tag_param_return_completion (
57+ builder : & mut CompletionBuilder ,
58+ sorted_index : usize ,
59+ ) -> Option < ( ) > {
60+ let token = LuaGeneralToken :: cast ( builder. trigger_token . clone ( ) ) ?;
61+ let comment = token. ancestors :: < LuaComment > ( ) . next ( ) ?;
62+ let comment_owner = comment. get_owner ( ) ?;
63+ let closure = match comment_owner {
64+ LuaAst :: LuaAssignStat ( stat) => {
65+ let ( _, expr_list) = stat. get_var_and_expr_list ( ) ;
66+ let mut result_closure = None ;
67+ for value_expr in expr_list {
68+ if let LuaExpr :: ClosureExpr ( closure) = value_expr {
69+ result_closure = Some ( closure. clone ( ) ) ;
70+ break ;
71+ }
72+ }
73+
74+ result_closure
75+ }
76+ LuaAst :: LuaLocalFuncStat ( f) => f. get_closure ( ) ,
77+ LuaAst :: LuaFuncStat ( f) => f. get_closure ( ) ,
78+ LuaAst :: LuaLocalStat ( local_stat) => {
79+ let mut result_closure = None ;
80+ let expr_list = local_stat. get_value_exprs ( ) ;
81+ for value_expr in expr_list {
82+ if let LuaExpr :: ClosureExpr ( closure) = value_expr {
83+ result_closure = Some ( closure. clone ( ) ) ;
84+ break ;
85+ }
86+ }
87+
88+ result_closure
89+ }
90+ LuaAst :: LuaTableField ( field) => {
91+ let value_expr = field. get_value_expr ( ) ?;
92+ if let LuaExpr :: ClosureExpr ( closure) = value_expr {
93+ Some ( closure)
94+ } else {
95+ None
96+ }
97+ }
98+ _ => return None ,
99+ } ?;
100+
101+ let mut param_orders = vec ! [ ] ;
102+
103+ for param in closure. get_params_list ( ) ?. get_params ( ) {
104+ if let Some ( name_token) = param. get_name_token ( ) {
105+ param_orders. push ( Some ( name_token. get_text ( ) . to_string ( ) ) ) ;
106+ } else {
107+ param_orders. push ( Some ( "..." . to_string ( ) ) ) ;
108+ }
109+ }
110+
111+ for doc_tag in comment. get_doc_tags ( ) {
112+ if let LuaDocTag :: Param ( param_tag) = doc_tag {
113+ if let Some ( param_name) = param_tag. get_name_token ( ) {
114+ let name_text = param_name. get_text ( ) ;
115+ for param_order in param_orders. iter_mut ( ) {
116+ if let Some ( name) = param_order {
117+ if name == name_text {
118+ * param_order = None ;
119+ break ;
120+ }
121+ }
122+ }
123+ }
124+ }
125+ }
126+
127+ if param_orders. iter ( ) . all ( |p| p. is_none ( ) ) {
128+ return None ;
129+ }
130+
131+ let prev_token_text = builder. trigger_token . text ( ) ;
132+ let prefix = if prev_token_text. starts_with ( "--- " ) {
133+ "--- @"
134+ } else {
135+ "---@"
136+ } ;
137+
138+ let mut insert_text = String :: new ( ) ;
139+ for ( i, param_name) in param_orders. iter ( ) . enumerate ( ) {
140+ let indent = if i == 0 { "" } else { prefix } ;
141+
142+ if let Some ( name) = param_name {
143+ let insert_snippet = format ! (
144+ "{}param {} ${{{}:any}}\n " ,
145+ indent,
146+ name,
147+ insert_text. len( ) + 1
148+ ) ;
149+ insert_text. push_str ( & insert_snippet) ;
150+ }
151+ }
152+
153+ let idx = insert_text. len ( ) + 1 ;
154+ insert_text. push_str ( & format ! ( "{}return ${{{}:any}}" , prefix, idx) ) ;
155+
156+ let completion_item = CompletionItem {
157+ label : "param/@return" . to_string ( ) ,
158+ kind : Some ( lsp_types:: CompletionItemKind :: EVENT ) ,
159+ insert_text : Some ( insert_text) ,
160+ insert_text_format : Some ( lsp_types:: InsertTextFormat :: SNIPPET ) ,
161+ sort_text : Some ( format ! ( "{:03}" , sorted_index) ) ,
162+ insert_text_mode : Some ( lsp_types:: InsertTextMode :: ADJUST_INDENTATION ) ,
163+ ..Default :: default ( )
164+ } ;
165+
166+ builder. add_completion_item ( completion_item) ;
167+ Some ( ( ) )
168+ }
0 commit comments