lifepillar / vim-mucomplete

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

`cmd` method should be handled differently #42

Closed lacygoill closed 7 years ago

lacygoill commented 7 years ago

Hello,

If I write this in /tmp/vimrc.vim:

set cot=menu,menuone
set rtp+=~/.vim/plugged/vim-mucomplete/

let g:mucomplete#chains = {}
let g:mucomplete#chains.default = ['cmd', 'keyn']

" foobar
" foo

And if I start Vim like this:

vim -Nu /tmp/vimrc.vim /tmp/vimrc.vim

I position the cursor after the last foo and hit Tab: the text is not completed into foobar like I expected. If I replace the cmd method with another method, which is also unable to complete foo, like omni:

 let g:mucomplete#chains.default = ['omni', 'keyn']

This time, foo is completed into foobar.

It seems the cmd method is special, because when it fails the result of the next keys is inconsistent. On my system, if I insert foo, hit C-x C-v, then C-x C-n or C-x C-p, I expect C-x C-v to fail, then C-x C-n to complete the text by looking at the other keywords in the current file. That's not what Vim does. It just seems to retry C-x C-v.

For all the other standard completion mappings, C-x C-d, C-x C-o, C-x C-t …, the first C-x seems to make us leave the CTRL-X sub-mode, and then the next key (C-d, C-o, C-t, …) is interpreted as if we were in insert mode.

See what happens with the following chain ['cmd', 'defs', 'keyp']: http://imgur.com/a/iwqvK

The text is:

" foobar
    " foo

After hitting Tab, the result is:

" foobar
" foobar

The keyp method was correctly applied, but the indentation of the line was changed, which was unexpected. The cause is, again, the cmd method. After it failed, the defs method was tried. C-x C-d was hit. C-x made us leave CTRL-X sub-mode, and C-d deleted one level of shiftwidth at the start of the line.

The interaction with the plugin is even weirder. Consider this chain ['cmd', 'omni', 'keyp'] and this text:

" foobar
" foo| 3

The pipe represents the cursor. Hit Tab. What should happen? Without the plugin, here's the result you get:

" foobar
" foo foo2

The C-o from C-x C-o is interpreted as entering the normal sub-mode (described in :h i^o). And the C-x from the next C-x C-p is interpreted as the normal decrement command (:h ^x). Finally, the last C-p inserts the previous word which here is foo.

Here's a gif showing the whole sequence: http://imgur.com/a/2KikK

But that's not what the plugin does, it just seems to stop at the first failing method cmd: http://imgur.com/a/cG4Oy

I don't understand. But it seems the only solution to make the cmd method work reliably would be to prefix all the methods with the keys stored in s:cnp. I don't know if it's worth the trouble, because, when autocompletion is enabled, it means at least 2 additional keys to hit for each method to try, after each character inserted.

Another alternative would be to remove the method entirely from the plugin to avoid future bug reports.

lacygoill commented 7 years ago

Or you could apply some kind of logic:

if s:compl_methods contains the cmd method, then use a modified version of s:compl_mappings in which all the completion mappings are prefixed with s:cnp, otherwise use the default version.

But again, I don't know if it's worth the trouble and what would be the impact on autocompletion.

lifepillar commented 7 years ago

It would be worth reporting the different behavior of <c-x><c-v>. It looks like a bug to me.

That said, given the limited scope of <c-x><c-v>, I'd rather remove it than trying to solve all the problems it creates.

lacygoill commented 7 years ago

I agree with you, you should probably remove the method altogether.

I will try to submit a bug report on Vim's bug tracker, but it's complex. There are other inconsistent key sequences in CTRL-X sub-mode. I don't remember them all, I'll see if I can.

lacygoill commented 7 years ago

Inside the verify_completion() function, there's this line:

return s:pumvisible ? s:act_on_pumvisible() : (s:cycle ? s:next_method_cyclic() : s:next_method())

If s:pumvisible is not set, meaning the current method failed, and if the current method is cmd, we could prefix:

(s:cycle ? s:next_method_cyclic() : s:next_method())

with s:cnp.

It would give something like:

return s:pumvisible ? s:act_on_pumvisible() : (s:compl_methods[s:i] ==# 'cmd' ? s:cnp : '') . (s:cycle ? s:next_method_cyclic() : s:next_method())

I haven't tested it yet, but I thought that maybe it could work. Not sure it's worth making the code more complex just for cmd, but it might be useful.

lacygoill commented 7 years ago

Weird, I have the following error:

Error detected while processing function mucomplete#verify_completion:
line    3:
E121: Undefined variable: s:cnp
Error detected while processing function mucomplete#verify_completion:
line    3:
E15: Invalid expression: s:pumvisible ? s:act_on_pumvisible() : (s:compl_methods[s:i] ==# 'cmd' ? s:cnp : '') . (s:cycle ? s:next_method_cyclic() : s:next_method())

Why doesn't it recognize s:cnp?

Anyway, it seems to work and fix the bug when I replace s:cnp with "\<c-g>\<c-g>" or get(s:, 'cnp', "\<c-g>\<c-g>"):

return s:pumvisible ? s:act_on_pumvisible() : (s:compl_methods[s:i] ==# 'cmd' ? get(s:, 'cnp', "\<c-g>\<c-g>") : '') . (s:cycle ? s:next_method_cyclic() : s:next_method())

With line continuations to make the code a little more readable:

return s:pumvisible
          \ ? s:act_on_pumvisible()
          \ : (s:compl_methods[s:i] ==# 'cmd'
          \   ? get(s:, 'cnp', "\<c-g>\<c-g>") : '')
          \   . (s:cycle ? s:next_method_cyclic() : s:next_method())
lifepillar commented 7 years ago

Sorry for the delayed feedback. I'm keeping this and the corresponding pull request open until I decide what to do with the cmd method.

lifepillar commented 7 years ago

I've decided to keep the 'cmd' method and apply https://github.com/lifepillar/vim-mucomplete/pull/45, which should fix this issue.

lifepillar commented 7 years ago

For completeness, I will note here that <c-x><c-v> seems to interact badly with <c-r>= in some circumstances, at least up to Vim 7.4 (included). To see what I mean, type the following in Insert mode:

set fo<c-x><c-v><c-r>=<cr><c-w>fo<c-x><c-v>

In older versions of Vim, the second <c-x><c-v> does not return any suggestion. Besides, after using <c-r>=, command-line completion seems to be messed up, e.g., offering completions for functions instead of commands. Since µcomplete relies on <c-r>=, it looks like µcomplete is not working correctly (but this is a Vim bug).

I am able to reproduce this in Vim 7.2, and in Vim 7.4 from Ubuntu 16.10. In Vim 8.0, this appears to be fixed.