luukvbaal / statuscol.nvim

Status column plugin that provides a configurable 'statuscolumn' and click handlers.
MIT License
531 stars 25 forks source link

The statuscol didn't get updated to reduce its width after the sign(s) of diagnostic disappear. #65

Open nyngwang opened 1 year ago

nyngwang commented 1 year ago

With the following partial setup config, the statuscol didn't get updated to reduce its width after the sign(s) of diagnostic disappear. My current workaround it to manually call set nu! twice.

require('statuscol').setup {
  relculright = true,
  bt_ignore = { 'terminal' },
  ft_ignore = { 'oil' },
  segments = {
    {
      sign = { name = { "Diagnostic" }, maxwidth = 2, auto = true },
      click = "v:lua.ScSa"
    },

https://github.com/luukvbaal/statuscol.nvim/assets/24765272/37880f7f-c0a5-492b-b98d-b80a77b1fb52

luukvbaal commented 1 year ago

What Neovim version are you using? There have been fixes regarding the statuscolumn width that are only in the nightly builds.

nyngwang commented 1 year ago

when testing: (still the current HEAD, just checked.)

NVIM v0.10.0-dev-316+ge124672ce
Build type: Release
LuaJIT 2.1.0-beta3
luukvbaal commented 1 year ago

Going to need a more complete repro then, I can't reproduce on HEAD.

nyngwang commented 1 year ago

I'm sorry that I cannot provide minimal.lua at the moment since it requires adding LSP config in it too. My dotfiles is kinda complex. The following script is the full setup for statuscol.nvim:

use {
  'luukvbaal/statuscol.nvim',
  config = function ()
    local builtin = require('statuscol.builtin')
    require('statuscol').setup {
      relculright = true,
      bt_ignore = { 'terminal' },
      ft_ignore = { 'oil' },
      segments = {
        {
          sign = { name = { "Diagnostic" }, maxwidth = 2, auto = true },
          click = "v:lua.ScSa"
        },
        { text = { builtin.lnumfunc }, click = 'v:lua.ScLa', },
        {
          sign = { name = { ".*" }, maxwidth = 1, colwidth = 1, auto = true },
          click = "v:lua.ScSa"
        },
        {
          text = { ' ', builtin.foldfunc, ' ' },
          condition = { builtin.not_empty, true, builtin.not_empty },
          click = 'v:lua.ScFa'
        },
      },
      clickhandlers = {
        FoldOther = false,
      },
    }
    vim.opt.foldcolumn = '0'
    vim.keymap.set('n', '<Leader>as', function ()
      if vim.wo.foldcolumn == '1'
        then vim.opt.foldcolumn = '0'
        else vim.opt.foldcolumn = '1'
      end
      vim.cmd('redraw')
    end)
  end
}
luukvbaal commented 1 year ago

There is a functionaltest in the neovim repo that simulates what would happen with custom sign segments in a statuscolumn when (un)placing signs: https://github.com/neovim/neovim/blob/e124672ce9a81e0ca32e6c30ea3730ad5fe981af/test/functional/ui/statuscolumn_spec.lua#L588.

As long as that test keeps passing, it's hard to tell what plugin or option could interfere with the statuscolumn width not being reset upon sign removal.

luukvbaal commented 1 year ago

What does :set numberwidth say?

nyngwang commented 1 year ago

What does :set numberwidth say?

:set numberwidth? gives me numberwidth=4.

I suspect this is related: I'm using a plugin to auto-save the current buf for me. Is there any autocmd that statuscol uses to trigger the update?

update: even without the auto-save, calling :w manually didn't trigger any update of the numberwidth.

luukvbaal commented 1 year ago

If it says 4 then it is expected that it will not reduce in with with that repro. It's unexpected that it is not at least 4 wide to begin with. But I recommend setting numberwidth to 1 so that the width is completely determined by the actual statuscolumn content.

nyngwang commented 1 year ago

But I never set numberwidth explicitly in my dotfiles. Did you mean I should add one line in my dotfiles to set it to 1?

Oops, I just found that: But if the default value is 4, can statuscol support us to set it to 1 be default to prevent the behavior I just described?

'numberwidth' 'nuw' number  (default: 4)
            local to window
luukvbaal commented 1 year ago

IDK, overwriting the users' value might also lead to bug reports. Might be better to just recommend a value of 1 in the README.

nyngwang commented 1 year ago

But setting it to 1 doesn't help. I got the same result as the DEMO in my OP.

nyngwang commented 1 year ago

I just created a workaround for this, which I think could be added to statuscol.nvim:

vim.api.nvim_create_autocmd({ 'CursorHold' }, {
  callback = function ()
    vim.wo.numberwidth = vim.wo.numberwidth
  end
})

https://github.com/luukvbaal/statuscol.nvim/assets/24765272/0a16de4c-6344-4185-b86c-d6b0b5330a40

luukvbaal commented 1 year ago

But setting it to 1 doesn't help. I got the same result as the DEMO in my OP.

Then I still need a way to reproduce this first. The statuscolumn width is already supposed to be reset and rebuild upon sign removal in neovim. I'd rather fix this in neovim if that doesn't always happen than add workarounds.

nyngwang commented 1 year ago

Understood. I think I will keep my workaround locally. I, unfortunately, don't have enough time to produce the minimal.lua recently... You could keep this open and wait for someone who also encounters this in the future. (you can still close it if you want)

hbiel commented 11 months ago

I'm experiencing the same issue. Using the following minimal config i can reproduce this on the latest nightly 0.10.0-dev-64c2c7c.

vim.o.nu = true
vim.o.relativenumber = true

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "https://github.com/folke/lazy.nvim.git",
        "--branch=stable",
        lazypath,
    })
end
vim.opt.runtimepath:prepend(lazypath)

require("lazy").setup({
    spec = {
        "luukvbaal/statuscol.nvim",
        config = function()
            require("statuscol").setup({
                segments = {
                    {
                        condition = { function() return not vim.tbl_contains({ "i" }, vim.fn.mode()) end, },
                        text = { function() return "%l %r" end, },
                    },
                    {
                        condition = { function() return vim.tbl_contains({ "i" }, vim.fn.mode()) end, },
                        text = { function() return "%l" end, },
                    },
                },
            })
        end,
    },
})

It's also not specific to this plugin but also happens on heirline.nvim. Hope this helps.

luukvbaal commented 11 months ago

Hmm that repro seems quite different to the original issue. What exactly do you expect to happen in that repro? If you expect the width to decrease, the repro should also include vim.o.numberwidth = 1. If you expect the entire statuscolumn to update when entering/leaving insert mode, I'm not sure if that should happen if the width of the statuscolumn doesn't decrease, without explicitly asking for it.

luukvbaal commented 11 months ago

I think this works like you would expect @hbiel:

vim.o.nu = true
vim.o.relativenumber = true
vim.o.numberwidth = 1

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "https://github.com/folke/lazy.nvim.git",
        "--branch=stable",
        lazypath,
    })
end
vim.opt.runtimepath:prepend(lazypath)

require("lazy").setup({
    spec = {
        "luukvbaal/statuscol.nvim",
        config = function()
            require("statuscol").setup({
                segments = {
                    {
                        condition = { function() return not insert end, },
                        text = { function() return "%l %r" end, },
                    },
                    {
                        condition = { function() return insert end, },
                        text = { function() return "%l" end, },
                    },
                },
            })
        end,
    },
})

local id = vim.api.nvim_create_augroup("InsertRedraw", {})
vim.api.nvim_create_autocmd("InsertEnter", { group = id, callback = function()
    _G.insert = true
    vim.cmd("redraw!")
end})
vim.api.nvim_create_autocmd("InsertLeave", { group = id, callback = function()
    _G.insert = false
    vim.cmd("redraw!")
end})

I think it is expected that these autocommands are required.

hbiel commented 11 months ago

Hmm that repro seems quite different to the original issue. What exactly do you expect to happen in that repro? If you expect the width to decrease, the repro should also include vim.o.numberwidth = 1. If you expect the entire statuscolumn to update when entering/leaving insert mode, I'm not sure if that should happen if the width of the statuscolumn doesn't decrease, without explicitly asking for it.

I see. I just assumed that this is related somehow.

I think this works like you would expect @hbiel: ...

Thanks for the input! I still have issues with this example though: The width of the statuscolumn gets reduced only after adding a new line in insert mode not immediately on entering insert mode.

luukvbaal commented 11 months ago

Yeah currently neovim only rebuilds the entire statuscolumn whenever the signcolumn is invalid and whenever the number of lines in the buffer changes. I don't think neovim should implicitly rebuild the statuscolumn whenever the mode changes but perhaps it needs a way to force a rebuild. For now I guess the only hacky way to force that is to append/delete a line or place/unplace a sign.

hbiel commented 11 months ago

I agree. No need to do it implicitly for everyone. But some way to trigger a redraw would be nice.

Thanks for the explanation!

luukvbaal commented 11 months ago

This InsertEnter autocommand forces a statuscolumn rebuild:

vim.api.nvim_create_autocmd("InsertEnter", { group = id, callback = function()
    _G.insert = true
    vim.o.statuscolumn = vim.o.statuscolumn
end})

If the linked neovim PR gets merged, a :redraw will be sufficient.