From 34ebffac16b1cf0f2d291b65b29a0cbf717cc57f Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Wed, 4 Dec 2019 22:34:31 +0100 Subject: [PATCH 1/2] provide completions for protocol functions --- .../language_server/providers/completion.ex | 28 +++++++++++++++++++ .../test/providers/completion_test.exs | 26 +++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/apps/language_server/lib/language_server/providers/completion.ex b/apps/language_server/lib/language_server/providers/completion.ex index 06f82c4d9..8cd1c6d58 100644 --- a/apps/language_server/lib/language_server/providers/completion.ex +++ b/apps/language_server/lib/language_server/providers/completion.ex @@ -285,6 +285,34 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do end end + defp from_completion_item( + %{ + type: :protocol_function, + args: args, + spec: _spec, + name: name, + summary: summary, + arity: arity, + origin: origin + }, + context + ) do + def_str = if(context[:def_before] == nil, do: "def ") + + full_snippet = "#{def_str}#{snippet(name, args, arity)} do\n\t$0\nend" + label = "#{def_str}#{function_label(name, args, arity)}" + + %__MODULE__{ + label: label, + kind: :interface, + detail: "#{origin} protocol function", + documentation: summary, + insert_text: full_snippet, + priority: 2, + filter_text: name + } + end + defp from_completion_item(%{type: :field, name: name, origin: origin}, _context) do %__MODULE__{ label: to_string(name), diff --git a/apps/language_server/test/providers/completion_test.exs b/apps/language_server/test/providers/completion_test.exs index 99d20c7e5..6d4249062 100644 --- a/apps/language_server/test/providers/completion_test.exs +++ b/apps/language_server/test/providers/completion_test.exs @@ -55,4 +55,30 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do assert(Enum.any?(items, fn %{"label" => label} -> label == lfn end)) end end + + test "provides completions for protocol functions" do + text = """ + defimpl Enumerable, for: MyModule do + + #^ + end + """ + + {line, char} = {1, 1} + TestUtils.assert_has_cursor_char(text, line, char) + {:ok, %{"items" => items}} = Completion.completion(text, line, char, true) + + completions = + items + |> Enum.filter(&(&1["detail"] == "Enumerable protocol function")) + |> Enum.map(& &1["label"]) + |> Enum.sort() + + assert completions == [ + "def count(enumerable)", + "def member?(enumerable,element)", + "def reduce(enumerable,acc,fun)", + "def slice(enumerable)" + ] + end end From fc40bf60134e457b51a387086e395e01bcbb4dda Mon Sep 17 00:00:00 2001 From: Lukasz Samson Date: Thu, 5 Dec 2019 23:22:41 +0100 Subject: [PATCH 2/2] make test not depend on std lib --- apps/language_server/mix.exs | 4 ++++ .../test/providers/completion_test.exs | 10 +++------- .../test/support/fixtures/example_protocol.ex | 11 +++++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 apps/language_server/test/support/fixtures/example_protocol.ex diff --git a/apps/language_server/mix.exs b/apps/language_server/mix.exs index 6aab9fdf9..d18f98b0f 100644 --- a/apps/language_server/mix.exs +++ b/apps/language_server/mix.exs @@ -10,6 +10,7 @@ defmodule ElixirLS.LanguageServer.Mixfile do config_path: "config/config.exs", deps_path: "../../deps", lockfile: "../../mix.lock", + elixirc_paths: elixirc_paths(Mix.env()), build_embedded: false, start_permanent: true, build_per_environment: false, @@ -31,4 +32,7 @@ defmodule ElixirLS.LanguageServer.Mixfile do {:dialyxir, "~> 1.0.0-rc.6", runtime: false} ] end + + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] end diff --git a/apps/language_server/test/providers/completion_test.exs b/apps/language_server/test/providers/completion_test.exs index 6d4249062..adcac9f70 100644 --- a/apps/language_server/test/providers/completion_test.exs +++ b/apps/language_server/test/providers/completion_test.exs @@ -58,7 +58,7 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do test "provides completions for protocol functions" do text = """ - defimpl Enumerable, for: MyModule do + defimpl ElixirLS.LanguageServer.Fixtures.ExampleProtocol, for: MyModule do #^ end @@ -70,15 +70,11 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do completions = items - |> Enum.filter(&(&1["detail"] == "Enumerable protocol function")) + |> Enum.filter(&(&1["detail"] =~ "protocol function")) |> Enum.map(& &1["label"]) - |> Enum.sort() assert completions == [ - "def count(enumerable)", - "def member?(enumerable,element)", - "def reduce(enumerable,acc,fun)", - "def slice(enumerable)" + "def my_fun(example,arg)" ] end end diff --git a/apps/language_server/test/support/fixtures/example_protocol.ex b/apps/language_server/test/support/fixtures/example_protocol.ex new file mode 100644 index 000000000..2e122eef6 --- /dev/null +++ b/apps/language_server/test/support/fixtures/example_protocol.ex @@ -0,0 +1,11 @@ +defprotocol ElixirLS.LanguageServer.Fixtures.ExampleProtocol do + @moduledoc """ + ExampleProtocol protocol used in tests. + """ + + @doc """ + Does what `my_fun` does for `t` + """ + @spec my_fun(t, integer) :: binary + def my_fun(example, arg) +end