To: vim_dev@googlegroups.com Subject: Patch 8.2.3389 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3389 Problem: Cannot stop insert mode completion without side effects. Solution: Add CTRL-X CTRL-Z. (closes #8821) Files: runtime/doc/index.txt, runtime/doc/insert.txt, src/insexpand.c, src/testdir/test_ins_complete.vim *** ../vim-8.2.3388/runtime/doc/index.txt 2021-06-10 19:39:07.273697695 +0200 --- runtime/doc/index.txt 2021-08-31 19:05:25.366528171 +0200 *************** *** 168,173 **** --- 168,174 ---- |i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down |i_CTRL-X_CTRL-U| CTRL-X CTRL-U complete with 'completefunc' |i_CTRL-X_CTRL-V| CTRL-X CTRL-V complete like in : command line + |i_CTRL-X_CTRL-Z| CTRL-X CTRL-Z stop completion, keeping the text as-is |i_CTRL-X_CTRL-]| CTRL-X CTRL-] complete tags |i_CTRL-X_s| CTRL-X s spelling suggestions *** ../vim-8.2.3388/runtime/doc/insert.txt 2021-01-31 17:02:06.254490174 +0100 --- runtime/doc/insert.txt 2021-08-31 19:06:08.002398301 +0200 *************** *** 640,645 **** --- 640,647 ---- 12. Spelling suggestions |i_CTRL-X_s| 13. keywords in 'complete' |i_CTRL-N| |i_CTRL-P| + Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text. + All these, except CTRL-N and CTRL-P, are done in CTRL-X mode. This is a sub-mode of Insert and Replace modes. You enter CTRL-X mode by typing CTRL-X and one of the CTRL-X commands. You exit CTRL-X mode by typing a key that is *************** *** 1042,1047 **** --- 1044,1055 ---- other contexts unless a double CTRL-X is used. + Stop completion *compl-stop* + + *i_CTRL-X_CTRL-Z* + CTRL-X CTRL-Z Stop completion without changing the text. + + FUNCTIONS FOR FINDING COMPLETIONS *complete-functions* This applies to 'completefunc' and 'omnifunc'. *** ../vim-8.2.3388/src/insexpand.c 2021-08-05 16:23:05.482890089 +0200 --- src/insexpand.c 2021-08-31 19:10:57.721764812 +0200 *************** *** 37,42 **** --- 37,43 ---- # define CTRL_X_SPELL 14 # define CTRL_X_LOCAL_MSG 15 // only used in "ctrl_x_msgs" # define CTRL_X_EVAL 16 // for builtin function complete() + # define CTRL_X_CMDLINE_CTRL_X 17 // CTRL-X typed in CTRL_X_CMDLINE # define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT] *************** *** 60,65 **** --- 61,67 ---- N_(" Spelling suggestion (s^N^P)"), N_(" Keyword Local completion (^N^P)"), NULL, // CTRL_X_EVAL doesn't use msg. + N_(" Command-line completion (^V^N^P)"), }; #if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) *************** *** 80,86 **** "omni", "spell", NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs" ! "eval" }; #endif --- 82,89 ---- "omni", "spell", NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs" ! "eval", ! "cmdline", }; #endif *************** *** 222,230 **** void ins_ctrl_x(void) { ! // CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X ! // CTRL-V works like CTRL-N ! if (ctrl_x_mode != CTRL_X_CMDLINE) { // if the next ^X<> won't ADD nothing, then reset // compl_cont_status --- 225,231 ---- void ins_ctrl_x(void) { ! if (!ctrl_x_mode_cmdline()) { // if the next ^X<> won't ADD nothing, then reset // compl_cont_status *************** *** 238,243 **** --- 239,248 ---- edit_submode_pre = NULL; showmode(); } + else + // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X + // CTRL-V look like CTRL-N + ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X; } /* *************** *** 255,261 **** return ctrl_x_mode == CTRL_X_PATH_DEFINES; } int ctrl_x_mode_dictionary(void) { return ctrl_x_mode == CTRL_X_DICTIONARY; } int ctrl_x_mode_thesaurus(void) { return ctrl_x_mode == CTRL_X_THESAURUS; } ! int ctrl_x_mode_cmdline(void) { return ctrl_x_mode == CTRL_X_CMDLINE; } int ctrl_x_mode_function(void) { return ctrl_x_mode == CTRL_X_FUNCTION; } 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; } --- 260,268 ---- return ctrl_x_mode == CTRL_X_PATH_DEFINES; } int ctrl_x_mode_dictionary(void) { return ctrl_x_mode == CTRL_X_DICTIONARY; } int ctrl_x_mode_thesaurus(void) { return ctrl_x_mode == CTRL_X_THESAURUS; } ! int ctrl_x_mode_cmdline(void) { ! return ctrl_x_mode == CTRL_X_CMDLINE ! || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X; } int ctrl_x_mode_function(void) { return ctrl_x_mode == CTRL_X_FUNCTION; } 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; } *************** *** 272,278 **** } /* ! * Whether CTRL-X was typed without a following character. */ int ctrl_x_mode_not_defined_yet(void) --- 279,286 ---- } /* ! * Whether CTRL-X was typed without a following character, ! * not including when in CTRL-X CTRL-V mode. */ int ctrl_x_mode_not_defined_yet(void) *************** *** 333,344 **** case 0: // Not in any CTRL-X mode return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X); case CTRL_X_NOT_DEFINED_YET: return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O ! || c == Ctrl_S || c == Ctrl_K || c == 's'); case CTRL_X_SCROLL: return (c == Ctrl_Y || c == Ctrl_E); case CTRL_X_WHOLE_LINE: --- 341,354 ---- case 0: // Not in any CTRL-X mode return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X); case CTRL_X_NOT_DEFINED_YET: + case CTRL_X_CMDLINE_CTRL_X: return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O ! || c == Ctrl_S || c == Ctrl_K || c == 's' ! || c == Ctrl_Z); case CTRL_X_SCROLL: return (c == Ctrl_Y || c == Ctrl_E); case CTRL_X_WHOLE_LINE: *************** *** 396,401 **** --- 406,412 ---- return vim_isfilec(c) && !vim_ispathsep(c); case CTRL_X_CMDLINE: + case CTRL_X_CMDLINE_CTRL_X: case CTRL_X_OMNI: // Command line and Omni completion can work with just about any // printable character, but do stop at white space. *************** *** 1860,1865 **** --- 1871,1899 ---- } #endif + if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) + { + if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c) + || !vim_is_ctrl_x_key(c)) + { + // Not starting another completion mode. + ctrl_x_mode = CTRL_X_CMDLINE; + + // CTRL-X CTRL-Z should stop completion without inserting anything + if (c == Ctrl_Z) + retval = TRUE; + } + else + { + ctrl_x_mode = CTRL_X_CMDLINE; + + // Other CTRL-X keys first stop completion, then start another + // completion mode. + ins_compl_prep(' '); + ctrl_x_mode = CTRL_X_NOT_DEFINED_YET; + } + } + // Set "compl_get_longest" when finding the first matches. if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) *************** *** 1933,1938 **** --- 1967,1978 ---- case Ctrl_Q: ctrl_x_mode = CTRL_X_CMDLINE; break; + case Ctrl_Z: + ctrl_x_mode = CTRL_X_NORMAL; + edit_submode = NULL; + showmode(); + retval = TRUE; + break; case Ctrl_P: case Ctrl_N: // ^X^P means LOCAL expansion if nothing interrupted (eg we *************** *** 2929,2934 **** --- 2969,2975 ---- break; case CTRL_X_CMDLINE: + case CTRL_X_CMDLINE_CTRL_X: if (expand_cmdline(&compl_xp, compl_pattern, (int)STRLEN(compl_pattern), &num_matches, &matches) == EXPAND_OK) *** ../vim-8.2.3388/src/testdir/test_ins_complete.vim 2021-07-25 20:27:03.223912393 +0200 --- src/testdir/test_ins_complete.vim 2021-08-31 18:58:12.079869338 +0200 *************** *** 730,735 **** --- 730,795 ---- call assert_equal('call getqflist(', getline(2)) exe "normal oabcxyz(\\" call assert_equal('abcxyz(', getline(3)) + com! -buffer TestCommand1 echo 'TestCommand1' + com! -buffer TestCommand2 echo 'TestCommand2' + write TestCommand1Test + write TestCommand2Test + " Test repeating and switching to another CTRL-X mode + exe "normal oT\\\\\\\" + call assert_equal('TestCommand2Test', getline(4)) + call delete('TestCommand1Test') + call delete('TestCommand2Test') + delcom TestCommand1 + delcom TestCommand2 + close! + endfunc + + " Test for stopping completion without changing the match + func Test_complete_stop() + new + func Save_mode1() + let g:mode1 = mode(1) + return '' + endfunc + func Save_mode2() + let g:mode2 = mode(1) + return '' + endfunc + inoremap =Save_mode1() + inoremap =Save_mode2() + call setline(1, ['aaa bbb ccc ']) + exe "normal A\\\\\\\" + call assert_equal('ic', g:mode1) + call assert_equal('i', g:mode2) + call assert_equal('aaa bbb ccc ', getline(1)) + exe "normal A\\\\\\\" + call assert_equal('ic', g:mode1) + call assert_equal('i', g:mode2) + call assert_equal('aaa bbb ccc aaa', getline(1)) + set completeopt+=noselect + exe "normal A \\\\\\\\\\" + call assert_equal('ic', g:mode1) + call assert_equal('i', g:mode2) + call assert_equal('aaa bbb ccc aaa bb', getline(1)) + set completeopt& + exe "normal A d\\\\\\" + call assert_equal('ic', g:mode1) + call assert_equal('i', g:mode2) + call assert_equal('aaa bbb ccc aaa bb d', getline(1)) + com! -buffer TestCommand1 echo 'TestCommand1' + com! -buffer TestCommand2 echo 'TestCommand2' + exe "normal oT\\\\\\\\\" + call assert_equal('ic', g:mode1) + call assert_equal('i', g:mode2) + call assert_equal('TestCommand2', getline(2)) + delcom TestCommand1 + delcom TestCommand2 + unlet g:mode1 + unlet g:mode2 + iunmap + iunmap + delfunc Save_mode1 + delfunc Save_mode2 close! endfunc *** ../vim-8.2.3388/src/version.c 2021-08-30 21:26:12.860831195 +0200 --- src/version.c 2021-08-31 18:59:39.959593224 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3389, /**/ -- BEDEVERE: Wait. Wait ... tell me, what also floats on water? ALL: Bread? No, no, no. Apples .... gravy ... very small rocks ... ARTHUR: A duck. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///