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

User completion functions using complete_check() #70

Open
lifepillar opened this issue Aug 24, 2017 · 5 comments
Open

User completion functions using complete_check() #70

lifepillar opened this issue Aug 24, 2017 · 5 comments

Comments

@lifepillar
Copy link
Owner

lifepillar commented Aug 24, 2017

MUcomplete cannot exploit the optimization provided by complete_add() and complete_check() in user completion functions (see :h E840 for an example). This means that a function like CompleteMonths() cannot be interrupted by pressing a key when it is invoked by MUcomplete. This can be easily verified by setting

Edit: here, I am referring to the second implementation of CompleteMonths() in :help E840.

set completefunc=CompleteMonths
let b:mucomplete_chain = ['user']

then typing something like Ju<tab>x. The x will take more than 3s to appear. Compare with Ju<c-x><c-u>x: in this case, the x will appear within ~300ms.

The reason is that MUcomplete sends <c-r> immediately after each completion mapping, effectively preventing further keys to be passed along to the buffer. Sending <c-r>, however, is used as a synchronization mechanism to prevent s:verify_completion() to be called too early, that is, before pumvisible() becomes true. Removing the vacuous expression <c-r><c-r>=''<cr> (see s:try_completion()) breaks MUcomplete.

I don't know any workaround, unless Vim implements a PumVisible event. But if you have some idea about a different approach, please comment below (or send a pull request!).

@sharethewisdom
Copy link

have you tried a simple timer? the callback function could turn off the timer when pumvisible() is true...

function! s:isPumVisible()
  if pumvisible() && exists('s:wait')
    call timer_stop(s:wait)
    call s:continue()
  endif
endfunction
let s:wait=timer_start(50, function('s:isPumVisible'),{'repeat':-1})

( I sense that due to this issue neopairs.vim may not work properly, but I have little time to find out.)

@lifepillar
Copy link
Owner Author

No, I haven't dealt into any timer-based solution yet. I'll take a look, although a method using timers would be compatible only with Vim 8 or later.

@lifepillar
Copy link
Owner Author

I have taken a look at timers, but that would require a complete overhaul of µcomplete and reduce backward compatibility. Besides, robust completion with timers is very tricky to get right, IMO (although there are plugins out there that use timers).

I've come to the conclusion that the inability to exploit complete_add() and complete_check() is an inherent limitation of µcomplete, so I am closing this.

@blahgeek
Copy link

Hi @lifepillar , I'm thinking about something like this:

diff --git a/autoload/mucomplete.vim b/autoload/mucomplete.vim
index 2c6e6fd..1a3f848 100644
--- a/autoload/mucomplete.vim
+++ b/autoload/mucomplete.vim
@@ -233,7 +233,34 @@ fun! s:act_on_pumvisible()
         \ : s:insert_entry()
 endf
 
+fun! mucomplete#CompletefuncWrapper(findstart, base)
+  if !exists('b:mucomplete_old_completefunc')
+    return -3
+  endif
+
+  let Fn = function(b:mucomplete_old_completefunc)
+  " restore
+  let &l:completefunc = b:mucomplete_old_completefunc
+  unlet b:mucomplete_old_completefunc
+
+  let res = Fn(a:findstart, a:base)
+  if !a:findstart && !complete_check() && empty(l:res) && empty(complete_info()['items'])
+    echom 'complete check: ' . complete_check() . ' res' . empty(l:res)
+    call feedkeys(s:next_method())
+  endif
+  return l:res
+endf
+
 fun! s:try_completion() " Assumes s:i in [0, s:N - 1]
+  if get(g:, 'mucomplete#user_async', 0)
+        \ && s:compl_methods[s:i] == "user"
+        \ && !exists('b:mucomplete_old_completefunc') && !empty(&l:completefunc)
+    let b:mucomplete_old_completefunc = &l:completefunc
+    let &l:completefunc = 'mucomplete#CompletefuncWrapper'
+
+    return s:compl_mappings[s:compl_methods[s:i]]
+  endif
+
   return s:compl_mappings[s:compl_methods[s:i]] . "\<c-r>\<c-r>=''\<cr>\<plug>(MUcompleteVerify)"
 endf

I'm still testing this method. Any suggestions?

@lifepillar lifepillar reopened this Jan 28, 2020
@lifepillar
Copy link
Owner Author

That is an interesting idea. As explained above, removing \<c-r>=''\<cr> causes issues, in general. Does that work on a completion chain with several methods? If so, could you turn that into a pull request, possibly with at least a test (see the test folder)?

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

No branches or pull requests

3 participants