@@ -129,6 +129,15 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
129
129
text_before_cursor = String . slice ( line_text , 0 , character - 1 )
130
130
text_after_cursor = String . slice ( line_text , ( character - 1 ) .. - 1 // 1 )
131
131
132
+ full_text_before_cursor =
133
+ if line >= 2 do
134
+ Enum . slice ( lines , 0 .. ( line - 2 ) )
135
+ else
136
+ [ ]
137
+ end
138
+ |> Kernel . ++ ( [ text_before_cursor ] )
139
+ |> Enum . join ( "\n " )
140
+
132
141
prefix = get_prefix ( text_before_cursor )
133
142
134
143
env = ElixirSense.Core.Metadata . get_env ( metadata , { line , character } )
@@ -156,19 +165,62 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
156
165
nil
157
166
end
158
167
168
+ container_cursor_quoted =
169
+ case NormalizedCode.Fragment . container_cursor_to_quoted ( full_text_before_cursor ,
170
+ token_metadata: true ,
171
+ columns: true
172
+ ) do
173
+ { :ok , ast } -> ast
174
+ _ -> nil
175
+ end
176
+
159
177
do_block_indent =
160
- lines
161
- |> Enum . slice ( 0 .. ( line - 1 ) )
162
- |> Enum . reverse ( )
163
- |> Enum . find_value ( 0 , fn line_text ->
164
- if Regex . match? ( ~r/ (?<=\s |^)do\s *(#.*)?$/ u , line_text ) do
165
- String . length ( line_text ) - String . length ( String . trim_leading ( line_text ) )
178
+ if container_cursor_quoted != nil and Version . match? ( System . version ( ) , ">= 1.14.0-dev" ) do
179
+ case Macro . path ( container_cursor_quoted , & match? ( { :__cursor__ , _ , [ ] } , & 1 ) ) do
180
+ nil ->
181
+ 0
182
+
183
+ [ _cursor | rest ] ->
184
+ Enum . find_value ( rest , 0 , fn
185
+ { _ , meta , _ } when is_list ( meta ) ->
186
+ if Keyword . has_key? ( meta , :do ) do
187
+ line = Keyword . fetch! ( meta , :line )
188
+ line_text = Enum . at ( lines , line - 1 )
189
+ String . length ( line_text ) - String . length ( String . trim_leading ( line_text ) )
190
+ end
191
+
192
+ _ ->
193
+ nil
194
+ end )
166
195
end
167
- end )
196
+ else
197
+ lines
198
+ |> Enum . slice ( 0 .. ( line - 1 ) )
199
+ |> Enum . reverse ( )
200
+ |> Enum . reduce_while ( { 0 , 0 } , fn line_text , { do_count , indent } ->
201
+ if Regex . match? ( ~r/ (?<=\s |^)do\s *(#.*)?$/ u , line_text ) or
202
+ Regex . match? ( ~r/ (?<=\s |^)fn\s *.*(->)?(#.*)?$/ u , line_text ) do
203
+ if do_count == 0 do
204
+ { :halt ,
205
+ { 0 , String . length ( line_text ) - String . length ( String . trim_leading ( line_text ) ) } }
206
+ else
207
+ { :cont , { do_count - 1 , indent } }
208
+ end
209
+ else
210
+ if Regex . match? ( ~r/ (?<=\s |^)end[\s \) ]*(#.*)?$/ u , line_text ) do
211
+ { :cont , { do_count + 1 , indent } }
212
+ else
213
+ { :cont , { do_count , indent } }
214
+ end
215
+ end
216
+ end )
217
+ |> elem ( 1 )
218
+ end
168
219
169
220
line_indent = String . length ( line_text ) - String . length ( String . trim_leading ( line_text ) )
170
221
171
222
context = % {
223
+ container_cursor_to_quoted: container_cursor_quoted ,
172
224
text_before_cursor: text_before_cursor ,
173
225
text_after_cursor: text_after_cursor ,
174
226
prefix: prefix ,
@@ -290,7 +342,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
290
342
"line" => context . line - 1 ,
291
343
"character" =>
292
344
context . character - String . length ( hint ) - 1 -
293
- ( context . line_indent - context . do_block_indent )
345
+ max ( context . line_indent - context . do_block_indent , 0 )
294
346
} ,
295
347
"end" => % {
296
348
"line" => context . line - 1 ,
@@ -314,7 +366,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
314
366
"line" => context . line - 1 ,
315
367
"character" =>
316
368
context . character - String . length ( hint ) - 1 -
317
- ( context . line_indent - context . do_block_indent )
369
+ max ( context . line_indent - context . do_block_indent , 0 )
318
370
} ,
319
371
"end" => % { "line" => context . line - 1 , "character" => context . character - 1 }
320
372
} ,
0 commit comments