Skip to content

Commit

Permalink
handle one more case
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszsamson committed Feb 7, 2024
1 parent 8f6938e commit c7cf458
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 42 deletions.
19 changes: 11 additions & 8 deletions apps/language_server/lib/language_server/ast_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ defmodule ElixirLS.LanguageServer.AstUtils do
end
end

def node_range(_), do: nil

def get_literal_end(true, {line, column}, _), do: {line, column + 4}
def get_literal_end(false, {line, column}, _), do: {line, column + 5}
def get_literal_end(nil, {line, column}, _), do: {line, column + 3}
Expand Down Expand Up @@ -361,14 +363,15 @@ defmodule ElixirLS.LanguageServer.AstUtils do
# TODO pass line_length to format
# TODO locals_without_parens to quoted_to_algebra
# TODO pass comments to quoted_to_algebra
code = if Version.match?(System.version(), ">= 1.13.0-dev") do
ast
|> Code.quoted_to_algebra(escape: false)
|> Inspect.Algebra.format(:infinity)
|> IO.iodata_to_binary()
else
Macro.to_string(ast)
end
code =
if Version.match?(System.version(), ">= 1.13.0-dev") do
ast
|> Code.quoted_to_algebra(escape: false)
|> Inspect.Algebra.format(:infinity)
|> IO.iodata_to_binary()
else
Macro.to_string(ast)
end

lines = code |> SourceFile.lines()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,51 +328,63 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do
|> List.flatten()
end

@empty_node {:__block__, [], []}

def ast_node_ranges({:ok, ast}, line, character) do
{_new_ast, {acc, []}} =
{_new_ast, {acc, [@empty_node]}} =
Macro.traverse(
ast,
{[], []},
{[], [@empty_node]},
fn
{form, _meta, _args} = ast, {acc, parent_ast} ->
parent_ast_from_stack =
case parent_ast do
[] -> []
[item | _] -> item
end
ast, {acc, [parent_ast_from_stack | _] = parent_ast} ->
matching_range =
case AstUtils.node_range(ast) do
range(start_line, start_character, end_line, end_character) ->
start_character =
if match?({:%{}, _, _}, ast) and match?({:%, _, _}, parent_ast_from_stack) and
Version.match?(System.version(), "< 1.16.2") do
# workaround elixir bug
# https://github.com/elixir-lang/elixir/commit/fd4e6b530c0e010712b06909c89820b08e49c238
# undo column offset for structs inner map node
start_character + 1
else
start_character
end

range = range(start_line, start_character, end_line, end_character)

case AstUtils.node_range(ast) do
range(start_line, start_character, end_line, end_character) ->
start_character =
if form == :%{} and match?({:%, _, _}, parent_ast_from_stack) and
Version.match?(System.version(), "< 1.16.2") do
# workaround elixir bug
# https://github.com/elixir-lang/elixir/commit/fd4e6b530c0e010712b06909c89820b08e49c238
# undo column offset for structs inner map node
start_character + 1
if (start_line < line or (start_line == line and start_character <= character)) and
(end_line > line or (end_line == line and end_character >= character)) do
# dbg({ast, range, parent_ast_from_stack})
# {ast, {[range | acc], [ast | parent_ast]}}
range
else
start_character
# dbg({ast, range, {line, character}, "outside"})
# {ast, {acc, [ast | parent_ast]}}
nil
end

range = range(start_line, start_character, end_line, end_character)
nil ->
# dbg({ast, "nil"})
# {ast, {acc, [ast | parent_ast]}}
nil
end

if (start_line < line or (start_line == line and start_character <= character)) and
(end_line > line or (end_line == line and end_character >= character)) do
# dbg({ast, range, parent_ast_from_stack})
{ast, {[range | acc], [ast | parent_ast]}}
else
# dbg({ast, range, {line, character}, "outside"})
{ast, {acc, [ast | parent_ast]}}
end
ranges_acc =
if matching_range != nil do
[matching_range | acc]
else
acc
end

nil ->
# dbg({ast, "nil"})
{ast, {acc, [ast | parent_ast]}}
end
parent_acc =
if match?({_, _, _}, ast) do
[ast | parent_ast]
else
parent_ast
end

other, {acc, parent_ast} ->
# dbg({other, "other"})
{other, {acc, parent_ast}}
{ast, {ranges_acc, parent_acc}}
end,
fn
{_, _meta, _} = ast, {acc, [_ | tail]} ->
Expand Down
35 changes: 35 additions & 0 deletions apps/language_server/test/providers/selection_ranges_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -957,4 +957,39 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRangesTest do
# var2
assert_range(ranges, range(0, 7, 0, 11))
end

describe "keyword args" do
test "single line" do
text = """
my(1, a: 2, b: 3)
"""

ranges = get_ranges(text, 0, 6)

# full range
assert_range(ranges, range(0, 0, 1, 0))
# full call
assert_range(ranges, range(0, 0, 0, 17))
# full keyword
assert_range(ranges, range(0, 6, 0, 16))
end

test "multi line" do
text = """
my(1, a: 2,
b: 3,
c: 4
)
"""

ranges = get_ranges(text, 1, 2)

# full range
assert_range(ranges, range(0, 0, 4, 0))
# full call
assert_range(ranges, range(0, 0, 3, 1))
# full keyword
assert_range(ranges, range(0, 6, 2, 6))
end
end
end

0 comments on commit c7cf458

Please sign in to comment.