Skip to content

Commit f60af5f

Browse files
authored
Snippet variants with n-1 placeholders to use after pipe (#501)
This is a simple implementation based on harcoded variants for the most common use-cases: case, unless and if.
1 parent e10d4b2 commit f60af5f

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

apps/language_server/lib/language_server/providers/completion.ex

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
5656
{"ExUnit.Case", "describe"} => "describe \"$1\" do\n\t$0\nend"
5757
}
5858

59+
# Alternative snippets versions to be preferred when preceded by a pipe
60+
@pipe_func_snippets %{
61+
{"Kernel.SpecialForms", "case"} => "case do\n\t$1 ->\n\t\t$0\nend",
62+
{"Kernel", "if"} => "if do\n\t$0\nend",
63+
{"Kernel", "unless"} => "unless do\n\t$0\nend"
64+
}
65+
5966
@use_name_only MapSet.new([
6067
{"Kernel", "not"},
6168
{"Kernel", "use"},
@@ -493,7 +500,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
493500
completion
494501
end
495502

496-
if snippet = Map.get(@func_snippets, {origin, name}) do
503+
if snippet = snippet_for({origin, name}, context) do
497504
%{completion | insert_text: snippet, kind: :snippet, label: name}
498505
else
499506
completion
@@ -504,6 +511,15 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
504511
nil
505512
end
506513

514+
defp snippet_for(key, %{pipe_before?: true}) do
515+
# Get pipe-friendly version of snippet if available, otherwise fallback to standard
516+
Map.get(@pipe_func_snippets, key) || Map.get(@func_snippets, key)
517+
end
518+
519+
defp snippet_for(key, _context) do
520+
Map.get(@func_snippets, key)
521+
end
522+
507523
defp def_snippet(def_str, name, args, arity, opts) do
508524
if Keyword.get(opts, :snippets_supported, false) do
509525
"#{def_str}#{function_snippet(name, args, arity, opts)} do\n\t$0\nend"

apps/language_server/test/providers/completion_test.exs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,4 +940,68 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
940940
refute Enum.any?(items, fn i -> i["label"] == "make_ref/0" end)
941941
end
942942
end
943+
944+
describe "use the (arity - 1) version of snippets after pipe" do
945+
test "case/2 snippet skips the condition argument" do
946+
text = """
947+
defmodule MyModule do
948+
def hello do
949+
[1, 2]
950+
|> Enum.random()
951+
|> ca
952+
# ^
953+
end
954+
end
955+
"""
956+
957+
{line, char} = {4, 9}
958+
TestUtils.assert_has_cursor_char(text, line, char)
959+
assert {:ok, %{"items" => items}} = Completion.completion(text, line, char, @supports)
960+
assert %{"insertText" => insert_text} = Enum.find(items, &match?(%{"label" => "case"}, &1))
961+
assert insert_text =~ "case do\n\t"
962+
end
963+
964+
test "unless/2 snippet skips the condition argument" do
965+
text = """
966+
defmodule MyModule do
967+
def hello do
968+
[1, 2]
969+
|> Enum.random()
970+
|> unl
971+
# ^
972+
end
973+
end
974+
"""
975+
976+
{line, char} = {4, 10}
977+
TestUtils.assert_has_cursor_char(text, line, char)
978+
assert {:ok, %{"items" => items}} = Completion.completion(text, line, char, @supports)
979+
980+
assert %{"insertText" => insert_text} =
981+
Enum.find(items, &match?(%{"label" => "unless"}, &1))
982+
983+
assert insert_text =~ "unless do\n\t"
984+
end
985+
986+
test "if/2 snippet skips the condition argument" do
987+
text = """
988+
defmodule MyModule do
989+
def hello do
990+
[1, 2]
991+
|> Enum.random()
992+
|> if
993+
# ^
994+
end
995+
end
996+
"""
997+
998+
{line, char} = {4, 9}
999+
TestUtils.assert_has_cursor_char(text, line, char)
1000+
assert {:ok, %{"items" => items}} = Completion.completion(text, line, char, @supports)
1001+
1002+
assert %{"insertText" => insert_text} = Enum.find(items, &match?(%{"label" => "if"}, &1))
1003+
1004+
assert insert_text =~ "if do\n\t"
1005+
end
1006+
end
9431007
end

0 commit comments

Comments
 (0)