Open Integralist opened 3 months ago
I've got exactly the same problem using lazyvim. The code is only formatted by goimports. That means that my imports are not split the way I like (with gofumpt) and what you mention, about the octal form, isn't set.
I really don't know if the problem isn't LSP or if conform.nvim isn't working correctly. But this is a big problem. Each time I fix something in a file, I need to quit neovim to force gofumpt
and push the code. Each time I save the file, the format is not OK for the project.
I search for days how to fix this.
I actually found a "workaround", but that "breaks lazyvim" (an alert appears).
If I do:
{
"stevearc/conform.nvim",
config = function(_, opts)
require("conform").setup({
go = { "gofumpt" },
})
end,
},
So, now, only gofumpt is used.
But, as I mentioned, do not do this as it break LazyVim to format others source files
Well, I think I've found a good "workaround" even if I'm not entirely satisfied with the way it works.
For no apparent reason, the conform
plugin won't use gofumpt
, no matter what list of formatters you give it. And what's worse, gopls
uses gofumpt
and gets the job done.
So, to let gopls
do the job that conform
doesn't do (this isn't a criticism, I love the plugin, but it doesn't work well for Go
) is to remove the go
formatter altogether. That way, gopls
will do the job.
So, with LazyVim, I did this:
-- ~/.config/nvim/lua/plugins/go.lua
return {
{
"stevearc/conform.nvim",
opts = function(_, opts)
-- stop formating Go files, leave gopls to the job with gofumpt
opts.formatters_by_ft["go"] = {}
end,
}
}
On the other hand, OK, sorry, it works actually.gofumpt
doesn't tell me to change the mode to 0oXXX
(sonarlint does) - I don't know why it suggests this diff.
But as far as imports are concerned, it finally lists and formats them as I want.
In other words, your issue is completely valid: conform
doesn't use gofumpt
and I have no explanation.
I tried adding the following before conform.setup
...
conform.formatters.gofumpt = {
prepend_args = { "-w", vim.api.nvim_buf_get_name(0) },
}
...but it just errors...
Error detected while processing BufWritePre Autocommands for "*":
Formatter failed. See :ConformInfo for details
And if I check the log I see...
07:26:14[DEBUG] Running formatters on /Users/integralist/Code/example/cmd/epp/main.go: { "gofumpt", "goimports", "goimports-reviser" }
07:26:14[INFO] Run gofumpt on /Users/integralist/Code/example/cmd/epp/main.go
07:26:14[DEBUG] Run command: { "gofumpt", "-w", "" }
07:26:14[INFO] gofumpt exited with code 2
07:26:14[DEBUG] gofumpt stdout: { "" }
07:26:14[DEBUG] gofumpt stderr: { "stat : no such file or directory", "" }
So my approach for getting the file name failed. @metal3d do you know of a way to get the buffer name?
I then tried moving it to here where I knew I could get the buffer number...
format_on_save = function(bufnr)
-- disable with a global or buffer-local variable
if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then
return
end
conform.formatters.gofumpt = {
prepend_args = { "-w", vim.api.nvim_buf_get_name(bufnr) },
}
return { async = true, timeout_ms = 5000, lsp_fallback = true }
end
Which looks like it worked, but I still get the Error detected while processing BufWritePre Autocommands for "*":
error, and if I check the logs I see...
07:30:51[DEBUG] Running formatters on /Users/integralist/Code/example/cmd/epp/main.go: { "gofumpt", "goimports", "goimports-reviser" }
07:30:51[INFO] Run gofumpt on /Users/integralist/Code/example/cmd/epp/main.go
07:30:51[DEBUG] Run command: { "gofumpt", "-w", "/Users/integralist/Code/examplecmd/epp/main.go" }
07:30:51[DEBUG] gofumpt exited with code 0
07:30:51[INFO] Run goimports on /Users/integralist/Code/example/cmd/epp/main.go
07:30:51[DEBUG] Run command: { "goimports", "-srcdir", "/Users/integralist/Code/example/cmd/epp" }
07:30:51[DEBUG] goimports exited with code 0
07:30:51[INFO] Run goimports-reviser on /Users/integralist/Code/example/cmd/epp/main.go
07:30:51[DEBUG] Creating temp file /Users/integralist/Code/example/cmd/epp/.conform.3587335.main.go
07:30:51[DEBUG] Run command: { "goimports-reviser", "-format", "/Users/integralist/Code/example/cmd/epp/.conform.3587335.main.go" }
07:30:51[INFO] goimports-reviser exited with code 1
07:30:51[DEBUG] goimports-reviser stdout: nil
07:30:51[DEBUG] goimports-reviser stderr: { "2024/05/02 07:30:51 Failed to fix file: 1:2: expected 'package', found 'EOF'", "" }
07:30:51[DEBUG] Cleaning up temp file /Users/integralist/Code/example/cmd/epp/.conform.3587335.main.go
07:30:51[WARN] Aborting because a formatter returned empty output for buffer /Users/integralist/Code/domainr/mustang/cmd/epp/main.go
07:30:51[ERROR] Formatter 'goimports-reviser' error: 2024/05/02 07:30:51 Failed to fix file: 1:2: expected 'package', found 'EOF'
Looks like formatting with gofumpt like this and the use of goimports-reviser
are conflicting somehow?
I will investigate too.
That's probably the only problem that I have to fix among all the plugins that are activated in my NeoVim setup.
And because I'm developing a lot with Go, I really need to fix this behavior.
Unfortunately I'm not comfortable with Lua yet. After 20 years using Vim then NeoVim, I was using vim-plug and CoC until last week. CoC-Go plugin has no problem with gopls and gofumpt but I wonder if it actually doesn't only use gopls with the gofumpt option. And so, if the behavior is the same than deactivating "conform" like I did...
I decided to give LazyVim a chance, and I like it. Because "conform" is activated when we use the "Extras" setup for Go, I finally get this problem.
I need to train a bit on Lua (it's a very simple language) and to read the plugin source code.
Anyway, the plugin is very well.
This is what I have now in my "golang.lua" plugin in LazyVim:
return {
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "goimports-reviser" })
end,
},
{
"stevearc/conform.nvim",
opts = function(_, opts)
-- stop using conform for go, gopls sould do the job
opts.formatters_by_ft["go"] = { "goimports-reviser" }
end,
},
}
And I you mentionned, the FileMode is still "0775" instead of "0o775".
If I remove everything as opts.formatters_by_ft["go"] = { }
so gofumpt is OK with gopls.
So, there is a real problem and it's unclear where to fix this...
@Integralist it seems that I finally found how to make it work. The problem comes from gopls that fails using STDIN (see the description after the lua snippet):
return {
{
"williamboman/mason.nvim",
opts = function(_, opts)
opts.ensure_installed = opts.ensure_installed or {}
vim.list_extend(opts.ensure_installed, { "goimports-reviser" })
end,
},
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
go = { "goimports-reviser", "gofumpt" },
},
formatters = {
gofumpt = {
command = "gofumpt",
args = { "$FILENAME" },
},
},
},
},
}
You can avoid the mason part, this is for my LazyVim setup.
Actually, in the README file, there is an example to configure a formatter. Conform uses the standard output to read the result, so no need to set "-w".
But, Conform sends the content of the file to stdin. And the is the problem... take a look:
$ cat cmd/test/foo.go | gofumpt
package main
import (
"log"
"os"
)
func main() {
err := os.MkdirAll("example", 0775)
if err != nil {
log.Fatalf("Error creating directory: %s", err)
}
}
$ gofumpt cmd/test/foo.go
package main
import (
"log"
"os"
)
func main() {
err := os.MkdirAll("example", 0o775)
if err != nil {
log.Fatalf("Error creating directory: %s", err)
}
}
gofumpt fails with STDIN, so I set "$FILENAME" as input and that's OK. We can also set stdin
to false I guess.
See https://github.com/mvdan/gofumpt/issues/117#issuecomment-813349378 and https://github.com/mvdan/gofumpt/issues/277 maybe, there are several information.
But it only affects imports, not what we can see about modfiles.
Wow. Epic discovery. Thanks for your perseverance with this. Very appreciated 🙇♂️
😄 I found your issue because I had the same 😉
I'm as stubborn as a mule and I couldn't stay on a failure. The verbose mode guided me quite a bit, and I reproduced what "Conform" was doing to see the result. And that's when it hit me.
It was your example that really helped me, because my problem only concerned the import order and I thought I'd found the solution. But I realized that it went further than that. And the unformatted file.mod is a real proof of concept.
In any case, you've guided me a long way towards the solution, with your tests and your example. That's the strength of sharing with free software 😄
It's not completely OK...
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
go = { "gofumpt", "goimports-reviser" },
},
formatters = {
gofumpt = {
command = "gofumpt",
args = { "$FILENAME" },
},
},
},
},
Now, whatever the change I do, it's overwritten by one of the formatter...
OK... fixed, the stdin = false
option was missing. This works:
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
go = { "gofumpt", "goimports-reviser" },
},
formatters = {
gofumpt = {
command = "gofumpt",
args = { "$FILENAME" },
stdin = false,
},
},
},
},
So is the issue here that gofumpt
produces different formatting when run on stdin vs when run on a file? If so, could you open a PR to change the default configuration? Might help other users avoid the same issues.
@metal3d your solution didn't work for me 😞
Here we can see I have a test file that indicates the file wasn't formatted with gofumpt (we can see the octal issue too)...
Now here is my config...
I've copied the formatters { ... }
block that you had but when I edit the main.go file I have it doesn't get formatted.
If I check the debug log I see...
That's weird. I don't have the same log. It doesn't create temporary file on my side.
It works as expected as soon as I added the argument and set stdin to false.
I will make some others tests in a few hours.
So is the issue here that
gofumpt
produces different formatting when run on stdin vs when run on a file? If so, could you open a PR to change the default configuration? Might help other users avoid the same issues.
I will make a few more tests as @Integralist still has a problem. But, yes, I will make a pull request as soon as possible.
Thanks @metal3d I appreciate your efforts here ❤️
Just wondering if anyone had any further updates on this issue.
I know y'all are doing this off your own back, so of course I appreciate that it's likely no one has had any time to spare to investigate this further. So just to reiterate I'm not pushing for answers but am just interested if there are any updates that might help give me some ideas of what to try next. Thanks! 🙇🏻
If not then that's fine, I might just have to set up my own auto0command to apply gofumpt in the time being.
For anyone interested this is what I'm doing manually...
vim.api.nvim_create_autocmd({ "BufWritePost" }, {
group = vim.api.nvim_create_augroup("GoFumpt", { clear = true }),
pattern = "*.go",
command = "silent !gofumpt -w %"
})
I should add that the above workaround isn't ideal as it causes race conditions with conform's formatters from what I can tell.
Hello
I just stumbled upon this issue after trying getting stuck trying to make conform work with gofumpt
looking at the conform.log
the command is running just by itself (probably just doing a buffer pipe into the gofumpt command?)
19:32:30[DEBUG] Running formatters on /Users/whjc/dotfiles/main.go: { "gofumpt" }
19:32:30[INFO] Run gofumpt on /Users/whjc/dotfiles/main.go
19:32:30[DEBUG] Run command: { "gofumpt" }
19:32:30[DEBUG] Run default CWD: /Users/whjc/dotfiles
19:32:30[DEBUG] gofumpt exited with code 0
$ cat main.go | gofumpt
This just prints the main.go
file as is, which is why we're not seeing any changes to the file.
But then trying to add the file as arg, seemed to have worked (with the default args like stdin=true, etc)
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
go = { "gofumpt" },
},
formatters = {
gofumpt = {
args = { "$FILENAME" },
},
},
},
}
19:35:55[INFO] Run gofumpt on /Users/whjc/dotfiles/main.go
19:35:55[DEBUG] Run command: { "gofumpt", "/Users/whjc/dotfiles/main.go" }
19:35:55[DEBUG] Run default CWD: /Users/whjc/dotfiles
19:35:55[DEBUG] gofumpt exited with code 0
$ gofumpt main.go
# or
$ cat main.go | gofumpt main.go
both yield the same formatted stdout, as expected 🤷
not sure if this is the ideal, but it seems to be working so far
Actually this isn't enough, depending on how the file save events are setup, it will output the formatted value, overriding any file changes if any.
then it looks like gofumpt just isn't processing stdin pipes? not sure how to solve this issue only on conform
Neovim version (nvim -v)
0.9.5
Operating system/version
MacOS 14.4.1
Add the debug logs
log_level = vim.log.levels.DEBUG
and pasted the log contents below.Log file
Log file: /Users/integralist/.local/state/nvim/conform.log 07:38:12[INFO] Run gofumpt on /Users/integralist/Code/example/example-api/cmd/maxmind/main.go 07:38:12[DEBUG] Run command: { "gofumpt" } 07:38:12[DEBUG] gofumpt exited with code 0 07:38:12[INFO] Run goimports on /Users/integralist/Code/example/example-api/cmd/maxmind/main.go 07:38:12[DEBUG] Run command: { "goimports", "-srcdir", "/Users/integralist/Code/example/example-api/cmd/maxmind" } 07:38:12[DEBUG] goimports exited with code 0 07:38:12[INFO] Run goimports-reviser on /Users/integralist/Code/example/example-api/cmd/maxmind/main.go 07:38:12[DEBUG] Creating temp file /Users/integralist/Code/example/example-api/cmd/maxmind/.conform.4003455.main.go 07:38:12[DEBUG] Run command: { "goimports-reviser", "-format", "/Users/integralist/Code/example/example-api/cmd/maxmind/.conform.4003455.main.go" } 07:38:13[DEBUG] goimports-reviser exited with code 0 07:38:13[DEBUG] Cleaning up temp file /Users/integralist/Code/example/example-api/cmd/maxmind/.conform.4003455.main.go
Formatters for this buffer: LSP: gopls gofumpt ready (go) /Users/integralist/.local/share/nvim/mason/bin/gofumpt goimports ready (go) /Users/integralist/.local/share/nvim/mason/bin/goimports goimports-reviser ready (go) /Users/integralist/.local/share/nvim/mason/bin/goimports-reviser
Describe the bug
It looks like only
gofumpt
is being run when it should begofumpt -w <PATH>
.The
-w
writes the formatting changes back to disk, whilegofumpt
with no arguments defaults to displaying the whole file (with any potential changes included).What is the severity of this bug?
tolerable (can work around it)
Steps To Reproduce
Example change from gofumpt on my Go file (see below for example code)...
The
-d
flag shows the diff:Expected Behavior
When I write to my buffer, I expect the call to
gofumpt
to apply the formatting changes to my file.Minimal example file
Minimal init.lua
Additional context
Here is the log when using the repro.lua above