diff options
Diffstat (limited to 'src/nvim/ex_getln.c')
-rw-r--r-- | src/nvim/ex_getln.c | 245 |
1 files changed, 131 insertions, 114 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 3b5953ae69..a7c0b06050 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -35,6 +35,7 @@ #include "nvim/getchar.h" #include "nvim/highlight.h" #include "nvim/highlight_defs.h" +#include "nvim/highlight_group.h" #include "nvim/if_cscope.h" #include "nvim/indent.h" #include "nvim/keymap.h" @@ -48,7 +49,6 @@ #include "nvim/memory.h" #include "nvim/menu.h" #include "nvim/message.h" -#include "nvim/misc1.h" #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/ops.h" @@ -192,13 +192,12 @@ typedef struct command_line_state { typedef struct cmdline_info CmdlineInfo; -/* The current cmdline_info. It is initialized in getcmdline() and after that - * used by other functions. When invoking getcmdline() recursively it needs - * to be saved with save_cmdline() and restored with restore_cmdline(). - * TODO: make it local to getcmdline() and pass it around. */ +/// The current cmdline_info. It is initialized in getcmdline() and after that +/// used by other functions. When invoking getcmdline() recursively it needs +/// to be saved with save_cmdline() and restored with restore_cmdline(). static struct cmdline_info ccline; -static int cmd_showtail; // Only show path tail in lists ? +static int cmd_showtail; // Only show path tail in lists ? static int new_cmdpos; // position set by set_cmdline_pos() @@ -232,7 +231,7 @@ static int compl_selected; /// |:checkhealth| completion items /// -/// Regenerates on every new command line prompt, to accomodate changes on the +/// Regenerates on every new command line prompt, to accommodate changes on the /// runtime files. typedef struct { garray_T names; // healthcheck names @@ -312,7 +311,7 @@ static char_u *get_healthcheck_names(expand_T *xp, int idx) healthchecks.last_gen = last_prompt_id; } return idx < - (int)healthchecks.names.ga_len ? ((char_u **)(healthchecks.names.ga_data))[idx] : NULL; + healthchecks.names.ga_len ? ((char_u **)(healthchecks.names.ga_data))[idx] : NULL; } /// Transform healthcheck file path into it's name. @@ -633,7 +632,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat validate_cursor(); // May redraw the status line to show the cursor position. - if (p_ru && curwin->w_status_height > 0) { + if (p_ru && (curwin->w_status_height > 0 || global_stl_height() > 0)) { curwin->w_redr_status = true; } @@ -732,9 +731,10 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool /// Internal entry point for cmdline mode. /// -/// caller must use save_cmdline and restore_cmdline. Best is to use -/// getcmdline or getcmdline_prompt, instead of calling this directly. -static uint8_t *command_line_enter(int firstc, long count, int indent) +/// @param count only used for incremental search +/// @param indent indent for inside conditionals +/// @param init_ccline clear ccline first +static uint8_t *command_line_enter(int firstc, long count, int indent, bool init_ccline) { // can be invoked recursively, identify each level static int cmdline_level = 0; @@ -751,6 +751,20 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) CommandLineState *s = &state; s->save_p_icm = vim_strsave(p_icm); init_incsearch_state(&s->is_state); + CmdlineInfo save_ccline; + bool did_save_ccline = false; + + if (ccline.cmdbuff != NULL) { + // Currently ccline can never be in use if init_ccline is false. + // Some changes will be needed if this is no longer the case. + assert(init_ccline); + // Being called recursively. Since ccline is global, we need to save + // the current buffer and restore it when returning. + save_cmdline(&save_ccline); + did_save_ccline = true; + } else if (init_ccline) { + memset(&ccline, 0, sizeof(struct cmdline_info)); + } if (s->firstc == -1) { s->firstc = NUL; @@ -773,7 +787,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) ccline.cmdindent = (s->firstc > 0 ? s->indent : 0); // alloc initial ccline.cmdbuff - alloc_cmdbuff(exmode_active ? 250 : s->indent + 1); + alloc_cmdbuff(indent + 50); ccline.cmdlen = ccline.cmdpos = 0; ccline.cmdbuff[0] = NUL; @@ -880,7 +894,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) TryState tstate; Error err = ERROR_INIT; bool tl_ret = true; - dict_T *dict = get_vim_var_dict(VV_EVENT); + save_v_event_T save_v_event; + dict_T *dict = get_v_event(&save_v_event); char firstcbuf[2]; firstcbuf[0] = (char)(firstc > 0 ? firstc : '-'); firstcbuf[1] = 0; @@ -894,7 +909,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) apply_autocmds(EVENT_CMDLINEENTER, (char_u *)firstcbuf, (char_u *)firstcbuf, false, curbuf); - tv_dict_clear(dict); + restore_v_event(dict, &save_v_event); tl_ret = try_leave(&tstate, &err); @@ -906,6 +921,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) } tl_ret = true; } + may_trigger_modechanged(); state_enter(&s->state); @@ -924,7 +940,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) if (tv_dict_get_number(dict, "abort") != 0) { s->gotesc = 1; } - tv_dict_clear(dict); + restore_v_event(dict, &save_v_event); } cmdmsg_rl = false; @@ -995,6 +1011,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) } cmdline_level--; + + if (did_save_ccline) { + restore_cmdline(&save_ccline); + } else { + ccline.cmdbuff = NULL; + } + return p; } @@ -1023,11 +1046,13 @@ static int command_line_execute(VimState *state, int key) CommandLineState *s = (CommandLineState *)state; s->c = key; - if (s->c == K_EVENT || s->c == K_COMMAND) { + if (s->c == K_EVENT || s->c == K_COMMAND || s->c == K_LUA) { if (s->c == K_EVENT) { state_handle_k_event(); - } else { + } else if (s->c == K_COMMAND) { do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT); + } else { + map_execute_lua(); } if (!cmdline_was_last_drawn) { @@ -1336,15 +1361,9 @@ static int command_line_execute(VimState *state, int key) s->c = get_expr_register(); if (s->c == '=') { - // Need to save and restore ccline. And set "textlock" - // to avoid nasty things like going to another buffer when - // evaluating an expression. - CmdlineInfo save_ccline; - save_cmdline(&save_ccline); textlock++; p = get_expr_line(); textlock--; - restore_cmdline(&save_ccline); if (p != NULL) { len = (int)STRLEN(p); @@ -1587,6 +1606,10 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ if (search_delim == ccline.cmdbuff[skiplen]) { pat = last_search_pattern(); + if (pat == NULL) { + restore_last_search_pattern(); + return FAIL; + } skiplen = 0; patlen = (int)STRLEN(pat); } else { @@ -1885,10 +1908,7 @@ static int command_line_handle_key(CommandLineState *s) beep_flush(); s->c = ESC; } else { - CmdlineInfo save_ccline; - save_cmdline(&save_ccline); s->c = get_expr_register(); - restore_cmdline(&save_ccline); } } @@ -2116,7 +2136,7 @@ static int command_line_handle_key(CommandLineState *s) int len = 0; int old_firstc; - xfree(ccline.cmdbuff); + XFREE_CLEAR(ccline.cmdbuff); s->xpc.xp_context = EXPAND_NOTHING; if (s->hiscnt == hislen) { p = s->lookfor; // back to the old one @@ -2289,7 +2309,8 @@ static int command_line_changed(CommandLineState *s) if (has_event(EVENT_CMDLINECHANGED)) { TryState tstate; Error err = ERROR_INIT; - dict_T *dict = get_vim_var_dict(VV_EVENT); + save_v_event_T save_v_event; + dict_T *dict = get_v_event(&save_v_event); char firstcbuf[2]; firstcbuf[0] = (char)(s->firstc > 0 ? s->firstc : '-'); @@ -2303,7 +2324,7 @@ static int command_line_changed(CommandLineState *s) apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf, (char_u *)firstcbuf, false, curbuf); - tv_dict_clear(dict); + restore_v_event(dict, &save_v_event); bool tl_ret = try_leave(&tstate, &err); if (!tl_ret && ERROR_SET(&err)) { @@ -2398,14 +2419,7 @@ static void abandon_cmdline(void) /// @param indent indent for inside conditionals char_u *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED) { - // Be prepared for situations where cmdline can be invoked recursively. - // That includes cmd mappings, event handlers, as well as update_screen() - // (custom status line eval), which all may invoke ":normal :". - CmdlineInfo save_ccline; - save_cmdline(&save_ccline); - char_u *retval = command_line_enter(firstc, count, indent); - restore_cmdline(&save_ccline); - return retval; + return command_line_enter(firstc, count, indent, true); } /// Get a command line with a prompt @@ -2429,8 +2443,14 @@ char *getcmdline_prompt(const char firstc, const char *const prompt, const int a const int msg_col_save = msg_col; CmdlineInfo save_ccline; - save_cmdline(&save_ccline); - + bool did_save_ccline = false; + if (ccline.cmdbuff != NULL) { + // Save the values of the current cmdline and restore them below. + save_cmdline(&save_ccline); + did_save_ccline = true; + } else { + memset(&ccline, 0, sizeof(struct cmdline_info)); + } ccline.prompt_id = last_prompt_id++; ccline.cmdprompt = (char_u *)prompt; ccline.cmdattr = attr; @@ -2442,9 +2462,11 @@ char *getcmdline_prompt(const char firstc, const char *const prompt, const int a int msg_silent_saved = msg_silent; msg_silent = 0; - char *const ret = (char *)command_line_enter(firstc, 1L, 0); + char *const ret = (char *)command_line_enter(firstc, 1L, 0, false); - restore_cmdline(&save_ccline); + if (did_save_ccline) { + restore_cmdline(&save_ccline); + } msg_silent = msg_silent_saved; // Restore msg_col, the prompt from input() may have changed it. // But only if called recursively and the commandline is therefore being @@ -2488,27 +2510,25 @@ char *get_text_locked_msg(void) } /// Check if "curbuf->b_ro_locked" or "allbuf_lock" is set and -/// return TRUE when it is and give an error message. -int curbuf_locked(void) +/// return true when it is and give an error message. +bool curbuf_locked(void) { if (curbuf->b_ro_locked > 0) { emsg(_("E788: Not allowed to edit another buffer now")); - return TRUE; + return true; } return allbuf_locked(); } -/* - * Check if "allbuf_lock" is set and return TRUE when it is and give an error - * message. - */ -int allbuf_locked(void) +// Check if "allbuf_lock" is set and return true when it is and give an error +// message. +bool allbuf_locked(void) { if (allbuf_lock > 0) { emsg(_("E811: Not allowed to change buffer information now")); - return TRUE; + return true; } - return FALSE; + return false; } static int cmdline_charsize(int idx) @@ -2598,7 +2618,6 @@ bool cmdline_at_end(void) /* * Allocate a new command line buffer. * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. - * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen. */ static void alloc_cmdbuff(int len) { @@ -3364,53 +3383,23 @@ void put_on_cmdline(char_u *str, int len, int redraw) } } -/* - * Save ccline, because obtaining the "=" register may execute "normal :cmd" - * and overwrite it. But get_cmdline_str() may need it, thus make it - * available globally in prev_ccline. - */ +/// Save ccline, because obtaining the "=" register may execute "normal :cmd" +/// and overwrite it. static void save_cmdline(struct cmdline_info *ccp) { *ccp = ccline; + memset(&ccline, 0, sizeof(struct cmdline_info)); ccline.prev_ccline = ccp; - ccline.cmdbuff = NULL; - ccline.cmdprompt = NULL; - ccline.xpc = NULL; - ccline.special_char = NUL; - ccline.level = 0; + ccline.cmdbuff = NULL; // signal that ccline is not in use } -/* - * Restore ccline after it has been saved with save_cmdline(). - */ +/// Restore ccline after it has been saved with save_cmdline(). static void restore_cmdline(struct cmdline_info *ccp) FUNC_ATTR_NONNULL_ALL { ccline = *ccp; } -/* - * Save the command line into allocated memory. Returns a pointer to be - * passed to restore_cmdline_alloc() later. - */ -char_u *save_cmdline_alloc(void) - FUNC_ATTR_NONNULL_RET -{ - struct cmdline_info *p = xmalloc(sizeof(struct cmdline_info)); - save_cmdline(p); - return (char_u *)p; -} - -/* - * Restore the command line from the return value of save_cmdline_alloc(). - */ -void restore_cmdline_alloc(char_u *p) - FUNC_ATTR_NONNULL_ALL -{ - restore_cmdline((struct cmdline_info *)p); - xfree(p); -} - /// Paste a yank register into the command line. /// Used by CTRL-R command in command-line mode. /// insert_reg() can't be used here, because special characters from the @@ -3426,7 +3415,6 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) char_u *arg; char_u *p; bool allocated; - struct cmdline_info save_ccline; // check for valid regname; also accept special characters for CTRL-R in // the command line @@ -3444,13 +3432,11 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) } - // Need to save and restore ccline. And set "textlock" to avoid nasty - // things like going to another buffer when evaluating an expression. - save_cmdline(&save_ccline); + // Need to set "textlock" to avoid nasty things like going to another + // buffer when evaluating an expression. textlock++; const bool i = get_spec_reg(regname, &arg, &allocated, true); textlock--; - restore_cmdline(&save_ccline); if (i) { // Got the value of a special register in "arg". @@ -3629,7 +3615,7 @@ void compute_cmdrow(void) } else { win_T *wp = lastwin_nofloating(); cmdline_row = wp->w_winrow + wp->w_height - + wp->w_status_height; + + wp->w_hsep_height + wp->w_status_height + global_stl_height(); } lines_left = cmdline_row; } @@ -4983,6 +4969,9 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u ** if (xp->xp_context == EXPAND_USER_LIST) { return ExpandUserList(xp, num_file, file); } + if (xp->xp_context == EXPAND_USER_LUA) { + return ExpandUserLua(xp, num_file, file); + } if (xp->xp_context == EXPAND_PACKADD) { return ExpandPackAddDir(pat, num_file, file); } @@ -5044,8 +5033,8 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u ** { EXPAND_SYNTAX, get_syntax_name, true, true }, { EXPAND_SYNTIME, get_syntime_arg, true, true }, { EXPAND_HIGHLIGHT, (ExpandFunc)get_highlight_name, true, true }, - { EXPAND_EVENTS, get_event_name, true, true }, - { EXPAND_AUGROUP, get_augroup_name, true, true }, + { EXPAND_EVENTS, expand_get_event_name, true, true }, + { EXPAND_AUGROUP, expand_get_augroup_name, true, true }, { EXPAND_CSCOPE, get_cscope_name, true, true }, { EXPAND_SIGN, get_sign_name, true, true }, { EXPAND_PROFILE, get_profile_name, true, true }, @@ -5301,7 +5290,6 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T typval_T args[4]; char_u *pat = NULL; const sctx_T save_current_sctx = current_sctx; - struct cmdline_info save_ccline; if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) { return NULL; @@ -5323,15 +5311,10 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T args[1].vval.v_string = xp->xp_line; args[2].vval.v_number = xp->xp_col; - // Save the cmdline, we don't know what the function may do. - save_ccline = ccline; - ccline.cmdbuff = NULL; - ccline.cmdprompt = NULL; current_sctx = xp->xp_script_ctx; void *const ret = user_expand_func(xp->xp_arg, 3, args); - ccline = save_ccline; current_sctx = save_current_sctx; if (ccline.cmdbuff != NULL) { ccline.cmdbuff[ccline.cmdlen] = keep; @@ -5411,6 +5394,35 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file) return OK; } +static int ExpandUserLua(expand_T *xp, int *num_file, char_u ***file) +{ + typval_T rettv; + nlua_call_user_expand_func(xp, &rettv); + if (rettv.v_type != VAR_LIST) { + tv_clear(&rettv); + return FAIL; + } + + list_T *const retlist = rettv.vval.v_list; + + garray_T ga; + ga_init(&ga, (int)sizeof(char *), 3); + // Loop over the items in the list. + TV_LIST_ITER_CONST(retlist, li, { + if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING + || TV_LIST_ITEM_TV(li)->vval.v_string == NULL) { + continue; // Skip non-string items and empty strings. + } + + GA_APPEND(char *, &ga, xstrdup((const char *)TV_LIST_ITEM_TV(li)->vval.v_string)); + }); + tv_list_unref(retlist); + + *file = ga.ga_data; + *num_file = ga.ga_len; + return OK; +} + /// Expand color scheme, compiler or filetype names. /// Search from 'runtimepath': /// 'runtimepath'/{dirnames}/{pat}.vim @@ -5912,10 +5924,8 @@ int get_history_idx(int histype) } -/* - * Get pointer to the command line info to use. cmdline_paste() may clear - * ccline and put the previous value in prev_ccline. - */ +/// Get pointer to the command line info to use. save_cmdline() may clear +/// ccline and put the previous value in ccline.prev_ccline. static struct cmdline_info *get_ccline_ptr(void) { if ((State & CMDLINE) == 0) { @@ -6315,6 +6325,11 @@ int hist_type2char(int type) return NUL; } +void cmdline_init(void) +{ + memset(&ccline, 0, sizeof(struct cmdline_info)); +} + /// Open a window on the current command line and history. Allow editing in /// the window. Returns when the window is closed. /// Returns: @@ -6323,7 +6338,6 @@ int hist_type2char(int type) /// K_IGNORE if editing continues static int open_cmdwin(void) { - struct cmdline_info save_ccline; bufref_T old_curbuf; bufref_T bufref; win_T *old_curwin = curwin; @@ -6424,9 +6438,6 @@ static int open_cmdwin(void) } redraw_later(curwin, SOME_VALID); - // Save the command line info, can be used recursively. - save_cmdline(&save_ccline); - // No Ex mode here! exmode_active = false; @@ -6464,8 +6475,6 @@ static int open_cmdwin(void) // Restore KeyTyped in case it is modified by autocommands KeyTyped = save_KeyTyped; - // Restore the command line info. - restore_cmdline(&save_ccline); cmdwin_type = 0; cmdwin_level = 0; @@ -6529,13 +6538,13 @@ static int open_cmdwin(void) set_bufref(&bufref, curbuf); win_goto(old_curwin); if (win_valid(wp) && wp != curwin) { - win_close(wp, true); + win_close(wp, true, false); } // win_close() may have already wiped the buffer when 'bh' is // set to 'wipe', autocommands may have closed other windows if (bufref_valid(&bufref) && bufref.br_buf != curbuf) { - close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false); + close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false, false); } // Restore window sizes. @@ -6547,11 +6556,19 @@ static int open_cmdwin(void) cmdmsg_rl = save_cmdmsg_rl; State = save_State; + may_trigger_modechanged(); setmouse(); return cmdwin_result; } +/// @return true if in the cmdwin, not editing the command line. +bool is_in_cmdwin(void) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return cmdwin_type != 0 && get_cmdline_type() == NUL; +} + /// Get script string /// /// Used for commands which accept either `:command script` or |