diff --git a/apps/language_server/lib/language_server/providers/completion.ex b/apps/language_server/lib/language_server/providers/completion.ex index 34d75255c..d29148539 100644 --- a/apps/language_server/lib/language_server/providers/completion.ex +++ b/apps/language_server/lib/language_server/providers/completion.ex @@ -161,6 +161,7 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do |> Enum.map(&from_completion_item(&1, context, options)) |> maybe_add_do(context) |> maybe_add_end(context) + |> maybe_add_keywords(context) |> Enum.reject(&is_nil/1) |> sort_items() @@ -238,8 +239,40 @@ defmodule ElixirLS.LanguageServer.Providers.Completion do end end + defp maybe_add_keywords(completion_items, %{text_after_cursor: ""} = context) do + kw = Map.get(context, :text_before_cursor) |> String.trim_leading() |> get_keyword() + + if kw != "" do + item = %__MODULE__{ + label: kw, + kind: :keyword, + detail: "keyword", + insert_text: kw, + tags: [], + priority: 0 + } + + [item | completion_items] + else + completion_items + end + end + + defp maybe_add_keywords(completion_items, _context) do + completion_items + end + ## Helpers + defp get_keyword(t) do + cond do + Enum.member?(["t", "tr", "tru", "true"], t) -> "true" + Enum.member?(["f", "fa", "fal", "fals", "false"], t) -> "false" + Enum.member?(["n", "ni", "nil"], t) -> "nil" + true -> "" + end + end + defp is_incomplete(items) do if Enum.empty?(items) do false diff --git a/apps/language_server/test/providers/completion_test.exs b/apps/language_server/test/providers/completion_test.exs index c9cac62db..fe803c142 100644 --- a/apps/language_server/test/providers/completion_test.exs +++ b/apps/language_server/test/providers/completion_test.exs @@ -685,6 +685,42 @@ defmodule ElixirLS.LanguageServer.Providers.CompletionTest do end end + describe "keyword completion" do + setup do + text = """ + defmodule MyModule do + def dummy_function() do + t + #^ + end + end + """ + + %{text: text, location: {2, 5}} + end + + test "first", context do + %{text: text, location: {line, char}} = context + + TestUtils.assert_has_cursor_char(text, line, char) + + opts = Keyword.merge(@supports, signature_after_complete: true) + {:ok, %{"items" => items}} = Completion.completion(text, line, char, opts) + + [item] = items |> Enum.filter(&(&1["insertText"] == "true")) + + assert %{ + "detail" => "keyword", + "documentation" => %{:kind => "markdown", "value" => ""}, + "insertText" => "true", + "insertTextFormat" => 2, + "kind" => 14, + "label" => "true", + "sortText" => "00000000" + } = item + end + end + describe "function completion" do setup do text = """