[vim/vim] Ctrl-L doesn't work with complete() (#7567)

18 views
Skip to first unread message

David Briscoe

unread,
Dec 28, 2020, 9:14:04 PM12/28/20
to vim/vim, Subscribed

Describe the bug
When using complete() to create a completion menu, CTRL-L fails to insert a character from the current match. Instead, a literal ^L is inserted.

CTRL-L Add one character from the current match, may reduce the number of matches.

To Reproduce

minimal.vim:

" From :help complete()
inoremap <C-j> <C-R>=ListMonths()<CR>
func! ListMonths()
    call complete(col('.'), ['January', 'February', 'March',
                \ 'April', 'May', 'June', 'July', 'August', 'September',
                \ 'October', 'November', 'December'])
    return ''
endfunc

" Set options that avoid filling first completion.
set completeopt=menuone,noinsert,noselect

Detailed steps to reproduce the behavior:

  1. Run gvim --clean minimal.vim (see above)
  2. source % to load minimal.vim
  3. Start inserting
  4. type C-n to open ins-completion menu
  5. type M to limit to March, May
  6. type C-L to insert 'a'
  7. works!
  8. type C-u to clear
  9. type C-j to open complete() completion menu
  10. type M to limit to March, May
  11. type C-L to insert 'a'
  12. fails!

Expected behavior
The letter a (the next character in the first match "March") is inserted just like it is for ins-completion.

Actual behavior
A literal ^L is inserted.

Environment (please complete the following information):

  • Vim version

    VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Dec 7 2020 23:02:04)
    MS-Windows 64-bit GUI version with OLE support
    Included patches: 1-2107
    Compiled by appveyor@APPVYR-WIN

  • OS: Windows 10 OS Build 18363.1256

  • GUI

Additional context
Encountered this using asyncomplete which uses complete() in prabirshrestha/asyncomplete.vim#177.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

Christian Brabandt

unread,
Dec 29, 2020, 4:04:24 PM12/29/20
to vim/vim, Subscribed

Run gvim --clean minimal.vim (see above)
source % to load minimal.vim
Start inserting
type C-n to open ins-completion menu
type M to limit to March, May
type C-L to insert 'a'
works!

Typing Ctrl-N starts keyword completion mode. In that mode, after limiting the popup menu, typing Ctrl-L does add one character from the popup menu. Note: this does not use the completion function ListMonths().

type C-u to clear
type C-j to open complete() completion menu
type M to limit to March, May
type C-L to insert 'a'

You are in insert mode completion here (CTRL_X_EVAL). In that mode, Ctrl-L will always be inserted literally. This might need to be added to the documentation.

Here is a tentative fix, I don't know how much does this break:

diff --git a/src/edit.c b/src/edit.c
index a152d8449..b10726693 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -627,7 +627,7 @@ edit(
                // "compl_leader".  Except when at the original match and
                // there is nothing to add, CTRL-L works like CTRL-P then.
                if (c == Ctrl_L
-                       && (!ctrl_x_mode_line_or_eval()
+                       && (!ctrl_x_mode_whole_line()
                            || ins_compl_long_shown_match()))
                {
                    ins_compl_addfrommatch();
diff --git a/src/insexpand.c b/src/insexpand.c
index 02f593d7c..8ed512fcc 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -1195,7 +1195,7 @@ ins_compl_dictionaries(
     // When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
     // to only match at the start of a line.  Otherwise just match the
     // pattern. Also need to double backslashes.
-    if (ctrl_x_mode_line_or_eval())
+    if (ctrl_x_mode_whole_line())
     {
        char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
        size_t len;

Haven't tested it very thoroughly yet.

Christian Brabandt

unread,
Dec 29, 2020, 4:25:21 PM12/29/20
to vim/vim, Subscribed

Test failure:

Failures:
        From test_popup.vim:
        Found errors in Test_popup_complete():
        command line..script /home/chrisbra/code/vim-src/src/testdir/runtest.vim[468]..function RunTheTest[39]..Test_popup_complete line 57: Expected ['J\f'] but got ['Ja']

this would be expected however. Not sure we should change this however, I am not sure if people rely on the current behaviour.

David Briscoe

unread,
Dec 31, 2020, 4:04:17 AM12/31/20
to vim/vim, Subscribed

I found a related issue from the past committed in e421450:

Patch 7.4.653
Problem: Insert mode completion with complete() may have CTRL-L work like
CTRL-P.
Solution: Handle completion with complete() differently. (Yasuhiro
Matsumoto, Christian Brabandt, Hirohito Higashi)
Files: src/edit.c

I think the most relevant part of that commit is these lines where Ctrl_L is removed from "relevant inputs" for CTRL_X_EVAL. (Most of the commit is replacing CTRL_X_WHOLE_LINE with CTRL_X_MODE_LINE_OR_EVAL to add the new CTRL_X_EVAL id.) It seems CTRL_X_EVAL was originally implemented as CTRL_X_WHOLE_LINE (instead of keyword completion as I'd expect). And that commit is specifically allowing ^L to be inserted?

I dug up the report for that patch and I think the bug was that people didn't want Ctrl-L to behave like Ctrl-P in CTRL_X_EVAL, but I don't understand if the irritation was the inability to insert literal ^L? @mattn, you originally reported and authored the patch. Is it correct that you rely on inserting literal ^L?

To me, CTRL_X mode would work the same regardless of which submode you're in -- all of the inputs described in :h popupmenu-keys should work. But if that would break people's workflows, is there an alternative? Is there a way for me to map ins_compl_addfrommatch() to a key (it doesn't appear to be exposed)?

Reply all
Reply to author
Forward
0 new messages