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

(Example) Show last line of the folded region for treesitter provider #38

Closed ranjithshegde closed 1 year ago

ranjithshegde commented 2 years ago

Feature description

Since lsp provider folds differently than the treesitter parser, showing the last line of the folded region for treesitter can be helpful.

I have written an example configuration that sets the virtual_text handler to set the last line, and uses some internal functions to use default highlights for the displayed line.

Note: This is a personal/opinionated example, the users's tastes may differ, but this example could be used as a guide to creating your own virt-text-handler

Another note: using this snippet for lsp or indent provider wont break it but would be very redundant and cluttered, so its not recommended

Describe the solution you'd like

Edit/use this snippet in advanced_configuration example section

local function set_end_lines(bufnr, text, lnum, end_lnum)
    local current_buf_folds = require("ufo.fold.buffer").pool[bufnr]
    local nss = {}
    for _, ns in pairs(vim.api.nvim_get_namespaces()) do
        if require("ufo.decorator").ns ~= ns then
            table.insert(nss, ns)
        end
    end

    local syntax = vim.bo[bufnr].syntax ~= ""
    local winid = vim.api.nvim_get_current_win()
    local wininfo = vim.fn.getwininfo(winid)[1]
    local width = vim.api.nvim_win_get_width(winid) - wininfo.textoff

    local virt_text = require("ufo.render").getVirtText(bufnr, text, width, end_lnum, syntax, nss)

    if not vim.tbl_isempty(current_buf_folds.foldedLines) and current_buf_folds.foldedLines[lnum] ~= nil then
        vim.api.nvim_buf_set_extmark(current_buf_folds.bufnr, current_buf_folds.ns, lnum - 1, 0, {
            id = current_buf_folds.foldedLines[lnum].id,
            end_row = lnum - 1,
            end_col = 0,
            virt_text = virt_text,
            virt_text_win_col = 0,
            priority = 10,
            hl_mode = "combine",
        })
    end

    return virt_text
end

local function handler(virt_text, lnum, end_lnum, width, truncate)
    local result = {}

    local counts = ("    %d    "):format(end_lnum - lnum)
    local suffix = " ⋯⋯  "
    local padding = ""

    local bufnr = vim.api.nvim_get_current_buf()
    local end_text = vim.api.nvim_buf_get_lines(bufnr, end_lnum - 1, end_lnum, false)[1]
    local end_virt_text = set_end_lines(bufnr, end_text, lnum, end_lnum)

    local sufWidth = (2 * vim.fn.strdisplaywidth(suffix)) + vim.fn.strdisplaywidth(counts)
    for _, v in ipairs(end_virt_text) do
        sufWidth = sufWidth + vim.fn.strdisplaywidth(v[1])
    end

    local target_width = width - sufWidth
    local cur_width = 0

    for _, chunk in ipairs(virt_text) do
        local chunk_text = chunk[1]

        local chunk_width = vim.fn.strdisplaywidth(chunk_text)
        if target_width > cur_width + chunk_width then
            table.insert(result, chunk)
        else
            chunk_text = truncate(chunk_text, target_width - cur_width)
            local hl_group = chunk[2]
            table.insert(result, { chunk_text, hl_group })
            chunk_width = vim.fn.strdisplaywidth(chunk_text)

            if cur_width + chunk_width < target_width then
                padding = padding .. (" "):rep(target_width - cur_width - chunk_width)
            end
            break
        end
        cur_width = cur_width + chunk_width
    end

    table.insert(result, { suffix, "UfoFoldedEllipsis" })
    table.insert(result, { counts, "MoreMsg" })
    table.insert(result, { suffix, "UfoFoldedEllipsis" })

    for _, v in ipairs(end_virt_text) do
        table.insert(result, v)
    end

    table.insert(result, { padding, "" })

    return result
end

require("ufo").setup {
  -- your other config
  fold_virt_text_handler = handler,
end

Additional context

Some examples folds1

folds2

kevinhwang91 commented 2 years ago

I will export the API later, need your test.

Added enable_fold_end_virt_text option,

    require('ufo').setup({
        enable_fold_end_virt_text = true,
        fold_virt_text_handler = function (virtText, lnum, endLnum, width, truncate, ctx)
            local end_virt_text = ctx.end_virt_text
            -- ......
        end
    })
kevinhwang91 commented 1 year ago

enable_fold_end_virt_text may be deprecated, feel free to share your opinion under https://github.com/kevinhwang91/nvim-ufo/pull/74

kevinhwang91 commented 1 year ago

Please use enable_get_fold_virt_text instead.