Skip to content

Commit fc90e3c

Browse files
Allow to restrict looking for the mix.exs in the current workspace root only, closes #424 (#425)
Co-authored-by: Łukasz Samson <[email protected]>
1 parent 91a0602 commit fc90e3c

File tree

14 files changed

+186
-3
lines changed

14 files changed

+186
-3
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
### Unreleased
22

3+
#### Improvements
4+
5+
- It is possible to restrict `mix.exs` search (projectDir) to the current root folder only, so in multi-root workspace configurations ElixirLS won't start in the outermost containing the `mix.exs` folder
6+
37
### v0.22.1: 10 July 2024
48

59
#### Improvements

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ If you run into issues with the extension, try these debugging steps:
9191
- After stopping your editor, remove the entire `.elixir_ls` directory, then restart your editor.
9292
- NOTE: This will cause you to have to re-run the entire dialyzer build
9393

94-
You may need to set `elixirLS.mixEnv`, `elixirLS.mixTarget`, and `elixirLS.projectDir` if your project requires it. By default, ElixirLS compiles code with `MIX_ENV=test`, `MIX_TARGET=host`, and assumes that `mix.exs` is located in the workspace root directory.
94+
You may need to set `elixirLS.mixEnv`, `elixirLS.mixTarget`, `elixirLS.projectDir` and/or `elixirLS.useCurrentRootFolderAsProjectDir` if your project requires it. By default, ElixirLS compiles code with `MIX_ENV=test`, `MIX_TARGET=host`, and assumes that `mix.exs` is located in the workspace root directory.
9595

9696
If you get an error like the following immediately on startup:
9797

package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@
165165
"minLength": 0,
166166
"default": ""
167167
},
168+
"elixirLS.useCurrentRootFolderAsProjectDir": {
169+
"scope": "resource",
170+
"type": "boolean",
171+
"description": "Don't try to look for mix.exs in parent directories",
172+
"default": false
173+
},
168174
"elixirLS.fetchDeps": {
169175
"scope": "resource",
170176
"type": "boolean",
@@ -682,4 +688,4 @@
682688
"@vscode/extension-telemetry": "^0.9.0",
683689
"vscode-languageclient": "^9.0.0"
684690
}
685-
}
691+
}

src/project.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,16 @@ export class WorkspaceTracker {
5858
uri = uri + "/";
5959
}
6060

61+
const useCurrentRootFolderAsProjectDir = vscode.workspace
62+
.getConfiguration("elixirLS", folder)
63+
.get<boolean>("useCurrentRootFolderAsProjectDir");
64+
65+
6166
let outermostFolder: vscode.WorkspaceFolder | null = null;
6267

63-
for (const element of this.sortedWorkspaceFolders()) {
68+
const sortedWorkspaceFolders = useCurrentRootFolderAsProjectDir ? [uri] : this.sortedWorkspaceFolders();
69+
70+
for (const element of sortedWorkspaceFolders) {
6471
if (uri.startsWith(element)) {
6572
const foundFolder = vscode.workspace.getWorkspaceFolder(
6673
vscode.Uri.parse(element)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
defmodule SingleFolderMix.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :containing_folder_with_mix,
7+
version: "0.1.0",
8+
elixir: "~> 1.14",
9+
start_permanent: Mix.env() == :prod,
10+
deps: deps()
11+
]
12+
end
13+
14+
# Run "mix help compile.app" to learn about applications.
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
# Run "mix help deps" to learn about dependencies.
22+
defp deps do
23+
[
24+
# {:dep_from_hexpm, "~> 0.3.0"},
25+
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
26+
]
27+
end
28+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Ignore package tarball (built via "mix hex.build").
23+
single_folder_mix-*.tar
24+
25+
# Temporary files, for example, from tests.
26+
/tmp/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SingleFolderMix
2+
3+
**TODO: Add description**
4+
5+
## Installation
6+
7+
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
8+
by adding `single_folder_mix` to your list of dependencies in `mix.exs`:
9+
10+
```elixir
11+
def deps do
12+
[
13+
{:single_folder_mix, "~> 0.1.0"}
14+
]
15+
end
16+
```
17+
18+
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
19+
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
20+
be found at <https://hexdocs.pm/single_folder_mix>.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
defmodule SingleFolderMix do
2+
@moduledoc """
3+
Documentation for `SingleFolderMix`.
4+
"""
5+
6+
@doc """
7+
Hello world.
8+
9+
## Examples
10+
11+
iex> SingleFolderMix.hello()
12+
:world
13+
14+
"""
15+
def hello do
16+
:world
17+
end
18+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
defmodule SingleFolderMix.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :single_folder_mix,
7+
version: "0.1.0",
8+
elixir: "~> 1.14",
9+
start_permanent: Mix.env() == :prod,
10+
deps: deps()
11+
]
12+
end
13+
14+
# Run "mix help compile.app" to learn about applications.
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
# Run "mix help deps" to learn about dependencies.
22+
defp deps do
23+
[
24+
# {:dep_from_hexpm, "~> 0.3.0"},
25+
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
26+
]
27+
end
28+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
defmodule SingleFolderMixTest do
2+
use ExUnit.Case
3+
doctest SingleFolderMix
4+
5+
test "greets the world" do
6+
assert SingleFolderMix.hello() == :world
7+
end
8+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ExUnit.start()

src/test/multiRoot/extension.test.ts

+32
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,36 @@ suite("Multi root workspace tests", () => {
227227
)
228228
);
229229
}).timeout(30000);
230+
231+
test("extension starts first client on the same folder with mix.exs if useCurrentRootFolderAsProjectDir is true", async () => {
232+
vscode.workspace.getConfiguration("elixirLS").update("useCurrentRootFolderAsProjectDir", true, vscode.ConfigurationTarget.WorkspaceFolder);
233+
234+
const fileUri = vscode.Uri.file(
235+
path.join(
236+
fixturesPath,
237+
"containing_folder",
238+
"single_folder_mix",
239+
"mix.exs"
240+
)
241+
);
242+
243+
const workspaceFolderUri = vscode.Uri.file(
244+
path.join(fixturesPath, "containing_folder", "single_folder_mix")
245+
);
246+
247+
await waitForLanguageClientManagerUpdate(extension, async () => {
248+
const document = await vscode.workspace.openTextDocument(fileUri);
249+
await vscode.window.showTextDocument(document);
250+
});
251+
252+
assert.ok(!extension.exports.languageClientManager.defaultClient);
253+
assert.equal(extension.exports.languageClientManager.clients.size, 3);
254+
255+
assert.equal(
256+
extension.exports.languageClientManager.getClientByUri(fileUri),
257+
extension.exports.languageClientManager.clients.get(
258+
workspaceFolderUri.toString()
259+
)
260+
);
261+
}).timeout(30000);
230262
});

telemetry.json

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
},
136136
"lsp_config": {
137137
"elixir_ls.projectDir": {"classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Is project dir overriden"},
138+
"elixir_ls.useCurrentRootFolderAsProjectDir": {"classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Is project dir set to the current root in multi-root workspace"},
138139
"elixir_ls.autoBuild": {"classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Is auto build enabled"},
139140
"elixir_ls.dialyzerEnabled": {"classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Is dialyzer enabled"},
140141
"elixir_ls.fetchDeps": {"classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Is auto fetching of dependencies enabled"},

0 commit comments

Comments
 (0)