diff options
Diffstat (limited to 'src/nvim/ex_getln.c')
-rw-r--r-- | src/nvim/ex_getln.c | 293 |
1 files changed, 164 insertions, 129 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 3f7bc45c2e..93684e8606 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -23,6 +23,7 @@ #include "nvim/digraph.h" #include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/userfunc.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" @@ -136,6 +137,15 @@ struct cmdline_info { /// Last value of prompt_id, incremented when doing new prompt static unsigned last_prompt_id = 0; +typedef struct { + colnr_T vs_curswant; + colnr_T vs_leftcol; + linenr_T vs_topline; + int vs_topfill; + linenr_T vs_botline; + int vs_empty_rows; +} viewstate_T; + typedef struct command_line_state { VimState state; int firstc; @@ -151,16 +161,8 @@ typedef struct command_line_state { int histype; // history type to be used pos_T search_start; // where 'incsearch' starts searching pos_T save_cursor; - colnr_T old_curswant; - colnr_T init_curswant; - colnr_T old_leftcol; - colnr_T init_leftcol; - linenr_T old_topline; - linenr_T init_topline; - int old_topfill; - int init_topfill; - linenr_T old_botline; - linenr_T init_botline; + viewstate_T init_viewstate; + viewstate_T old_viewstate; pos_T match_start; pos_T match_end; int did_incsearch; @@ -228,6 +230,28 @@ static int compl_selected; static int cmd_hkmap = 0; // Hebrew mapping during command line +static void save_viewstate(viewstate_T *vs) + FUNC_ATTR_NONNULL_ALL +{ + vs->vs_curswant = curwin->w_curswant; + vs->vs_leftcol = curwin->w_leftcol; + vs->vs_topline = curwin->w_topline; + vs->vs_topfill = curwin->w_topfill; + vs->vs_botline = curwin->w_botline; + vs->vs_empty_rows = curwin->w_empty_rows; +} + +static void restore_viewstate(viewstate_T *vs) + FUNC_ATTR_NONNULL_ALL +{ + curwin->w_curswant = vs->vs_curswant; + curwin->w_leftcol = vs->vs_leftcol; + curwin->w_topline = vs->vs_topline; + curwin->w_topfill = vs->vs_topfill; + curwin->w_botline = vs->vs_botline; + curwin->w_empty_rows = vs->vs_empty_rows; +} + /// Internal entry point for cmdline mode. /// /// caller must use save_cmdline and restore_cmdline. Best is to use @@ -238,21 +262,18 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) static int cmdline_level = 0; cmdline_level++; - CommandLineState state, *s = &state; - memset(s, 0, sizeof(CommandLineState)); - s->firstc = firstc; - s->count = count; - s->indent = indent; - s->save_msg_scroll = msg_scroll; - s->save_State = State; + CommandLineState state = { + .firstc = firstc, + .count = count, + .indent = indent, + .save_msg_scroll = msg_scroll, + .save_State = State, + .ignore_drag_release = true, + .match_start = curwin->w_cursor, + }; + CommandLineState *s = &state; s->save_p_icm = vim_strsave(p_icm); - s->ignore_drag_release = true; - s->match_start = curwin->w_cursor; - s->init_curswant = curwin->w_curswant; - s->init_leftcol = curwin->w_leftcol; - s->init_topline = curwin->w_topline; - s->init_topfill = curwin->w_topfill; - s->init_botline = curwin->w_botline; + save_viewstate(&state.init_viewstate); if (s->firstc == -1) { s->firstc = NUL; @@ -270,11 +291,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) clearpos(&s->match_end); s->save_cursor = curwin->w_cursor; // may be restored later s->search_start = curwin->w_cursor; - s->old_curswant = curwin->w_curswant; - s->old_leftcol = curwin->w_leftcol; - s->old_topline = curwin->w_topline; - s->old_topfill = curwin->w_topfill; - s->old_botline = curwin->w_botline; + save_viewstate(&state.old_viewstate); assert(indent >= 0); @@ -415,8 +432,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level); tv_dict_set_keys_readonly(dict); // not readonly: - tv_dict_add_special(dict, S_LEN("abort"), - s->gotesc ? kSpecialVarTrue : kSpecialVarFalse); + tv_dict_add_bool(dict, S_LEN("abort"), + s->gotesc ? kBoolVarTrue : kBoolVarFalse); try_enter(&tstate); apply_autocmds(EVENT_CMDLINELEAVE, (char_u *)firstcbuf, (char_u *)firstcbuf, false, curbuf); @@ -433,6 +450,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) ExpandCleanup(&s->xpc); ccline.xpc = NULL; + if (s->gotesc) { + // There might be a preview window open for inccommand. Close it. + close_preview_windows(); + } + if (s->did_incsearch) { if (s->gotesc) { curwin->w_cursor = s->save_cursor; @@ -444,11 +466,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) } curwin->w_cursor = s->search_start; // -V519 } - curwin->w_curswant = s->old_curswant; - curwin->w_leftcol = s->old_leftcol; - curwin->w_topline = s->old_topline; - curwin->w_topfill = s->old_topfill; - curwin->w_botline = s->old_botline; + restore_viewstate(&s->old_viewstate); highlight_match = false; validate_cursor(); // needed for TAB redraw_all_later(SOME_VALID); @@ -531,7 +549,7 @@ static int command_line_check(VimState *state) static int command_line_execute(VimState *state, int key) { - if (key == K_IGNORE) { + if (key == K_IGNORE || key == K_NOP) { return -1; // get another key } @@ -609,6 +627,16 @@ static int command_line_execute(VimState *state, int key) s->c = Ctrl_N; } } + if (compl_match_array || s->did_wild_list) { + if (s->c == Ctrl_E) { + s->res = nextwild(&s->xpc, WILD_CANCEL, WILD_NO_BEEP, + s->firstc != '@'); + } else if (s->c == Ctrl_Y) { + s->res = nextwild(&s->xpc, WILD_APPLY, WILD_NO_BEEP, + s->firstc != '@'); + s->c = Ctrl_E; + } + } // Hitting CR after "emenu Name.": complete submenu if (s->xpc.xp_context == EXPAND_MENUNAMES && p_wmnu @@ -878,7 +906,9 @@ static int command_line_execute(VimState *state, int key) } if (s->c == cedit_key || s->c == K_CMDWIN) { - if (ex_normal_busy == 0 && got_int == false) { + // TODO(vim): why is ex_normal_busy checked here? + if ((s->c == K_CMDWIN || ex_normal_busy == 0) + && got_int == false) { // Open a window to edit the command line (and history). s->c = open_cmdwin(); s->some_key_typed = true; @@ -923,22 +953,28 @@ static int command_line_execute(VimState *state, int key) // - wildcard expansion is only done when the 'wildchar' key is really // typed, not when it comes from a macro if ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm) { + int options = WILD_NO_BEEP; + if (wim_flags[s->wim_index] & WIM_BUFLASTUSED) { + options |= WILD_BUFLASTUSED; + } if (s->xpc.xp_numfiles > 0) { // typed p_wc at least twice // if 'wildmode' contains "list" may still need to list if (s->xpc.xp_numfiles > 1 && !s->did_wild_list - && (wim_flags[s->wim_index] & WIM_LIST)) { - (void)showmatches(&s->xpc, false); + && ((wim_flags[s->wim_index] & WIM_LIST) + || (p_wmnu && (wim_flags[s->wim_index] & WIM_FULL) != 0))) { + (void)showmatches(&s->xpc, p_wmnu + && ((wim_flags[s->wim_index] & WIM_LIST) == 0)); redrawcmd(); s->did_wild_list = true; } if (wim_flags[s->wim_index] & WIM_LONGEST) { - s->res = nextwild(&s->xpc, WILD_LONGEST, WILD_NO_BEEP, - s->firstc != '@'); + s->res = nextwild(&s->xpc, WILD_LONGEST, options, + s->firstc != '@'); } else if (wim_flags[s->wim_index] & WIM_FULL) { - s->res = nextwild(&s->xpc, WILD_NEXT, WILD_NO_BEEP, - s->firstc != '@'); + s->res = nextwild(&s->xpc, WILD_NEXT, options, + s->firstc != '@'); } else { s->res = OK; // don't insert 'wildchar' now } @@ -949,11 +985,11 @@ static int command_line_execute(VimState *state, int key) // if 'wildmode' first contains "longest", get longest // common part if (wim_flags[0] & WIM_LONGEST) { - s->res = nextwild(&s->xpc, WILD_LONGEST, WILD_NO_BEEP, - s->firstc != '@'); + s->res = nextwild(&s->xpc, WILD_LONGEST, options, + s->firstc != '@'); } else { - s->res = nextwild(&s->xpc, WILD_EXPAND_KEEP, WILD_NO_BEEP, - s->firstc != '@'); + s->res = nextwild(&s->xpc, WILD_EXPAND_KEEP, options, + s->firstc != '@'); } // if interrupted while completing, behave like it failed @@ -990,11 +1026,11 @@ static int command_line_execute(VimState *state, int key) s->did_wild_list = true; if (wim_flags[s->wim_index] & WIM_LONGEST) { - nextwild(&s->xpc, WILD_LONGEST, WILD_NO_BEEP, - s->firstc != '@'); + nextwild(&s->xpc, WILD_LONGEST, options, + s->firstc != '@'); } else if (wim_flags[s->wim_index] & WIM_FULL) { - nextwild(&s->xpc, WILD_NEXT, WILD_NO_BEEP, - s->firstc != '@'); + nextwild(&s->xpc, WILD_NEXT, options, + s->firstc != '@'); } } else { vim_beep(BO_WILD); @@ -1075,7 +1111,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match) int found = searchit(curwin, curbuf, &t, NULL, next_match ? FORWARD : BACKWARD, pat, s->count, search_flags, - RE_SEARCH, 0, NULL, NULL); + RE_SEARCH, NULL); emsg_off--; ui_busy_stop(); if (found) { @@ -1111,11 +1147,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match) update_topline(); validate_cursor(); highlight_match = true; - s->old_curswant = curwin->w_curswant; - s->old_leftcol = curwin->w_leftcol; - s->old_topline = curwin->w_topline; - s->old_topfill = curwin->w_topfill; - s->old_botline = curwin->w_botline; + save_viewstate(&s->old_viewstate); update_screen(NOT_VALID); redrawcmdline(); } else { @@ -1236,11 +1268,7 @@ static int command_line_handle_key(CommandLineState *s) s->search_start = s->save_cursor; // save view settings, so that the screen won't be restored at the // wrong position - s->old_curswant = s->init_curswant; - s->old_leftcol = s->init_leftcol; - s->old_topline = s->init_topline; - s->old_topfill = s->init_topfill; - s->old_botline = s->init_botline; + s->old_viewstate = s->init_viewstate; } redrawcmd(); } else if (ccline.cmdlen == 0 && s->c != Ctrl_W @@ -1818,6 +1846,7 @@ static int command_line_changed(CommandLineState *s) if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) { pos_T end_pos; proftime_T tm; + searchit_arg_T sia; // if there is a character waiting, search and redraw later if (char_avail()) { @@ -1844,8 +1873,10 @@ static int command_line_changed(CommandLineState *s) if (!p_hls) { search_flags += SEARCH_KEEP; } + memset(&sia, 0, sizeof(sia)); + sia.sa_tm = &tm; i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count, - search_flags, &tm, NULL); + search_flags, &sia); emsg_off--; // if interrupted while searching, behave like it failed if (got_int) { @@ -1867,10 +1898,7 @@ static int command_line_changed(CommandLineState *s) // first restore the old curwin values, so the screen is // positioned in the same way as the actual search command - curwin->w_leftcol = s->old_leftcol; - curwin->w_topline = s->old_topline; - curwin->w_topfill = s->old_topfill; - curwin->w_botline = s->old_botline; + restore_viewstate(&s->old_viewstate); changed_cline_bef_curs(); update_topline(); @@ -1924,21 +1952,21 @@ static int command_line_changed(CommandLineState *s) // - Immediately undo the effects. State |= CMDPREVIEW; emsg_silent++; // Block error reporting as the command may be incomplete + msg_silent++; // Block messages, namely ones that prompt do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_NOWAIT); + msg_silent--; // Unblock messages emsg_silent--; // Unblock error reporting // Restore the window "view". curwin->w_cursor = s->save_cursor; - curwin->w_curswant = s->old_curswant; - curwin->w_leftcol = s->old_leftcol; - curwin->w_topline = s->old_topline; - curwin->w_topfill = s->old_topfill; - curwin->w_botline = s->old_botline; + restore_viewstate(&s->old_viewstate); update_topline(); redrawcmdline(); + } else if (State & CMDPREVIEW) { State = (State & ~CMDPREVIEW); + close_preview_windows(); update_screen(SOME_VALID); // Clear 'inccommand' preview. } @@ -1991,7 +2019,8 @@ char_u * getcmdline ( int firstc, long count, // only used for incremental search - int indent // indent for inside conditionals + int indent, // indent for inside conditionals + bool do_concat FUNC_ATTR_UNUSED ) { // Be prepared for situations where cmdline can be invoked recursively. @@ -2167,17 +2196,18 @@ static void correct_screencol(int idx, int cells, int *col) * Get an Ex command line for the ":" command. */ char_u * -getexline ( - int c, /* normally ':', NUL for ":append" */ +getexline( + int c, // normally ':', NUL for ":append" void *cookie, - int indent /* indent for inside conditionals */ + int indent, // indent for inside conditionals + bool do_concat ) { /* When executing a register, remove ':' that's in front of each line. */ if (exec_from_reg && vpeekc() == ':') (void)vgetc(); - return getcmdline(c, 1L, indent); + return getcmdline(c, 1L, indent, do_concat); } /* @@ -2187,11 +2217,12 @@ getexline ( * Returns a string in allocated memory or NULL. */ char_u * -getexmodeline ( - int promptc, /* normally ':', NUL for ":append" and '?' for - :s prompt */ +getexmodeline( + int promptc, // normally ':', NUL for ":append" and '?' + // for :s prompt void *cookie, - int indent /* indent for inside conditionals */ + int indent, // indent for inside conditionals + bool do_concat ) { garray_T line_ga; @@ -2320,7 +2351,7 @@ redraw: } while (++vcol % 8); p++; } else { - len = MB_PTR2LEN(p); + len = utfc_ptr2len(p); msg_outtrans_len(p, len); vcol += ptr2cells(p); p += len; @@ -2428,9 +2459,10 @@ redraw: /* make following messages go to the next line */ msg_didout = FALSE; msg_col = 0; - if (msg_row < Rows - 1) - ++msg_row; - emsg_on_display = FALSE; /* don't want os_delay() */ + if (msg_row < Rows - 1) { + msg_row++; + } + emsg_on_display = false; // don't want os_delay() if (got_int) ga_clear(&line_ga); @@ -2692,7 +2724,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) goto color_cmdline_error; } if (tv.v_type != VAR_LIST) { - PRINT_ERRMSG(_("E5400: Callback should return list")); + PRINT_ERRMSG("%s", _("E5400: Callback should return list")); goto color_cmdline_error; } if (tv.vval.v_list == NULL) { @@ -3031,7 +3063,7 @@ void cmdline_screen_cleared(void) } } -/// called by ui_flush, do what redraws neccessary to keep cmdline updated. +/// called by ui_flush, do what redraws necessary to keep cmdline updated. void cmdline_ui_flush(void) { if (!ui_has(kUICmdline)) { @@ -3557,7 +3589,7 @@ static int ccheck_abbr(int c) // Do not consider '<,'> be part of the mapping, skip leading whitespace. // Actually accepts any mark. - while (ascii_iswhite(ccline.cmdbuff[spos]) && spos < ccline.cmdlen) { + while (spos < ccline.cmdlen && ascii_iswhite(ccline.cmdbuff[spos])) { spos++; } if (ccline.cmdlen - spos > 5 @@ -3781,6 +3813,12 @@ ExpandOne ( return NULL; } + if (mode == WILD_CANCEL) { + ss = vim_strsave(orig_save); + } else if (mode == WILD_APPLY) { + ss = vim_strsave(findex == -1 ? orig_save : xp->xp_files[findex]); + } + /* free old names */ if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) { FreeWild(xp->xp_numfiles, xp->xp_files); @@ -3792,7 +3830,7 @@ ExpandOne ( if (mode == WILD_FREE) /* only release file name */ return NULL; - if (xp->xp_numfiles == -1) { + if (xp->xp_numfiles == -1 && mode != WILD_APPLY && mode != WILD_CANCEL) { xfree(orig_save); orig_save = orig; orig_saved = TRUE; @@ -4684,6 +4722,9 @@ ExpandFromContext ( flags |= EW_KEEPALL; if (options & WILD_SILENT) flags |= EW_SILENT; + if (options & WILD_NOERROR) { + flags |= EW_NOERROR; + } if (options & WILD_ALLLINKS) { flags |= EW_ALLLINKS; } @@ -4697,8 +4738,7 @@ ExpandFromContext ( int free_pat = FALSE; int i; - /* for ":set path=" and ":set tags=" halve backslashes for escaped - * space */ + // for ":set path=" and ":set tags=" halve backslashes for escaped space if (xp->xp_backslash != XP_BS_NONE) { free_pat = TRUE; pat = vim_strsave(pat); @@ -4966,8 +5006,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int ret; bool did_curdir = false; - /* for ":set path=" and ":set tags=" halve backslashes for escaped - * space */ + // for ":set path=" and ":set tags=" halve backslashes for escaped space pat = vim_strsave(filepat); for (i = 0; pat[i]; ++i) if (pat[i] == '\\' && pat[i + 1] == ' ') @@ -5000,19 +5039,24 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, hashtab_T found_ht; hash_init(&found_ht); for (s = path; ; s = e) { + e = vim_strchr(s, ENV_SEPCHAR); + if (e == NULL) { + e = s + STRLEN(s); + } + if (*s == NUL) { if (did_curdir) { break; } // Find directories in the current directory, path is empty. did_curdir = true; - } else if (*s == '.') { + flags |= EW_DIR; + } else if (STRNCMP(s, ".", e - s) == 0) { did_curdir = true; - } - - e = vim_strchr(s, ENV_SEPCHAR); - if (e == NULL) { - e = s + STRLEN(s); + flags |= EW_DIR; + } else { + // Do not match directories inside a $PATH item. + flags &= ~EW_DIR; } l = (size_t)(e - s); @@ -5324,12 +5368,12 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options) // Concatenate new results to previous ones. ga_grow(ga, num_p); + // take over the pointers and put them in "ga" for (int i = 0; i < num_p; i++) { - ((char_u **)ga->ga_data)[ga->ga_len] = vim_strsave(p[i]); + ((char_u **)ga->ga_data)[ga->ga_len] = p[i]; ga->ga_len++; } - - FreeWild(num_p, p); + xfree(p); } } } @@ -6065,12 +6109,9 @@ static int open_cmdwin(void) set_bufref(&old_curbuf, curbuf); - /* Save current window sizes. */ + // Save current window sizes. win_size_save(&winsizes); - /* Don't execute autocommands while creating the window. */ - block_autocmds(); - // When using completion in Insert mode with <C-R>=<C-F> one can open the // command line window, but we don't want the popup menu then. pum_undisplay(true); @@ -6079,10 +6120,9 @@ static int open_cmdwin(void) cmdmod.tab = 0; cmdmod.noswapfile = 1; - /* Create a window for the command-line buffer. */ + // Create a window for the command-line buffer. if (win_split((int)p_cwh, WSP_BOT) == FAIL) { beep_flush(); - unblock_autocmds(); return K_IGNORE; } cmdwin_type = get_cmdline_type(); @@ -6097,13 +6137,11 @@ static int open_cmdwin(void) curbuf->b_p_ma = true; curwin->w_p_fen = false; - // Do execute autocommands for setting the filetype (load syntax). - unblock_autocmds(); - // But don't allow switching to another buffer. + // Don't allow switching to another buffer. curbuf_lock++; - /* Showing the prompt may have set need_wait_return, reset it. */ - need_wait_return = FALSE; + // Showing the prompt may have set need_wait_return, reset it. + need_wait_return = false; const int histtype = hist_char2type(cmdwin_type); if (histtype == HIST_CMD || histtype == HIST_DEBUG) { @@ -6115,11 +6153,11 @@ static int open_cmdwin(void) } curbuf_lock--; - /* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin - * sets 'textwidth' to 78). */ + // Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin + // sets 'textwidth' to 78). curbuf->b_p_tw = 0; - /* Fill the buffer with the history. */ + // Fill the buffer with the history. init_history(); if (hislen > 0 && histtype != HIST_INVALID) { i = hisidx[histtype]; @@ -6160,9 +6198,10 @@ static int open_cmdwin(void) // Trigger CmdwinEnter autocommands. typestr[0] = (char_u)cmdwin_type; typestr[1] = NUL; - apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, FALSE, curbuf); - if (restart_edit != 0) /* autocmd with ":startinsert" */ + apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, false, curbuf); + if (restart_edit != 0) { // autocmd with ":startinsert" stuffcharReadbuff(K_NOP); + } i = RedrawingDisabled; RedrawingDisabled = 0; @@ -6179,10 +6218,10 @@ static int open_cmdwin(void) const bool save_KeyTyped = KeyTyped; - /* Trigger CmdwinLeave autocommands. */ - apply_autocmds(EVENT_CMDWINLEAVE, typestr, typestr, FALSE, curbuf); + // Trigger CmdwinLeave autocommands. + apply_autocmds(EVENT_CMDWINLEAVE, typestr, typestr, false, curbuf); - /* Restore KeyTyped in case it is modified by autocommands */ + // Restore KeyTyped in case it is modified by autocommands KeyTyped = save_KeyTyped; // Restore the command line info. @@ -6241,9 +6280,7 @@ static int open_cmdwin(void) } } - /* Don't execute autocommands while deleting the window. */ - block_autocmds(); - // Avoid command-line window first character being concealed + // Avoid command-line window first character being concealed. curwin->w_p_cole = 0; wp = curwin; set_bufref(&bufref, curbuf); @@ -6256,10 +6293,8 @@ static int open_cmdwin(void) close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false); } - /* Restore window sizes. */ + // Restore window sizes. win_size_restore(&winsizes); - - unblock_autocmds(); } ga_clear(&winsizes); @@ -6308,7 +6343,7 @@ char *script_get(exarg_T *const eap, size_t *const lenp) for (;;) { char *const theline = (char *)eap->getline( eap->cstack->cs_looplevel > 0 ? -1 : - NUL, eap->cookie, 0); + NUL, eap->cookie, 0, true); if (theline == NULL || strcmp(end_pattern, theline) == 0) { xfree(theline); |