Skip to content

Commit

Permalink
Don't return empty completions for single char prefix
Browse files Browse the repository at this point in the history
Related: #400

VS Code in particular handles empty completions lists very poorly,
refusing to make further completion requests. This commit removes the
logic that was preventing completions from being returned when the
prefix is a single character.
  • Loading branch information
zachallaun committed Oct 11, 2023
1 parent 2dbd183 commit 3dc27b9
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 42 deletions.
33 changes: 3 additions & 30 deletions apps/server/lib/lexical/server/code_intelligence/completion.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ defmodule Lexical.Server.CodeIntelligence.Completion do
alias Lexical.Completion.Translatable
alias Lexical.Document
alias Lexical.Document.Position
alias Lexical.Math
alias Lexical.Project
alias Lexical.Protocol.Types.Completion
alias Lexical.Protocol.Types.InsertTextFormat
Expand Down Expand Up @@ -38,7 +37,7 @@ defmodule Lexical.Server.CodeIntelligence.Completion do
case Env.new(project, document, position) do
{:ok, env} ->
completions = completions(project, env, context)
Logger.warning("Emitting completions: #{inspect(completions)}")
Logger.info("Emitting completions: #{inspect(completions)}")
completion_list(completions)

{:error, _} = error ->
Expand All @@ -51,7 +50,7 @@ defmodule Lexical.Server.CodeIntelligence.Completion do
prefix_tokens = Env.prefix_tokens(env, 1)

cond do
prefix_tokens == [] ->
prefix_tokens == [] or not context_will_give_meaningful_completions?(env) ->
[]

match?([{:operator, :do, _}], prefix_tokens) and Env.empty?(env.suffix) ->
Expand All @@ -61,9 +60,6 @@ defmodule Lexical.Server.CodeIntelligence.Completion do
|> Builder.snippet(do_end_snippet, label: "do/end block")
|> List.wrap()

Enum.empty?(prefix_tokens) or not context_will_give_meaningful_completions?(env) ->
[]

Env.in_context?(env, :struct_arguments) and not Env.in_context?(env, :struct_field_value) and
not prefix_is_trigger?(env) ->
project
Expand Down Expand Up @@ -107,30 +103,7 @@ defmodule Lexical.Server.CodeIntelligence.Completion do
end

defp context_will_give_meaningful_completions?(%Env{} = env) do
case Code.Fragment.cursor_context(env.prefix) do
{:local_or_var, name} ->
local_length = length(name)

surround_begin =
Math.clamp(env.position.character - local_length - 1, 1, env.position.character)

case Code.Fragment.surround_context(env.prefix, {1, surround_begin}) do
:none ->
local_length > 1

_other ->
true
end

:none ->
false

{:unquoted_atom, name} ->
length(name) > 1

_ ->
true
end
Code.Fragment.cursor_context(env.prefix) != :none
end

defp displayable?(%Project{} = project, result) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,16 @@ defmodule Lexical.Server.CodeIntelligence.CompletionTest do
end
end

test "ignores erlang modules", %{project: project} do
assert %Completion.List{is_incomplete: true, items: []} =
complete(project, ":e|", as_list: false)
test "completes erlang modules", %{project: project} do
assert [_ | _] = completions = complete(project, ":e|")

for completion <- completions do
assert completion.kind == :module
end
end
end

describe "ignoring things" do
test "return empty items and mark is_incomplete when single character contexts", %{
project: project
} do
assert %Completion.List{is_incomplete: true, items: []} =
complete(project, "def my_thing() d|", as_list: false)
end

test "returns an incomplete completion list when the context is empty", %{project: project} do
assert %Completion.List{is_incomplete: true, items: []} =
complete(project, " ", as_list: false)
Expand Down
2 changes: 0 additions & 2 deletions apps/server/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
alias Lexical.RemoteControl.Search.Store

ExUnit.configure(timeout: :infinity)
ExUnit.start()

0 comments on commit 3dc27b9

Please sign in to comment.