Skip to content

Commit 128c131

Browse files
committed
fix(nix_flake_fmt): handle flakes with a formatter package
nixpkgs [recently add a `nix fmt` entrypoint](NixOS/nixpkgs@374e6bc), and I was excited to be able to use `nix_flake_fmt` in the project. I was disappointed to find that it doesn't actually work in nixpkgs, though :( The problem boils down to how `nix eval .#formatter` behaves if your flake defines a `formatter` package. See: ```console $ nix eval nixpkgs#formatter «derivation /nix/store/nadgq8kci2an9d3ddz1lk662gl53d8yz-formatter-0.4.0.drv» ``` This is *not* the `nix fmt` entrypoint, it's a [completely unrelated package](NixOS/nixpkgs@b99357e). Here's the `nix fmt` entrypoint: ```console $ nix repl nixpkgs nix-repl> formatter.x86_64-linux «derivation /nix/store/rza8g2jxr1h7nd58qq3ryfz2zdqnggga-treefmt.drv» ``` This simple `nix repl` session is quite challenging to port to `nix eval`, though. After quite a bit of futzing around, I found that I could accomplish this with a combination of `nix flake metadata` and `builtins.getFlake`: ``` $ nix flake metadata nixpkgs --json | jq .resolvedUrl "github:NixOS/nixpkgs/nixpkgs-unstable" $ nix eval --expr "(builtins.getFlake "github:NixOS/nixpkgs/nixpkgs-unstable").formatter.x86_64-linux" --impure «derivation /nix/store/rza8g2jxr1h7nd58qq3ryfz2zdqnggga-treefmt.drv» ```
1 parent 4f76cb4 commit 128c131

File tree

1 file changed

+56
-16
lines changed

1 file changed

+56
-16
lines changed

lua/null-ls/builtins/formatting/nix_flake_fmt.lua

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,52 @@ local find_nix_fmt = function(opts, done)
6565
return nix_current_system
6666
end
6767

68+
local get_flake_ref = function(root)
69+
local status, stdout_lines, stderr_lines = run_job({
70+
command = "nix",
71+
args = {
72+
"--extra-experimental-features",
73+
"nix-command flakes",
74+
"flake",
75+
"metadata",
76+
"--json",
77+
root,
78+
},
79+
})
80+
81+
if status ~= 0 then
82+
local stderr = table.concat(stderr_lines, "\n")
83+
vim.defer_fn(function()
84+
log:warn(string.format("unable to get flake ref for '%s'. stderr: %s", root, stderr))
85+
end, 0)
86+
return
87+
end
88+
89+
local stdout = table.concat(stdout_lines, "\n")
90+
local metadata = vim.json.decode(stdout)
91+
local flake_ref = metadata.resolvedUrl
92+
if flake_ref == nil then
93+
vim.defer_fn(function()
94+
log:warn(
95+
string.format("flake metadata does not have a 'resolvedUrl'. metadata: %s", vim.inspect(metadata))
96+
)
97+
end, 0)
98+
return
99+
end
100+
101+
return flake_ref
102+
end
103+
68104
local evaluate_flake_formatter = function(root)
69105
local nix_current_system = get_current_system()
70106
if nix_current_system == nil then
71107
return
72108
end
73-
109+
local flake_ref = get_flake_ref(root)
74110
local eval_nix_formatter = [[
75111
let
76112
system = "]] .. nix_current_system .. [[";
113+
flake = builtins.getFlake "]] .. flake_ref .. [[";
77114
# Various functions vendored from nixpkgs lib (to avoid adding a
78115
# dependency on nixpkgs).
79116
lib = rec {
@@ -87,19 +124,21 @@ local find_nix_fmt = function(opts, done)
87124
# getExe is simplified to assume meta.mainProgram is specified.
88125
getExe = x: getExe' x x.meta.mainProgram;
89126
};
90-
in
91-
formatterBySystem:
92-
builtins.toJSON (
93-
if formatterBySystem ? ${system} then
94-
let
95-
formatter = formatterBySystem.${system};
96-
drv = formatter.drvPath;
97-
bin = lib.getExe formatter;
98-
in
99-
{ inherit drv bin; }
127+
result =
128+
if flake ? formatter then
129+
if flake.formatter ? ${system} then
130+
let
131+
formatter = flake.formatter.${system};
132+
drv = formatter.drvPath;
133+
bin = lib.getExe formatter;
134+
in
135+
{ inherit drv bin; }
136+
else
137+
{ error = "this flake does not define a formatter for system: ${system}"; }
100138
else
101-
{ error = "this flake does not define a formatter for system: ${system}"; }
102-
)
139+
{ error = "this flake does not define any formatters"; };
140+
in
141+
builtins.toJSON result
103142
]]
104143

105144
client.send_progress_notification(NOTIFICATION_TOKEN, {
@@ -114,12 +153,13 @@ local find_nix_fmt = function(opts, done)
114153
"--extra-experimental-features",
115154
"nix-command flakes",
116155
"eval",
117-
".#formatter",
118156
"--raw",
119-
"--apply",
157+
-- We need `--impure` to be able to call `builtins.getFlake`
158+
-- on an unlocked flake ref.
159+
"--impure",
160+
"--expr",
120161
eval_nix_formatter,
121162
},
122-
cwd = root,
123163
})
124164

125165
if status ~= 0 then

0 commit comments

Comments
 (0)