lifepillar / vim-mucomplete

Chained completion that works the way you want!
MIT License
911 stars 18 forks source link

Minimum prefix length is not being used when backspacing over a word. #170

Closed prati0100 closed 4 years ago

prati0100 commented 4 years ago

Hi,

I have a fairly large tags file on a rather slow computer, and I'm using omnifunc = ccomplete#Complete. At 2 prefix length there are too many possible suggestions, and so vim freezes for a few seconds. So I set the minimum prefix length to 4. This speeds up the suggestion speed.

The problem is that when I mis-type something, and I try deleting, the suggestions are triggered always regardless of the minimum prefix length. This results in me seeing a huge freeze because of vim computing all those possible suggestions.

For example if I type (* is the cursor position)

fo*: suggestions don't show up (working as expected). fooo*: suggestions show up (working as expected).

Now if I backspace two characters: fo*: suggestions show up (not working as expected).

lifepillar commented 4 years ago

MUcomplete does absolutely nothing as long as the pop-up menu is open, and it has no control over the behaviour of completions while you delete characters. That's Vim's defaul behaviour. I suggest that you press CTRL-E before deleting, to dismiss the pop-up menu. Or define a custom mapping, e.g.:

Edit: the following snippet is wrong. Please read my post below.

    fun! s:dismiss_or_delete()
      return pumvisible()
            \ && len(mucomplete#get_compl_text()) <= get(g:, 'mucomplete#minimum_prefix_length', 4)
            \ ? "\<c-e>\<bs>" : "\<bs>"
    endf
    inoremap <expr> <bs> <sid>dismiss_or_delete()

With the above mapping, when you press Backspace and the popup menu is open and there are no more than g:mucomplete#minimum_prefix_length non-whitespace characters before the cursor, the popup menu is closed, then a character is deleted. In all other circumstances, Backspace behaves as usual. Hope this helps.

prati0100 commented 4 years ago

This works. Thanks for always being so helpful :-)

PS: The snippet you gave has an off-by-one:

-   \ && len(mucomplete#get_compl_text()) <= get(g:, 'mucomplete#minimum_prefix_length', 4)
+   \ && len(mucomplete#get_compl_text()) <= get(g:, 'mucomplete#minimum_prefix_length', 4) + 1
lifepillar commented 4 years ago

There is a mistake in my suggested solution. You cannot use mucomplete#get_compl_text() because that function returns (more or less) all the text before the cursor, not just a word. Something like this should be used instead (modulo off-by-one errors):

    fun! s:dismiss_or_delete()
      return pumvisible()
            \ && len(matchstr(getline('.'), '\S*\%'.col('.').'c')) <= get(g:, 'mucomplete#minimum_prefix_length', 4)
            \ ? "\<c-e>\<bs>" : "\<bs>"

    endf
    inoremap <expr> <bs> <sid>dismiss_or_delete()

Btw,

I have a fairly large tags file on a rather slow computer

Consider setting g:mucomplete#completion_delay to some positive value (see :help g:mucomplete#completion_delay). By doing so, you won't be slowed down by completion while typing.

prati0100 commented 4 years ago

There is a mistake in my suggested solution. You cannot use mucomplete#get_compl_text() because that function returns (more or less) all the text before the cursor, not just a word.

That explains the off-by-one I noticed. The line I tested on was indented by one tab, and so that is probably why the completion triggered with 3 characters.

Consider setting g:mucomplete#completion_delay to some positive value (see :help g:mucomplete#completion_delay). By doing so, you won't be slowed down by completion while typing.

Thanks for the suggestion. This coupled with the above function works pretty well for most cases. The only problem now is that there is a long freeze when I use any struct variable (when I type foo->). Guess I'll have to go check out the ccomplete source to speed it up.

prati0100 commented 4 years ago

The only problem now is that there is a long freeze when I use any struct variable (when I type foo->).

Actually, I found the following when going through the mucomplete documentation:

When auto-completion is on, by default most completion methods are enabled when there are at least two keyword characters in front of the cursor (see 'iskeyword').

So, I set iskeyword=a-z,A-Z,48-57,_ so -> doesn't trigger completion. But when I type foo->, the completion is still triggered.

Am I interpreting the documentation wrong or is this a bug? Should I open a separate issue?

lifepillar commented 4 years ago

- and > are not keyword characters anyway. You may change the regular expression that triggers a given completion method for a given filetype by setting g:mucomplete#can_complete. See :help g:mucomplete#can_complete for an example.

lifepillar commented 4 years ago

Specifically, you may try something like:

" Trigger completion in C buffers only when there are at least four keyword chars before the cursor
let s:c_cond = { t -> t =~# '\k\{4}$' }
let g:mucomplete#can_complete = {}
let g:mucomplete#can_complete.c = { 'omni': s:c_cond }

Here, I am assuming that you are working with C.

Edit: fix typo.

prati0100 commented 4 years ago

Thanks. This works great.

For future readers, there is one small typo here:

let s:cond = { t -> t =~# '\k\{4}$' }

s/cond/c_cond/

lifepillar commented 4 years ago

there is one small typo

Fixed, thanks.