oxalica / nil

NIx Language server, an incremental analysis assistant for writing in Nix.
Apache License 2.0
1.4k stars 43 forks source link

`nix fmt` support #70

Open opeik opened 1 year ago

opeik commented 1 year ago

Hi there,

I'm using vscode-nix-ide which breaks if you ask nil to format with nix fmt. Instead of formatting the file, it clears it instead. This seems to be caused by nix fmt not accepting input from stdin.

On a side note, it would be cool if nil could use self.formatter."${system}" by default.

VSCode configuration ```json "nix.enableLanguageServer": true, "nix.serverPath": "nil", "nix.serverSettings": { "nil": { "formatting": { "command": ["nix", "fmt"] } } }, ```
App versions ``` ❯ nix --version nix (Nix) 2.11.1 ❯ nil --version nil 2022-10-03 release ❯ code --list-extensions --show-versions alefragnani.Bookmarks@13.3.1 eamodio.gitlens@13.3.2 esbenp.prettier-vscode@9.10.4 golang.go@0.38.0 GraphQL.vscode-graphql@0.8.6 GraphQL.vscode-graphql-syntax@1.1.0 Gruntfuggly.todo-tree@0.0.224 jnoortheen.nix-ide@0.2.1 marp-team.marp-vscode@2.5.0 monokai.theme-monokai-pro-vscode@1.2.0 ms-azuretools.vscode-docker@1.24.0 ms-python.python@2023.4.1 ms-python.vscode-pylance@2023.3.20 ms-vscode-remote.remote-ssh@0.98.0 ms-vscode-remote.remote-ssh-edit@0.84.0 ms-vscode.remote-explorer@0.2.0 ms-vsliveshare.vsliveshare@1.0.5834 quicktype.quicktype@12.0.46 redhat.vscode-yaml@1.12.1 rust-lang.rust-analyzer@0.3.1426 skellock.just@2.0.0 streetsidesoftware.code-spell-checker@2.19.0 tamasfe.even-better-toml@0.19.0 timonwong.shellcheck@0.29.4 usernamehw.errorlens@3.7.0 vadimcn.vscode-lldb@1.8.1 vscodevim.vim@1.25.2 ```
oxalica commented 1 year ago

This seems to be caused by nix fmt not accepting input from stdin.

nix fmt automatically add an argument . to the underlying formatter if there is none, which makes it format the whole directory instead of using stdio interface.

After some digging, I found that you setting formatting command to ["nix", "fmt", "--", "--"] work for me, as long as the underlying formatter supports stdio interface.

On a side note, it would be cool if nil could use self.formatter."${system}" by default.

I'm afraid not. nix fmt requires dumping the whole directory, evaluation and maybe building on every change. It would cause unacceptable delay/hanging with format-on-save.

My suggestion is to set fixed and responsive formatter for nil instead, and use nix fmt only in CI or pre-commit hooks.

figsoda commented 1 year ago

maybe nil can evaluate .#formatter.${system} once at startup and use that as a fallback to nil.formatting.command if it exists

oxalica commented 1 year ago

maybe nil can evaluate .#formatter.${system} once at startup and use that as a fallback to nil.formatting.command if it exists

formatter interface uses file IO by design, which is not compatible with ours. So we cannot do it in general. If only Nix Flakes can enforce the stdio interface by using, to say nix fmt -- -, then it can be guaranteed to work.

oxalica commented 1 year ago

XRef: https://github.com/NixOS/nix/pull/8063

nyabinary commented 3 months ago

This seems to be caused by nix fmt not accepting input from stdin.

nix fmt automatically add an argument . to the underlying formatter if there is none, which makes it format the whole directory instead of using stdio interface.

After some digging, I found that you setting formatting command to ["nix", "fmt", "--", "--"] work for me, as long as the underlying formatter supports stdio interface.

On a side note, it would be cool if nil could use self.formatter."${system}" by default.

I'm afraid not. nix fmt requires dumping the whole directory, evaluation and maybe building on every change. It would cause unacceptable delay/hanging with format-on-save.

My suggestion is to set fixed and responsive formatter for nil instead, and use nix fmt only in CI or pre-commit hooks.

["nix", "fmt", "--", "-"] also works :3

losnappas commented 2 months ago

nix fmt (with nix fmt -- - using nixfmt-rfc-style) is incredibly slow, any methods of speeding it up?

sellout commented 1 month ago

nix fmt (with nix fmt -- - using nixfmt-rfc-style) is incredibly slow, any methods of speeding it up?

My trick for speeding up nix fmt is to get an alias into my environment. E.g.,

devShells.${system}.default = pkgs.mkShell {
  shellHook = ''
    alias flake-fmt=${self.formatter.${system}.meta.mainProgram}
  '';
};

this avoids the need to evaluate the flake on each execution of the formatter and now I can set up flake-fmt to run-on-save in my editor and it’s very speedy.

Unfortunately, it doesn’t work quite as smoothly with direnv/use flake, but https://github.com/direnv/direnv/issues/73 has a lot of workarounds for getting aliases into the shell from direnv.

sellout commented 1 month ago

I’ve modified this a bit. My infra is a bit more involved, but it boils down to

devShells.${system}.default = pkgs.mkShell {
  shellHook = ''
    export PROJECT_FORMATTER=${lib.getExe self.formatter.${system}}
  '';
};

and then I have a script on the PATH that does roughly

"$PROJECT_FORMATTER" "$@"

And this now has no issues with using Direnv.