Skip to content

Commit

Permalink
Autocompletion: more specific CompletionItemKind (#419)
Browse files Browse the repository at this point in the history
* Autocompletion: more specific CompletionItemKind

Instead of returning module for all types of modules, return "interface"
for behaviours and protocols, and "struct" for structs.

Also add the subtype to the label

* fix server test

* Treat exceptions as structs

* Fix formatting
  • Loading branch information
axelson authored Nov 28, 2020
1 parent 88ec52e commit 6ffa871
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 8 deletions.
25 changes: 21 additions & 4 deletions apps/language_server/lib/language_server/providers/completion.ex
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,25 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
"module"
end

kind =
case subtype do
:behaviour -> :interface
:protocol -> :interface
:exception -> :struct
:struct -> :struct
_ -> :module
end

label =
if subtype do
"#{name} (#{subtype})"
else
name
end

%__MODULE__{
label: name,
kind: :module,
label: label,
kind: kind,
detail: detail,
documentation: summary,
insert_text: name,
Expand Down Expand Up @@ -582,8 +598,9 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do
text != ""
end

defp completion_kind(type) do
case type do
# LSP CompletionItemKind enumeration
defp completion_kind(kind) do
case kind do
:text -> 1
:method -> 2
:function -> 3
Expand Down
90 changes: 88 additions & 2 deletions apps/language_server/test/providers/completion_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
assert length(items) == 0
end

test "completions of protocols are rendered as an interface" do
text = """
defmodule MyModule do
def dummy_function() do
ElixirLS.LanguageServer.Fixtures.ExampleP
# ^
end
end
"""

{line, char} = {2, 45}
TestUtils.assert_has_cursor_char(text, line, char)

{:ok, %{"items" => [item]}} = Completion.completion(text, line, char, @supports)

# 8 is interface
assert item["kind"] == 8
assert item["label"] == "ExampleProtocol (protocol)"
end

test "provides completions for protocol functions" do
text = """
defimpl ElixirLS.LanguageServer.Fixtures.ExampleProtocol, for: MyModule do
Expand All @@ -132,6 +152,50 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
]
end

test "completions of behaviours are rendered as an interface" do
text = """
defmodule MyModule do
def dummy_function() do
ElixirLS.LanguageServer.Fixtures.ExampleB
# ^
end
end
"""

{line, char} = {2, 45}
TestUtils.assert_has_cursor_char(text, line, char)

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

assert [item, _] = items

# 8 is interface
assert item["kind"] == 8
assert item["label"] == "ExampleBehaviour (behaviour)"
end

test "completions of exceptions are rendered as a struct" do
text = """
defmodule MyModule do
def dummy_function() do
ElixirLS.LanguageServer.Fixtures.ExampleE
# ^
end
end
"""

{line, char} = {2, 45}
TestUtils.assert_has_cursor_char(text, line, char)

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

assert [item] = items

# 22 is struct
assert item["kind"] == 22
assert item["label"] == "ExampleException (exception)"
end

test "provides completions for callbacks without `def` before" do
text = """
defmodule MyModule do
Expand Down Expand Up @@ -199,7 +263,7 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
|> Enum.filter(&(&1["detail"] =~ "struct"))
|> Enum.map(& &1["label"])

assert "NaiveDateTime" in completions
assert "NaiveDateTime (struct)" in completions

{line, char} = {4, 17}
TestUtils.assert_has_cursor_char(text, line, char)
Expand All @@ -221,7 +285,7 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
|> Enum.filter(&(&1["detail"] =~ "struct"))
|> Enum.map(& &1["label"])

assert "NaiveDateTime" in completions
assert "NaiveDateTime (struct)" in completions
end

describe "deprecated" do
Expand Down Expand Up @@ -257,6 +321,28 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do
end

describe "structs and maps" do
test "completions of structs are rendered as a struct" do
text = """
defmodule MyModule do
def dummy_function() do
ElixirLS.LanguageServer.Fixtures.ExampleS
# ^
end
end
"""

{line, char} = {2, 45}
TestUtils.assert_has_cursor_char(text, line, char)

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

assert [item] = items

# 22 is struct
assert item["kind"] == 22
assert item["label"] == "ExampleStruct (struct)"
end

test "returns struct fields in call syntax" do
text = """
defmodule MyModule do
Expand Down
4 changes: 2 additions & 2 deletions apps/language_server/test/server_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,8 @@ defmodule ElixirLS.LanguageServer.ServerTest do
%{
"detail" => "behaviour",
"documentation" => _,
"kind" => 9,
"label" => "GenServer"
"kind" => 8,
"label" => "GenServer (behaviour)"
}
| _
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ElixirLS.LanguageServer.Fixtures.ExampleException do
defexception [:message]
end
3 changes: 3 additions & 0 deletions apps/language_server/test/support/fixtures/example_struct.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ElixirLS.LanguageServer.Fixtures.ExampleStruct do
defstruct [:name]
end

0 comments on commit 6ffa871

Please sign in to comment.