Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement zr and zm more like default behavior #150

Open
fisher-j opened this issue Aug 24, 2023 · 8 comments
Open

implement zr and zm more like default behavior #150

fisher-j opened this issue Aug 24, 2023 · 8 comments
Labels
enhancement New feature or request

Comments

@fisher-j
Copy link

fisher-j commented Aug 24, 2023

Feature description

Related to #62, I would like it if zr would decrease the amount of folding and zm would increase the amount of folding.

Describe the solution you'd like

Starting with no folds, zm would need to be aware of the maximum fold level currently used in a document and incrementally reduce this value. The foldlevel could possibly be tracked by a buffer local variable (vim.b.ufo_foldlevel?), similar to foldlevel.

zr would then increment vim.b.ufo_foldlevel up to the maximum currently used in the document.

Additional context

Thank you for your work on this plugin, it has made it possible for me to use folds on large markdown documents with many code chunks, where before it was impossibly slow!

@fisher-j fisher-j added the enhancement New feature or request label Aug 24, 2023
@kevinhwang91
Copy link
Owner

vim.b.ufo_foldlevel -> vim.w.ufo_foldlevel

Have you encountered any performance issues by customizing yourself? IMO, the built-in zr and zm behaviors are not good workflow.

Maybe enhance ufo to preview the folded/unfolded level code in the future.

@fisher-j
Copy link
Author

fisher-j commented Aug 24, 2023 via email

@kevinhwang91
Copy link
Owner

Have you understood the comment #62 (comment) ?

@fisher-j
Copy link
Author

fisher-j commented Aug 25, 2023 via email

@PriceHiller
Copy link

PriceHiller commented Dec 22, 2023

Hey @fisher-j and anyone else who comes across this.

I've implemented this in my Neovim config somewhat and thus far it's been working well enough for me.

Here's the code:

-- Ensure our ufo foldlevel is set for the buffer
vim.api.nvim_create_autocmd("BufReadPre", {
    callback = function()
        vim.b.ufo_foldlevel = 0
    end
})

---@param num integer Set the fold level to this number
local set_buf_foldlevel = function(num)
    vim.b.ufo_foldlevel = num
    require("ufo").closeFoldsWith(num)
end

---@param num integer The amount to change the UFO fold level by
local change_buf_foldlevel_by = function(num)
    local foldlevel = vim.b.ufo_foldlevel or 0
    -- Ensure the foldlevel can't be set negatively
    if foldlevel + num >= 0 then
        foldlevel = foldlevel + num
    else
        foldlevel = 0
    end
    set_buf_foldlevel(foldlevel)
end

-- Keymaps
vim.keymap.set("n", "zm", function()
    local count = vim.v.count
    if count == 0 then
        count = 1
    end
    change_buf_foldlevel_by(-(count))
end, { desc = "UFO: Fold More" })

vim.keymap.set("n", "zr", function()
    local count = vim.v.count
    if count == 0 then
        count = 1
    end
    change_buf_foldlevel_by(count)
end, { desc = "UFO: Fold Less" })

-- 99% sure `zS` isn't mapped by default
vim.keymap.set("n", "zS", function()
    if vim.v.count == 0 then
        vim.notify("No foldlevel given to set!", vim.log.levels.WARN)
    else
        set_buf_foldlevel(vim.v.count)
    end
end, { desc = "UFO: Set Foldlevel" })

Mostly I've just written a wrapper around require('ufo').closeFoldsWith to keep track of a separate ufo_foldlevel buffer variable.

If you're curious, I've implemented it into my config here. I use lazy.nvim to manage my plugins so I set my keybindings through lazy's keys table. That's the only significant difference between the code above and my code in terms of the folding.

I'm sure there's problems that can be caused/extend from this, but thus far it seems to be working quite well for me. YMMV.

Hope someone else finds this helpful 🙂.

@mehalter
Copy link

Thanks for this code snippet @treatybreaker ! I am looking to improve it a bit, @kevinhwang91 is there a way internally to retrieve the max fold level of a buffer? I'm curious if this information is stored anywhere when setting up the folds

@mehalter
Copy link

Here is the code I'm trying to get working currently:

-- return the max fold level of the buffer (for now doing the opposite and folding incrementally is unbounded)
-- Also jarring if you start folding incrementally after opening all folds
local function max_level()
  -- return vim.wo.foldlevel -- find a way for this to return max fold level
  return 0
end

---Set the fold level to the provided value and store it locally to the buffer
---@param num integer the fold level to set
local function set_fold(num)
  -- vim.w.ufo_foldlevel = math.min(math.max(0, num), max_level()) -- when max_level is implemneted properly
  vim.b.ufo_foldlevel = math.max(0, num)
  require("ufo").closeFoldsWith(vim.b.ufo_foldlevel)
end

---Shift the current fold level by the provided amount
---@param dir number positive or negative number to add to the current fold level to shift it
local shift_fold = function(dir) set_fold((vim.b.ufo_foldlevel or max_level()) + dir) end

-- when max_level is implemented properly
-- vim.keymap.set("n", "zR", function() set_win_fold(max_level()) end, { desc = "Open all folds" })
vim.keymap.set("n", "zR", require("ufo").openAllFolds, { desc = "Open all folds" })

vim.keymap.set("n", "zM", function() set_fold(0) end, { desc = "Close all folds" })

vim.keymap.set("n", "zr", function() shift_fold(vim.v.count == 0 and 1 or vim.v.count) end, { desc = "Fold less" })

vim.keymap.set("n", "zm", function() shift_fold(-(vim.v.count == 0 and 1 or vim.v.count)) end, { desc = "Fold more" })

If we had a way to dynamically fetch the max fold level from nvim-ufo it would be completely seamless when moving between using zr/zm alongside zR and zM. Let me know what you think and if anyone knows of this sort of information being available!

@kevinhwang91
Copy link
Owner

Here is the code I'm trying to get working currently:

-- return the max fold level of the buffer (for now doing the opposite and folding incrementally is unbounded)
-- Also jarring if you start folding incrementally after opening all folds
local function max_level()
  -- return vim.wo.foldlevel -- find a way for this to return max fold level
  return 0
end

---Set the fold level to the provided value and store it locally to the buffer
---@param num integer the fold level to set
local function set_fold(num)
  -- vim.w.ufo_foldlevel = math.min(math.max(0, num), max_level()) -- when max_level is implemneted properly
  vim.b.ufo_foldlevel = math.max(0, num)
  require("ufo").closeFoldsWith(vim.b.ufo_foldlevel)
end

---Shift the current fold level by the provided amount
---@param dir number positive or negative number to add to the current fold level to shift it
local shift_fold = function(dir) set_fold((vim.b.ufo_foldlevel or max_level()) + dir) end

-- when max_level is implemented properly
-- vim.keymap.set("n", "zR", function() set_win_fold(max_level()) end, { desc = "Open all folds" })
vim.keymap.set("n", "zR", require("ufo").openAllFolds, { desc = "Open all folds" })

vim.keymap.set("n", "zM", function() set_fold(0) end, { desc = "Close all folds" })

vim.keymap.set("n", "zr", function() shift_fold(vim.v.count == 0 and 1 or vim.v.count) end, { desc = "Fold less" })

vim.keymap.set("n", "zm", function() shift_fold(-(vim.v.count == 0 and 1 or vim.v.count)) end, { desc = "Fold more" })

If we had a way to dynamically fetch the max fold level from nvim-ufo it would be completely seamless when moving between using zr/zm alongside zR and zM. Let me know what you think and if anyone knows of this sort of information being available!

May take time to explore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants