Skip to content

Commit

Permalink
address todos
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszsamson committed Feb 9, 2024
1 parent ce8e2ff commit 7a3cf91
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 24 deletions.
41 changes: 23 additions & 18 deletions apps/language_server/lib/language_server/ast_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ defmodule ElixirLS.LanguageServer.AstUtils do
@binary_operators ~w[| . ** * / + - ++ -- +++ --- .. <> in |> <<< >>> <<~ ~>> <~ ~> <~> < > <= >= == != === !== =~ && &&& and || ||| or = => :: when <- -> \\]a
@unary_operators ~w[@ + - ! ^ not &]a

def node_range(atom) when is_atom(atom), do: nil
def node_range(node, options \\ [])
def node_range(atom, _options) when is_atom(atom), do: nil

def node_range([{{:__block__, _, [_]} = first, _} | _] = list) do
def node_range([{{:__block__, _, [_]} = first, _} | _] = list, _options) do
case List.last(list) do
{_, last} ->
case {node_range(first), node_range(last)} do
Expand All @@ -23,9 +24,9 @@ defmodule ElixirLS.LanguageServer.AstUtils do
end
end

def node_range(list) when is_list(list), do: nil
def node_range(list, _options) when is_list(list), do: nil

def node_range({:__block__, meta, args} = _ast) do
def node_range({:__block__, meta, args} = _ast, _options) do
line = Keyword.get(meta, :line)
column = Keyword.get(meta, :column)

Expand Down Expand Up @@ -85,10 +86,10 @@ defmodule ElixirLS.LanguageServer.AstUtils do
end

# interpolated charlist AST is too complicated to handle via the generic algorithm
def node_range({{:., _, [List, :to_charlist]}, meta, _args} = ast) do
def node_range({{:., _, [List, :to_charlist]}, meta, _args} = ast, options) do
line = Keyword.get(meta, :line) - 1
column = Keyword.get(meta, :column) - 1
{end_line, end_column} = get_eoe_by_formatting(ast, {line, column})
{end_line, end_column} = get_eoe_by_formatting(ast, {line, column}, options)
# on elixir 1.15+ formatter changes charlist '' to ~c"" sigil so we need to correct columns
# if charlist is single line
correction =
Expand All @@ -102,14 +103,14 @@ defmodule ElixirLS.LanguageServer.AstUtils do
end

# interpolated atom AST is too complicated to handle via the generic algorithm
def node_range({{:., _, [:erlang, :binary_to_atom]}, meta, _args} = ast) do
def node_range({{:., _, [:erlang, :binary_to_atom]}, meta, _args} = ast, options) do
line = Keyword.get(meta, :line) - 1
column = Keyword.get(meta, :column) - 1
{end_line, end_column} = get_eoe_by_formatting(ast, {line, column})
{end_line, end_column} = get_eoe_by_formatting(ast, {line, column}, options)
range(line, column, end_line, end_column)
end

def node_range({form, meta, args} = ast) do
def node_range({form, meta, args} = ast, options) do
line = Keyword.get(meta, :line)
column = Keyword.get(meta, :column)

Expand Down Expand Up @@ -218,7 +219,7 @@ defmodule ElixirLS.LanguageServer.AstUtils do
{last[:line] - 1, last[:column] - 1 + last_length}
else
# last is nil on 1.12
get_eoe_by_formatting(ast, {line, column})
get_eoe_by_formatting(ast, {line, column}, options)
end

form == :% and match?([_, _], args) ->
Expand All @@ -235,7 +236,7 @@ defmodule ElixirLS.LanguageServer.AstUtils do
form == :<<>> or (is_atom(form) and String.starts_with?(to_string(form), "sigil_")) ->
# interpolated string AST is too complicated
# try to format it instead
get_eoe_by_formatting(ast, {line, column})
get_eoe_by_formatting(ast, {line, column}, options)

form == :& and match?([int] when is_integer(int), args) ->
[int] = args
Expand Down Expand Up @@ -317,7 +318,7 @@ defmodule ElixirLS.LanguageServer.AstUtils do
end
end

def node_range(_), do: nil
def node_range(_, _options), do: nil

def get_literal_end(true, {line, column}, _), do: {line, column + 4}
def get_literal_end(false, {line, column}, _), do: {line, column + 5}
Expand Down Expand Up @@ -376,15 +377,19 @@ defmodule ElixirLS.LanguageServer.AstUtils do
def get_delimiter_length("\"\"\""), do: 3
def get_delimiter_length("'''"), do: 3

defp get_eoe_by_formatting(ast, {line, column}) do
# TODO pass line_length to format
# TODO locals_without_parens to quoted_to_algebra
# TODO pass comments to quoted_to_algebra
defp get_eoe_by_formatting(ast, {line, column}, options) do
formatter_opts = Keyword.get(options, :formatter_opts, [])
locals_without_parens = Keyword.get(formatter_opts, :locals_without_parens, [])
line_length = Keyword.get(formatter_opts, :line_length, 98)

code =
if Version.match?(System.version(), ">= 1.13.0-dev") do
ast
|> Code.quoted_to_algebra(escape: false)
|> Inspect.Algebra.format(:infinity)
|> Code.quoted_to_algebra(
escape: false,
locals_without_parens: locals_without_parens
)
|> Inspect.Algebra.format(line_length)
|> IO.iodata_to_binary()
else
Macro.to_string(ast)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do

@stop_tokens [:",", :";", :eol, :eof, :pipe_op]

def selection_ranges(text, positions) do
def selection_ranges(text, positions, options \\ []) do
lines = SourceFile.lines(text)
full_file_range = full_range(lines)

Expand Down Expand Up @@ -71,7 +71,7 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do

comment_block_ranges = comment_block_ranges(lines, comment_groups, line, character)

ast_node_ranges = ast_node_ranges(parse_result, line, character)
ast_node_ranges = ast_node_ranges(parse_result, line, character, options)

surround_context_ranges = surround_context_ranges(text, line, character)

Expand Down Expand Up @@ -334,15 +334,19 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do

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

def ast_node_ranges({:ok, ast}, line, character) do
def ast_node_ranges({:ok, ast}, line, character, options) do
node_range_options = [
formatter_opts: Keyword.get(options, :formatter_opts, [])
]

{_new_ast, {acc, [@empty_node]}} =
Macro.traverse(
ast,
{[], [@empty_node]},
fn
ast, {acc, [parent_ast_from_stack | _] = parent_ast} ->
matching_range =
case AstUtils.node_range(ast) do
case AstUtils.node_range(ast, node_range_options) do
range(start_line, start_character, end_line, end_character) ->
start_character =
if match?({:%{}, _, _}, ast) and match?({:%, _, _}, parent_ast_from_stack) and
Expand Down Expand Up @@ -403,7 +407,7 @@ defmodule ElixirLS.LanguageServer.Providers.SelectionRanges do
|> sort_ranges_widest_to_narrowest()
end

def ast_node_ranges(_, _, _), do: []
def ast_node_ranges(_, _, _, _), do: []

def surround_context_ranges(text, line, character) do
case NormalizedCode.Fragment.surround_context(text, {line + 1, character + 1}) do
Expand Down
12 changes: 11 additions & 1 deletion apps/language_server/lib/language_server/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,17 @@ defmodule ElixirLS.LanguageServer.Server do

fun = fn ->
if String.ends_with?(uri, [".ex", ".exs"]) or source_file.language_id in ["elixir"] do
ranges = SelectionRanges.selection_ranges(source_file.text, positions)
formatter_opts =
case SourceFile.formatter_for(uri, state.project_dir, state.mix_project?) do
{:ok, {_, opts, _formatter_exs_dir}} -> opts
{:error, _} -> []
end

ranges =
SelectionRanges.selection_ranges(source_file.text, positions,
formatter_opts: formatter_opts
)

{:ok, ranges}
else
# TODO no support for eex
Expand Down

0 comments on commit 7a3cf91

Please sign in to comment.