Skip to content

Commit 7cc91da

Browse files
committed
Add notification when search backend is not ready
1 parent bc23ba1 commit 7cc91da

File tree

5 files changed

+160
-9
lines changed

5 files changed

+160
-9
lines changed

apps/engine/lib/engine/search/store.ex

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule Engine.Search.Store do
33
A persistent store for search entries
44
"""
55

6+
alias Engine.Dispatch
67
alias Engine.Search.Store
78
alias Engine.Search.Store.State
89

@@ -195,19 +196,31 @@ defmodule Engine.Search.Store do
195196
end
196197

197198
def handle_call({:exact, subject, constraints}, _from, {ref, %State{} = state}) do
198-
{:reply, State.exact(state, subject, constraints), {ref, state}}
199+
state
200+
|> State.exact(subject, constraints)
201+
|> maybe_broadcast_loading(state)
202+
|> then(&{:reply, &1, {ref, state}})
199203
end
200204

201205
def handle_call({:prefix, prefix, constraints}, _from, {ref, %State{} = state}) do
202-
{:reply, State.prefix(state, prefix, constraints), {ref, state}}
206+
state
207+
|> State.prefix(prefix, constraints)
208+
|> maybe_broadcast_loading(state)
209+
|> then(&{:reply, &1, {ref, state}})
203210
end
204211

205212
def handle_call({:fuzzy, subject, constraints}, _from, {ref, %State{} = state}) do
206-
{:reply, State.fuzzy(state, subject, constraints), {ref, state}}
213+
state
214+
|> State.fuzzy(subject, constraints)
215+
|> maybe_broadcast_loading(state)
216+
|> then(&{:reply, &1, {ref, state}})
207217
end
208218

209219
def handle_call({:all, constraints}, _from, {ref, %State{} = state}) do
210-
{:reply, State.all(state, constraints), {ref, state}}
220+
state
221+
|> State.all(constraints)
222+
|> maybe_broadcast_loading(state)
223+
|> then(&{:reply, &1, {ref, state}})
211224
end
212225

213226
def handle_call({:update, path, entries}, _from, {ref, %State{} = state}) do
@@ -217,13 +230,17 @@ defmodule Engine.Search.Store do
217230
end
218231

219232
def handle_call({:parent, entry}, _from, {_, %State{} = state} = orig_state) do
220-
parent = State.parent(state, entry)
221-
{:reply, parent, orig_state}
233+
state
234+
|> State.parent(entry)
235+
|> maybe_broadcast_loading(state)
236+
|> then(&{:reply, &1, orig_state})
222237
end
223238

224239
def handle_call({:siblings, entry}, _from, {_, %State{} = state} = orig_state) do
225-
siblings = State.siblings(state, entry)
226-
{:reply, siblings, orig_state}
240+
state
241+
|> State.siblings(entry)
242+
|> maybe_broadcast_loading(state)
243+
|> then(&{:reply, &1, orig_state})
227244
end
228245

229246
def handle_call(:on_stop, _, {ref, %State{} = state}) do
@@ -300,4 +317,11 @@ defmodule Engine.Search.Store do
300317
defp enabled? do
301318
:persistent_term.get({__MODULE__, :enabled?}, false)
302319
end
320+
321+
defp maybe_broadcast_loading({:error, :loading} = result, %State{project: project}) do
322+
Dispatch.broadcast(search_store_loading(project: project))
323+
result
324+
end
325+
326+
defp maybe_broadcast_loading(result, _state), do: result
303327
end

apps/engine/test/engine/search/store_test.exs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ defmodule Engine.Search.StoreTest do
1212
import Engine.Test.Entry.Builder
1313
import EventualAssertions
1414
import Fixtures
15+
import Forge.EngineApi.Messages
1516
import Forge.Test.CodeSigil
1617

1718
@backends [Ets]
@@ -394,4 +395,67 @@ defmodule Engine.Search.StoreTest do
394395
pid -> Process.alive?(pid)
395396
end
396397
end
398+
399+
describe "broadcasting search_store_loading when queries arrive during loading" do
400+
setup %{project: project} do
401+
destroy_backend(Ets, project)
402+
403+
start_supervised!(Dispatch)
404+
start_supervised!(Ets)
405+
406+
blocking_create = fn _project ->
407+
Process.sleep(:infinity)
408+
end
409+
410+
start_supervised!({Store, [project, blocking_create, &default_update/2, Ets]})
411+
412+
assert_eventually alive?()
413+
414+
Dispatch.register_listener(self(), [search_store_loading()])
415+
Store.enable()
416+
Process.sleep(10)
417+
418+
on_exit(fn ->
419+
after_each_test(Ets, project)
420+
end)
421+
422+
{:ok, project: project}
423+
end
424+
425+
test "exact/2 broadcasts search_store_loading when loading", %{project: project} do
426+
assert {:error, :loading} = Store.exact("SomeModule", [])
427+
assert_receive search_store_loading(project: received_project)
428+
assert received_project == project
429+
end
430+
431+
test "prefix/2 broadcasts search_store_loading when loading", %{project: project} do
432+
assert {:error, :loading} = Store.prefix("Some", [])
433+
assert_receive search_store_loading(project: received_project)
434+
assert received_project == project
435+
end
436+
437+
test "fuzzy/2 broadcasts search_store_loading when loading", %{project: project} do
438+
assert {:error, :loading} = Store.fuzzy("Some", [])
439+
assert_receive search_store_loading(project: received_project)
440+
assert received_project == project
441+
end
442+
443+
test "all/1 broadcasts search_store_loading when loading", %{project: project} do
444+
assert {:error, :loading} = Store.all([])
445+
assert_receive search_store_loading(project: received_project)
446+
assert received_project == project
447+
end
448+
449+
test "parent/1 broadcasts search_store_loading when loading", %{project: project} do
450+
assert {:error, :loading} = Store.parent(%Entry{})
451+
assert_receive search_store_loading(project: received_project)
452+
assert received_project == project
453+
end
454+
455+
test "siblings/1 broadcasts search_store_loading when loading", %{project: project} do
456+
assert {:error, :loading} = Store.siblings(%Entry{})
457+
assert_receive search_store_loading(project: received_project)
458+
assert received_project == project
459+
end
460+
end
397461
end

apps/expert/lib/expert/project/search_listener.ex

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ defmodule Expert.Project.SearchListener do
2222
def init([%Project{} = project]) do
2323
EngineApi.register_listener(project, self(), [
2424
project_reindex_requested(),
25-
project_reindexed()
25+
project_reindexed(),
26+
search_store_loading()
2627
])
2728

2829
{:ok, project}
@@ -50,4 +51,18 @@ defmodule Expert.Project.SearchListener do
5051

5152
{:noreply, project}
5253
end
54+
55+
def handle_info(search_store_loading(), %Project{} = project) do
56+
message = "Search index is loading for #{Project.name(project)}..."
57+
Logger.info(message)
58+
59+
GenLSP.notify(Expert.get_lsp(), %GenLSP.Notifications.WindowShowMessage{
60+
params: %GenLSP.Structures.ShowMessageParams{
61+
type: GenLSP.Enumerations.MessageType.info(),
62+
message: message
63+
}
64+
})
65+
66+
{:noreply, project}
67+
end
5368
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
defmodule Expert.Project.SearchListenerTest do
2+
alias Expert.EngineApi
3+
alias Expert.Test.DispatchFake
4+
alias Forge.Project
5+
alias GenLSP.Notifications.WindowShowMessage
6+
alias GenLSP.Structures.ShowMessageParams
7+
8+
use ExUnit.Case
9+
use Patch
10+
use DispatchFake
11+
12+
import Forge.EngineApi.Messages
13+
import Forge.Test.Fixtures
14+
import Expert.Test.Protocol.TransportSupport
15+
16+
setup do
17+
project = project()
18+
DispatchFake.start()
19+
20+
start_supervised!({Expert.Project.SearchListener, project})
21+
22+
{:ok, project: project}
23+
end
24+
25+
describe "handling search_store_loading message" do
26+
setup [:with_patched_transport]
27+
28+
test "shows window/showMessage notification", %{project: project} do
29+
EngineApi.broadcast(project, search_store_loading(project: project))
30+
31+
expected_type = GenLSP.Enumerations.MessageType.info()
32+
expected_message = "Search index is loading for #{Project.name(project)}..."
33+
34+
assert_receive {:transport,
35+
%WindowShowMessage{
36+
params: %ShowMessageParams{
37+
type: ^expected_type,
38+
message: ^expected_message
39+
}
40+
}}
41+
end
42+
end
43+
end

apps/forge/lib/forge/engine_api/messages.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ defmodule Forge.EngineApi.Messages do
4141

4242
defrecord :project_reindexed, project: nil, elapsed_ms: 0, status: :success
4343

44+
defrecord :search_store_loading, project: nil
45+
4446
@type compile_status :: :successful | :error
4547
@type name_and_arity :: {atom, non_neg_integer}
4648
@type field_list :: Keyword.t() | [atom]
@@ -125,4 +127,7 @@ defmodule Forge.EngineApi.Messages do
125127
elapsed_ms: non_neg_integer(),
126128
status: :success | {:error, term()}
127129
)
130+
131+
@type search_store_loading ::
132+
record(:search_store_loading, project: Forge.Project.t())
128133
end

0 commit comments

Comments
 (0)