nvim-ufo icon indicating copy to clipboard operation
nvim-ufo copied to clipboard

High level folds wrongly folded

Open stevanmilic opened this issue 1 year ago • 15 comments

Neovim version (nvim -v | head -n1)

head

Operating system/version

macOS 12.4

How to reproduce the issue

When executing vim.lsp.buf.format() the high-level folds are broken i.e. the high-level fold includes other lines that shouldn't be in it. Opening/closing the fold brings back the good folding. Here's the video showing the issue:

https://user-images.githubusercontent.com/6879030/181639721-54edb378-942a-44b3-b466-5a67625f0a05.mov

setup:

vim.o.foldlevel = 99
vim.o.foldlevelstart = 99
vim.o.foldenable = true
require("ufo").setup({
    open_fold_hl_timeout = 0,
    -- enable_fold_end_virt_text = true,
    provider_selector = function(bufnr, filetype)
        return 'treesitter'
    end
})
vim.keymap.set("n", "zR", "<cmd> lua require('ufo').openAllFolds()<cr>")
vim.keymap.set("n", "zM", "<cmd> lua require('ufo').closeAllFolds()<cr>")

NOTE: the bug also happens with indent provider.

Expected behavior

The folds to be correctly represented after the format is being done.

Actual behavior

The folds are miss-calculated.

stevanmilic avatar Jul 28 '22 21:07 stevanmilic

Fixted

kevinhwang91 avatar Jul 29 '22 03:07 kevinhwang91

@kevinhwang91 the issue still occurs, it isn't fixed with latest commit.

stevanmilic avatar Jul 29 '22 06:07 stevanmilic

UFO_LOG=info nvim and provide the log. BTW, what's the formater you use?

kevinhwang91 avatar Jul 29 '22 07:07 kevinhwang91

Will provide the log 👍🏻 I'm using sumneko_lua formatter in this case, but also happens with black (null-ls) formatter. BTW I remember having this issue with default tree-sitter foldexpr, it could be something with my config, but I was checking autocmds I have in my set-up, and nothing should affect the problem.

stevanmilic avatar Jul 29 '22 07:07 stevanmilic

log:

[22-07-29 09:12:42] [INFO] manager.lua:195 : apply fold ranges: { {
    endLine = 3,
    startLine = 1
  } }
[22-07-29 09:12:42] [INFO] manager.lua:196 : apply fold rowPairs: {}
[22-07-29 09:12:48] [INFO] manager.lua:195 : apply fold ranges: { {
    endLine = 3,
    startLine = 1
  } }
[22-07-29 09:12:48] [INFO] manager.lua:196 : apply fold rowPairs: { 3 }
[22-07-29 09:12:51] [INFO] manager.lua:195 : apply fold ranges: { {
    endLine = 3,
    startLine = 1
  } }
[22-07-29 09:12:51] [INFO] manager.lua:196 : apply fold rowPairs: {
  [3] = 5
}

file:

-- smart dd
function smart_dd()
    return ""
end

vim.keymap.set("n", "dd", smart_dd, { noremap = true, expr = true })

stevanmilic avatar Jul 29 '22 07:07 stevanmilic

reproduced. I will fix it later.

kevinhwang91 avatar Jul 29 '22 07:07 kevinhwang91

After debugging, this is nvim_buf_set_text issue called from lua vim.lsp.buf.format(), you can disable ufo and then open the text you provided, and then:

  1. 2,4fold
  2. 5delete
  3. lua vim.lsp.buf.format()

image

line 4-6 are folded. If ufo is enabled, will add this range to extmark and apply folds with these additional ranges.

kevinhwang91 avatar Jul 29 '22 08:07 kevinhwang91

https://github.com/neovim/neovim/issues/19571

kevinhwang91 avatar Jul 29 '22 09:07 kevinhwang91

@kevinhwang91 do you have in-mind any workaround that I can use, to make the folds stable? The one that comes to my mind is saving and restoring the view – before and after the formatting, but I'm not sure if that's safe as the folded lines could change.

stevanmilic avatar Jul 29 '22 23:07 stevanmilic

saving and restoring the view: is this issue existing for now? before and after the formatting: There're two format ways, one is full edit, and another is local range edit. As a workaround, ufo can delete any folds manually if the range is edited. After formatting:

  1. Full edit: the fold will be always opened.
  2. Local range edit: local fold will be always opened, others will keep the original status.

~~This workaround I don't think is good, which must delete fold after every change will cause perf regression while editing.~~

AFAIK, sumneko_lua formatter always does full edit for a buffer that doesn't diff content. You should use lua vim.lsp.buf.range_formatting instead.

kevinhwang91 avatar Jul 30 '22 03:07 kevinhwang91

A full edit will always open all folds, please use a range format. I think null-ls can do this. Most language server has diff content before generating textEdit[] even for textDocument/formatting interface.

kevinhwang91 avatar Jul 30 '22 05:07 kevinhwang91

Got it, thanks for the input! I hope the issue gets fixed upstream soon 🤞🏻

stevanmilic avatar Jul 30 '22 07:07 stevanmilic

FYI: https://github.com/fannheyward/coc-pyright/blob/bae9ce6dce09c67fcd0d15394864553c70951d50/src/formatters/black.ts#L5-L31 https://github.com/fannheyward/coc-pyright/blob/bae9ce6dce09c67fcd0d15394864553c70951d50/src/common.ts#L199-L228

kevinhwang91 avatar Jul 30 '22 07:07 kevinhwang91

https://github.com/kevinhwang91/nvim-ufo/commit/65af01fe5efecf005dc33a6d6afe4469c5be467c it does fix the issue I'm having, looks neat so far 👌🏻 the only drawback is that it would open all the folds after the line that has been deleted, but that's an edge-case we're solving anyway.

stevanmilic avatar Jul 30 '22 07:07 stevanmilic

Great, AFAIK, https://github.com/mattn/efm-langserver will diff result to generate multiple textEdit

kevinhwang91 avatar Jul 30 '22 07:07 kevinhwang91

I think upstream can't keep the folds while the lines are changed. ufo will clear the folds if the lines changed to make sure that the folds are correct. Users should use a range edit instead of a full edit.

kevinhwang91 avatar Oct 27 '22 00:10 kevinhwang91