From: Thomas M Kehrenberg Date: Sat, 13 Jun 2026 14:36:58 +0000 (+0000) Subject: patch 9.2.0624: C-N/C-P cannot be mapped in complete() completion X-Git-Tag: v9.2.0624^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=076585e6addb5688f123ef3e174fcfee993b7602;p=thirdparty%2Fvim.git patch 9.2.0624: C-N/C-P cannot be mapped in complete() completion Problem: Keys valid in CTRL-X mode are never mapped while insert completion is active, so and cannot be remapped for completion started by complete(). Solution: Do not disable mappings in CTRL_X_EVAL mode. In this mode a mapping cannot interfere with selecting the completion method, which is what the no-mapping rule exists for. related: #6440 related: #16880 closes: #20489 Signed-off-by: Thomas M Kehrenberg Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index e8b9518e53..caad78ceba 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.2. Last change: 2026 Jun 09 +*builtin.txt* For Vim version 9.2. Last change: 2026 Jun 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1986,6 +1986,14 @@ complete({startcol}, {matches}) *complete()* *E785* The match can be selected with CTRL-N and CTRL-P as usual with Insert mode completion. The popup menu will appear if specified, see |ins-completion-menu|. + Unlike with other |ins-completion| modes, the CTRL-N and + CTRL-P keys can be mapped while this completion is active. + For example, to make CTRL-N move the selection without + inserting the match: > + + inoremap complete_info().mode ==# 'eval' + \ ? '' : '' +< Example (using legacy Vim script): > diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 5946f26e76..688d65fb3f 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1,4 +1,4 @@ -*insert.txt* For Vim version 9.2. Last change: 2026 Jun 09 +*insert.txt* For Vim version 9.2. Last change: 2026 Jun 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -690,7 +690,8 @@ When the popup menu is displayed there are a few more special keys, see Note: The keys that are valid in CTRL-X mode are not mapped. This allows for `:map ` to work (assuming "<" is not in 'cpo'). The key that ends CTRL-X mode (any key that is not a valid CTRL-X mode command) is mapped. -Also, when doing completion with 'complete' mappings apply as usual. +Also, when doing completion with 'complete' or when completion was started +with |complete()| mappings apply as usual. *E565* Note: While completion is active Insert mode can't be used recursively and diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 937bf4f216..b78a3738a6 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.2. Last change: 2026 Jun 09 +*version9.txt* For Vim version 9.2. Last change: 2026 Jun 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -52677,6 +52677,8 @@ Changed ~ - On Unix, filename completion for single-file Ex commands now treats embedded whitespace as part of the filename, like on other platforms. - Rewrite the clientserver socketserver backend to use channels and JSON. +- During |complete()|-triggered completion, CTRL-N and CTRL-P are now subject + to insert-mode mappings. *added-9.3* diff --git a/src/getchar.c b/src/getchar.c index d02b9009cb..25422be0d1 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -2718,6 +2718,7 @@ typedef enum { /* * Check if the bytes at the start of the typeahead buffer are a character used * in Insert mode completion. This includes the form with a CTRL modifier. + * During completion started by complete() keys are mapped as usual. */ static int at_ins_compl_key(void) @@ -2733,8 +2734,9 @@ at_ins_compl_key(void) // to the CTRL-N/CTRL-P completion keys here. && !(p[2] & MOD_MASK_SHIFT)) c = p[3] & 0x1f; - return (ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c)) - || (compl_status_local() && (c == Ctrl_N || c == Ctrl_P)); + return !ctrl_x_mode_eval() + && ((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c)) + || (compl_status_local() && (c == Ctrl_N || c == Ctrl_P))); } /* @@ -2872,7 +2874,8 @@ handle_mapping( * - in insert or cmdline mode and 'paste' option set * - waiting for "hit return to continue" and CR or SPACE typed * - waiting for a char with --more-- - * - in Ctrl-X mode, and we get a valid char for that mode + * - in Ctrl-X mode (not started by complete()), and we get a valid char + * for that mode * - currently receiving OSC sequence */ tb_c1 = typebuf.tb_buf[typebuf.tb_off]; diff --git a/src/insexpand.c b/src/insexpand.c index bbb15b003e..c63b49c7f4 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -359,7 +359,7 @@ int ctrl_x_mode_omni(void) { return ctrl_x_mode == CTRL_X_OMNI; } int ctrl_x_mode_spell(void) { return ctrl_x_mode == CTRL_X_SPELL; } -static int ctrl_x_mode_eval(void) +int ctrl_x_mode_eval(void) { return ctrl_x_mode == CTRL_X_EVAL; } int ctrl_x_mode_line_or_eval(void) { return ctrl_x_mode == CTRL_X_WHOLE_LINE || ctrl_x_mode == CTRL_X_EVAL; } diff --git a/src/proto/insexpand.pro b/src/proto/insexpand.pro index e973eac4f7..2c1882dc19 100644 --- a/src/proto/insexpand.pro +++ b/src/proto/insexpand.pro @@ -14,6 +14,7 @@ int ctrl_x_mode_cmdline(void); int ctrl_x_mode_function(void); int ctrl_x_mode_omni(void); int ctrl_x_mode_spell(void); +int ctrl_x_mode_eval(void); int ctrl_x_mode_line_or_eval(void); int ctrl_x_mode_register(void); int ctrl_x_mode_not_default(void); diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 7eda457e1a..c741fd1e73 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -6331,4 +6331,30 @@ func Test_completion_with_mapped_ctrl_r() bwipe! endfunc +" Keys are mapped during completion started by complete(), but not in other +" CTRL-X modes. +func Test_mapped_ctrl_n_during_complete_function() + new + inoremap call complete(1, ['foo', 'foobar']) + inoremap let b:info = + \ [getline('.'), complete_info(['selected']).selected] + + " During completion started by complete() the mapping applies: + " moves the selection without inserting it. + inoremap complete_info().mode ==# 'eval' ? '' : '' + call feedkeys("i\\<*C-N>\\\", 'tx') + call assert_equal(['foo', 1], b:info) + call assert_equal('foobar', getline(1)) + + " In other CTRL-X modes the mapping is ignored: the builtin selects + " and inserts the next match. + %delete _ + call setline(1, ['foo', 'foobar', '']) + inoremap pumvisible() ? '' : '' + call feedkeys("3GAf\\\\\\", 'tx') + call assert_equal(['foobar', 1], b:info) + + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab nofoldenable diff --git a/src/version.c b/src/version.c index b798c6348c..28606e3d3e 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 624, /**/ 623, /**/