Patch 8.2.1634

5 views
Skip to first unread message

Bram Moolenaar

unread,
Sep 7, 2020, 4:06:05 PM9/7/20
to vim...@googlegroups.com

Patch 8.2.1634
Problem: Loop to handle keys for the command line is too long.
Solution: Move a few more parts to separate functions. (Yegappan Lakshmanan,
closes #6895)
Files: src/ex_getln.c, src/testdir/test_cmdline.vim


*** ../vim-8.2.1633/src/ex_getln.c 2020-09-06 15:53:56.627809181 +0200
--- src/ex_getln.c 2020-09-07 22:01:37.510195897 +0200
***************
*** 21,26 ****
--- 21,27 ----
#define CMDLINE_NOT_CHANGED 1
#define CMDLINE_CHANGED 2
#define GOTO_NORMAL_MODE 3
+ #define PROCESS_NEXT_KEY 4

// The current cmdline_info. It is initialized in getcmdline() and after that
// used by other functions. When invoking getcmdline() recursively it needs
***************
*** 39,45 ****
static int cmd_hkmap = 0; // Hebrew mapping during command line
#endif

! static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline);
static int cmdline_charsize(int idx);
static void set_cmdspos(void);
static void set_cmdspos_cursor(void);
--- 40,46 ----
static int cmd_hkmap = 0; // Hebrew mapping during command line
#endif

! static char_u *getcmdline_int(int firstc, long count, int indent, int clear_ccline);
static int cmdline_charsize(int idx);
static void set_cmdspos(void);
static void set_cmdspos_cursor(void);
***************
*** 768,773 ****
--- 769,988 ----
}

/*
+ * Handle the backslash key pressed in the command-line mode. CTRL-\ CTRL-N
+ * goes to Normal mode, CTRL-\ CTRL-G goes to Insert mode when 'insertmode' is
+ * set, CTRL-\ e prompts for an expression.
+ */
+ static int
+ cmdline_handle_backslash_key(int c, int *gotesc)
+ {
+ ++no_mapping;
+ ++allow_keys;
+ c = plain_vgetc();
+ --no_mapping;
+ --allow_keys;
+
+ // CTRL-\ e doesn't work when obtaining an expression, unless it
+ // is in a mapping.
+ if (c != Ctrl_N && c != Ctrl_G && (c != 'e'
+ || (ccline.cmdfirstc == '=' && KeyTyped)
+ #ifdef FEAT_EVAL
+ || cmdline_star > 0
+ #endif
+ ))
+ {
+ vungetc(c);
+ return PROCESS_NEXT_KEY;
+ }
+
+ #ifdef FEAT_EVAL
+ if (c == 'e')
+ {
+ char_u *p = NULL;
+ int len;
+
+ /*
+ * Replace the command line with the result of an expression.
+ * Need to save and restore the current command line, to be
+ * able to enter a new one...
+ */
+ if (ccline.cmdpos == ccline.cmdlen)
+ new_cmdpos = 99999; // keep it at the end
+ else
+ new_cmdpos = ccline.cmdpos;
+
+ c = get_expr_register();
+ if (c == '=')
+ {
+ // Need to save and restore ccline. And set "textwinlock"
+ // to avoid nasty things like going to another buffer when
+ // evaluating an expression.
+ ++textwinlock;
+ p = get_expr_line();
+ --textwinlock;
+
+ if (p != NULL)
+ {
+ len = (int)STRLEN(p);
+ if (realloc_cmdbuff(len + 1) == OK)
+ {
+ ccline.cmdlen = len;
+ STRCPY(ccline.cmdbuff, p);
+ vim_free(p);
+
+ // Restore the cursor or use the position set with
+ // set_cmdline_pos().
+ if (new_cmdpos > ccline.cmdlen)
+ ccline.cmdpos = ccline.cmdlen;
+ else
+ ccline.cmdpos = new_cmdpos;
+
+ KeyTyped = FALSE; // Don't do p_wc completion.
+ redrawcmd();
+ return CMDLINE_CHANGED;
+ }
+ vim_free(p);
+ }
+ }
+ beep_flush();
+ got_int = FALSE; // don't abandon the command line
+ did_emsg = FALSE;
+ emsg_on_display = FALSE;
+ redrawcmd();
+ return CMDLINE_NOT_CHANGED;
+ }
+ #endif
+
+ if (c == Ctrl_G && p_im && restart_edit == 0)
+ restart_edit = 'a';
+ *gotesc = TRUE; // will free ccline.cmdbuff after putting it
+ // in history
+ return GOTO_NORMAL_MODE;
+ }
+
+ /*
+ * Completion for 'wildchar' or 'wildcharm' key.
+ * - hitting <ESC> twice means: abandon command line.
+ * - wildcard expansion is only done when the 'wildchar' key is really
+ * typed, not when it comes from a macro
+ * Returns CMDLINE_CHANGED if command line is changed or CMDLINE_NOT_CHANGED.
+ */
+ static int
+ cmdline_wildchar_complete(
+ int c,
+ int escape,
+ int *did_wild_list,
+ int *wim_index_p,
+ expand_T *xp,
+ int *gotesc)
+ {
+ int wim_index = *wim_index_p;
+ int res;
+ int j;
+ int options = WILD_NO_BEEP;
+
+ if (wim_flags[wim_index] & WIM_BUFLASTUSED)
+ options |= WILD_BUFLASTUSED;
+ if (xp->xp_numfiles > 0) // typed p_wc at least twice
+ {
+ // if 'wildmode' contains "list" may still need to list
+ if (xp->xp_numfiles > 1
+ && !*did_wild_list
+ && (wim_flags[wim_index] & WIM_LIST))
+ {
+ (void)showmatches(xp, FALSE);
+ redrawcmd();
+ *did_wild_list = TRUE;
+ }
+ if (wim_flags[wim_index] & WIM_LONGEST)
+ res = nextwild(xp, WILD_LONGEST, options, escape);
+ else if (wim_flags[wim_index] & WIM_FULL)
+ res = nextwild(xp, WILD_NEXT, options, escape);
+ else
+ res = OK; // don't insert 'wildchar' now
+ }
+ else // typed p_wc first time
+ {
+ wim_index = 0;
+ j = ccline.cmdpos;
+ // if 'wildmode' first contains "longest", get longest
+ // common part
+ if (wim_flags[0] & WIM_LONGEST)
+ res = nextwild(xp, WILD_LONGEST, options, escape);
+ else
+ res = nextwild(xp, WILD_EXPAND_KEEP, options, escape);
+
+ // if interrupted while completing, behave like it failed
+ if (got_int)
+ {
+ (void)vpeekc(); // remove <C-C> from input stream
+ got_int = FALSE; // don't abandon the command line
+ (void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
+ #ifdef FEAT_WILDMENU
+ xp->xp_context = EXPAND_NOTHING;
+ #endif
+ *wim_index_p = wim_index;
+ return CMDLINE_CHANGED;
+ }
+
+ // when more than one match, and 'wildmode' first contains
+ // "list", or no change and 'wildmode' contains "longest,list",
+ // list all matches
+ if (res == OK && xp->xp_numfiles > 1)
+ {
+ // a "longest" that didn't do anything is skipped (but not
+ // "list:longest")
+ if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
+ wim_index = 1;
+ if ((wim_flags[wim_index] & WIM_LIST)
+ #ifdef FEAT_WILDMENU
+ || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
+ #endif
+ )
+ {
+ if (!(wim_flags[0] & WIM_LONGEST))
+ {
+ #ifdef FEAT_WILDMENU
+ int p_wmnu_save = p_wmnu;
+ p_wmnu = 0;
+ #endif
+ // remove match
+ nextwild(xp, WILD_PREV, 0, escape);
+ #ifdef FEAT_WILDMENU
+ p_wmnu = p_wmnu_save;
+ #endif
+ }
+ #ifdef FEAT_WILDMENU
+ (void)showmatches(xp, p_wmnu
+ && ((wim_flags[wim_index] & WIM_LIST) == 0));
+ #else
+ (void)showmatches(xp, FALSE);
+ #endif
+ redrawcmd();
+ *did_wild_list = TRUE;
+ if (wim_flags[wim_index] & WIM_LONGEST)
+ nextwild(xp, WILD_LONGEST, options, escape);
+ else if (wim_flags[wim_index] & WIM_FULL)
+ nextwild(xp, WILD_NEXT, options, escape);
+ }
+ else
+ vim_beep(BO_WILD);
+ }
+ #ifdef FEAT_WILDMENU
+ else if (xp->xp_numfiles == -1)
+ xp->xp_context = EXPAND_NOTHING;
+ #endif
+ }
+ if (wim_index < 3)
+ ++wim_index;
+ if (c == ESC)
+ *gotesc = TRUE;
+
+ *wim_index_p = wim_index;
+ return (res == OK) ? CMDLINE_CHANGED : CMDLINE_NOT_CHANGED;
+ }
+
+ /*
* Handle backspace, delete and CTRL-W keys in the command-line mode.
* Returns:
* CMDLINE_NOT_CHANGED - if the command line is not changed
***************
*** 1245,1250 ****
--- 1460,1500 ----
}

/*
+ * Initialize the current command-line info.
+ */
+ static int
+ init_ccline(int firstc, int indent)
+ {
+ ccline.overstrike = FALSE; // always start in insert mode
+
+ /*
+ * set some variables for redrawcmd()
+ */
+ ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
+ ccline.cmdindent = (firstc > 0 ? indent : 0);
+
+ // alloc initial ccline.cmdbuff
+ alloc_cmdbuff(exmode_active ? 250 : indent + 1);
+ if (ccline.cmdbuff == NULL)
+ return FAIL;
+ ccline.cmdlen = ccline.cmdpos = 0;
+ ccline.cmdbuff[0] = NUL;
+ sb_text_start_cmdline();
+
+ // autoindent for :insert and :append
+ if (firstc <= 0)
+ {
+ vim_memset(ccline.cmdbuff, ' ', indent);
+ ccline.cmdbuff[indent] = NUL;
+ ccline.cmdpos = indent;
+ ccline.cmdspos = indent;
+ ccline.cmdlen = indent;
+ }
+
+ return OK;
+ }
+
+ /*
* getcmdline() - accept a command line starting with firstc.
*
* firstc == ':' get ":" command line.
***************
*** 1278,1284 ****
int firstc,
long count UNUSED, // only used for incremental search
int indent, // indent for inside conditionals
! int init_ccline) // clear ccline first
{
int c;
int i;
--- 1528,1534 ----
int firstc,
long count UNUSED, // only used for incremental search
int indent, // indent for inside conditionals
! int clear_ccline) // clear ccline first
{
int c;
int i;
***************
*** 1316,1322 ****
save_cmdline(&save_ccline);
did_save_ccline = TRUE;
}
! if (init_ccline)
CLEAR_FIELD(ccline);

#ifdef FEAT_EVAL
--- 1566,1572 ----
save_cmdline(&save_ccline);
did_save_ccline = TRUE;
}
! if (clear_ccline)
CLEAR_FIELD(ccline);

#ifdef FEAT_EVAL
***************
*** 1332,1366 ****
cmd_hkmap = 0;
#endif

- ccline.overstrike = FALSE; // always start in insert mode
-
#ifdef FEAT_SEARCH_EXTRA
init_incsearch_state(&is_state);
#endif

! /*
! * set some variables for redrawcmd()
! */
! ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
! ccline.cmdindent = (firstc > 0 ? indent : 0);
!
! // alloc initial ccline.cmdbuff
! alloc_cmdbuff(exmode_active ? 250 : indent + 1);
! if (ccline.cmdbuff == NULL)
goto theend; // out of memory
- ccline.cmdlen = ccline.cmdpos = 0;
- ccline.cmdbuff[0] = NUL;
- sb_text_start_cmdline();
-
- // autoindent for :insert and :append
- if (firstc <= 0)
- {
- vim_memset(ccline.cmdbuff, ' ', indent);
- ccline.cmdbuff[indent] = NUL;
- ccline.cmdpos = indent;
- ccline.cmdspos = indent;
- ccline.cmdlen = indent;
- }

ExpandInit(&xpc);
ccline.xpc = &xpc;
--- 1582,1593 ----
cmd_hkmap = 0;
#endif

#ifdef FEAT_SEARCH_EXTRA
init_incsearch_state(&is_state);
#endif

! if (init_ccline(firstc, indent) != OK)
goto theend; // out of memory

ExpandInit(&xpc);
ccline.xpc = &xpc;
***************
*** 1572,1659 ****
// mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
if (c == Ctrl_BSL)
{
! ++no_mapping;
! ++allow_keys;
! c = plain_vgetc();
! --no_mapping;
! --allow_keys;
! // CTRL-\ e doesn't work when obtaining an expression, unless it
! // is in a mapping.
! if (c != Ctrl_N && c != Ctrl_G && (c != 'e'
! || (ccline.cmdfirstc == '=' && KeyTyped)
! #ifdef FEAT_EVAL
! || cmdline_star > 0
! #endif
! ))
! {
! vungetc(c);
! c = Ctrl_BSL;
! }
! #ifdef FEAT_EVAL
! else if (c == 'e')
! {
! char_u *p = NULL;
! int len;
!
! /*
! * Replace the command line with the result of an expression.
! * Need to save and restore the current command line, to be
! * able to enter a new one...
! */
! if (ccline.cmdpos == ccline.cmdlen)
! new_cmdpos = 99999; // keep it at the end
! else
! new_cmdpos = ccline.cmdpos;
!
! c = get_expr_register();
! if (c == '=')
! {
! // Need to save and restore ccline. And set "textwinlock"
! // to avoid nasty things like going to another buffer when
! // evaluating an expression.
! ++textwinlock;
! p = get_expr_line();
! --textwinlock;
!
! if (p != NULL)
! {
! len = (int)STRLEN(p);
! if (realloc_cmdbuff(len + 1) == OK)
! {
! ccline.cmdlen = len;
! STRCPY(ccline.cmdbuff, p);
! vim_free(p);
!
! // Restore the cursor or use the position set with
! // set_cmdline_pos().
! if (new_cmdpos > ccline.cmdlen)
! ccline.cmdpos = ccline.cmdlen;
! else
! ccline.cmdpos = new_cmdpos;
!
! KeyTyped = FALSE; // Don't do p_wc completion.
! redrawcmd();
! goto cmdline_changed;
! }
! vim_free(p);
! }
! }
! beep_flush();
! got_int = FALSE; // don't abandon the command line
! did_emsg = FALSE;
! emsg_on_display = FALSE;
! redrawcmd();
goto cmdline_not_changed;
! }
! #endif
! else
! {
! if (c == Ctrl_G && p_im && restart_edit == 0)
! restart_edit = 'a';
! gotesc = TRUE; // will free ccline.cmdbuff after putting it
! // in history
! goto returncmd; // back to Normal mode
! }
}

#ifdef FEAT_CMDWIN
--- 1799,1813 ----
// mode when 'insertmode' is set, CTRL-\ e prompts for an expression.
if (c == Ctrl_BSL)
{
! res = cmdline_handle_backslash_key(c, &gotesc);
! if (res == CMDLINE_CHANGED)
! goto cmdline_changed;
! else if (res == CMDLINE_NOT_CHANGED)
goto cmdline_not_changed;
! else if (res == GOTO_NORMAL_MODE)
! goto returncmd; // back to cmd mode
! c = Ctrl_BSL; // backslash key not processed by
! // cmdline_handle_backslash_key()
}

#ifdef FEAT_CMDWIN
***************
*** 1705,1819 ****
}
}

! /*
! * Completion for 'wildchar' or 'wildcharm' key.
! * - hitting <ESC> twice means: abandon command line.
! * - wildcard expansion is only done when the 'wildchar' key is really
! * typed, not when it comes from a macro
! */
if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
{
! int options = WILD_NO_BEEP;
!
! if (wim_flags[wim_index] & WIM_BUFLASTUSED)
! options |= WILD_BUFLASTUSED;
! if (xpc.xp_numfiles > 0) // typed p_wc at least twice
! {
! // if 'wildmode' contains "list" may still need to list
! if (xpc.xp_numfiles > 1
! && !did_wild_list
! && (wim_flags[wim_index] & WIM_LIST))
! {
! (void)showmatches(&xpc, FALSE);
! redrawcmd();
! did_wild_list = TRUE;
! }
! if (wim_flags[wim_index] & WIM_LONGEST)
! res = nextwild(&xpc, WILD_LONGEST, options,
! firstc != '@');
! else if (wim_flags[wim_index] & WIM_FULL)
! res = nextwild(&xpc, WILD_NEXT, options, firstc != '@');
! else
! res = OK; // don't insert 'wildchar' now
! }
! else // typed p_wc first time
! {
! wim_index = 0;
! j = ccline.cmdpos;
! // if 'wildmode' first contains "longest", get longest
! // common part
! if (wim_flags[0] & WIM_LONGEST)
! res = nextwild(&xpc, WILD_LONGEST, options, firstc != '@');
! else
! res = nextwild(&xpc, WILD_EXPAND_KEEP, options,
! firstc != '@');
!
! // if interrupted while completing, behave like it failed
! if (got_int)
! {
! (void)vpeekc(); // remove <C-C> from input stream
! got_int = FALSE; // don't abandon the command line
! (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE);
! #ifdef FEAT_WILDMENU
! xpc.xp_context = EXPAND_NOTHING;
! #endif
! goto cmdline_changed;
! }
!
! // when more than one match, and 'wildmode' first contains
! // "list", or no change and 'wildmode' contains "longest,list",
! // list all matches
! if (res == OK && xpc.xp_numfiles > 1)
! {
! // a "longest" that didn't do anything is skipped (but not
! // "list:longest")
! if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j)
! wim_index = 1;
! if ((wim_flags[wim_index] & WIM_LIST)
! #ifdef FEAT_WILDMENU
! || (p_wmnu && (wim_flags[wim_index] & WIM_FULL) != 0)
! #endif
! )
! {
! if (!(wim_flags[0] & WIM_LONGEST))
! {
! #ifdef FEAT_WILDMENU
! int p_wmnu_save = p_wmnu;
! p_wmnu = 0;
! #endif
! // remove match
! nextwild(&xpc, WILD_PREV, 0, firstc != '@');
! #ifdef FEAT_WILDMENU
! p_wmnu = p_wmnu_save;
! #endif
! }
! #ifdef FEAT_WILDMENU
! (void)showmatches(&xpc, p_wmnu
! && ((wim_flags[wim_index] & WIM_LIST) == 0));
! #else
! (void)showmatches(&xpc, FALSE);
! #endif
! redrawcmd();
! did_wild_list = TRUE;
! if (wim_flags[wim_index] & WIM_LONGEST)
! nextwild(&xpc, WILD_LONGEST, options,
! firstc != '@');
! else if (wim_flags[wim_index] & WIM_FULL)
! nextwild(&xpc, WILD_NEXT, options, firstc != '@');
! }
! else
! vim_beep(BO_WILD);
! }
! #ifdef FEAT_WILDMENU
! else if (xpc.xp_numfiles == -1)
! xpc.xp_context = EXPAND_NOTHING;
! #endif
! }
! if (wim_index < 3)
! ++wim_index;
! if (c == ESC)
! gotesc = TRUE;
! if (res == OK)
goto cmdline_changed;
}

--- 1859,1870 ----
}
}

! // Completion for 'wildchar' or 'wildcharm' key.
if ((c == p_wc && !gotesc && KeyTyped) || c == p_wcm)
{
! res = cmdline_wildchar_complete(c, firstc != '@', &did_wild_list,
! &wim_index, &xpc, &gotesc);
! if (res == CMDLINE_CHANGED)
goto cmdline_changed;
}

*** ../vim-8.2.1633/src/testdir/test_cmdline.vim 2020-09-04 21:18:40.480161935 +0200
--- src/testdir/test_cmdline.vim 2020-09-07 21:58:07.854738838 +0200
***************
*** 829,834 ****
--- 829,843 ----
" completion after a range followed by a pipe (|) character
call feedkeys(":1,10 | chist\t\<C-B>\"\<CR>", 'xt')
call assert_equal('"1,10 | chistory', @:)
+
+ " use <Esc> as the 'wildchar' for completion
+ set wildchar=<Esc>
+ call feedkeys(":g/a\\xb/clearj\<Esc>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"g/a\xb/clearjumps', @:)
+ " pressing <esc> twice should cancel the command
+ call feedkeys(":chist\<Esc>\<Esc>", 'xt')
+ call assert_equal('"g/a\xb/clearjumps', @:)
+ set wildchar&
endfunc

func Test_cmdline_write_alternatefile()
*** ../vim-8.2.1633/src/version.c 2020-09-07 18:53:18.387974569 +0200
--- src/version.c 2020-09-07 21:59:37.598506235 +0200
***************
*** 756,757 ****
--- 756,759 ----
{ /* Add new patch number below this line */
+ /**/
+ 1634,
/**/

--
Q: How do you tell the difference between a female cat and a male cat?
A: You ask it a question and if HE answers, it's a male but, if SHE
answers, it's a female.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages