aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_getln.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_getln.c')
-rw-r--r--src/nvim/ex_getln.c245
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