kevinhwang91 / nvim-ufo

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

XCode Folding Ribbon #24

Open kevinhwang91 opened 2 years ago

kevinhwang91 commented 2 years ago

Feature description

https://github.com/CodeEditApp/CodeEditTextView/issues/43

Describe the solution you'd like

Use the sign column Use floating window

Additional context

No response

kevinhwang91 commented 1 year ago

High priority for this feature.

xiyaowong commented 1 year ago

🐮

kevinhwang91 commented 1 year ago

image

No idea how to handle lower and upper bar icons. The suggestion is welcome.

kevinhwang91 commented 1 year ago

image

It's too hard.

  1. 19-22 and 23-43 are level1, 22 line is the lower but 23 line is the upper, it can't balance aesthetics and practicality;
  2. A line may be lower/upper of different levels, like 1-4 is level1, but 1-3 can be level2, so upper and lower are not a pair, WTF;
akinsho commented 1 year ago

@kevinhwang91 I don't fully understand some of the issue you are seeing, but the result of the screenshot so far looks great. I'm guessing that the highlights are in slightly wrong places because of confusing behaviour of nvim folds maybe

kevinhwang91 commented 1 year ago

@kevinhwang91 I don't fully understand some of the issue you are seeing, but the result of the screenshot so far looks great. I'm guessing that the highlights are in slightly wrong places because of confusing behaviour of nvim folds maybe

  1. not pretty as GUI, depending on the user icon and font. image
  2. The endLnum of folds may overlap each, hard to compute with high perf. Must take a time to explore.

IMO, must highlight the current fold range with uppe/lower or the bar body, otherwise, it's useless.

kevinhwang91 commented 1 year ago

maybe only use to indicator the startLnum and highlight current range is a compromise method. The upper/lower icon is hard to select and ⁀‿ in some fonts are asymmetric. This is the limitation of terminal.

image

kevinhwang91 commented 1 year ago

I get sucked with the UI. There're many potential errors that need to handle. BTW, ctrl-w+o will work fine with the floating window foldcolumn. https://user-images.githubusercontent.com/17562139/181925985-66dbf19e-bd79-4659-9c3f-c66b1cbe0796.mp4

shofel commented 1 year ago

I love the appearance of the xcode folding ribbon. Thanks for sharing it!

Looks like the lower bounds do not add lot's of value, so it's ok to omit them.

Regarding the upper boundary: what if just leave the arrow as it is? That is the only change to make is to encode levels of a fold with a color instead of a number :thinking:

image

image

kevinhwang91 commented 1 year ago

I love the appearance of the xcode folding ribbon. Thanks for sharing it!

Looks like the lower bounds do not add lot's of value, so it's ok to omit them.

Regarding the upper boundary: what if just leave the arrow as it is? That is the only change to make is to encode levels of a fold with a color instead of a number thinking

image

image

Not bad, but must solve the perf first, I will give a try if I have time.

i-am-the-slime commented 1 year ago

@kevinhwang91 whatever comes of this, your prototype looks really cool!

WhiteBlackGoose commented 1 year ago

Hi, Kevin, this looks great. Do you mind pushing the branch yet? Ik it's WIP, but I could be an alpha tester :laughing: I mean, even the prototype looks good for me.

Btw, does your new feature depend on the patch to nvim?

kevinhwang91 commented 1 year ago

@WhiteBlackGoose Thanks for your attention. I have tested the incomplete code and found it will make nearly a millisecond regression for redraw even if using ffi. If the code is complete, I think the regression will be worse which makes me think it's not a productive implementation. IMO, the enhanced UI shouldn't make Neovim lag, so I have stopped dev for this feature for now.

WhiteBlackGoose commented 1 year ago

Oh, I see, sad :/

kevinhwang91 commented 1 year ago

@WhiteBlackGoose Maybe can get better perf to use statuscolumn. I will give it a try if I have spare time.

WhiteBlackGoose commented 1 year ago

Nice, good luck with that!

kevinhwang91 commented 1 year ago

https://github.com/kevinhwang91/nvim-ufo/issues/4#issuecomment-1382702538

The ribbon is slightly more complicated than the VSCode style. The perf is not bad. Less than 1ms regression in a redraw even if a monitor in portrait orientation with hundred visible lines.

Go ahead if statuscolumn become stable.

Chaitanyabsprip commented 1 year ago

I was trying to do the vscode style markers using the status column, could make it work with treesitter method(not ufo), couldn't figure out how to convert promise to a function that could be fed into the status column opt, can you help me with that? I was trying to use the ufo.getFolds() method

ribru17 commented 9 months ago

Is there any code available showing how to achieve this affect? If anyone wants to use the unfinished feature now

kevinhwang91 commented 9 months ago

Is there any code available showing how to achieve this affect? If anyone wants to use the unfinished feature now

No, will implement it if I have spare time.

ribru17 commented 9 months ago

Thank you. Also I managed to create a minimal version of this without the start and end indicators. If anyone is interested:

      {
        'luukvbaal/statuscol.nvim',
        config = function()
          local builtin = require('statuscol.builtin')
          local c = require('statuscol.ffidef').C
          local util = require('utils')
          for i = 0, 8, 1 do
            vim.api.nvim_set_hl(0, 'FoldCol' .. i, {
              bg = util.blend(
                string.format(
                  '#%06x',
                  vim.api.nvim_get_hl(0, { name = 'Normal' }).fg
                ),
                string.format(
                  '#%06x',
                  vim.api.nvim_get_hl(0, { name = 'Normal' }).bg
                ),
                0.125 * i
              ),
            })
          end
          require('statuscol').setup {
            relculright = true,
            segments = {
              { text = { '%s' }, click = 'v:lua.ScSa' },
              { text = { builtin.lnumfunc, ' ' }, click = 'v:lua.ScLa' },
              {
                -- hl = 'FoldColumn',
                text = {
                  function(args)
                    local fold_level = c.fold_info(args.wp, args.lnum).level
                    local hl = '%#FoldCol' .. fold_level .. '#'
                    if fold_level > 8 then
                      hl = '%#FoldCol8#'
                    end
                    return hl .. ' '
                  end,
                },
                click = 'v:lua.ScFa',
              },
            },
          }
        end,
      },

Util functions:

local function hexToRgb(hex_str)
  local hex = '[abcdef0-9][abcdef0-9]'
  local pat = '^#(' .. hex .. ')(' .. hex .. ')(' .. hex .. ')$'
  hex_str = string.lower(hex_str)

  assert(
    string.find(hex_str, pat) ~= nil,
    'hex_to_rgb: invalid hex_str: ' .. tostring(hex_str)
  )

  local r, g, b = string.match(hex_str, pat)
  return { tonumber(r, 16), tonumber(g, 16), tonumber(b, 16) }
end

function M.blend(fg, bg, alpha)
  bg = hexToRgb(bg)
  fg = hexToRgb(fg)

  local blendChannel = function(i)
    local ret = (alpha * fg[i] + ((1 - alpha) * bg[i]))
    return math.floor(math.min(math.max(0, ret), 255) + 0.5)
  end

  return string.format(
    '#%02X%02X%02X',
    blendChannel(1),
    blendChannel(2),
    blendChannel(3)
  )
end
ribru17 commented 3 months ago

UPDATE: For anyone still interested I managed to get this working with the statuscol plugin.

foldpreview

Implementation for the status column is here and the necessary highlight groups are here (with some utility functions here)