kevinhwang91 / nvim-ufo

Not UFO in the sky, but an ultra fold in Neovim.
BSD 3-Clause "New" or "Revised" License
2.23k stars 44 forks source link

High level folds wrongly folded #60

Closed stevanmilic closed 1 year ago

stevanmilic commented 2 years ago

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.

kevinhwang91 commented 2 years ago

Fixted

stevanmilic commented 2 years ago

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

kevinhwang91 commented 2 years ago

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

stevanmilic commented 2 years ago

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 commented 2 years ago

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 })
kevinhwang91 commented 2 years ago

reproduced. I will fix it later.

kevinhwang91 commented 2 years ago

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 commented 2 years ago

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

stevanmilic commented 2 years ago

@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.

kevinhwang91 commented 2 years ago

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 commented 2 years ago

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.

stevanmilic commented 2 years ago

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

kevinhwang91 commented 2 years ago

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

stevanmilic commented 2 years ago

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.

kevinhwang91 commented 2 years ago

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

kevinhwang91 commented 1 year ago

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.