@@ -7,7 +7,9 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
7
7
with the Language Server Protocol. We also attempt to determine the context based on the line
8
8
text before the cursor so we can filter out suggestions that are not relevant.
9
9
"""
10
+ alias ElixirLS.LanguageServer.Protocol.TextEdit
10
11
alias ElixirLS.LanguageServer.SourceFile
12
+ import ElixirLS.LanguageServer.Protocol , only: [ range: 4 ]
11
13
12
14
@ enforce_keys [ :label , :kind , :insert_text , :priority , :tags ]
13
15
defstruct [
@@ -21,7 +23,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
21
23
:priority ,
22
24
:tags ,
23
25
:command ,
24
- { :preselect , false }
26
+ { :preselect , false } ,
27
+ :additional_text_edit
25
28
]
26
29
27
30
@ func_snippets % {
@@ -102,8 +105,10 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
102
105
103
106
# TODO: Don't call into here directly
104
107
# Can we use ElixirSense.Providers.Suggestion? ElixirSense.suggestions/3
108
+ metadata = ElixirSense.Core.Parser . parse_string ( text , true , true , line )
109
+
105
110
env =
106
- ElixirSense.Core.Parser . parse_string ( text , true , true , line )
111
+ metadata
107
112
|> ElixirSense.Core.Metadata . get_env ( line )
108
113
109
114
scope =
@@ -139,8 +144,18 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
139
144
module: env . module
140
145
}
141
146
147
+ position_to_insert_alias =
148
+ ElixirSense.Core.Metadata . get_position_to_insert_alias ( metadata , line ) || { line , 0 }
149
+
150
+ context =
151
+ Map . put (
152
+ context ,
153
+ :position_to_insert_alias ,
154
+ SourceFile . elixir_position_to_lsp ( text , position_to_insert_alias )
155
+ )
156
+
142
157
items =
143
- ElixirSense . suggestions ( text , line , character )
158
+ ElixirSense . suggestions ( text , line , character , required_alias: true )
144
159
|> maybe_reject_derived_functions ( context , options )
145
160
|> Enum . map ( & from_completion_item ( & 1 , context , options ) )
146
161
|> maybe_add_do ( context )
@@ -285,6 +300,44 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
285
300
}
286
301
end
287
302
303
+ defp from_completion_item (
304
+ % {
305
+ type: :module ,
306
+ name: name ,
307
+ summary: summary ,
308
+ subtype: subtype ,
309
+ metadata: metadata ,
310
+ required_alias: required_alias
311
+ } ,
312
+ % {
313
+ def_before: nil ,
314
+ position_to_insert_alias: { line_to_insert_alias , column_to_insert_alias }
315
+ } ,
316
+ options
317
+ ) do
318
+ completion_without_additional_text_edit =
319
+ from_completion_item (
320
+ % { type: :module , name: name , summary: summary , subtype: subtype , metadata: metadata } ,
321
+ % { def_before: nil } ,
322
+ options
323
+ )
324
+
325
+ alias_value =
326
+ Atom . to_string ( required_alias )
327
+ |> String . replace_prefix ( "Elixir." , "" )
328
+
329
+ indentation = 1 .. column_to_insert_alias // 1 |> Enum . map ( fn _ -> " " end ) |> Enum . join ( )
330
+ alias_edit = indentation <> "alias " <> alias_value <> "\n "
331
+
332
+ struct ( completion_without_additional_text_edit ,
333
+ additional_text_edit: % TextEdit {
334
+ range: range ( line_to_insert_alias , 0 , line_to_insert_alias , 0 ) ,
335
+ newText: alias_edit
336
+ } ,
337
+ documentation: alias_value <> "\n " <> summary
338
+ )
339
+ end
340
+
288
341
defp from_completion_item (
289
342
% { type: :module , name: name , summary: summary , subtype: subtype , metadata: metadata } ,
290
343
% { def_before: nil } ,
@@ -989,6 +1042,12 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
989
1042
"filterText" => item . filter_text ,
990
1043
"sortText" => String . pad_leading ( to_string ( idx ) , 8 , "0" ) ,
991
1044
"insertText" => item . insert_text ,
1045
+ "additionalTextEdits" =>
1046
+ if item . additional_text_edit do
1047
+ [ item . additional_text_edit ]
1048
+ else
1049
+ nil
1050
+ end ,
992
1051
"command" => item . command ,
993
1052
"insertTextFormat" =>
994
1053
if Keyword . get ( options , :snippets_supported , false ) do
0 commit comments