Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert mode is slow and laggy with this source enabled #91

Open
rbuchberger opened this issue Dec 11, 2023 · 12 comments
Open

Insert mode is slow and laggy with this source enabled #91

rbuchberger opened this issue Dec 11, 2023 · 12 comments
Assignees

Comments

@rbuchberger
Copy link

Hello! Firstly, thanks a ton for this awesome plugin. I use it every day to earn a living.

I'm having an issue very similar to this one in the main cmp repo: hrsh7th/nvim-cmp#1608
Basically, when this plugin is enabled, typing in insert mode becomes slow and laggy. It's most noticeable with typescript files in big projects (Slow language server), but I can see a difference with simple rust files as well.

Asciinema recording: (Note the jumpiness when holding the 'a' key) - asciicast

My neovim config
My cmp config specifically

Please let me know if I can do any more troubleshooting! Thanks.

@quangnguyen30192
Copy link
Owner

Thank you for using this plugin, I don't have that typescript project which has the large codebase. I will try to investigate

@rbuchberger rbuchberger changed the title Insert mode is slow and lagy with this source enabled Insert mode is slow and laggy with this source enabled Dec 14, 2023
@rbuchberger
Copy link
Author

Thanks! I'm pretty sure it's not specific to typescript, it just has to do with slow completion results. You can probably test with a well placed sleep function. Is it possible that some function is running synchronously when it should be async?

@ckarren
Copy link

ckarren commented Dec 15, 2023

Just wanted to add that I'm experiencing the same issue regardless of filetype.

@bartels
Copy link

bartels commented Dec 20, 2023

I noticed insert mode being lag immediately after trying this plugin. I have honza/vim-snippets installed. Disabling it made things much better. But that means not having any packaged snippets to use.

Then I tried disabling just the snipmate support with ultisnip settings: let g:UltiSnipsEnableSnipMate = 0.
And that seems to makes things much better as well, but still allows me to use

Could the lag be from having many snippets installed?

@wookayin
Copy link

wookayin commented Jan 25, 2024

The reason is on this line:
https://github.com/quangnguyen30192/cmp-nvim-ultisnips/blob/main/lua/cmp_nvim_ultisnips/source.lua#L27

function source.complete(self, _, callback)
  local items = {}
  local snippets = cmpu_snippets.load_snippets(self.expandable_only) -- -------------HERE

which then calls cmp_nvim_ultisnips#get_current_snippets.

This is called so many times, on every single character. This is quite an inefficient implementation.

get_current_snippets is an awfully stateful function, vim_helper.buf.line_till_cursor reads the line until the cursor. It's even slower due to RPC. Instead, we can use cmp's completion context (see cmp.Context) which already provides the completion string.

The snippet results can be cached as they usually do not change. We can reload the snippet data only when needed, e.g. reading only once when the buffer loads (and invalidate the cache when UltiSnip refreshes).

Or being asynchronous when loading the available snippet items would be another option.

@quangnguyen30192
Copy link
Owner

Thanks for the heads up, that's a good suggestion. I'll try to make it great.

@wookayin
Copy link

Thanks! Performance problems are non-trivial, but thanks for writing the great plugin. Please let me know if there's anything I can help you with. In my free cycle I will try to see if I can suggest more concrete ideas for improvement.

@cristobaltapia
Copy link

cristobaltapia commented May 20, 2024

So, I was being bothered by this too, so I tried to take a look at this. But since I am not good at lua, I asked chatGPT. It came up with this solution, which works much faster:

function source.complete(self, _, callback)
  local items = {}

  -- Get all UltiSnips snippets for the current filetype
  local snippets = vim.fn["UltiSnips#SnippetsInCurrentScope"]()

  -- Iterate through each snippet and format it for nvim-cmp
  for trigger, snippet in pairs(snippets) do
    table.insert(items, {
      label = trigger,
      insertText = trigger,
      kind = cmp.lsp.CompletionItemKind.Snippet,
      documentation = {
        kind = cmp.lsp.MarkupKind.Markdown,
        value = snippet,
      },
    })
  end

  -- Invoke the callback with the completion items
  callback({ items = items, isIncomplete = false })
end

function source.resolve(self, completion_item, callback)
  callback(completion_item)
end

The only problem is the documentation, which is not showing. I could not solve that problem, even with the help of ChatGPT

Did some editing to fix the issue with the description.

@quangnguyen30192
Copy link
Owner

Hey guys, thanks for your patience when using this plugin. Most of you guys have experienced in this performance issue, this is quite tricky to fix because underneath, utilsnips is using python as a bridge to work with the snippet system. This is we can't fully control to make performance better in term of using throttling, debouncing or caching, particularly to this plugin itself.

However nvim cmp offers us several options we can try regarding the performance improvement https://github.com/hrsh7th/nvim-cmp/blob/main/doc/cmp.txt#L441C1-L472

cmp will serve as a proxy, that can do throttling or debouncing before accessing to the source of the snippet.

Please try and let me know

@quangnguyen30192
Copy link
Owner

Thanks @cristobaltapia for your code (or your AI's code) but this is not enough sources which are also fetched from the snippet python API where the performance bottle neck is

@quangnguyen30192 quangnguyen30192 self-assigned this May 21, 2024
@cristobaltapia
Copy link

Yes, I don't get the snippet for the preview, but I get the completions for the snippets and their description, which is enough for me at least. I'm looking forward for a better solution though (it is nice to have the snippet preview).

@smjonas
Copy link
Collaborator

smjonas commented May 27, 2024

get_current_snippets is an awfully stateful function, vim_helper.buf.line_till_cursor reads the line until the cursor. It's even slower due to RPC. Instead, we can use cmp's completion context (see cmp.Context) which already provides the completion string.

@wookayin in a recent commit, I have moved the Python code to a separate file and reduced the "statefulness" of the function. While trying to implement your suggestion above, do you know how I could pass an arbitrary Lua string to a Python function with pyeval? This is a place where the function is now called:

snippets_for_ft[ft] = vim.fn.pyeval("ultisnips_utils.fetch_current_snippets(False)")

Simply using string concatenation wouldn't work since the completion string could contain special characters like ".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants