Skip to content

Commit 0fee808

Browse files
committed
Use helper for dot formatter
1 parent 024e56c commit 0fee808

File tree

6 files changed

+65
-17
lines changed

6 files changed

+65
-17
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
### Unreleased
2+
- Added option `elixirLS.dotFormatter` to specify path to custom `.formatter.exs`
23

34
### v0.28.1: 24 May 2025
45

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ Below is a list of configuration options supported by the ElixirLS language serv
486486
<dt>elixirLS.additionalWatchedExtensions</dt><dd>Additional file types capable of triggering a build on change</dd>
487487
<dt>elixirLS.languageServerOverridePath</dt><dd>Absolute path to an alternative ElixirLS release that will override the packaged release</dd>
488488
<dt>elixirLS.stdlibSrcDir</dt><dd>Path to Elixir's std lib source code. See [here](https://github.com/elixir-lsp/elixir_sense/pull/277) for more info</dd>
489+
<dt>elixirLS.dotFormatter</dt><dd>Path to a custom <code>.formatter.exs</code> file used when formatting documents</dd>
489490
</dl>
490491

491492
## Debug Adapter configuration options

apps/language_server/lib/language_server/providers/formatting.ex

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@ defmodule ElixirLS.LanguageServer.Providers.Formatting do
44
import ElixirLS.LanguageServer.RangeUtils
55
require Logger
66

7-
def format(%SourceFile{} = source_file, uri = "file:" <> _, project_dir, mix_project?)
7+
def format(
8+
%SourceFile{} = source_file,
9+
uri = "file:" <> _,
10+
project_dir,
11+
mix_project?,
12+
opts \\ []
13+
)
814
when is_binary(project_dir) do
915
file_path = SourceFile.Path.absolute_from_uri(uri, project_dir)
1016
# file_path and project_dir are absolute paths with universal separators
1117
if SourceFile.Path.path_in_dir?(file_path, project_dir) do
1218
# file in project_dir we find formatter and options for file
13-
case SourceFile.formatter_for(uri, project_dir, mix_project?) do
14-
{:ok, {formatter, opts}} ->
15-
formatter_exs_dir = opts[:root]
19+
case SourceFile.formatter_for(uri, project_dir, mix_project?, opts) do
20+
{:ok, {formatter, formatter_opts}} ->
21+
formatter_exs_dir = formatter_opts[:root]
1622

17-
if should_format?(uri, formatter_exs_dir, opts[:inputs], project_dir) do
18-
do_format(source_file, formatter, opts)
23+
if should_format?(uri, formatter_exs_dir, formatter_opts[:inputs], project_dir) do
24+
do_format(source_file, formatter, formatter_opts)
1925
else
2026
JsonRpc.show_message(
2127
:info,
@@ -48,7 +54,7 @@ defmodule ElixirLS.LanguageServer.Providers.Formatting do
4854
end
4955

5056
# if project_dir is not set or schema is not file we format with default options
51-
def format(%SourceFile{} = source_file, _uri, _project_dir, _mix_project?) do
57+
def format(%SourceFile{} = source_file, _uri, _project_dir, _mix_project?, _opts \\ []) do
5258
do_format(source_file, nil, [])
5359
end
5460

apps/language_server/lib/language_server/server.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,14 @@ defmodule ElixirLS.LanguageServer.Server do
15351535
state = %__MODULE__{}
15361536
) do
15371537
source_file = get_source_file(state, uri)
1538-
fun = fn -> Formatting.format(source_file, uri, state.project_dir, state.mix_project?) end
1538+
dot_formatter = Map.get(state.settings || %{}, "dotFormatter")
1539+
1540+
fun = fn ->
1541+
Formatting.format(source_file, uri, state.project_dir, state.mix_project?,
1542+
dot_formatter: dot_formatter
1543+
)
1544+
end
1545+
15391546
{:async, fun, state}
15401547
end
15411548

apps/language_server/lib/language_server/source_file.ex

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,10 @@ defmodule ElixirLS.LanguageServer.SourceFile do
235235
"""
236236
end
237237

238-
@spec formatter_for(String.t(), String.t() | nil, boolean) ::
238+
@spec formatter_for(String.t(), String.t() | nil, boolean, keyword()) ::
239239
{:ok, {function | nil, keyword()}} | {:error, any}
240-
def formatter_for(uri = "file:" <> _, project_dir, mix_project?) when is_binary(project_dir) do
240+
def formatter_for(uri = "file:" <> _, project_dir, mix_project?, opts \\ [])
241+
when is_binary(project_dir) do
241242
path = __MODULE__.Path.from_uri(uri)
242243

243244
try do
@@ -250,7 +251,7 @@ defmodule ElixirLS.LanguageServer.SourceFile do
250251
{:ok, config_mtime} = MixProjectCache.config_mtime()
251252
{:ok, mix_project} = MixProjectCache.get()
252253

253-
opts = [
254+
formatter_opts = [
254255
deps_paths: deps_paths,
255256
manifest_path: manifest_path,
256257
config_mtime: config_mtime,
@@ -286,16 +287,20 @@ defmodule ElixirLS.LanguageServer.SourceFile do
286287
end
287288
]
288289

289-
{:ok, Mix.Tasks.ElixirLSFormat.formatter_for_file(path, opts)}
290+
formatter_opts =
291+
formatter_opts
292+
|> maybe_put_dot_formatter(opts)
293+
294+
{:ok, Mix.Tasks.ElixirLSFormat.formatter_for_file(path, formatter_opts)}
290295
else
291296
{:error, :project_not_loaded}
292297
end
293298
else
294-
opts = [
295-
root: project_dir
296-
]
299+
formatter_opts =
300+
[root: project_dir]
301+
|> maybe_put_dot_formatter(opts)
297302

298-
{:ok, Mix.Tasks.ElixirLSFormat.formatter_for_file(path, opts)}
303+
{:ok, Mix.Tasks.ElixirLSFormat.formatter_for_file(path, formatter_opts)}
299304
end
300305
catch
301306
kind, payload ->
@@ -322,7 +327,15 @@ defmodule ElixirLS.LanguageServer.SourceFile do
322327
end
323328
end
324329

325-
def formatter_for(_, _, _), do: {:error, :project_dir_not_set}
330+
def formatter_for(_, _, _, _), do: {:error, :project_dir_not_set}
331+
332+
defp maybe_put_dot_formatter(opts_list, opts) do
333+
if dot = Keyword.get(opts, :dot_formatter) do
334+
Keyword.put(opts_list, :dot_formatter, dot)
335+
else
336+
opts_list
337+
end
338+
end
326339

327340
defp format_code(code, opts) do
328341
try do

apps/language_server/test/providers/formatting_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,4 +503,24 @@ defmodule ElixirLS.LanguageServer.Providers.FormattingTest do
503503

504504
MixProjectCache.store(state)
505505
end
506+
507+
@tag :fixture
508+
test "custom dot formatter path is used" do
509+
in_fixture(Path.join(__DIR__, ".."), "formatter", fn ->
510+
store_mix_cache()
511+
project_dir = Path.expand(".")
512+
path = Path.join(project_dir, "lib/custom.ex")
513+
File.write!(path, "foo 1")
514+
source_file = %SourceFile{text: "foo 1", version: 1, dirty?: true}
515+
uri = SourceFile.Path.to_uri(path)
516+
517+
assert {:ok, [%TextEdit{}, %TextEdit{}]} =
518+
Formatting.format(source_file, uri, project_dir, true)
519+
520+
assert {:ok, []} =
521+
Formatting.format(source_file, uri, project_dir, true,
522+
dot_formatter: Path.join(project_dir, "lib/.formatter.exs")
523+
)
524+
end)
525+
end
506526
end

0 commit comments

Comments
 (0)