Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snippet variants with n-1 placeholders to use after pipe #501

Merged
merged 1 commit into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion apps/language_server/lib/language_server/providers/completion.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
{"ExUnit.Case", "describe"} => "describe \"$1\" do\n\t$0\nend"
}

# Alternative snippets versions to be preferred when preceded by a pipe
@pipe_func_snippets %{
{"Kernel.SpecialForms", "case"} => "case do\n\t$1 ->\n\t\t$0\nend",
{"Kernel", "if"} => "if do\n\t$0\nend",
{"Kernel", "unless"} => "unless do\n\t$0\nend"
}

@use_name_only MapSet.new([
{"Kernel", "not"},
{"Kernel", "use"},
Expand Down Expand Up @@ -493,7 +500,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
completion
end

if snippet = Map.get(@func_snippets, {origin, name}) do
if snippet = snippet_for({origin, name}, context) do
%{completion | insert_text: snippet, kind: :snippet, label: name}
else
completion
Expand All @@ -504,6 +511,15 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
nil
end

defp snippet_for(key, %{pipe_before?: true}) do
# Get pipe-friendly version of snippet if available, otherwise fallback to standard
Map.get(@pipe_func_snippets, key) || Map.get(@func_snippets, key)
end

defp snippet_for(key, _context) do
Map.get(@func_snippets, key)
end

defp def_snippet(def_str, name, args, arity, opts) do
if Keyword.get(opts, :snippets_supported, false) do
"#{def_str}#{function_snippet(name, args, arity, opts)} do\n\t$0\nend"
Expand Down
64 changes: 64 additions & 0 deletions apps/language_server/test/providers/completion_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -940,4 +940,68 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
refute Enum.any?(items, fn i -> i["label"] == "make_ref/0" end)
end
end

describe "use the (arity - 1) version of snippets after pipe" do
test "case/2 snippet skips the condition argument" do
text = """
defmodule MyModule do
def hello do
[1, 2]
|> Enum.random()
|> ca
# ^
end
end
"""

{line, char} = {4, 9}
TestUtils.assert_has_cursor_char(text, line, char)
assert {:ok, %{"items" => items}} = Completion.completion(text, line, char, @supports)
assert %{"insertText" => insert_text} = Enum.find(items, &match?(%{"label" => "case"}, &1))
assert insert_text =~ "case do\n\t"
end

test "unless/2 snippet skips the condition argument" do
text = """
defmodule MyModule do
def hello do
[1, 2]
|> Enum.random()
|> unl
# ^
end
end
"""

{line, char} = {4, 10}
TestUtils.assert_has_cursor_char(text, line, char)
assert {:ok, %{"items" => items}} = Completion.completion(text, line, char, @supports)

assert %{"insertText" => insert_text} =
Enum.find(items, &match?(%{"label" => "unless"}, &1))

assert insert_text =~ "unless do\n\t"
end

test "if/2 snippet skips the condition argument" do
text = """
defmodule MyModule do
def hello do
[1, 2]
|> Enum.random()
|> if
# ^
end
end
"""

{line, char} = {4, 9}
TestUtils.assert_has_cursor_char(text, line, char)
assert {:ok, %{"items" => items}} = Completion.completion(text, line, char, @supports)

assert %{"insertText" => insert_text} = Enum.find(items, &match?(%{"label" => "if"}, &1))

assert insert_text =~ "if do\n\t"
end
end
end