Vim-go: Poor compatiblity with coc.vim

Created on 19 May 2020  路  15Comments  路  Source: fatih/vim-go

This bug is fixed by #2887

What did you do? (required: The issue will be closed when not provided)

Have following .vimrc:

call plug#begin()

let g:go_imports_autosave = 1
Plug 'fatih/vim-go', { 'for': 'go', 'do': ':GoUpdateBinaries' }
Plug 'neoclide/coc.nvim', {'branch': 'release'}

call plug#end()

Following :CocConfig (in my case in ~/.vim/coc-settings.json):

{
  "coc.preferences.useQuickfixForLocations": true,
  "coc.preferences.snippets.enable": true,
  "coc.preferences.extensionUpdateCheck": "never",
  "suggest.disableMenu": true,
  "suggest.snippetIndicator": "",
  "diagnostic.level": "warning",
  "languageserver": {
    "golang": {
      "command": "gopls",
      "rootPatterns": ["go.mod", ".vim/", ".git/", ".hg/"],
      "filetypes": ["go"]
    }
  }
}

And following file:

package main

import (
    "os"
)

func main() {
    fmt.Println(os.Args)
}

Then I save this file, and it's "fmt" is correctly added, but I get an error on line func main() that says [compiler] [E] undeclared name: fmt

What did you expect to happen?

I expect that coc.vim processes file that is transformed with goimports

What happened instead?

It seems coc.vim processed file without imports added and marked errors on it, and only after this the contents of buffer were replaced leaving wrong errors in wrong places.

Configuration (MUST fill this out)

As above

vim-go version:

master

Vim version (first three lines from :version):


VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Apr 13 2020 07:47:09)
macOS version
Included patches: 1-550

Go version (go version):


go version go1.14.2 darwin/amd64

Go environment

go env Output:


GO111MODULE=""
GOARCH="amd64"
GOBIN="/Users/sheerun/go/bin"
GOCACHE="/Users/sheerun/Library/Caches/go-build"
GOENV="/Users/sheerun/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/sheerun/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.14.2_1/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.14.2_1/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/sheerun/Source/Projects/gossandra/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/qc/03n3xp8n0v3866tj26mg953r0000gn/T/go-build495168971=/tmp/go-build -gno-record-gcc-switches -fno-common"

gopls version

gopls version Output:


golang.org/x/tools/gopls 0.4.1
golang.org/x/tools/[email protected] h1:0e3BPxGV4B3cd0zdMuccwW72SgmHp92lAjOyxX/ScAw=

vim-go configuration:

vim-go configuration

g:go_jump_to_error = 1
g:go_imports_autosave = 1
g:go_loaded_gosnippets = 1
g:go_loaded_install = 1

filetype detection configuration:

filetype detection

filetype detection:ON plugin:ON indent:ON

Most helpful comment

If someone has similar issue in the future: I've started using coc.vim without vim-go. It turns out coc.vim supports autocomplete, formatting, go to definition, and listing references, plus it works not only for go but also for other languages. Here's .vimrc (I use vim-plug):

call plug#begin()

Plug 'sheerun/vim-polyglot'
Plug 'neoclide/coc.nvim', {'branch': 'release'}

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~ '\s'
endfunction

inoremap <silent><expr> <TAB>
  \ pumvisible() ? "\<C-n>" :
  \ <SID>check_back_space() ? "\<TAB>" :
  \ coc#refresh()

nmap <silent> <Enter> <Plug>(coc-definition)
nmap <silent> <Leader>r <Plug>(coc-references)
nmap <silent> <Leader>f <Plug>(coc-fix-current)

call plug#end()

And here's :CocConfig:

{
  "coc.preferences.useQuickfixForLocations": true,
  "coc.preferences.extensionUpdateCheck": "never",
  "coc.preferences.messageLevel": "error",
  "coc.preferences.snippets.enable": true,
  "coc.preferences.formatOnType": true,
  "suggest.disableMenu": true,
  "suggest.snippetIndicator": "",
  "diagnostic.level": "warning",
  "diagnostic.messageDelay": 0,
  "diagnostic.checkCurrentLine": true,
  "diagnostic.format": "%message",
  "languageserver": {
    "golang": {
      "command": "gopls",
      "rootPatterns": ["go.mod", ".git/"],
      "disableWorkspaceFolders": true,
      "filetypes": ["go"],
      "initializationOptions": {
        "completeUnimported": true
      }
    }
  }
}

I add missing / remove unused imports by pressing <Leader>f and applying quickfix.

All 15 comments

I don't believe this is issue with coc.vim, because vim-go currently saves file two times instead of one (one with unformatted contents and one with formatted contents), #2887 fixes this by formatting file in memory and then saving one time.

I don't understand why you're filing this as an issue with vim-go given that you've determined the error isn't coming from vim-go. Have you reached out to coc.nvim to file an issue there?

coc parses file as soon as it changes. the "fix" on their part would mean that file would be parsed and linted two times for each time vim-go changes it, which would not be sufficient and would cause performance issues as well as glitches in UI. I think true fix is to write file one time instead of two times

Do you experience this error if you use let g:go_fmt_command='goimports'?

yes, it's the same (which makes sense because let g:go_imports_autosave = 1 causes vim-go to follow practically the same code path)

Forgive me, but I don't see how it's writing the file without the adjusted imports in a way that's causing coc to see that file as changed. When g:go_fmt_command='goimports' is used where are the two writes that you're referring to?

To see this please create main.go:

锘匡豢package main

import (
        "fmt"
        "os"
)

func main() {
        fmt.Println(os.Args)
}

Then please install fswatch and run fswatch main.go

Then open this file in vim, remove "fmt" line, and save file.

With current version of vim-go, the output is:

/Users/sheerun/Source/Projects/project/main.go
/Users/sheerun/Source/Projects/project/main.go

which means system marks this file as changed two times. If you use my branch as follows:

Plug 'sheerun/vim-go', { 'branch': 'improve-formatting-2', 'for': 'go', 'do': ':GoUpdateBinaries' }

Then the output after saving is:

/Users/sheerun/Source/Projects/project/main.go

which means file is saved one time

This would cause issues not only with Coc but also any software that depends on filesystem changes notificatons, like live-reloading or servers

Yes, it will save twice, but it should not be being saved with the insufficient imports if you use let g:go_fmt_command='goimports'; I don't see a way for coc.nvim to see the file with the insufficient imports in that case.

I installed coc.nvim to test this and was able to see the error a few times, but it's not consistent. I noticed, too, that the error I only saw the error when coc.nvim comes before vim-go in the runtime path (and even then it's not consistent). I suspect the problem is happening because of the event that coc.nvim is using to decide when to check the file. And since coc.nvim is primarily async, it's entirely possible that any errors that could seemingly be resolved with #2887 would only be made less likely and not actually eliminated.

The issue is not that file is written multiple times, but that file is written multiple times with different contents (one before formatting and one after formatting), #2887 makes sure that file is not written to disk before being formatted so it's not possible it doesn't solve this problem :)

I don't see a place in vim-go's code where it writes the file to disk (other than the temp file) before the imports are adjusted when you have g:go_fmt_command='goimports'. Where do you see that?

@sheerun the order of operations for formatting when g:go_fmt_command is goimports are:

  1. use issues command to save
  2. before saving to disk the file is saved to a temporary file via the BufWritePre autocmd
  3. the temporary is formatted with g:go_fmt_command
  4. the temporary file is moved to the buffer's file location
  5. the contents of the file on disk are read
  6. the BufWritePre autocmd completes
  7. Vim saves the file to disk.

The two file writes you see are from when the temporary file is moved to the buffer's file location and Vim saving the file to disk; I don't see a time there where it would be written to disk before the imports are adjusted. Do you?

I just know this happens (fswatch shows this), and my PR fixed this. I don't have time to debug exactly why it happens :(

If someone has similar issue in the future: I've started using coc.vim without vim-go. It turns out coc.vim supports autocomplete, formatting, go to definition, and listing references, plus it works not only for go but also for other languages. Here's .vimrc (I use vim-plug):

call plug#begin()

Plug 'sheerun/vim-polyglot'
Plug 'neoclide/coc.nvim', {'branch': 'release'}

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~ '\s'
endfunction

inoremap <silent><expr> <TAB>
  \ pumvisible() ? "\<C-n>" :
  \ <SID>check_back_space() ? "\<TAB>" :
  \ coc#refresh()

nmap <silent> <Enter> <Plug>(coc-definition)
nmap <silent> <Leader>r <Plug>(coc-references)
nmap <silent> <Leader>f <Plug>(coc-fix-current)

call plug#end()

And here's :CocConfig:

{
  "coc.preferences.useQuickfixForLocations": true,
  "coc.preferences.extensionUpdateCheck": "never",
  "coc.preferences.messageLevel": "error",
  "coc.preferences.snippets.enable": true,
  "coc.preferences.formatOnType": true,
  "suggest.disableMenu": true,
  "suggest.snippetIndicator": "",
  "diagnostic.level": "warning",
  "diagnostic.messageDelay": 0,
  "diagnostic.checkCurrentLine": true,
  "diagnostic.format": "%message",
  "languageserver": {
    "golang": {
      "command": "gopls",
      "rootPatterns": ["go.mod", ".git/"],
      "disableWorkspaceFolders": true,
      "filetypes": ["go"],
      "initializationOptions": {
        "completeUnimported": true
      }
    }
  }
}

I add missing / remove unused imports by pressing <Leader>f and applying quickfix.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

groob picture groob  路  3Comments

joeblubaugh picture joeblubaugh  路  3Comments

SirmaXX picture SirmaXX  路  3Comments

wpaulino picture wpaulino  路  4Comments

andrejvanderzee picture andrejvanderzee  路  3Comments