Skip to content

Commit 97c5ae4

Browse files
authored
Merge pull request elixir-editors#58 from mattbaker/find-refs-in-umbrella
Support Find References in umbrella apps
2 parents 8832a28 + 891f66f commit 97c5ae4

File tree

12 files changed

+196
-54
lines changed

12 files changed

+196
-54
lines changed

apps/language_server/lib/language_server/build.ex

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@ defmodule ElixirLS.LanguageServer.Build do
88
{nil, nil}
99
else
1010
spawn_monitor(fn ->
11-
{us, _} =
12-
:timer.tc(fn ->
13-
IO.puts("Compiling with Mix env #{Mix.env()}")
14-
15-
case reload_project() do
16-
{:ok, mixfile_diagnostics} ->
17-
{status, diagnostics} = compile()
18-
Server.build_finished(parent, {status, mixfile_diagnostics ++ diagnostics})
19-
20-
{:error, mixfile_diagnostics} ->
21-
Server.build_finished(parent, {:error, mixfile_diagnostics})
22-
end
23-
end)
24-
25-
JsonRpc.log_message(:info, "Compile took #{div(us, 1000)} milliseconds")
11+
with_build_lock(fn ->
12+
{us, _} =
13+
:timer.tc(fn ->
14+
IO.puts("Compiling with Mix env #{Mix.env()}")
15+
16+
case reload_project() do
17+
{:ok, mixfile_diagnostics} ->
18+
{status, diagnostics} = compile()
19+
Server.build_finished(parent, {status, mixfile_diagnostics ++ diagnostics})
20+
21+
{:error, mixfile_diagnostics} ->
22+
Server.build_finished(parent, {:error, mixfile_diagnostics})
23+
end
24+
end)
25+
26+
JsonRpc.log_message(:info, "Compile took #{div(us, 1000)} milliseconds")
27+
end)
2628
end)
2729
end
2830
end
@@ -93,6 +95,10 @@ defmodule ElixirLS.LanguageServer.Build do
9395
}
9496
end
9597

98+
def with_build_lock(func) do
99+
:global.trans({__MODULE__, self()}, func)
100+
end
101+
96102
defp reload_project do
97103
mixfile = Path.absname(System.get_env("MIX_EXS") || "mix.exs")
98104

apps/language_server/lib/language_server/providers/references.ex

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ defmodule ElixirLS.LanguageServer.Providers.References do
55
any function or module identified at the provided location.
66
"""
77

8-
alias ElixirLS.LanguageServer.SourceFile
8+
alias ElixirLS.LanguageServer.{SourceFile, Build}
99
alias ElixirSense.Core.{Metadata, Parser, Source, Introspection}
1010

1111
def references(text, line, character, _include_declaration) do
12-
xref_at_cursor(text, line, character)
13-
|> Enum.filter(fn %{line: line} -> is_integer(line) end)
14-
|> Enum.map(&build_location/1)
12+
Build.with_build_lock(fn ->
13+
xref_at_cursor(text, line, character)
14+
|> Enum.filter(fn %{line: line} -> is_integer(line) end)
15+
|> Enum.map(&build_location/1)
16+
end)
1517
end
1618

1719
def supported? do
@@ -48,19 +50,39 @@ defmodule ElixirLS.LanguageServer.Providers.References do
4850
defp add_arity({mod, fun}, %{scope: {fun, arity}, module: mod}), do: {mod, fun, arity}
4951
defp add_arity({mod, fun}, _env), do: {mod, fun, nil}
5052

51-
def callers(nil), do: []
52-
def callers(mfa), do: Mix.Tasks.Xref.calls() |> Enum.filter(caller_filter(mfa))
53+
defp callers(mfa) do
54+
if Mix.Project.umbrella?() do
55+
umbrella_calls()
56+
else
57+
Mix.Tasks.Xref.calls()
58+
end
59+
|> Enum.filter(caller_filter(mfa))
60+
end
61+
62+
def umbrella_calls() do
63+
build_dir = Path.expand(Mix.Project.config()[:build_path])
64+
65+
Mix.Project.apps_paths()
66+
|> Enum.flat_map(fn {app, path} ->
67+
Mix.Project.in_project(app, path, [build_path: build_dir], fn _ ->
68+
Mix.Tasks.Xref.calls()
69+
|> Enum.map(fn %{file: file} = call ->
70+
Map.put(call, :file, Path.expand(file))
71+
end)
72+
end)
73+
end)
74+
end
5375

5476
defp caller_filter({module, nil, nil}), do: &match?(%{callee: {^module, _, _}}, &1)
5577
defp caller_filter({module, func, nil}), do: &match?(%{callee: {^module, ^func, _}}, &1)
5678
defp caller_filter({module, func, arity}), do: &match?(%{callee: {^module, ^func, ^arity}}, &1)
5779

58-
defp build_location(call) do
80+
defp build_location(%{file: file, line: line}) do
5981
%{
60-
"uri" => SourceFile.path_to_uri(call.file),
82+
"uri" => SourceFile.path_to_uri(file),
6183
"range" => %{
62-
"start" => %{"line" => call.line - 1, "character" => 0},
63-
"end" => %{"line" => call.line - 1, "character" => 0}
84+
"start" => %{"line" => line - 1, "character" => 0},
85+
"end" => %{"line" => line - 1, "character" => 0}
6486
}
6587
}
6688
end

apps/language_server/lib/language_server/server.ex

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,13 @@ defmodule ElixirLS.LanguageServer.Server do
339339

340340
defp handle_request(references_req(_id, uri, line, character, include_declaration), state) do
341341
fun = fn ->
342-
{
343-
:ok,
344-
References.references(state.source_files[uri].text, line, character, include_declaration)
345-
}
342+
{:ok,
343+
References.references(
344+
state.source_files[uri].text,
345+
line,
346+
character,
347+
include_declaration
348+
)}
346349
end
347350

348351
{:async, fun, state}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule A do
2+
def fun do
3+
B.fun()
4+
end
5+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule B do
2+
def fun do
3+
:ok
4+
end
5+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule References.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[app: :references, version: "0.1.0"]
6+
end
7+
8+
def application do
9+
[]
10+
end
11+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule App1 do
2+
def hello() do
3+
App2.hello()
4+
end
5+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
defmodule App1.Mixfile do
2+
use Mix.Project
3+
4+
def project do
5+
[app: :app1, version: "0.1.0", deps: deps()]
6+
end
7+
8+
def application do
9+
[]
10+
end
11+
12+
defp deps do
13+
[{:app2, in_umbrella: true}]
14+
end
15+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
defmodule App2 do
2+
def hello do
3+
:app2
4+
end
5+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule App2.Mixfile do
2+
use Mix.Project
3+
4+
def project do
5+
[app: :app2, version: "0.1.0"]
6+
end
7+
8+
def application do
9+
[]
10+
end
11+
end

0 commit comments

Comments
 (0)