nvim-lua / lsp-status.nvim

Utility functions for getting diagnostic status and progress messages from LSP servers, for use in the Neovim statusline
MIT License
625 stars 41 forks source link

Lag with rust-analyzer indexing #36

Closed onsails closed 3 years ago

onsails commented 3 years ago

With lsp_status.register_progress() neovim lags on each typed character. Apparently it's happening due to lots of indexing progress messages from rust-analyzer. Also the lag is noticeable in process of initial indexing just after rust-analyzer server started inside a project.

The details are here

wbthomason commented 3 years ago

Thanks for the report! Can you send the relevant snippet(s) of your config?

I suppose we need some sort of rate limiting, though I'm not entirely sure what policy that should use.

onsails commented 3 years ago

besides regular setup made just as instructed in readme, I have the following lualine config:

local lualine = require('lualine')
lualine.status()

local lsp_status = require('lsp-status');
local lspconfig = require('lspconfig'); 

lsp_status.register_progress()
local function lsp()
    return require('lsp-status').status()
end
lualine.sections.lualine_c = { lsp }
lualine.theme = 'forest_night'

and rust-analyzer is setup this way:

lspconfig.rust_analyzer.setup({
    capabilities = capabilities,
    on_attach = on_attach,
    settings = {
        ["rust-analyzer"] = {
            cargo = {
                loadOutDirsFromCheck = true,
                allFeatures = true
            },
            procMacro = {
                enable = true
            },
            checkOnSave = {
                command = "clippy"
            },
        }
    },
    root_dir = util.root_pattern('Cargo.lock', '.git'),
})
wbthomason commented 3 years ago

I'm wondering if this has to do with how often lualine evaluates the lsp component. I haven't been able to reproduce the issue yet, but - looking through status, diagnostics, and messages, I'm not sure where redundant work can be avoided. Those functions mostly just look through a table filled by a callback when message events come in. It's possible that the implementation could be optimized (e.g. table.insert is used a lot and could be replaced, there are a few places where maybe we could skip some loops?), but I'm surprised that this would cause so severe an error if the component isn't being invoked too often.

Another alternative (and maybe the best option) would be to change the plugin to generate a statusline string on a fixed frequency, then make status query this string. I'm not likely to get to this work anytime soon, but I'd happily review a PR for it.

Also, if you have a public repo I could use to reproduce this issue, that would be very helpful.

onsails commented 3 years ago

@wbthomason thank you for investigating it. As mentioned by @kid in https://github.com/neovim/nvim-lspconfig/issues/395 the issue also happens with vim-airline. Furthermore until I switched to neovim lsp I've been using vim-airline + coc, rust-analyzer status messages were smooth back then thanks to throttling/debounce implemented in coc I suppose.

I've managed to create a minimal reproducer. It requires cargo and rust-analyzer available in $PATH, starting command is in readme.

You can notice that the spinning rectangle is freezing and if you hold down l key for example you will notice it's lagging.

wbthomason commented 3 years ago

Beautiful, thanks for the repo to reproduce the issue. I'll give it a go as soon as I have a chance.

nerosnm commented 3 years ago

I also get a little bit of lag for a moment each time right after I save, although that goes away quickly each time and doesn't come back until I save again. I'm using rust-analyzer and lightline.vim.

Edit: okay, it doesn't just happen when I save, it also happens when inserting lines and text. It's unfortunately pretty disruptive.

wbthomason commented 3 years ago

Sorry, I still have not had time to look into this in depth. I tried to reproduce it using @onsails's minimal repro setup, but can't - I don't see any lag.

At a guess, this is just happening because we update the statusline on every new message, and some statuslines take a long time to draw. It looks like coc-rust-analyzer does eager updates too (https://github.com/fannheyward/coc-rust-analyzer/blob/ead54f58cef1275263fcf6a7281ce14a472c29ea/src/ctx.ts#L59-L60), so there must be something happening in coc.nvim's StatusBarItem type (or somewhere related) to avoid updating so frequently.

If anyone wants to take a stab at a PR for this, I'd be happy to help guide things from the lsp-status end. I would suggest looking at coc's StatusBarItem code and replicating any debounce logic here.

joshuachp commented 3 years ago

@wbthomason thank you for investigating it. As mentioned by @kid in neovim/nvim-lspconfig#395 the issue also happens with vim-airline. Furthermore until I switched to neovim lsp I've been using vim-airline + coc, rust-analyzer status messages were smooth back then thanks to throttling/debounce implemented in coc I suppose.

I've managed to create a minimal reproducer. It requires cargo and rust-analyzer available in $PATH, starting command is in readme.

You can notice that the spinning rectangle is freezing and if you hold down l key for example you will notice it's lagging.

I had the lag before, but can not reproduce it with this test.

I want to propose an optimization. Instead of calculating the statusline text in statusline.status() we calculate it in the lsp_handler and set a buffer variable with the result of statusline.lsp_status(). When we need to redraw the statusline we just return this variable. Also, I added a variable to check if we need to render the new statusline only if the text changed.

I created a draft PR with the changes #42 if you can please test if it improves the performances.

nerosnm commented 3 years ago

I'm not the original reporter, but I just wanted to chime in and say I tested your branch @joshuachp, and it does seem to solve the problem for me. I'll keep using it and see if that holds true long-term.

Edit: Unfortunately, after using it a bit more, I'm still seeing the same lag

joshuachp commented 3 years ago

I'm not the original reporter, but I just wanted to chime in and say I tested your branch @joshuachp, and it does seem to solve the problem for me. I'll keep using it and see if that holds true long-term.

Edit: Unfortunately, after using it a bit more, I'm still seeing the same lag

Thanks for testing, I think that in the case of rust-analyzer we are hitting a limitation of neovim if we redraw on every update, it will always lag no matter what. I will try to limit the number of redraws with next commit.

wbthomason commented 3 years ago

Closed by #43 and #45