From b9f55cc5997a590aa97357f14bfc347871b0a1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Samson?= Date: Mon, 9 Nov 2020 04:38:51 +0100 Subject: [PATCH] Remove support for query prefixes in WorkspaceSymbolsProvider (#396) Closes #392 --- README.md | 20 +- .../providers/workspace_symbols.ex | 36 +-- .../test/providers/workspace_symbols_test.exs | 260 +++++++----------- 3 files changed, 107 insertions(+), 209 deletions(-) diff --git a/README.md b/README.md index 6aaa9b3dd..a4d729752 100644 --- a/README.md +++ b/README.md @@ -196,25 +196,7 @@ The completions include: ## Workspace Symbols -With Dialyzer integration enabled ElixirLS will build an index of symbols (modules, functions, types and callbacks). The symbols are taken from the current workspace, all dependencies and stdlib (Elixir and erlang). This feature enables quick navigation to symbol definitions. However due to sheer number of different symbols and fuzzy search utilized by the provider, ElixirLS uses query prefixes to improve search results relevance. - -Use the following rules when navigating to workspace symbols: -* no prefix - search for modules - * `:erl` - * `Enu` -* `f ` prefix - search for functions - * `f inse` - * `f :ets.inse` - * `f Enum.cou` - * `f count/0` -* `t ` prefix - search for types - * `t t/0` - * `t :erlang.time_u` - * `t DateTime.` -* `c ` prefix - search for callbacks - * `c handle_info` - * `c GenServer.in` - * `c :gen_statem` +With Dialyzer integration enabled ElixirLS will build an index of symbols (modules, functions, types and callbacks). The symbols are taken from the current workspace, all dependencies and stdlib (Elixir and erlang). This feature enables quick navigation to symbol definitions. ## Troubleshooting diff --git a/apps/language_server/lib/language_server/providers/workspace_symbols.ex b/apps/language_server/lib/language_server/providers/workspace_symbols.ex index e1001b7c8..12d732ad5 100644 --- a/apps/language_server/lib/language_server/providers/workspace_symbols.ex +++ b/apps/language_server/lib/language_server/providers/workspace_symbols.ex @@ -54,20 +54,7 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do @spec symbols(String.t()) :: {:ok, [symbol_information_t]} def symbols(query, server \\ __MODULE__) do - results = - case query do - "f " <> fun_query -> - query(:functions, fun_query, server) - - "t " <> type_query -> - query(:types, type_query, server) - - "c " <> callback_query -> - query(:callbacks, callback_query, server) - - module_query -> - query(:modules, module_query, server) - end + results = query(query, server) {:ok, results} end @@ -109,10 +96,10 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do end @impl GenServer - def handle_call({:query, key, query}, from, state) do + def handle_call({:query, query}, from, state) do {:ok, _pid} = Task.start_link(fn -> - results = get_results(state, key, query) + results = get_results(state, query) GenServer.reply(from, results) end) @@ -356,13 +343,13 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do |> elem(0) end - defp query(kind, query, server) do + defp query(query, server) do case String.trim(query) do "" -> [] trimmed -> - GenServer.call(server, {:query, kind, trimmed}) + GenServer.call(server, {:query, trimmed}) end end @@ -446,14 +433,13 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do :ok end - @spec get_results(state_t, key_t, String.t()) :: [symbol_information_t] - defp get_results(state, key, query) do + @spec get_results(state_t, String.t()) :: [symbol_information_t] + defp get_results(state, query) do query_downcase = String.downcase(query) query_length = String.length(query) arity_suffix = Regex.run(@arity_suffix_regex, query) - state - |> Map.fetch!(key) + (state.modules ++ state.functions ++ state.types ++ state.callbacks) |> process_chunked(fn chunk -> chunk |> Enum.map(&{&1, get_score(&1.name, query, query_downcase, query_length, arity_suffix)}) @@ -509,15 +495,15 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do end defp symbol_name(:functions, {module, function, arity}) do - "f #{inspect(module)}.#{function}/#{arity}" + "#{inspect(module)}.#{function}/#{arity}" end defp symbol_name(:types, {module, type, arity}) do - "t #{inspect(module)}.#{type}/#{arity}" + "#{inspect(module)}.#{type}/#{arity}" end defp symbol_name(:callbacks, {module, callback, arity}) do - "c #{inspect(module)}.#{callback}/#{arity}" + "#{inspect(module)}.#{callback}/#{arity}" end @spec build_range(nil | non_neg_integer) :: range_t diff --git a/apps/language_server/test/providers/workspace_symbols_test.exs b/apps/language_server/test/providers/workspace_symbols_test.exs index acbe78924..dcf86a3af 100644 --- a/apps/language_server/test/providers/workspace_symbols_test.exs +++ b/apps/language_server/test/providers/workspace_symbols_test.exs @@ -44,180 +44,110 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbolsTest do end test "returns modules", %{server: server} do - assert {:ok, - [ - %{ - kind: 2, - location: %{ - range: %{end: %{character: 0, line: 1}, start: %{character: 0, line: 0}}, - uri: uri - }, - name: "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols" - } - ]} = WorkspaceSymbols.symbols("ElixirLS.LanguageServer.Fixtures.", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") - - assert {:ok, - [ - %{ - kind: 2, - location: %{ - range: %{end: %{character: 0, line: 1}, start: %{character: 0, line: 0}}, - uri: uri - }, - name: "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols" - } - ]} = WorkspaceSymbols.symbols("work", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + assert {:ok, list} = WorkspaceSymbols.symbols("ElixirLS.LanguageServer.Fixtures.", server) + + assert module = + Enum.find(list, &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols")) + + assert module.kind == 2 + assert module.location.uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + + assert module.location.range == %{ + end: %{character: 0, line: 1}, + start: %{character: 0, line: 0} + } + + assert WorkspaceSymbols.symbols("work", server) + |> elem(1) + |> Enum.any?(&(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols")) end test "returns functions", %{server: server} do - assert { - :ok, - [ - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 1}, start: %{character: 0, line: 0}}, - uri: uri - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.module_info/1" - }, - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 1}, start: %{character: 0, line: 0}} - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.module_info/0" - }, - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 1}, start: %{character: 0, line: 0}} - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.behaviour_info/1" - }, - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 3}, start: %{character: 0, line: 2}} - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_macro/1" - }, - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 2}, start: %{character: 0, line: 1}} - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_function/1" - }, - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 1}, start: %{character: 0, line: 0}} - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.__info__/1" - } - ] - } = WorkspaceSymbols.symbols("f ElixirLS.LanguageServer.Fixtures.", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") - - assert {:ok, - [ - %{ - kind: 12, - location: %{ - range: %{end: %{character: 0, line: 2}, start: %{character: 0, line: 1}}, - uri: uri - }, - name: "f ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_function/1" - } - ]} = WorkspaceSymbols.symbols("f fun", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + assert {:ok, list} = WorkspaceSymbols.symbols("ElixirLS.LanguageServer.Fixtures.", server) + + assert some_function = + Enum.find( + list, + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_function/1") + ) + + assert some_function.kind == 12 + + assert some_function.location.uri + |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + + assert some_function.location.range == %{ + end: %{character: 0, line: 2}, + start: %{character: 0, line: 1} + } + + assert WorkspaceSymbols.symbols("fun", server) + |> elem(1) + |> Enum.any?( + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_function/1") + ) end test "returns types", %{server: server} do - assert { - :ok, - [ - %{ - kind: 5, - location: %{ - range: %{end: %{character: 0, line: 8}, start: %{character: 0, line: 7}}, - uri: uri - }, - name: "t ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_type/0" - }, - %{ - kind: 5, - location: %{ - range: %{end: %{character: 0, line: 9}, start: %{character: 0, line: 8}} - }, - name: "t ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_opaque_type/0" - } - ] - } = WorkspaceSymbols.symbols("t ElixirLS.LanguageServer.Fixtures.", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") - - assert { - :ok, - [ - %{ - kind: 5, - location: %{ - range: %{end: %{character: 0, line: 9}, start: %{character: 0, line: 8}}, - uri: uri - }, - name: "t ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_opaque_type/0" - } - ] - } = WorkspaceSymbols.symbols("t opa", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + assert {:ok, list} = WorkspaceSymbols.symbols("ElixirLS.LanguageServer.Fixtures.", server) + + assert some_type = + Enum.find( + list, + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_type/0") + ) + + assert some_type.kind == 5 + + assert some_type.location.uri + |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + + assert some_type.location.range == %{ + end: %{character: 0, line: 8}, + start: %{character: 0, line: 7} + } + + assert Enum.any?( + list, + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_opaque_type/0") + ) + + assert WorkspaceSymbols.symbols("opa", server) + |> elem(1) + |> Enum.any?( + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_opaque_type/0") + ) end test "returns callbacks", %{server: server} do - assert { - :ok, - [ - %{ - kind: 24, - location: %{ - range: %{end: %{character: 0, line: 5}, start: %{character: 0, line: 4}}, - uri: uri - }, - name: "c ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_callback/1" - }, - %{ - kind: 24, - location: %{ - range: %{end: %{character: 0, line: 6}, start: %{character: 0, line: 5}} - }, - name: "c ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_macrocallback/1" - } - ] - } = WorkspaceSymbols.symbols("c ElixirLS.LanguageServer.Fixtures.", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") - - assert {:ok, - [ - %{ - kind: 24, - location: %{ - range: %{end: %{character: 0, line: 6}, start: %{character: 0, line: 5}}, - uri: uri - }, - name: "c ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_macrocallback/1" - } - ]} = WorkspaceSymbols.symbols("c macr", server) - - assert uri |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + assert {:ok, list} = WorkspaceSymbols.symbols("ElixirLS.LanguageServer.Fixtures.", server) + + assert some_callback = + Enum.find( + list, + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_callback/1") + ) + + assert some_callback.kind == 24 + + assert some_callback.location.uri + |> String.ends_with?("test/support/fixtures/workspace_symbols.ex") + + assert some_callback.location.range == %{ + end: %{character: 0, line: 5}, + start: %{character: 0, line: 4} + } + + assert Enum.any?( + list, + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_macrocallback/1") + ) + + assert WorkspaceSymbols.symbols("macr", server) + |> elem(1) + |> Enum.any?( + &(&1.name == "ElixirLS.LanguageServer.Fixtures.WorkspaceSymbols.some_macrocallback/1") + ) end defp wait_until_indexed(pid) do