neoclide / coc.nvim

Nodejs extension host for vim & neovim, load extensions like VSCode and host language servers.
Other
24.15k stars 953 forks source link

coc format behavior differently between Neovim and Vim, create unnecessary empty change in neovim. #4994

Closed towry closed 2 months ago

towry commented 2 months ago

Result from CocInfo

## versions

vim version: NVIM v0.8.3
node version: v21.7.1
coc.nvim version: 0.0.82-2ec31666 2024-04-23 09:10:14 +0800
coc.nvim directory: /Users/towry/.local/share/nvim/lazy/coc.nvim
term: WezTerm
platform: darwin

## Log of coc.nvim

2024-04-27T14:13:40.273 WARN (pid:10350) [workspace] - workspace.createOutputChannel is deprecated, please use window.createOutputChannel instead. 
    at Object.<anonymous> (/Users/towry/.config/coc/extensions/node_modules/coc-tailwindcss/out/index.js:14:7870)
    at Generator.next (<anonymous>)
2024-04-27T14:13:40.374 INFO (pid:10350) [model-fetch] - Using proxy http://127.0.0.1:1080 from system environment for api.github.com:
2024-04-27T14:13:40.384 INFO (pid:10350) [plugin] - coc.nvim initialized with node: v21.7.1 after 503
2024-04-27T14:13:40.615 ERROR (pid:10350) [model-fetch] - Fetch error for https://api.github.com/repos/JohnnyMorganz/StyLua/releases/latest: {
  method: 'GET',
  hostname: 'api.github.com',
  port: 443,
  path: '/repos/JohnnyMorganz/StyLua/releases/latest',
  agent: HttpsProxyAgent2 {
    _events: [Object: null prototype] {},
    _eventsCount: 0,
    _maxListeners: undefined,
    timeout: null,
    maxFreeSockets: 1,
    maxSockets: 1,
    maxTotalSockets: Infinity,
    sockets: {},
    freeSockets: {},
    requests: {},
    options: {},
    secureProxy: false,
    proxy: {
      host: '127.0.0.1',
      port: 1080,
      auth: undefined,
      rejectUnauthorized: true
    },
    promisifiedCallback: [Function: callback],
    [Symbol(shapeMode)]: false,
    [Symbol(kCapture)]: false
  },
  rejectUnauthorized: true,
  maxRedirects: 3,
  headers: {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)',
    'Accept-Encoding': 'gzip, deflate'
  }
} Error: Bad response from https://api.github.com/repos/JohnnyMorganz/StyLua/releases/latest: 403
    at RedirectableRequest.<anonymous> (/Users/towry/.local/share/nvim/lazy/coc.nvim/build/index.js:58187:16)
    at RedirectableRequest.emit (node:events:519:28)
    at RedirectableRequest._processResponse (/Users/towry/.local/share/nvim/lazy/coc.nvim/build/index.js:57168:14)
    at RedirectableRequest._onNativeResponse (/Users/towry/.local/share/nvim/lazy/coc.nvim/build/index.js:56957:16)
    at Object.onceWrapper (node:events:634:26)
    at ClientRequest.emit (node:events:519:28)
    at HTTPParser.parserOnIncomingClient (node:_http_client:698:27)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17)
    at TLSSocket.socketOnData (node:_http_client:540:22)
    at TLSSocket.emit (node:events:519:28)
2024-04-27T14:13:40.689 ERROR (pid:10350) [node-client] - request error on "nvim_call_function" [ 'pyxeval', [ '1' ] ] Error: request error on "nvim_call_function" - Vim:E319: No "python3" provider found. Run ":checkhealth provider"
    at UltiSnippetsProvider.init (/Users/towry/.config/coc/extensions/node_modules/coc-snippets/lib/index.js:3335:18)
    at /Users/towry/.config/coc/extensions/node_modules/coc-snippets/lib/index.js:1671:23
    at Array.map (<anonymous>)
    at ProviderManager.init (/Users/towry/.config/coc/extensions/node_modules/coc-snippets/lib/index.js:1670:33)
    at Object.activate (/Users/towry/.config/coc/extensions/node_modules/coc-snippets/lib/index.js:3921:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
2024-04-27T14:13:45.351 ERROR (pid:10350) [timing] - activate @statiolake/coc-stylua timeout after 5000ms
2024-04-27T14:13:45.574 INFO (pid:10350) [attach] - receive notification: format []

Describe the bug

In Vim, after run :Format on already formatted file do not change the file, but it does change the file in Neovim (tested on 0.83,0.9,0.91,nightly versions).

The inconvenience result is that:

Reproduce the bug

We will close your issue when you don't provide minimal vimrc and we can't reproduce it

augroup vimrc | autocmd! | augroup end

set nocompatible
set number
set laststatus=2

let g:coc_global_extensions = ['coc-sumneko-lua', '@statiolake/coc-stylua']
" change this to your local coc.nvim location.
set runtimepath^=/Users/towry/.local/share/nvim/lazy/coc.nvim
filetype plugin indent on
syntax on
autocmd BufWritePre * call CocAction('format')
command! -nargs=0 Format :call CocActionAsync('format')

set expandtab shiftwidth=4 tabstop=4 softtabstop=4
-- --------
-- -----
-- -------
-- -----
--
local foo = function()
    print("foooo")
end

Note, the demo file should be already formated, if it is not, format and save it;

Screenshots (optional)

https://github.com/neoclide/coc.nvim/assets/8279858/dfce5ff5-8658-4ff6-8de8-42e4a05a5d7e

towry commented 2 months ago

It is this line causing the difference: https://github.com/neoclide/coc.nvim/blob/2ec3166653f76acd42b0d9f62161c4db2673c204/src/model/document.ts#L349

towry commented 2 months ago

tracked down to line https://github.com/neoclide/coc.nvim/blob/2ec3166653f76acd42b0d9f62161c4db2673c204/autoload/coc/compat.vim#L18

turns out when format without change, the arguments passed to nvim_buf_set_lines is (bufnr, 1, 1, 0, {})

And i test this function on a buffer, it did change the buffer and create empty change.

From :h nvim_buf_set_lines:

To insert lines at a given index, set start and end to the same index. To delete a range of lines, set replacement to an empty array.

So (bufnr, 1, 1, 0, {}) will do nothing but make an empty change since a:start is same as a:end and replacement is empty.

fannheyward commented 2 months ago

Thank you for your tracking, but I can't reproduce this with your mini.nivm and formatted demo.lua, with coc-sumneko-lua on nvim nightly. And I couldn't reproduce with other language servers too.

fannheyward commented 2 months ago

The checking fix in #4995 is OK, but I couldn't result any format without change, coc.nvim couldn't run to this check.

towry commented 2 months ago

@fannheyward Just tested on different version of coc.

coc release branch coc.nvim version: 0.0.82-2ec31666 2024-04-23 09:10:14 +0800

have issue.

coc tag v0.0.82, v0.0.81 doesn't have issue.

towry commented 2 months ago

I believe this issue was introduced after v0.0.82. another issue in format is that I have to use call CocAction('format') | sleep 1m to make it work in BufWritePre, otherwise the buf sometimes will be in dirty state.

But in v0.0.82, it works well without the need of sleep 1m.

You can discard this pr, and i will just stick to version v0.0.82.

fannheyward commented 2 months ago

I believe this issue was introduced after v0.0.82.

Thank you for your tests with different releases of coc, I don't complain your PR, but how to reproduce this, here's my tests:

  1. mkdir -p test-4994
  2. copy your mini.vim and demo.lua, and empty coc-settings.json. I've removed @statiolake/coc-stylua because sumneko-lua already supports formatting, no need to use stylus any more.
  3. When tested with nvim 0.10.0 nightly, I need to add nvim-treesitter, otherwise, nvim reports highlighting error
augroup vimrc | autocmd! | augroup end

set nocompatible
set number
set laststatus=2

let g:coc_global_extensions = ['coc-sumneko-lua']
" change this to your local coc.nvim location.
set runtimepath^=/Users/fannheyward/.local/share/nvim/plugged/coc.nvim
set runtimepath^=/Users/fannheyward/.local/share/nvim/plugged/nvim-treesitter 
filetype plugin indent on
syntax on
autocmd BufWritePre * call CocAction('format')
command! -nargs=0 Format :call CocActionAsync('format')

set expandtab shiftwidth=4 tabstop=4 softtabstop=4
  1. nvim -u mini.vim demo.lua, sumneko-lua reports unused local foo, the Lua LS is working
  2. :call CocAction('format'), no changes
  3. :Format, no changes
  4. :w to fire autocmd, no changes
  5. Tested with nvim 0.9.5 and 0.10.0 nightly, vim 9.1.0350, same results.

Also I've tested the formatting with tsserver, gopls, rust-analyzer servers, won't change on formatted files.

fannheyward commented 2 months ago

You can use coc.preferences.formatOnSave instead of BufWritePre.