Skip to content

fix(nix_flake_fmt): handle flakes with a formatter package #272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 27, 2025

Conversation

jfly
Copy link
Collaborator

@jfly jfly commented Apr 23, 2025

This fixes a bug with nix_flake_fmt where it doesn't handle flakes with a "formatter" package. I also did some refactoring in separate commits keep things clean. I suggest reading the commits independently.

  • refactor(fix nix_flake_fmt): split find_nix_fmt into smaller functions
  • refactor(nix_flake_fmt): pass data as JSON rather than ad-hoc lines
  • fix(nix_flake_fmt): handle flakes with a formatter package

IMO, this plugin has too much nix specific knowledge in it. I've submitted NixOS/nix#13063 to core nix to add a nix fmt --print-command option. That would allow us to delete a lot of code in this PR.

jfly added 2 commits April 22, 2025 17:12
This should make things a bit more readable without changing the behavior.
This makes the communication between our lua code and the `nix eval`
subprocess a bit clearer.
@jfly jfly force-pushed the fix-nix-flake-fmt branch from bec4823 to 5727f0b Compare April 23, 2025 00:12
jfly added a commit to jfly/nix that referenced this pull request Apr 23, 2025
I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With this extra option for `nix fmt`, I'd get to delete all this akward
code, and it would be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 23, 2025
For example, here's what this does in `nixpkgs`:

    $ nix fmt --print-command
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Motivation
==========

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With this extra option for `nix fmt`, I'd get to delete all this akward
code, and it would be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 23, 2025
For example, here's what this does in `nixpkgs`:

    $ nix fmt --print-command
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With this extra option for `nix fmt`, I'd get to delete all this akward
code, and it would be easier for other folks to build performant editor
integrations for `nix fmt`.
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»
```
@jfly jfly force-pushed the fix-nix-flake-fmt branch from 5727f0b to 128c131 Compare April 23, 2025 17:09
jfly and others added 2 commits April 23, 2025 10:20
…ation

There were 2 bugs here:

- In the `drv_path == nil` path, we'd abort execution without returning
  a result by calling `done(...)`.
- In that codepath and another, we'd return a `nil` result without
  clearing the progress notification.
  There might be bugs here if we are running multiple formats in
  parallel. I think that's OK to address in the future if it proves to
  be a problem.
jfly added a commit to jfly/nix that referenced this pull request Apr 23, 2025
`nix formatter run` is an alias for `nix fmt`. Nothing new there.

`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 23, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 23, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 24, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 24, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 24, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 24, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
@barrett-ruth
Copy link
Collaborator

NGL, feel like this should go into extras if it 300 LOC for a formatter.
image

@jfly
Copy link
Collaborator Author

jfly commented Apr 27, 2025

That's fair, @barrett-ruth. I am hopeful that nix will accept my PR, which will allow us to delete a lot of code here. I don't think this builtin has a lot of users (yet ;)), so I could see doing any of the following (in no particular order):

  1. Wait for my PR to nix to land.
  2. Merge this more or less as is, knowing that we'll get to delete a lot of code once my PR lands.
  3. Put this in none-ls-extras.

My preference would be 2: I joined the nix team meeting this week, and it seemed likely they'll accept my PR. But I'm happy to tackle this however you prefer!

@barrett-ruth
Copy link
Collaborator

Super cool that you joined there. I'll merge this for now. Please delete the code once merged!

@barrett-ruth barrett-ruth merged commit 04213ab into nvimtools:main Apr 27, 2025
3 checks passed
@jfly jfly deleted the fix-nix-flake-fmt branch April 27, 2025 21:30
@jfly
Copy link
Collaborator Author

jfly commented Apr 27, 2025

Thanks, @barrett-ruth!

jfly added a commit to jfly/nix that referenced this pull request Apr 30, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
jfly added a commit to jfly/nix that referenced this pull request Apr 30, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
Mic92 pushed a commit to Mic92/nix-1 that referenced this pull request Apr 30, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
Mic92 pushed a commit to Mic92/nix-1 that referenced this pull request Apr 30, 2025
`nix formatter build` is sort of like `nix build`: it builds, links, and
prints a path to the formatter program:

    $ nix formatter build
    /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt

Note that unlike `nix build`, this prints the full path to the program,
not just the store path (in the example above that would be
`/nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt`).

Motivation
----------

I maintain a vim plugin that automatically runs `nix fmt` on files on
save. Since `nix fmt` can be quite slow due to nix evaluation, I choose
to cache the `nix fmt `entrypoint. This was very awkward to do, see the
implementation for details:
https://github.com/nvimtools/none-ls.nvim/blob/786460723170bda9e9f95c55a382d21436575297/lua/null-ls/builtins/formatting/nix_flake_fmt.lua#L83-L110.

I recently discovered that my implementation was buggy (it didn't handle
flakes that expose a `formatter` package, such as nixpkgs), so I had to
rework the implementation:
nvimtools/none-ls.nvim#272.

With the new `nix formatter build` command, I can delete all this akward
code, and it will be easier for other folks to build performant editor
integrations for `nix fmt`.
@jfly
Copy link
Collaborator Author

jfly commented May 1, 2025

@barrett-ruth, my PR landed! I've reworked things over in #279

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants