Skip to content

Commit 96a16cd

Browse files
committed
Start projects dynamically
1 parent ad7e2e4 commit 96a16cd

File tree

3 files changed

+77
-37
lines changed

3 files changed

+77
-37
lines changed

apps/expert/lib/expert/configuration.ex

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ defmodule Expert.Configuration do
3030
@dialyzer {:nowarn_function, set_dialyzer_enabled: 2}
3131

3232
@spec new(Forge.uri(), map(), String.t() | nil) :: t
33-
def new(root_uri, %Structures.ClientCapabilities{} = client_capabilities, client_name) do
33+
def new(_root_uri, %Structures.ClientCapabilities{} = client_capabilities, client_name) do
3434
support = Support.new(client_capabilities)
35-
projects = find_projects(root_uri)
3635

37-
%__MODULE__{support: support, projects: projects, client_name: client_name}
36+
%__MODULE__{support: support, projects: [], client_name: client_name}
3837
|> tap(&set/1)
3938
end
4039

@@ -43,34 +42,6 @@ defmodule Expert.Configuration do
4342
struct!(__MODULE__, [support: Support.new()] ++ attrs)
4443
end
4544

46-
defp find_projects(root_uri) do
47-
root_path = Forge.Document.Path.from_uri(root_uri)
48-
root_mix_exs = Path.join(root_path, "mix.exs")
49-
50-
projects =
51-
if File.exists?(root_mix_exs) do
52-
[Project.new(root_uri)]
53-
else
54-
find_multiroot_projects(root_path)
55-
end
56-
57-
if projects == [], do: [Project.new(root_uri)], else: projects
58-
end
59-
60-
defp find_multiroot_projects(root_path) do
61-
mix_exs_blob = Path.join([root_path, "**", "mix.exs"])
62-
63-
for mix_exs_path <- Path.wildcard(mix_exs_blob),
64-
"deps" not in Path.split(mix_exs_path) do
65-
project_uri =
66-
mix_exs_path
67-
|> Path.dirname()
68-
|> Forge.Document.Path.to_uri()
69-
70-
Project.new(project_uri)
71-
end
72-
end
73-
7445
defp set(%__MODULE__{} = config) do
7546
:persistent_term.put(__MODULE__, config)
7647
end
@@ -168,4 +139,18 @@ defmodule Expert.Configuration do
168139
defp maybe_add_watched_extensions(%__MODULE__{} = old_config, _) do
169140
{:ok, old_config}
170141
end
142+
143+
@spec add_project(t, Project.t()) :: t
144+
def add_project(%__MODULE__{} = config, %Project{} = project) do
145+
if Enum.any?(config.projects, &(&1.root_uri == project.root_uri)) do
146+
config
147+
else
148+
projects = [project | config.projects]
149+
new_config = %__MODULE__{config | projects: projects}
150+
151+
set(new_config)
152+
153+
new_config
154+
end
155+
end
171156
end

apps/expert/lib/expert/state.ex

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,29 @@ defmodule Expert.State do
6666

6767
Transport.write(registrations())
6868

69-
for project <- config.projects do
70-
Logger.info("Starting project at uri #{project.root_uri}")
71-
result = Expert.Project.Supervisor.start(project)
72-
Logger.info("result: #{inspect(result)}")
73-
end
74-
7569
{:ok, new_state}
7670
end
7771

7872
def initialize(%__MODULE__{initialized?: true}, %Requests.Initialize{}) do
7973
{:error, :already_initialized}
8074
end
8175

76+
defp maybe_start_project(project, config) do
77+
already_started? =
78+
Enum.any?(config.projects, fn p ->
79+
p.root_uri == project.root_uri
80+
end)
81+
82+
if already_started? do
83+
:ok
84+
else
85+
Logger.info("Starting project at uri #{project.root_uri}")
86+
result = Expert.Project.Supervisor.start(project)
87+
Logger.info("result: #{inspect(result)}")
88+
:ok
89+
end
90+
end
91+
8292
def in_flight?(%__MODULE__{} = state, request_id) do
8393
Map.has_key?(state.in_flight_requests, request_id)
8494
end
@@ -180,6 +190,18 @@ defmodule Expert.State do
180190
language_id: language_id
181191
} = did_open.params.text_document
182192

193+
project = Project.find_project(uri)
194+
config = state.configuration
195+
196+
state =
197+
if not is_nil(project) do
198+
maybe_start_project(project, config)
199+
config = Configuration.add_project(config, project)
200+
%__MODULE__{state | configuration: config}
201+
else
202+
state
203+
end
204+
183205
case Document.Store.open(uri, text, version, language_id) do
184206
:ok ->
185207
Logger.info("opened #{uri}")

apps/forge/lib/forge/project.ex

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,37 @@ defmodule Forge.Project do
341341
Forge.Path.parent_path?(document.path, root_path(project))
342342
end)
343343
end
344+
345+
def find_project(path) do
346+
project_root = find_parent_root_dir(path)
347+
348+
if is_nil(project_root) do
349+
nil
350+
else
351+
new(project_root)
352+
end
353+
end
354+
355+
defp find_parent_root_dir(path) do
356+
path = Forge.Document.Path.from_uri(path)
357+
path = path |> Path.expand() |> Path.dirname()
358+
359+
segments = Path.split(path)
360+
361+
traverse_path(segments)
362+
end
363+
364+
defp traverse_path([]), do: nil
365+
366+
defp traverse_path(segments) do
367+
path = Path.join(segments)
368+
mix_exs_path = Path.join(path, "mix.exs")
369+
370+
if File.exists?(mix_exs_path) do
371+
Document.Path.to_uri(path)
372+
else
373+
{_, rest} = List.pop_at(segments, -1)
374+
traverse_path(rest)
375+
end
376+
end
344377
end

0 commit comments

Comments
 (0)