我想在 vim 上保存时运行 gofmt 而不安装任何插件。这是我尝试过的(灵感来自https://gist.github.com/tbrisbout/a91ac3419440cde40c5f54dc32c94427):
function! GoFmt()
let file = expand('%')
silent execute "!gofmt -w " . file
edit!
endfunction
command! GoFmt call GoFmt()
augroup go_autocmd
autocmd BufWritePost *.go GoFmt
augroup END
Run Code Online (Sandbox Code Playgroud)
这仅在没有格式错误时有效。但是,如果代码包含错误,它会在屏幕底部显示错误消息,并且(看起来)它以文本形式出现在缓冲区上,因此整个代码都会被破坏。有没有一种简单的方法可以在 vim 上处理此类工作?
Gofmt 既是代码格式化程序又是linter,这一设计决策使其与 Vim 集成变得更加困难。在实践中,这意味着事情可以朝三种方向发展:
\n例如,我们可以天真地尝试通过以下方式使用gofmtfor和friendsgq:help \'formatprg\' but the chances of eventually overwritting our code with crap like:
<standard input>:4:2: expected statement, found \'.\'\n<standard input>:5:3: expected \'}\', found \'EOF\'\nRun Code Online (Sandbox Code Playgroud)\n太高了。就像您的情况一样,我们可以u撤消,但这并不有趣。我想我们将不得不解决gofmt糟糕的设计。
第一步:切换到:help BufWritePre. 我们已经看到gofmtcan handler stdin,它允许我们格式化缓冲区和文件。这很方便,因为在写入文件后对其进行格式化会无缘无故地再次写入该文件,并迫使我们将其重新加载到 Vim\xe2\x80\xa6 中,而所有这些似乎都是浪费。:help BufWritePost最好保留那些不影响 Vim 状态的东西。
function! GoFmt()\n echomsg "hello"\nendfunction\n\ncommand! GoFmt call GoFmt()\n\naugroup go_autocmd\n autocmd BufWritePre *.go GoFmt\naugroup END\nRun Code Online (Sandbox Code Playgroud)\n第二步:过滤整个缓冲区gofmt。
function! GoFmt()\n silent %!gofmt\nendfunction\nRun Code Online (Sandbox Code Playgroud)\nThird step: "handle" the worst case scenario with a basic undo. If the external command returns an error, we can get it via :help v:shell_error and do what needs to be done.
function! GoFmt()\n silent %!gofmt\n if v:shell_error > 0\n silent undo\n endif\nendfunction\nRun Code Online (Sandbox Code Playgroud)\nFourth step: try to keep the cursor in place.
\nfunction! GoFmt()\n let saved_view = winsaveview()\n silent %!gofmt\n if v:shell_error > 0\n silent undo\n endif\n call winrestview(saved_view)\nendfunction\nRun Code Online (Sandbox Code Playgroud)\nSee :help winsaveview() and :help winrestview().
Fifth step: if applicable, create a quickfix list with the errors reported by gofmt. :help getline() gives us all the lines of the buffer\xe2\x80\x94therefore all the errors\xe2\x80\x94in a list of which we modify each item so that the file name is the current file name instead of the useless <standard input>. We give that list to :help :cexpr to create a quickfix list before undoing the filter.
function! GoFmt()\n let saved_view = winsaveview()\n silent %!gofmt\n if v:shell_error > 0\n cexpr getline(1, \'$\')->map({ idx, val -> val->substitute(\'<standard input>\', expand(\'%\'), \'\') })\n silent undo\n endif\n call winrestview(saved_view)\nendfunction\nRun Code Online (Sandbox Code Playgroud)\nThis step has a bit of a "draw the rest of the * howl" vibe but it really is just a simple :help substitute() in a simple :help map(). For the { foo, bar -> baz } syntax, see :help lambda.
Sixth and last step: open the quickfix window if there are any valid errors, with :help :cwindow.
function! GoFmt()\n let saved_view = winsaveview()\n silent %!gofmt\n if v:shell_error > 0\n cexpr getline(1, \'$\')->map({ idx, val -> val->substitute(\'<standard input>\', expand(\'%\'), \'\') })\n silent undo\n cwindow\n endif\n call winrestview(saved_view)\nendfunction\nRun Code Online (Sandbox Code Playgroud)\n\n