Skip to content

Commit

Permalink
Selection ranges porvider (#1060)
Browse files Browse the repository at this point in the history
* selection ranges porvider

* handle structs

add range operation unit tests

* , and case

* wip

* wip

* more cases covered

* improve compatibility

* add comments on workaround

* resolve todo

* move function

* increase compatibility

* handle one more case

* improve compatibility

* increase compatibility

* do not run failing tests on old elixir versions

* fix an edge case when reduced range may no longer contain cursor

* use function

* don't run on < 1.14

* resolve some todos

* handle access

* address todos

* add test

* don't run test on 1.12

* add assert

* add comments

* remove IO.inspect
  • Loading branch information
lukaszsamson committed Feb 9, 2024
1 parent 1ab3110 commit 4cfc7f5
Show file tree
Hide file tree
Showing 14 changed files with 3,294 additions and 16 deletions.
409 changes: 409 additions & 0 deletions apps/language_server/lib/language_server/ast_utils.ex

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions apps/language_server/lib/language_server/protocol.ex
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ defmodule ElixirLS.LanguageServer.Protocol do
end
end

defmacro selection_range_req(id, uri, positions) do
quote do
request(unquote(id), "textDocument/selectionRange", %{
"textDocument" => %{"uri" => unquote(uri)},
"positions" => unquote(positions)
})
end
end

defmacro execute_command_req(id, command, arguments) do
quote do
request(unquote(id), "workspace/executeCommand", %{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.CommentBlock do
ranges =
lines
|> group_comments()
|> Enum.filter(fn group -> length(group) > 1 end)
|> Enum.map(&convert_comment_group_to_range/1)

{:ok, ranges}
end

@spec group_comments([Line.t()]) :: [[{Line.cell(), String.t()}]]
defp group_comments(lines) do
def group_comments(lines) do
lines
|> Enum.reduce([[]], fn
{_, cell, "#"}, [[{_, "#"} | _] = head | tail] ->
Expand All @@ -59,7 +60,6 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.CommentBlock do
_, acc ->
acc
end)
|> Enum.filter(fn group -> length(group) > 1 end)
end

@spec convert_comment_group_to_range([[{Line.cell(), String.t()}]]) :: FoldingRange.t()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.Indentation do
{:ok, ranges}
end

defp extract_cell({_line, cell, _first}), do: cell
def extract_cell({_line, cell, _first}), do: cell

@doc """
Pairs cells into {start, end} tuples of regions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,33 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.SpecialToken do
end

@spec group_tokens([Token.t()]) :: [[Token.t()]]
defp group_tokens(tokens) do
def group_tokens(tokens) do
do_group_tokens(tokens, [])
end

defp do_group_tokens([], acc), do: acc

# Don't create folding ranges for docs
defp do_group_tokens([{:identifier, _, doc_identifier}, {false, _, _} | rest], acc)
# Don't create folding ranges for @doc false
defp do_group_tokens(
[{:at_op, _, _}, {:identifier, _, doc_identifier}, {false, _, _} | rest],
acc
)
when doc_identifier in @docs do
do_group_tokens(rest, acc)
end

# Start a folding range for `@doc` and `@moduledoc`
defp do_group_tokens([{:identifier, _, doc_identifier} = token | rest], acc)
defp do_group_tokens(
[{:at_op, _, _} = at_op, {:identifier, _, doc_identifier} = token | rest],
acc
)
when doc_identifier in @docs do
acc = [[token] | acc]
acc = [[token, at_op] | acc]
do_group_tokens(rest, acc)
end

# Amend the folding range
defp do_group_tokens([{k, _, _} = token | rest], [[{:identifier, _, _}] = head | tail])
defp do_group_tokens([{k, _, _} = token | rest], [[{:identifier, _, _} | _] = head | tail])
when k in @kinds do
acc = [[token | head] | tail]
do_group_tokens(rest, acc)
Expand Down Expand Up @@ -118,7 +124,7 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.SpecialToken do
end

defp classify_group({kind, {start_line, _, _}, _}, {_, {end_line, _, _}, _}) do
kind = if kind == :identifier, do: :comment, else: :region
kind = if kind == :at_op, do: :comment, else: :region
{start_line, end_line, kind}
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.TokenPair do
end

@spec pair_tokens([Token.t()]) :: [{Token.t(), Token.t()}]
defp pair_tokens(tokens) do
def pair_tokens(tokens) do
do_pair_tokens(tokens, [], [])
end

Expand All @@ -82,8 +82,8 @@ defmodule ElixirLS.LanguageServer.Providers.FoldingRange.TokenPair do
pairs
) do
head_matches_any? = @token_pairs |> Map.has_key?(head_kind)
# Map.get/2 will always succeed because we only push matches to the stack.
head_matches_top? = @token_pairs |> Map.get(top_kind) |> Enum.member?(head_kind)
# Map.fetch!/2 will always succeed because we only push matches to the stack.
head_matches_top? = @token_pairs |> Map.fetch!(top_kind) |> Enum.member?(head_kind)

{new_stack, new_pairs} =
case {head_matches_any?, head_matches_top?} do
Expand Down
Loading

0 comments on commit 4cfc7f5

Please sign in to comment.