@@ -291,76 +291,87 @@ defmodule ElixirLS.LanguageServer.Diagnostics do
291291 # https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#diagnostic
292292
293293 # position is a 1 based line number
294- # we return a range of trimmed text in that line
295- defp range ( position , source_file )
296- when is_integer ( position ) and position >= 1 and not is_nil ( source_file ) do
294+ # we return a 0 length range at first non whitespace character in line
295+ defp range ( line_start , source_file )
296+ when is_integer ( line_start ) and not is_nil ( source_file ) do
297297 # line is 1 based
298- line = position - 1
299- text = Enum . at ( SourceFile . lines ( source_file ) , line ) || ""
298+ lines = SourceFile . lines ( source_file )
300299
301- start_idx = String . length ( text ) - String . length ( String . trim_leading ( text ) ) + 1
302- length = max ( String . length ( String . trim ( text ) ) , 1 )
300+ { line_start_lsp , char_start_lsp } =
301+ if line_start > 0 do
302+ case Enum . at ( lines , line_start - 1 ) do
303+ nil ->
304+ # position is outside file range - this will return end of the file
305+ SourceFile . elixir_position_to_lsp ( lines , { line_start , 1 } )
306+
307+ line ->
308+ # find first non whitespace character in line
309+ start_idx = String . length ( line ) - String . length ( String . trim_leading ( line ) ) + 1
310+ { line_start - 1 , SourceFile . elixir_character_to_lsp ( line , start_idx ) }
311+ end
312+ else
313+ # return begin of the file
314+ { 0 , 0 }
315+ end
303316
304317 % {
305318 "start" => % {
306- "line" => line ,
307- "character" => SourceFile . elixir_character_to_lsp ( text , start_idx )
319+ "line" => line_start_lsp ,
320+ "character" => char_start_lsp
308321 } ,
309322 "end" => % {
310- "line" => line ,
311- "character" => SourceFile . elixir_character_to_lsp ( text , start_idx + length )
323+ "line" => line_start_lsp ,
324+ "character" => char_start_lsp
312325 }
313326 }
314327 end
315328
316329 # position is a 1 based line number and 0 based character cursor (UTF8)
317330 # we return a 0 length range exactly at that location
318331 defp range ( { line_start , char_start } , source_file )
319- when line_start >= 1 and not is_nil ( source_file ) do
332+ when not is_nil ( source_file ) do
320333 lines = SourceFile . lines ( source_file )
321- # line is 1 based
322- start_line = Enum . at ( lines , line_start - 1 )
323- # SourceFile.elixir_character_to_lsp assumes char to be 1 based but it's 0 based here
324- character = SourceFile . elixir_character_to_lsp ( start_line , char_start + 1 )
334+ # elixir_position_to_lsp will handle positions outside file range
335+ { line_start_lsp , char_start_lsp } =
336+ SourceFile . elixir_position_to_lsp ( lines , { line_start , char_start - 1 } )
325337
326338 % {
327339 "start" => % {
328- "line" => line_start - 1 ,
329- "character" => character
340+ "line" => line_start_lsp ,
341+ "character" => char_start_lsp
330342 } ,
331343 "end" => % {
332- "line" => line_start - 1 ,
333- "character" => character
344+ "line" => line_start_lsp ,
345+ "character" => char_start_lsp
334346 }
335347 }
336348 end
337349
338350 # position is a range defined by 1 based line numbers and 0 based character cursors (UTF8)
339351 # we return exactly that range
340352 defp range ( { line_start , char_start , line_end , char_end } , source_file )
341- when line_start >= 1 and line_end >= 1 and not is_nil ( source_file ) do
353+ when not is_nil ( source_file ) do
342354 lines = SourceFile . lines ( source_file )
343- # line is 1 based
344- start_line = Enum . at ( lines , line_start - 1 )
345- end_line = Enum . at ( lines , line_end - 1 )
355+ # elixir_position_to_lsp will handle positions outside file range
356+ { line_start_lsp , char_start_lsp } =
357+ SourceFile . elixir_position_to_lsp ( lines , { line_start , char_start - 1 } )
346358
347- # SourceFile.elixir_character_to_lsp assumes char to be 1 based but it's 0 based here
348- start_char = SourceFile . elixir_character_to_lsp ( start_line , char_start + 1 )
349- end_char = SourceFile . elixir_character_to_lsp ( end_line , char_end + 1 )
359+ { line_end_lsp , char_end_lsp } =
360+ SourceFile . elixir_position_to_lsp ( lines , { line_end , char_end - 1 } )
350361
351362 % {
352363 "start" => % {
353- "line" => line_start - 1 ,
354- "character" => start_char
364+ "line" => line_start_lsp ,
365+ "character" => char_start_lsp
355366 } ,
356367 "end" => % {
357- "line" => line_end - 1 ,
358- "character" => end_char
368+ "line" => line_end_lsp ,
369+ "character" => char_end_lsp
359370 }
360371 }
361372 end
362373
363- # source file is unknown, position is 0 or invalid
374+ # source file is unknown
364375 # we discard any position information as it is meaningless
365376 # unfortunately LSP does not allow `null` range so we need to return something
366377 defp range ( _ , _ ) do
0 commit comments