diff options
Diffstat (limited to 'src/ex_getln.c')
-rw-r--r-- | src/ex_getln.c | 5371 |
1 files changed, 5371 insertions, 0 deletions
diff --git a/src/ex_getln.c b/src/ex_getln.c new file mode 100644 index 0000000000..3c242816b5 --- /dev/null +++ b/src/ex_getln.c @@ -0,0 +1,5371 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * ex_getln.c: Functions for entering and editing an Ex command line. + */ + +#include "vim.h" + +/* + * Variables shared between getcmdline(), redrawcmdline() and others. + * These need to be saved when using CTRL-R |, that's why they are in a + * structure. + */ +struct cmdline_info +{ + char_u *cmdbuff; /* pointer to command line buffer */ + int cmdbufflen; /* length of cmdbuff */ + int cmdlen; /* number of chars in command line */ + int cmdpos; /* current cursor position */ + int cmdspos; /* cursor column on screen */ + int cmdfirstc; /* ':', '/', '?', '=' or NUL */ + int cmdindent; /* number of spaces before cmdline */ + char_u *cmdprompt; /* message in front of cmdline */ + int cmdattr; /* attributes for prompt */ + int overstrike; /* Typing mode on the command line. Shared by + getcmdline() and put_on_cmdline(). */ +}; + +static struct cmdline_info ccline; /* current cmdline_info */ + +static int cmd_showtail; /* Only show path tail in lists ? */ + +#ifdef FEAT_EVAL +static int new_cmdpos; /* position set by set_cmdline_pos() */ +#endif + +#ifdef FEAT_CMDHIST +typedef struct hist_entry +{ + int hisnum; /* identifying number */ + char_u *hisstr; /* actual entry, separator char after the NUL */ +} histentry_T; + +static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL}; +static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */ +static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0}; + /* identifying (unique) number of newest history entry */ +static int hislen = 0; /* actual length of history tables */ + +static int hist_char2type __ARGS((int c)); +static void init_history __ARGS((void)); + +static int in_history __ARGS((int, char_u *, int)); +# ifdef FEAT_EVAL +static int calc_hist_idx __ARGS((int histype, int num)); +# endif +#endif + +#ifdef FEAT_RIGHTLEFT +static int cmd_hkmap = 0; /* Hebrew mapping during command line */ +#endif + +#ifdef FEAT_FKMAP +static int cmd_fkmap = 0; /* Farsi mapping during command line */ +#endif + +static int cmdline_charsize __ARGS((int idx)); +static void set_cmdspos __ARGS((void)); +static void set_cmdspos_cursor __ARGS((void)); +#ifdef FEAT_MBYTE +static void correct_cmdspos __ARGS((int idx, int cells)); +#endif +static void alloc_cmdbuff __ARGS((int len)); +static int realloc_cmdbuff __ARGS((int len)); +static void draw_cmdline __ARGS((int start, int len)); +#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) +static void redrawcmd_preedit __ARGS((void)); +#endif +#ifdef FEAT_WILDMENU +static void cmdline_del __ARGS((int from)); +#endif +static void redrawcmdprompt __ARGS((void)); +static void cursorcmd __ARGS((void)); +static int ccheck_abbr __ARGS((int)); +static int nextwild __ARGS((expand_T *xp, int type, int options)); +static int showmatches __ARGS((expand_T *xp, int wildmenu)); +static void set_expand_context __ARGS((expand_T *xp)); +static int ExpandFromContext __ARGS((expand_T *xp, char_u *, int *, char_u ***, int)); +static int expand_showtail __ARGS((expand_T *xp)); +#ifdef FEAT_CMDL_COMPL +static int ExpandRTDir __ARGS((char_u *pat, int *num_file, char_u ***file, char *dirname)); +# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) +static int ExpandUserDefined __ARGS((expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)); +# endif +#endif + +#ifdef FEAT_CMDWIN +static int ex_window __ARGS((void)); +#endif + +/* + * getcmdline() - accept a command line starting with firstc. + * + * firstc == ':' get ":" command line. + * firstc == '/' or '?' get search pattern + * firstc == '=' get expression + * firstc == '@' get text for input() function + * firstc == '>' get text for debug mode + * firstc == NUL get text for :insert command + * firstc == -1 like NUL, and break on CTRL-C + * + * The line is collected in ccline.cmdbuff, which is reallocated to fit the + * command line. + * + * Careful: getcmdline() can be called recursively! + * + * Return pointer to allocated string if there is a commandline, NULL + * otherwise. + */ +/*ARGSUSED*/ + char_u * +getcmdline(firstc, count, indent) + int firstc; + long count; /* only used for incremental search */ + int indent; /* indent for inside conditionals */ +{ + int c; + int i; + int j; + int gotesc = FALSE; /* TRUE when <ESC> just typed */ + int do_abbr; /* when TRUE check for abbr. */ +#ifdef FEAT_CMDHIST + char_u *lookfor = NULL; /* string to match */ + int hiscnt; /* current history line in use */ + int histype; /* history type to be used */ +#endif +#ifdef FEAT_SEARCH_EXTRA + pos_T old_cursor; + colnr_T old_curswant; + colnr_T old_leftcol; + linenr_T old_topline; +# ifdef FEAT_DIFF + int old_topfill; +# endif + linenr_T old_botline; + int did_incsearch = FALSE; + int incsearch_postponed = FALSE; +#endif + int did_wild_list = FALSE; /* did wild_list() recently */ + int wim_index = 0; /* index in wim_flags[] */ + int res; + int save_msg_scroll = msg_scroll; + int save_State = State; /* remember State when called */ + int some_key_typed = FALSE; /* one of the keys was typed */ +#ifdef FEAT_MOUSE + /* mouse drag and release events are ignored, unless they are + * preceded with a mouse down event */ + int ignore_drag_release = TRUE; +#endif +#ifdef FEAT_EVAL + int break_ctrl_c = FALSE; +#endif + expand_T xpc; + long *b_im_ptr = NULL; + +#ifdef FEAT_SNIFF + want_sniff_request = 0; +#endif +#ifdef FEAT_EVAL + if (firstc == -1) + { + firstc = NUL; + break_ctrl_c = TRUE; + } +#endif +#ifdef FEAT_RIGHTLEFT + /* start without Hebrew mapping for a command line */ + if (firstc == ':' || firstc == '=' || firstc == '>') + cmd_hkmap = 0; +#endif + + ccline.overstrike = FALSE; /* always start in insert mode */ +#ifdef FEAT_SEARCH_EXTRA + old_cursor = curwin->w_cursor; /* needs to be restored later */ + old_curswant = curwin->w_curswant; + old_leftcol = curwin->w_leftcol; + old_topline = curwin->w_topline; +# ifdef FEAT_DIFF + old_topfill = curwin->w_topfill; +# endif + old_botline = curwin->w_botline; +#endif + + /* + * set some variables for redrawcmd() + */ + ccline.cmdfirstc = (firstc == '@' ? 0 : firstc); + ccline.cmdindent = indent; + alloc_cmdbuff(exmode_active ? 250 : 0); /* alloc initial ccline.cmdbuff */ + if (ccline.cmdbuff == NULL) + return NULL; /* out of memory */ + ccline.cmdlen = ccline.cmdpos = 0; + ccline.cmdbuff[0] = NUL; + + ExpandInit(&xpc); + +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl && *curwin->w_p_rlc == 's' + && (firstc == '/' || firstc == '?')) + cmdmsg_rl = TRUE; + else + cmdmsg_rl = FALSE; +#endif + + redir_off = TRUE; /* don't redirect the typed command */ + if (!cmd_silent) + { + i = msg_scrolled; + msg_scrolled = 0; /* avoid wait_return message */ + gotocmdline(TRUE); + msg_scrolled += i; + redrawcmdprompt(); /* draw prompt or indent */ + set_cmdspos(); + } + xpc.xp_context = EXPAND_NOTHING; + xpc.xp_backslash = XP_BS_NONE; + + /* + * Avoid scrolling when called by a recursive do_cmdline(), e.g. when + * doing ":@0" when register 0 doesn't contain a CR. + */ + msg_scroll = FALSE; + + State = CMDLINE; + + if (firstc == '/' || firstc == '?' || firstc == '@') + { + /* Use ":lmap" mappings for search pattern and input(). */ + if (curbuf->b_p_imsearch == B_IMODE_USE_INSERT) + b_im_ptr = &curbuf->b_p_iminsert; + else + b_im_ptr = &curbuf->b_p_imsearch; + if (*b_im_ptr == B_IMODE_LMAP) + State |= LANGMAP; +#ifdef USE_IM_CONTROL + im_set_active(*b_im_ptr == B_IMODE_IM); +#endif + } +#ifdef USE_IM_CONTROL + else if (p_imcmdline) + im_set_active(TRUE); +#endif + +#ifdef FEAT_MOUSE + setmouse(); +#endif +#ifdef CURSOR_SHAPE + ui_cursor_shape(); /* may show different cursor shape */ +#endif + +#ifdef FEAT_CMDHIST + init_history(); + hiscnt = hislen; /* set hiscnt to impossible history value */ + histype = hist_char2type(firstc); +#endif + +#ifdef FEAT_DIGRAPHS + do_digraph(-1); /* init digraph typahead */ +#endif + + /* + * Collect the command string, handling editing keys. + */ + for (;;) + { +#ifdef USE_ON_FLY_SCROLL + dont_scroll = FALSE; /* allow scrolling here */ +#endif + quit_more = FALSE; /* reset after CTRL-D which had a more-prompt */ + + cursorcmd(); /* set the cursor on the right spot */ + c = safe_vgetc(); + if (KeyTyped) + { + some_key_typed = TRUE; +#ifdef FEAT_RIGHTLEFT + if (cmd_hkmap) + c = hkmap(c); +# ifdef FEAT_FKMAP + if (cmd_fkmap) + c = cmdl_fkmap(c); +# endif + if (cmdmsg_rl && !KeyStuffed) + { + /* Invert horizontal movements and operations. Only when + * typed by the user directly, not when the result of a + * mapping. */ + switch (c) + { + case K_RIGHT: c = K_LEFT; break; + case K_S_RIGHT: c = K_S_LEFT; break; + case K_C_RIGHT: c = K_C_LEFT; break; + case K_LEFT: c = K_RIGHT; break; + case K_S_LEFT: c = K_S_RIGHT; break; + case K_C_LEFT: c = K_C_RIGHT; break; + } + } +#endif + } + + /* + * Ignore got_int when CTRL-C was typed here. + * Don't ignore it in :global, we really need to break then, e.g., for + * ":g/pat/normal /pat" (without the <CR>). + * Don't ignore it for the input() function. + */ + if ((c == Ctrl_C +#ifdef UNIX + || c == intr_char +#endif + ) +#if defined(FEAT_EVAL) || defined(FEAT_CRYPT) + && firstc != '@' +#endif +#ifdef FEAT_EVAL + && !break_ctrl_c +#endif + && !global_busy) + got_int = FALSE; + +#ifdef FEAT_CMDHIST + /* free old command line when finished moving around in the history + * list */ + if (lookfor != NULL + && c != K_S_DOWN && c != K_S_UP && c != K_DOWN && c != K_UP + && c != K_PAGEDOWN && c != K_PAGEUP + && c != K_KPAGEDOWN && c != K_KPAGEUP + && c != K_LEFT && c != K_RIGHT + && (xpc.xp_numfiles > 0 || (c != Ctrl_P && c != Ctrl_N))) + { + vim_free(lookfor); + lookfor = NULL; + } +#endif + + /* + * <S-Tab> works like CTRL-P (unless 'wc' is <S-Tab>). + */ + if (c != p_wc && c == K_S_TAB && xpc.xp_numfiles != -1) + c = Ctrl_P; + +#ifdef FEAT_WILDMENU + /* Special translations for 'wildmenu' */ + if (did_wild_list && p_wmnu) + { + if (c == K_LEFT) + c = Ctrl_P; + else if (c == K_RIGHT) + c = Ctrl_N; + } + /* Hitting CR after "emenu Name.": complete submenu */ + if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu + && ccline.cmdpos > 1 + && ccline.cmdbuff[ccline.cmdpos - 1] == '.' + && ccline.cmdbuff[ccline.cmdpos - 2] != '\\' + && (c == '\n' || c == '\r' || c == K_KENTER)) + c = K_DOWN; +#endif + + /* free expanded names when finished walking through matches */ + if (xpc.xp_numfiles != -1 + && !(c == p_wc && KeyTyped) && c != p_wcm + && c != Ctrl_N && c != Ctrl_P && c != Ctrl_A + && c != Ctrl_L) + { + (void)ExpandOne(&xpc, NULL, NULL, 0, WILD_FREE); + did_wild_list = FALSE; +#ifdef FEAT_WILDMENU + if (!p_wmnu || (c != K_UP && c != K_DOWN)) +#endif + xpc.xp_context = EXPAND_NOTHING; + wim_index = 0; +#ifdef FEAT_WILDMENU + if (p_wmnu && wild_menu_showing != 0) + { + int skt = KeyTyped; + + if (wild_menu_showing == WM_SCROLLED) + { + /* Entered command line, move it up */ + cmdline_row--; + redrawcmd(); + } + else if (save_p_ls != -1) + { + /* restore 'laststatus' and 'winminheight' */ + p_ls = save_p_ls; + p_wmh = save_p_wmh; + last_status(FALSE); + update_screen(VALID); /* redraw the screen NOW */ + redrawcmd(); + save_p_ls = -1; + } + else + { +# ifdef FEAT_VERTSPLIT + win_redraw_last_status(topframe); +# else + lastwin->w_redr_status = TRUE; +# endif + redraw_statuslines(); + } + KeyTyped = skt; + wild_menu_showing = 0; + } +#endif + } + +#ifdef FEAT_WILDMENU + /* Special translations for 'wildmenu' */ + if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) + { + /* Hitting <Down> after "emenu Name.": complete submenu */ + if (ccline.cmdbuff[ccline.cmdpos - 1] == '.' && c == K_DOWN) + c = p_wc; + else if (c == K_UP) + { + /* Hitting <Up>: Remove one submenu name in front of the + * cursor */ + int found = FALSE; + + j = (int)(xpc.xp_pattern - ccline.cmdbuff); + i = 0; + while (--j > 0) + { + /* check for start of menu name */ + if (ccline.cmdbuff[j] == ' ' + && ccline.cmdbuff[j - 1] != '\\') + { + i = j + 1; + break; + } + /* check for start of submenu name */ + if (ccline.cmdbuff[j] == '.' + && ccline.cmdbuff[j - 1] != '\\') + { + if (found) + { + i = j + 1; + break; + } + else + found = TRUE; + } + } + if (i > 0) + cmdline_del(i); + c = p_wc; + xpc.xp_context = EXPAND_NOTHING; + } + } + if (xpc.xp_context == EXPAND_FILES && p_wmnu) + { + char_u upseg[5]; + + upseg[0] = PATHSEP; + upseg[1] = '.'; + upseg[2] = '.'; + upseg[3] = PATHSEP; + upseg[4] = NUL; + + if (ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP + && c == K_DOWN + && (ccline.cmdbuff[ccline.cmdpos - 2] != '.' + || ccline.cmdbuff[ccline.cmdpos - 3] != '.')) + { + /* go down a directory */ + c = p_wc; + } + else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN) + { + /* If in a direct ancestor, strip off one ../ to go down */ + int found = FALSE; + + j = ccline.cmdpos; + i = (int)(xpc.xp_pattern - ccline.cmdbuff); + while (--j > i) + { + if (vim_ispathsep(ccline.cmdbuff[j])) + { + found = TRUE; + break; + } + } + if (found + && ccline.cmdbuff[j - 1] == '.' + && ccline.cmdbuff[j - 2] == '.' + && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2)) + { + cmdline_del(j - 2); + c = p_wc; + } + } + else if (c == K_UP) + { + /* go up a directory */ + int found = FALSE; + + j = ccline.cmdpos - 1; + i = (int)(xpc.xp_pattern - ccline.cmdbuff); + while (--j > i) + { +#ifdef FEAT_MBYTE + if (has_mbyte) + j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j); +#endif + if (vim_ispathsep(ccline.cmdbuff[j]) +#ifdef BACKSLASH_IN_FILENAME + && vim_strchr(" *?[{`$%#", ccline.cmdbuff[j + 1]) + == NULL +#endif + ) + { + if (found) + { + i = j + 1; + break; + } + else + found = TRUE; + } + } + + if (!found) + j = i; + else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0) + j += 4; + else if (STRNCMP(ccline.cmdbuff + j, upseg + 1, 3) == 0 + && j == i) + j += 3; + else + j = 0; + if (j > 0) + { + /* TODO this is only for DOS/UNIX systems - need to put in + * machine-specific stuff here and in upseg init */ + cmdline_del(j); + put_on_cmdline(upseg + 1, 3, FALSE); + } + else if (ccline.cmdpos > i) + cmdline_del(i); + c = p_wc; + } + } +#if 0 /* If enabled <Down> on a file takes you _completely_ out of wildmenu */ + if (p_wmnu + && (xpc.xp_context == EXPAND_FILES + || xpc.xp_context == EXPAND_MENUNAMES) + && (c == K_UP || c == K_DOWN)) + xpc.xp_context = EXPAND_NOTHING; +#endif + +#endif /* FEAT_WILDMENU */ + + /* CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert + * mode when 'insertmode' is set, CTRL-\ e prompts for an expression. */ + if (c == Ctrl_BSL) + { + ++no_mapping; + ++allow_keys; + c = safe_vgetc(); + --no_mapping; + --allow_keys; + /* CTRL-\ e doesn't work when obtaining an expression. */ + if (c != Ctrl_N && c != Ctrl_G + && (c != 'e' || ccline.cmdfirstc == '=')) + { + vungetc(c); + c = Ctrl_BSL; + } +#ifdef FEAT_EVAL + else if (c == 'e') + { + struct cmdline_info save_ccline; + char_u *p; + + /* + * Replace the command line with the result of an expression. + * Need to save 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; + save_ccline = ccline; + ccline.cmdbuff = NULL; + ccline.cmdprompt = NULL; + c = get_expr_register(); + ccline = save_ccline; + if (c == '=') + { + p = get_expr_line(); + if (p != NULL + && realloc_cmdbuff((int)STRLEN(p) + 1) == OK) + { + ccline.cmdlen = STRLEN(p); + 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; + } + } + beep_flush(); + c = ESC; + } +#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 + if (c == cedit_key || c == K_CMDWIN) + { + /* + * Open a window to edit the command line (and history). + */ + c = ex_window(); + some_key_typed = TRUE; + } +# ifdef FEAT_DIGRAPHS + else +# endif +#endif +#ifdef FEAT_DIGRAPHS + c = do_digraph(c); +#endif + + if (c == '\n' || c == '\r' || c == K_KENTER || (c == ESC + && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL))) + { + gotesc = FALSE; /* Might have typed ESC previously, don't + truncate the cmdline now. */ + if (ccheck_abbr(c + ABBR_OFF)) + goto cmdline_changed; + if (!cmd_silent) + { + windgoto(msg_row, 0); + out_flush(); + } + break; + } + + /* + * 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) + { + 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, WILD_NO_BEEP); + else if (wim_flags[wim_index] & WIM_FULL) + res = nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP); + 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, WILD_NO_BEEP); + else + res = nextwild(&xpc, WILD_EXPAND_KEEP, WILD_NO_BEEP); + + /* 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 + nextwild(&xpc, WILD_PREV, 0); /* remove match */ +#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, WILD_NO_BEEP); + else if (wim_flags[wim_index] & WIM_FULL) + nextwild(&xpc, WILD_NEXT, WILD_NO_BEEP); + } + else + vim_beep(); + } +#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; + } + + gotesc = FALSE; + + /* <S-Tab> goes to last match, in a clumsy way */ + if (c == K_S_TAB && KeyTyped) + { + if (nextwild(&xpc, WILD_EXPAND_KEEP, 0) == OK + && nextwild(&xpc, WILD_PREV, 0) == OK + && nextwild(&xpc, WILD_PREV, 0) == OK) + goto cmdline_changed; + } + + if (c == NUL || c == K_ZERO) /* NUL is stored as NL */ + c = NL; + + do_abbr = TRUE; /* default: check for abbreviation */ + + /* + * Big switch for a typed command line character. + */ + switch (c) + { + case K_BS: + case Ctrl_H: + case K_DEL: + case K_KDEL: + case Ctrl_W: +#ifdef FEAT_FKMAP + if (cmd_fkmap && c == K_BS) + c = K_DEL; +#endif + if (c == K_KDEL) + c = K_DEL; + + /* + * delete current character is the same as backspace on next + * character, except at end of line + */ + if (c == K_DEL && ccline.cmdpos != ccline.cmdlen) + ++ccline.cmdpos; +#ifdef FEAT_MBYTE + if (has_mbyte && c == K_DEL) + ccline.cmdpos += mb_off_next(ccline.cmdbuff, + ccline.cmdbuff + ccline.cmdpos); +#endif + if (ccline.cmdpos > 0) + { + char_u *p; + + j = ccline.cmdpos; + p = ccline.cmdbuff + j; +#ifdef FEAT_MBYTE + if (has_mbyte) + { + p = mb_prevptr(ccline.cmdbuff, p); + if (c == Ctrl_W) + { + while (p > ccline.cmdbuff && vim_isspace(*p)) + p = mb_prevptr(ccline.cmdbuff, p); + i = mb_get_class(p); + while (p > ccline.cmdbuff && mb_get_class(p) == i) + p = mb_prevptr(ccline.cmdbuff, p); + if (mb_get_class(p) != i) + p += (*mb_ptr2len_check)(p); + } + } + else +#endif + if (c == Ctrl_W) + { + while (p > ccline.cmdbuff && vim_isspace(p[-1])) + --p; + i = vim_iswordc(p[-1]); + while (p > ccline.cmdbuff && !vim_isspace(p[-1]) + && vim_iswordc(p[-1]) == i) + --p; + } + else + --p; + ccline.cmdpos = (int)(p - ccline.cmdbuff); + ccline.cmdlen -= j - ccline.cmdpos; + i = ccline.cmdpos; + while (i < ccline.cmdlen) + ccline.cmdbuff[i++] = ccline.cmdbuff[j++]; + + /* Truncate at the end, required for multi-byte chars. */ + ccline.cmdbuff[ccline.cmdlen] = NUL; + redrawcmd(); + } + else if (ccline.cmdlen == 0 && c != Ctrl_W + && ccline.cmdprompt == NULL && indent == 0) + { + /* In ex and debug mode it doesn't make sense to return. */ + if (exmode_active +#ifdef FEAT_EVAL + || ccline.cmdfirstc == '>' +#endif + ) + goto cmdline_not_changed; + + vim_free(ccline.cmdbuff); /* no commandline to return */ + ccline.cmdbuff = NULL; + if (!cmd_silent) + { +#ifdef FEAT_RIGHTLEFT + if (cmdmsg_rl) + msg_col = Columns; + else +#endif + msg_col = 0; + msg_putchar(' '); /* delete ':' */ + } + redraw_cmdline = TRUE; + goto returncmd; /* back to cmd mode */ + } + goto cmdline_changed; + + case K_INS: + case K_KINS: +#ifdef FEAT_FKMAP + /* if Farsi mode set, we are in reverse insert mode - + Do not change the mode */ + if (cmd_fkmap) + beep_flush(); + else +#endif + ccline.overstrike = !ccline.overstrike; +#ifdef CURSOR_SHAPE + ui_cursor_shape(); /* may show different cursor shape */ +#endif + goto cmdline_not_changed; + + case Ctrl_HAT: + if (map_to_exists_mode((char_u *)"", LANGMAP)) + { + /* ":lmap" mappings exists, toggle use of mappings. */ + State ^= LANGMAP; +#ifdef USE_IM_CONTROL + im_set_active(FALSE); /* Disable input method */ +#endif + if (b_im_ptr != NULL) + { + if (State & LANGMAP) + *b_im_ptr = B_IMODE_LMAP; + else + *b_im_ptr = B_IMODE_NONE; + } + } +#ifdef USE_IM_CONTROL + else + { + /* There are no ":lmap" mappings, toggle IM. When + * 'imdisable' is set don't try getting the status, it's + * always off. */ + if ((p_imdisable && b_im_ptr != NULL) + ? *b_im_ptr == B_IMODE_IM : im_get_status()) + { + im_set_active(FALSE); /* Disable input method */ + if (b_im_ptr != NULL) + *b_im_ptr = B_IMODE_NONE; + } + else + { + im_set_active(TRUE); /* Enable input method */ + if (b_im_ptr != NULL) + *b_im_ptr = B_IMODE_IM; + } + } +#endif + if (b_im_ptr != NULL) + { + if (b_im_ptr == &curbuf->b_p_iminsert) + set_iminsert_global(); + else + set_imsearch_global(); + } +#ifdef CURSOR_SHAPE + ui_cursor_shape(); /* may show different cursor shape */ +#endif +#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP) + /* Show/unshow value of 'keymap' in status lines later. */ + status_redraw_curbuf(); +#endif + goto cmdline_not_changed; + +/* case '@': only in very old vi */ + case Ctrl_U: + /* delete all characters left of the cursor */ + j = ccline.cmdpos; + ccline.cmdlen -= j; + i = ccline.cmdpos = 0; + while (i < ccline.cmdlen) + ccline.cmdbuff[i++] = ccline.cmdbuff[j++]; + /* Truncate at the end, required for multi-byte chars. */ + ccline.cmdbuff[ccline.cmdlen] = NUL; + redrawcmd(); + goto cmdline_changed; + +#ifdef FEAT_CLIPBOARD + case Ctrl_Y: + /* Copy the modeless selection, if there is one. */ + if (clip_star.state != SELECT_CLEARED) + { + if (clip_star.state == SELECT_DONE) + clip_copy_modeless_selection(TRUE); + goto cmdline_not_changed; + } + break; +#endif + + case ESC: /* get here if p_wc != ESC or when ESC typed twice */ + case Ctrl_C: + /* In exmode it doesn't make sense to return. */ + if (exmode_active) + goto cmdline_not_changed; + + gotesc = TRUE; /* will free ccline.cmdbuff after + putting it in history */ + goto returncmd; /* back to cmd mode */ + + case Ctrl_R: /* insert register */ +#ifdef USE_ON_FLY_SCROLL + dont_scroll = TRUE; /* disallow scrolling here */ +#endif + putcmdline('"', TRUE); + ++no_mapping; + i = c = safe_vgetc(); /* CTRL-R <char> */ + if (i == Ctrl_O) + i = Ctrl_R; /* CTRL-R CTRL-O == CTRL-R CTRL-R */ + if (i == Ctrl_R) + c = safe_vgetc(); /* CTRL-R CTRL-R <char> */ + --no_mapping; +#ifdef FEAT_EVAL + /* + * Insert the result of an expression. + * Need to save the current command line, to be able to enter + * a new one... + */ + new_cmdpos = -1; + if (c == '=') + { + struct cmdline_info save_ccline; + + if (ccline.cmdfirstc == '=')/* can't do this recursively */ + { + beep_flush(); + c = ESC; + } + else + { + save_ccline = ccline; + ccline.cmdbuff = NULL; + ccline.cmdprompt = NULL; + c = get_expr_register(); + ccline = save_ccline; + } + } +#endif + if (c != ESC) /* use ESC to cancel inserting register */ + { + cmdline_paste(c, i == Ctrl_R); + KeyTyped = FALSE; /* Don't do p_wc completion. */ +#ifdef FEAT_EVAL + if (new_cmdpos >= 0) + { + /* set_cmdline_pos() was used */ + if (new_cmdpos > ccline.cmdlen) + ccline.cmdpos = ccline.cmdlen; + else + ccline.cmdpos = new_cmdpos; + } +#endif + } + redrawcmd(); + goto cmdline_changed; + + case Ctrl_D: + if (showmatches(&xpc, FALSE) == EXPAND_NOTHING) + break; /* Use ^D as normal char instead */ + + redrawcmd(); + continue; /* don't do incremental search now */ + + case K_RIGHT: + case K_S_RIGHT: + case K_C_RIGHT: + do + { + if (ccline.cmdpos >= ccline.cmdlen) + break; + i = cmdline_charsize(ccline.cmdpos); + if (KeyTyped && ccline.cmdspos + i >= Columns * Rows) + break; + ccline.cmdspos += i; +#ifdef FEAT_MBYTE + if (has_mbyte) + ccline.cmdpos += (*mb_ptr2len_check)(ccline.cmdbuff + + ccline.cmdpos); + else +#endif + ++ccline.cmdpos; + } + while ((c == K_S_RIGHT || c == K_C_RIGHT) + && ccline.cmdbuff[ccline.cmdpos] != ' '); +#ifdef FEAT_MBYTE + if (has_mbyte) + set_cmdspos_cursor(); +#endif + goto cmdline_not_changed; + + case K_LEFT: + case K_S_LEFT: + case K_C_LEFT: + do + { + if (ccline.cmdpos == 0) + break; + --ccline.cmdpos; +#ifdef FEAT_MBYTE + if (has_mbyte) /* move to first byte of char */ + ccline.cmdpos -= (*mb_head_off)(ccline.cmdbuff, + ccline.cmdbuff + ccline.cmdpos); +#endif + ccline.cmdspos -= cmdline_charsize(ccline.cmdpos); + } + while ((c == K_S_LEFT || c == K_C_LEFT) + && ccline.cmdbuff[ccline.cmdpos - 1] != ' '); +#ifdef FEAT_MBYTE + if (has_mbyte) + set_cmdspos_cursor(); +#endif + goto cmdline_not_changed; + + case K_IGNORE: + goto cmdline_not_changed; /* Ignore mouse */ + +#ifdef FEAT_MOUSE + case K_MIDDLEDRAG: + case K_MIDDLERELEASE: + goto cmdline_not_changed; /* Ignore mouse */ + + case K_MIDDLEMOUSE: +# ifdef FEAT_GUI + /* When GUI is active, also paste when 'mouse' is empty */ + if (!gui.in_use) +# endif + if (!mouse_has(MOUSE_COMMAND)) + goto cmdline_not_changed; /* Ignore mouse */ +#ifdef FEAT_CLIPBOARD + if (clip_star.available) + cmdline_paste('*', TRUE); + else +#endif + cmdline_paste(0, TRUE); + redrawcmd(); + goto cmdline_changed; + +#ifdef FEAT_DND + case K_DROP: + cmdline_paste('~', TRUE); + redrawcmd(); + goto cmdline_changed; +#endif + + case K_LEFTDRAG: + case K_LEFTRELEASE: + case K_RIGHTDRAG: + case K_RIGHTRELEASE: + /* Ignore drag and release events when the button-down wasn't + * seen before. */ + if (ignore_drag_release) + goto cmdline_not_changed; + /* FALLTHROUGH */ + case K_LEFTMOUSE: + case K_RIGHTMOUSE: + if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE) + ignore_drag_release = TRUE; + else + ignore_drag_release = FALSE; +# ifdef FEAT_GUI + /* When GUI is active, also move when 'mouse' is empty */ + if (!gui.in_use) +# endif + if (!mouse_has(MOUSE_COMMAND)) + goto cmdline_not_changed; /* Ignore mouse */ +# ifdef FEAT_CLIPBOARD + if (mouse_row < cmdline_row && clip_star.available) + { + int button, is_click, is_drag; + + /* + * Handle modeless selection. + */ + button = get_mouse_button(KEY2TERMCAP1(c), + &is_click, &is_drag); + if (mouse_model_popup() && button == MOUSE_LEFT + && (mod_mask & MOD_MASK_SHIFT)) + { + /* Translate shift-left to right button. */ + button = MOUSE_RIGHT; + mod_mask &= ~MOD_MASK_SHIFT; + } + clip_modeless(button, is_click, is_drag); + goto cmdline_not_changed; + } +# endif + + set_cmdspos(); + for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen; + ++ccline.cmdpos) + { + i = cmdline_charsize(ccline.cmdpos); + if (mouse_row <= cmdline_row + ccline.cmdspos / Columns + && mouse_col < ccline.cmdspos % Columns + i) + break; +#ifdef FEAT_MBYTE + if (has_mbyte) + { + /* Count ">" for double-wide char that doesn't fit. */ + correct_cmdspos(ccline.cmdpos, i); + ccline.cmdpos += (*mb_ptr2len_check)(ccline.cmdbuff + + ccline.cmdpos) - 1; + } +#endif + ccline.cmdspos += i; + } + goto cmdline_not_changed; + + /* Mouse scroll wheel: ignored here */ + case K_MOUSEDOWN: + case K_MOUSEUP: + /* Alternate buttons ignored here */ + case K_X1MOUSE: + case K_X1DRAG: + case K_X1RELEASE: + case K_X2MOUSE: + case K_X2DRAG: + case K_X2RELEASE: + goto cmdl |