@@ -7,7 +7,9 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
77 with the Language Server Protocol. We also attempt to determine the context based on the line
88 text before the cursor so we can filter out suggestions that are not relevant.
99 """
10+ alias ElixirLS.LanguageServer.Protocol.TextEdit
1011 alias ElixirLS.LanguageServer.SourceFile
12+ import ElixirLS.LanguageServer.Protocol , only: [ range: 4 ]
1113
1214 @ enforce_keys [ :label , :kind , :insert_text , :priority , :tags ]
1315 defstruct [
@@ -21,7 +23,8 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
2123 :priority ,
2224 :tags ,
2325 :command ,
24- { :preselect , false }
26+ { :preselect , false } ,
27+ :additional_text_edit
2528 ]
2629
2730 @ func_snippets % {
@@ -102,8 +105,10 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
102105
103106 # TODO: Don't call into here directly
104107 # Can we use ElixirSense.Providers.Suggestion? ElixirSense.suggestions/3
108+ metadata = ElixirSense.Core.Parser . parse_string ( text , true , true , line )
109+
105110 env =
106- ElixirSense.Core.Parser . parse_string ( text , true , true , line )
111+ metadata
107112 |> ElixirSense.Core.Metadata . get_env ( line )
108113
109114 scope =
@@ -139,8 +144,18 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
139144 module: env . module
140145 }
141146
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+
142157 items =
143- ElixirSense . suggestions ( text , line , character )
158+ ElixirSense . suggestions ( text , line , character , required_alias: true )
144159 |> maybe_reject_derived_functions ( context , options )
145160 |> Enum . map ( & from_completion_item ( & 1 , context , options ) )
146161 |> maybe_add_do ( context )
@@ -285,6 +300,44 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
285300 }
286301 end
287302
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+
288341 defp from_completion_item (
289342 % { type: :module , name: name , summary: summary , subtype: subtype , metadata: metadata } ,
290343 % { def_before: nil } ,
@@ -989,6 +1042,12 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
9891042 "filterText" => item . filter_text ,
9901043 "sortText" => String . pad_leading ( to_string ( idx ) , 8 , "0" ) ,
9911044 "insertText" => item . insert_text ,
1045+ "additionalTextEdits" =>
1046+ if item . additional_text_edit do
1047+ [ item . additional_text_edit ]
1048+ else
1049+ nil
1050+ end ,
9921051 "command" => item . command ,
9931052 "insertTextFormat" =>
9941053 if Keyword . get ( options , :snippets_supported , false ) do
0 commit comments