@@ -9,8 +9,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
9
9
"""
10
10
alias ElixirLS.LanguageServer.SourceFile
11
11
12
- @ enforce_keys [ :label , :kind , :insert_text , :priority ]
13
- defstruct [ :label , :kind , :detail , :documentation , :insert_text , :filter_text , :priority ]
12
+ @ enforce_keys [ :label , :kind , :insert_text , :priority , :tags ]
13
+ defstruct [ :label , :kind , :detail , :documentation , :insert_text , :filter_text , :priority , :tags ]
14
14
15
15
@ module_attr_snippets [
16
16
{ "doc" , "doc \" \" \" \n $0\n \" \" \" " , "Documents a function" } ,
@@ -84,7 +84,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
84
84
[ "." , "@" ]
85
85
end
86
86
87
- def completion ( text , line , character , snippets_supported ) do
87
+ def completion ( text , line , character , options ) do
88
88
line_text =
89
89
text
90
90
|> SourceFile . lines ( )
@@ -144,7 +144,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
144
144
|> Enum . reject ( & is_nil / 1 )
145
145
|> Enum . uniq_by ( & & 1 . insert_text )
146
146
|> sort_items ( )
147
- |> items_to_json ( snippets_supported )
147
+ |> items_to_json ( options )
148
148
149
149
{ :ok , % { "isIncomplete" => false , "items" => items_json } }
150
150
end
@@ -169,7 +169,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
169
169
detail: "module attribute" ,
170
170
insert_text: insert_text ,
171
171
filter_text: name_only ,
172
- priority: 3
172
+ priority: 3 ,
173
+ tags: [ ]
173
174
}
174
175
end
175
176
end
@@ -184,7 +185,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
184
185
kind: :variable ,
185
186
detail: "variable" ,
186
187
insert_text: name ,
187
- priority: 3
188
+ priority: 3 ,
189
+ tags: [ ]
188
190
}
189
191
end
190
192
@@ -200,14 +202,18 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
200
202
detail: "return value" ,
201
203
documentation: spec ,
202
204
insert_text: snippet ,
203
- priority: 5
205
+ priority: 5 ,
206
+ tags: [ ]
204
207
}
205
208
end
206
209
207
- defp from_completion_item ( % { type: :module , name: name , summary: summary , subtype: subtype } , % {
208
- def_before: nil ,
209
- prefix: prefix
210
- } ) do
210
+ defp from_completion_item (
211
+ % { type: :module , name: name , summary: summary , subtype: subtype , metadata: metadata } ,
212
+ % {
213
+ def_before: nil ,
214
+ prefix: prefix
215
+ }
216
+ ) do
211
217
capitalized? = String . first ( name ) == String . upcase ( String . first ( name ) )
212
218
213
219
if String . ends_with? ( prefix , ":" ) and capitalized? do
@@ -229,7 +235,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
229
235
documentation: summary ,
230
236
insert_text: name ,
231
237
filter_text: name ,
232
- priority: 4
238
+ priority: 4 ,
239
+ tags: metadata_to_tags ( metadata )
233
240
}
234
241
end
235
242
end
@@ -242,7 +249,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
242
249
name: name ,
243
250
summary: summary ,
244
251
arity: arity ,
245
- origin: origin
252
+ origin: origin ,
253
+ metadata: metadata
246
254
} ,
247
255
context
248
256
) do
@@ -269,7 +277,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
269
277
documentation: summary ,
270
278
insert_text: full_snippet ,
271
279
priority: 2 ,
272
- filter_text: name
280
+ filter_text: name ,
281
+ tags: metadata_to_tags ( metadata )
273
282
}
274
283
end
275
284
end
@@ -282,7 +291,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
282
291
name: name ,
283
292
summary: summary ,
284
293
arity: arity ,
285
- origin: origin
294
+ origin: origin ,
295
+ metadata: metadata
286
296
} ,
287
297
context
288
298
) do
@@ -298,7 +308,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
298
308
documentation: summary ,
299
309
insert_text: full_snippet ,
300
310
priority: 2 ,
301
- filter_text: name
311
+ filter_text: name ,
312
+ tags: metadata_to_tags ( metadata )
302
313
}
303
314
end
304
315
@@ -308,7 +319,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
308
319
detail: "#{ origin } struct field" ,
309
320
insert_text: "#{ name } : " ,
310
321
priority: 0 ,
311
- kind: :field
322
+ kind: :field ,
323
+ tags: [ ]
312
324
}
313
325
end
314
326
@@ -329,11 +341,12 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
329
341
documentation: "#{ doc } #{ formatted_spec } " ,
330
342
insert_text: "#{ name } : " ,
331
343
priority: 0 ,
332
- kind: :field
344
+ kind: :field ,
345
+ tags: [ ]
333
346
}
334
347
end
335
348
336
- defp from_completion_item ( % { type: :type_spec } = suggestion , _context ) do
349
+ defp from_completion_item ( % { type: :type_spec , metadata: metadata } = suggestion , _context ) do
337
350
% { name: name , arity: arity , origin: _origin , doc: doc , signature: signature , spec: spec } =
338
351
suggestion
339
352
@@ -357,7 +370,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
357
370
documentation: "#{ doc } #{ formatted_spec } " ,
358
371
insert_text: snippet ,
359
372
priority: 0 ,
360
- kind: :class
373
+ kind: :class ,
374
+ tags: metadata_to_tags ( metadata )
361
375
}
362
376
end
363
377
@@ -485,6 +499,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
485
499
detail: "module attribute" ,
486
500
insert_text: snippet ,
487
501
filter_text: name ,
502
+ tags: [ ] ,
488
503
priority: 6
489
504
}
490
505
end
@@ -503,6 +518,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
503
518
kind: :keyword ,
504
519
detail: "keyword" ,
505
520
insert_text: snippet ,
521
+ tags: [ ] ,
506
522
priority: 1
507
523
}
508
524
end )
@@ -516,7 +532,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
516
532
summary: summary ,
517
533
arity: arity ,
518
534
spec: spec ,
519
- origin: origin
535
+ origin: origin ,
536
+ metadata: metadata
520
537
} = info
521
538
522
539
# ElixirSense now returns types as an atom
@@ -571,7 +588,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
571
588
detail: detail ,
572
589
documentation: summary ,
573
590
insert_text: snippet ,
574
- priority: 7
591
+ priority: 7 ,
592
+ tags: metadata_to_tags ( metadata )
575
593
}
576
594
end
577
595
@@ -587,18 +605,20 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
587
605
end )
588
606
end
589
607
590
- defp items_to_json ( items , snippets_supported ) do
608
+ defp items_to_json ( items , options ) do
609
+ snippets_supported = Keyword . get ( options , :snippets_supported , false )
610
+
591
611
items =
592
612
Enum . reject ( items , fn item ->
593
- ! snippets_supported && snippet? ( item )
613
+ not snippets_supported and snippet? ( item )
594
614
end )
595
615
596
616
for { item , idx } <- Enum . with_index ( items ) do
597
- item_to_json ( item , idx , snippets_supported )
617
+ item_to_json ( item , idx , options )
598
618
end
599
619
end
600
620
601
- defp item_to_json ( item , idx , snippets_supported ) do
621
+ defp item_to_json ( item , idx , options ) do
602
622
json = % {
603
623
"label" => item . label ,
604
624
"kind" => completion_kind ( item . kind ) ,
@@ -608,17 +628,49 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
608
628
"sortText" => String . pad_leading ( to_string ( idx ) , 8 , "0" ) ,
609
629
"insertText" => item . insert_text ,
610
630
"insertTextFormat" =>
611
- if snippets_supported do
631
+ if Keyword . get ( options , : snippets_supported, false ) do
612
632
insert_text_format ( :snippet )
613
633
else
614
634
insert_text_format ( :plain_text )
615
635
end
616
636
}
617
637
638
+ # deprecated as of Language Server Protocol Specification - 3.15
639
+ json =
640
+ if Keyword . get ( options , :deprecated_supported , false ) do
641
+ Map . merge ( json , % {
642
+ "deprecated" => item . tags |> Enum . any? ( & ( & 1 == :deprecated ) )
643
+ } )
644
+ else
645
+ json
646
+ end
647
+
648
+ tags_supported = options |> Keyword . get ( :tags_supported , [ ] )
649
+
650
+ json =
651
+ if tags_supported != [ ] do
652
+ Map . merge ( json , % {
653
+ "tags" => item . tags |> Enum . map ( & tag_to_code / 1 ) |> Enum . filter ( & ( & 1 in tags_supported ) )
654
+ } )
655
+ else
656
+ json
657
+ end
658
+
618
659
for { k , v } <- json , not is_nil ( v ) , into: % { } , do: { k , v }
619
660
end
620
661
621
662
defp snippet? ( item ) do
622
663
item . kind == :snippet || String . match? ( item . insert_text , ~r/ \$ \d / )
623
664
end
665
+
666
+ # As defined by CompletionItemTag in https://microsoft.github.io/language-server-protocol/specifications/specification-current/
667
+ defp tag_to_code ( :deprecated ) , do: 1
668
+
669
+ defp metadata_to_tags ( metadata ) do
670
+ # As of Language Server Protocol Specification - 3.15 only one tag is supported
671
+ case metadata [ :deprecated ] do
672
+ nil -> [ ]
673
+ _ -> [ :deprecated ]
674
+ end
675
+ end
624
676
end
0 commit comments