diff --git a/apps/remote_control/lib/lexical/remote_control/api.ex b/apps/remote_control/lib/lexical/remote_control/api.ex index 2de0bc1de..80c494d77 100644 --- a/apps/remote_control/lib/lexical/remote_control/api.ex +++ b/apps/remote_control/lib/lexical/remote_control/api.ex @@ -118,4 +118,8 @@ defmodule Lexical.RemoteControl.Api do def reindex(%Project{} = project) do RemoteControl.call(project, Commands.Reindex, :perform, [project]) end + + def index_running?(%Project{} = project) do + RemoteControl.call(project, Commands.Reindex, :running?, []) + end end diff --git a/apps/remote_control/lib/lexical/remote_control/api/messages.ex b/apps/remote_control/lib/lexical/remote_control/api/messages.ex index d844b38a4..f60325a36 100644 --- a/apps/remote_control/lib/lexical/remote_control/api/messages.ex +++ b/apps/remote_control/lib/lexical/remote_control/api/messages.ex @@ -39,6 +39,10 @@ defmodule Lexical.RemoteControl.Api.Messages do defrecord :struct_discovered, module: nil, fields: [] + defrecord :project_reindex_requested, project: nil + + defrecord :project_reindexed, project: nil, elapsed_ms: 0, status: :success + @type compile_status :: :successful | :error @type name_and_arity :: {atom, non_neg_integer} @type field_list :: Keyword.t() | [atom] @@ -118,4 +122,14 @@ defmodule Lexical.RemoteControl.Api.Messages do ) @type struct_discovered :: record(:struct_discovered, module: module(), fields: field_list()) + + @type project_reindex_requested :: + record(:project_reindex_requested, project: Lexical.Project.t()) + + @type project_reindexed :: + record(:project_reindexed, + project: Lexical.Project.t(), + elapsed_ms: non_neg_integer(), + status: :success | {:error, term()} + ) end diff --git a/apps/remote_control/lib/lexical/remote_control/commands/reindex.ex b/apps/remote_control/lib/lexical/remote_control/commands/reindex.ex index c711d1c68..697b6b53e 100644 --- a/apps/remote_control/lib/lexical/remote_control/commands/reindex.ex +++ b/apps/remote_control/lib/lexical/remote_control/commands/reindex.ex @@ -66,11 +66,15 @@ defmodule Lexical.RemoteControl.Commands.Reindex do @moduledoc """ A simple genserver that prevents more than one reindexing job from running at the same time """ + alias Lexical.Document alias Lexical.Project + alias Lexical.RemoteControl.Api + alias Lexical.RemoteControl.Dispatch alias Lexical.RemoteControl.Search use GenServer + import Api.Messages def start_link(reindex_fun) when is_function(reindex_fun, 1) do GenServer.start_link(__MODULE__, reindex_fun, name: __MODULE__) @@ -127,8 +131,19 @@ defmodule Lexical.RemoteControl.Commands.Reindex do end defp do_reindex(%Project{} = project) do - with {:ok, entries} <- Search.Indexer.create_index(project) do - Search.Store.replace(entries) - end + Dispatch.broadcast(project_reindex_requested(project: project)) + + {elapsed_us, result} = + :timer.tc(fn -> + with {:ok, entries} <- Search.Indexer.create_index(project) do + Search.Store.replace(entries) + end + end) + + Dispatch.broadcast( + project_reindexed(project: project, elapsed_ms: round(elapsed_us / 1000), status: :success) + ) + + result end end diff --git a/apps/remote_control/lib/lexical/remote_control/search/indexer.ex b/apps/remote_control/lib/lexical/remote_control/search/indexer.ex index ea8673d34..ac5cfdf3d 100644 --- a/apps/remote_control/lib/lexical/remote_control/search/indexer.ex +++ b/apps/remote_control/lib/lexical/remote_control/search/indexer.ex @@ -107,7 +107,7 @@ defmodule Lexical.RemoteControl.Search.Indexer do fn chunk -> block_bytes = chunk |> Enum.map(&Map.get(path_to_size_map, &1)) |> Enum.sum() result = Enum.map(chunk, processor) - update_progress.(block_bytes, nil) + update_progress.(block_bytes, "Indexing") result end, timeout: timeout diff --git a/apps/remote_control/test/lexical/remote_control/dispatch/handlers/indexer_test.exs b/apps/remote_control/test/lexical/remote_control/dispatch/handlers/indexer_test.exs index 5c70e8139..a682c95d3 100644 --- a/apps/remote_control/test/lexical/remote_control/dispatch/handlers/indexer_test.exs +++ b/apps/remote_control/test/lexical/remote_control/dispatch/handlers/indexer_test.exs @@ -20,8 +20,8 @@ defmodule Lexical.RemoteControl.Dispatch.Handlers.IndexingTest do create_index = &Search.Indexer.create_index/1 update_index = &Search.Indexer.update_index/2 - start_supervised!(Commands.Reindex) start_supervised!(RemoteControl.Dispatch) + start_supervised!(Commands.Reindex) start_supervised!({Search.Store, [project, create_index, update_index]}) start_supervised!(Lexical.Server.Application.document_store_child_spec()) diff --git a/apps/server/lib/lexical/server/project/search_listener.ex b/apps/server/lib/lexical/server/project/search_listener.ex new file mode 100644 index 000000000..2af99b770 --- /dev/null +++ b/apps/server/lib/lexical/server/project/search_listener.ex @@ -0,0 +1,55 @@ +defmodule Lexical.Server.Project.SearchListener do + alias Lexical.Formats + alias Lexical.Project + alias Lexical.Protocol.Id + alias Lexical.Protocol.Requests + alias Lexical.RemoteControl.Api + alias Lexical.Server + alias Lexical.Server.Window + + import Api.Messages + + use GenServer + require Logger + + def start_link(%Project{} = project) do + GenServer.start_link(__MODULE__, [project], name: name(project)) + end + + defp name(%Project{} = project) do + :"#{Project.name(project)}::search_listener" + end + + @impl GenServer + def init([%Project{} = project]) do + Api.register_listener(project, self(), [ + project_reindex_requested(), + project_reindexed() + ]) + + {:ok, project} + end + + @impl GenServer + def handle_info(project_reindex_requested(), %Project{} = project) do + Logger.info("project reindex requested") + send_code_lens_refresh() + + {:noreply, project} + end + + def handle_info(project_reindexed(elapsed_ms: elapsed), %Project{} = project) do + message = "Reindexed #{Project.name(project)} in #{Formats.time(elapsed, unit: :millisecond)}" + Logger.info(message) + send_code_lens_refresh() + + Window.show_info_message(message) + + {:noreply, project} + end + + defp send_code_lens_refresh do + request = Requests.CodeLensRefresh.new(id: Id.next()) + Server.server_request(request) + end +end diff --git a/apps/server/lib/lexical/server/project/supervisor.ex b/apps/server/lib/lexical/server/project/supervisor.ex index 1693c6281..58adf99bc 100644 --- a/apps/server/lib/lexical/server/project/supervisor.ex +++ b/apps/server/lib/lexical/server/project/supervisor.ex @@ -5,6 +5,7 @@ defmodule Lexical.Server.Project.Supervisor do alias Lexical.Server.Project.Intelligence alias Lexical.Server.Project.Node alias Lexical.Server.Project.Progress + alias Lexical.Server.Project.SearchListener use Supervisor @@ -26,7 +27,8 @@ defmodule Lexical.Server.Project.Supervisor do {ProjectNodeSupervisor, project}, {Node, project}, {Diagnostics, project}, - {Intelligence, project} + {Intelligence, project}, + {SearchListener, project} ] Supervisor.init(children, strategy: :one_for_one) diff --git a/apps/server/lib/lexical/server/provider/handlers/code_lens.ex b/apps/server/lib/lexical/server/provider/handlers/code_lens.ex index 85fbd9e35..83527eff9 100644 --- a/apps/server/lib/lexical/server/provider/handlers/code_lens.ex +++ b/apps/server/lib/lexical/server/provider/handlers/code_lens.ex @@ -7,6 +7,7 @@ defmodule Lexical.Server.Provider.Handlers.CodeLens do alias Lexical.Protocol.Requests alias Lexical.Protocol.Responses alias Lexical.Protocol.Types.CodeLens + alias Lexical.RemoteControl alias Lexical.Server.Provider.Env alias Lexical.Server.Provider.Handlers @@ -51,6 +52,8 @@ defmodule Lexical.Server.Provider.Handlers.CodeLens do defp show_reindex_lens?(%Project{} = project, %Document{} = document) do document_path = Path.expand(document.path) - Features.indexing_enabled?() and document_path == Project.mix_exs_path(project) + + Features.indexing_enabled?() and document_path == Project.mix_exs_path(project) and + not RemoteControl.Api.index_running?(project) end end diff --git a/apps/server/lib/lexical/server/provider/handlers/commands.ex b/apps/server/lib/lexical/server/provider/handlers/commands.ex index d03dc4269..6d608e4ad 100644 --- a/apps/server/lib/lexical/server/provider/handlers/commands.ex +++ b/apps/server/lib/lexical/server/provider/handlers/commands.ex @@ -1,5 +1,4 @@ defmodule Lexical.Server.Provider.Handlers.Commands do - alias Lexical.Formats alias Lexical.Project alias Lexical.Protocol.Requests alias Lexical.Protocol.Responses @@ -43,14 +42,12 @@ defmodule Lexical.Server.Provider.Handlers.Commands do end defp reindex(%Project{} = project, request_id) do - case :timer.tc(RemoteControl.Api, :reindex, [project]) do - {elapsed, :ok} -> - message = "Reindexed #{Project.name(project)} in #{Formats.time(elapsed)}" - Window.show(:info, message) + case RemoteControl.Api.reindex(project) do + :ok -> Responses.ExecuteCommand.new(request_id, "ok") - {_elapsed, error} -> - Window.error("Indexing #{Project.name(project)} failed") + error -> + Window.show_error_message("Indexing #{Project.name(project)} failed") Logger.error("Indexing command failed due to #{inspect(error)}") internal_error(request_id, "Could not reindex: #{error}")