nvim-lualine / lualine.nvim

A blazing fast and easy to configure neovim statusline plugin written in pure lua.
MIT License
5.93k stars 461 forks source link

Lualine replaces statusline created by vim-visual-multi #951

Open farzadmf opened 1 year ago

farzadmf commented 1 year ago

Self Checks

How to reproduce the problem

  1. Start with the minimal config below
  2. Open a new buffer and have a couple of lines, something like:
    hello world
    I say hello
  3. Go to hello in either line and press Ctrl-n (default keymap to start visual-multi mode)
  4. VM (visual multi)'s update to statusline doesn't appear, or randomly appears and disappears

Expected behaviour

When using vim-airline, VM (visual multi), when enabled, seems to "take over" the status line, and it creates a status line with information about multi-cursors, which is updated as multi-cursors move around etc.

Actual behaviour

Seems like lualine doesn't let VM have the statusline and keeps clearing it and redrawing it.

Minimal config to reproduce the issue

call plug#begin("/private/tmp/algo/lualine/.local/share/nvim/plugged")

Plug 'nvim-lualine/lualine.nvim'
Plug 'https://github.com/mg979/vim-visual-multi'

call plug#end()

lua << END

require'lualine'.setup {
}
END

Additional information

jamestansx commented 1 year ago

In the meantime, you could manually hide/unhide lualine with autocmd.

Example ```lua vim.api.nvim_create_autocmd({ 'User' }, { pattern = 'visual_multi_start', callback = function() require('lualine').hide() end }) vim.api.nvim_create_autocmd({ 'User' }, { pattern = 'visual_multi_exit', callback = function() require('lualine').hide({unhide=true}) end }) ```

Ref: VM-faq

farzadmf commented 1 year ago

Thank you @jamestansx for the tip. it's a good start, but unfortunately I don't see VM's status messages either when I do this 🙁

jamestansx commented 1 year ago

I ain't sure why, could you try to reproduce with the following minimal config?

-- repro.lua
local root = vim.fn.fnamemodify("./.repro", ":p")
for _, name in ipairs({ "config", "data", "state", "cache" }) do
        vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/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", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

vim.opt.termguicolors = true

-- install plugins
local plugins = {
  {
    'nvim-lualine/lualine.nvim',
    config = true,
  },
  {
    'mg979/vim-visual-multi',
    version = false,
  },
}

vim.api.nvim_create_autocmd({ 'User' }, {
  pattern = 'visual_multi_start',
  callback = function()
    require('lualine').hide()
  end
})

vim.api.nvim_create_autocmd({ 'User' }, {
  pattern = 'visual_multi_exit',
  callback = function()
    require('lualine').hide({unhide=true})
  end
})

require("lazy").setup(plugins, {
        root = root .. "/plugins",
})

vim.cmd [[colorscheme habamax]]

nvim -u /path/to/repro.lua

BrunoMSantos commented 1 year ago

Any development on this one?

I'm currently setting lualine 'mode' element with a custom format function:

        lualine_a = {
          {
            'mode',
            fmt = function(mode)
              return vim.b['visual_multi'] and mode .. ' - MULTI' or mode
            end
          },
        },

Together with this in VM's init:

      vim.g.VM_set_statusline = 0 -- disable VM's statusline updates to prevent clobbering
      vim.g.VM_silent_exit = 1    -- because the status line already tells me the mode

What I still haven't worked out is how to get the vm-infoline in there as well. I see the relevant command in the default key binding: n \\l @<Plug>(VM-Show-Infoline), but I can't figure out how to run those types of commands :man_facepalming: Once I figure that out, it should be trivial to construct a custom component which wraps that though.

I would also like to do something theme wise to make it stand out a bit more, but haven't really looked into it yet.

BrunoMSantos commented 1 year ago

Ok, still no clue how to run that command specifically, but found out its implementation in VM's source code and managed to create a custom component for lualine with it:

{
  function()
    if vim.b['visual_multi'] then
      local ret = vim.api.nvim_exec2('call b:VM_Selection.Funcs.infoline()', { output = true })
      return string.match(ret.output, 'M.*')
    else
      return ''
    end
  end
}

It looses the colours of course and I'm using the match to get rid of some escapes(?) at the start of the string, but it works! Also wonder if there's a better way to do the weird looking exec2 line, but that's the only way I found of capturing the output instead of letting it print over the command line.

farzadmf commented 1 year ago

@BrunoMSantos that's something at least

But it's sad. When I start VM, I see its status for a split second before it's replaced by lualine.

The original comment provided a way to hide/unhide lualine with an autocmd, but lualine seems to take the whole status line with it when being hidden, so nothing else appears.

This is really sad as VM is a plugin a main 100000000 times a day and I can't live without it; it would be so nice if we could find a solution 🙁

BrunoMSantos commented 1 year ago

Have you tried what I posted? That is the solution. And if you improve on it, feel free to share.

farzadmf commented 1 year ago

I did, but the "built-in" status from VM looks nicer; it has colors and everything, and, for some reason, it looks shorter than this solution, not sure why

But yeah, your solution works

EDIT: had forgotten to set vim.g.VM_set_statusline = 0, and it looks nice. I just wish we had some colors (as you also mentioned that they're missing)

BrunoMSantos commented 1 year ago

You can easily shorten the output of the lualine component above to your taste. As for colours, yeah... maybe that is easy too, but I haven't looked into it.

farzadmf commented 1 year ago

You're right. I'm just too lazy to look into things; I just want something that "works" 😆

musjj commented 1 year ago

@jamestansx

I ain't sure why, could you try to reproduce with the following minimal config?

Weirdly enough, I can't reproduce it in the minimal config. I'm not sure which of my plugins is causing this behavior.

I tried using the default config for lualine, but the issue still happens in my config. I just don't have a clue on what could possible be interfering.

My config has grown pretty hairy recently, so the good-old halving till it works is kinda hard to do.

EDIT: Okay, I figured it out. It was because I set my laststatus to 0 (so that the default statusline is not visible in my dashbord, before lualine is lazy-loaded). Lualine recorded the user's laststatus value and restored it when you call the hide function. That caused the statusline to disappear. To fix it, set your laststatus to 2 (or other sensible values) before starting lualine.

nnhutan commented 10 months ago
local function get_visual_multi()
    local result = vim.fn["VMInfos"]()
    -- local current = result.current
    -- local total = result.total
    local ratio = result.ratio
    local patterns = result.patterns
    -- local status = result.status
    return "%#St_InsertMode# "
        .. " MULTI "
        .. "%#St_lspWarning#  "
        .. patterns[1]
        .. " "
        .. "%#StText#"
        .. " "
        .. ratio
end

Another approach to get useful information for statusline. We can use this to add to the custom section in the statusline

BrunoMSantos commented 10 months ago
local function get_visual_multi()
  local result = vim.fn["VMInfos"]()
  -- local current = result.current
  -- local total = result.total
  local ratio = result.ratio
  local patterns = result.patterns
  -- local status = result.status
  return "%#St_InsertMode# "
      .. " MULTI "
      .. "%#St_lspWarning#  "
      .. patterns[1]
      .. " "
      .. "%#StText#"
      .. " "
      .. ratio
end

Another approach to get useful information for statusline. We can use this to add to the custom section in the statusline

Thanks for sharing, managed to improve mine with this. One thing though, what are the '%#St_lspWarning#' bits about? Can't find that in documentation and don't see any difference between having those or not.

nnhutan commented 10 months ago
local function get_visual_multi()
    local result = vim.fn["VMInfos"]()
    -- local current = result.current
    -- local total = result.total
    local ratio = result.ratio
    local patterns = result.patterns
    -- local status = result.status
    return "%#St_InsertMode# "
        .. " MULTI "
        .. "%#St_lspWarning#  "
        .. patterns[1]
        .. " "
        .. "%#StText#"
        .. " "
        .. ratio
end

Another approach to get useful information for statusline. We can use this to add to the custom section in the statusline

Thanks for sharing, managed to improve mine with this. One thing though, what are the '%#St_lspWarning#' bits about? Can't find that in documentation and don't see any difference between having those or not.

Those are just the custom highlight groups for my custom statusline. You can arbitrarily use the information in the table returned when calling vim.fn["VMInfos"]()

BrunoMSantos commented 10 months ago

Ah, right. Yeah, don't think I want that, but thanks for the tips ;)

webdevcat-me commented 1 month ago

I wanted to have vim-visual-multi's special_statusline modes visible in the statusline whenever they were active, so here's what I ended up going with:

vim.g.VM_set_statusline = 0
vim.g.VM_silent_exit = 1

local function vm_mode()
  return vim.iter(string.gmatch(vim.fn['vm#themes#statusline'](), "%S+")):nth(2)
end

local function vm_status()
  return vim.fn['VMInfos']().status or ''
end

require('lualine').setup({
  sections = {
    lualine_a = {{'mode', fmt = function(mode) return vm_mode() or mode end}},
    lualine_b = {vm_status, 'branch', 'diff', 'diagnostics'},
  },
})

-- A redraw is absolutely necessary to see the special statusline modes.
-- And it has to be asynchronous. A synchronous call will not work,
-- hence the use of `defer_fn()` with a delay of 0.
vim.api.nvim_create_autocmd({'CmdlineEnter'}, {
  pattern = {'@'},
  callback = function(ev)
    if vim.b.visual_multi then
      local delay = 0
      vim.defer_fn(function() vim.cmd('execute "redrawstatus"') end, delay)
    end
  end
})

Here's what it looks like in VM visual line mode:

Screenshot from 2024-07-21 19-28-56

And here it is in the special "Run visual" mode (<Leader>+v after switching to extend mode with <Tab>):

Screenshot from 2024-07-21 19-30-17

Without the redraw, the special modes would all just look like this:

Screenshot from 2024-07-21 19-36-28

And this is when VM isn't active:

Screenshot from 2024-07-21 19-51-05