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.c1853
1 files changed, 1070 insertions, 783 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index a0bcccb5be..76c3680742 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1,50 +1,49 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-/*
- * ex_getln.c: Functions for entering and editing an Ex command line.
- */
+// ex_getln.c: Functions for entering and editing an Ex command line.
#include <assert.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
+#include "klib/kvec.h"
#include "nvim/api/extmark.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
#include "nvim/arabic.h"
#include "nvim/ascii.h"
-#include "nvim/assert.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdhist.h"
#include "nvim/cursor.h"
-#include "nvim/cursor_shape.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
-#include "nvim/event/loop.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
-#include "nvim/func_attr.h"
+#include "nvim/extmark.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/grid.h"
-#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
-#include "nvim/indent.h"
#include "nvim/keycodes.h"
-#include "nvim/lib/kvec.h"
-#include "nvim/log.h"
-#include "nvim/main.h"
+#include "nvim/macros.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
@@ -53,15 +52,18 @@
#include "nvim/message.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
+#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
#include "nvim/os/input.h"
-#include "nvim/os/time.h"
+#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/popupmenu.h"
+#include "nvim/pos.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
+#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@@ -96,7 +98,7 @@ typedef struct {
pos_T match_end;
bool did_incsearch;
bool incsearch_postponed;
- int magic_save;
+ optmagic_T magic_overruled_save;
} incsearch_state_T;
typedef struct command_line_state {
@@ -105,9 +107,9 @@ typedef struct command_line_state {
long count;
int indent;
int c;
- int gotesc; // TRUE when <ESC> just typed
- int do_abbr; // when TRUE check for abbr.
- char_u *lookfor; // string to match
+ int gotesc; // true when <ESC> just typed
+ int do_abbr; // when true check for abbr.
+ char *lookfor; // string to match
int hiscnt; // current history line in use
int save_hiscnt; // history line before attempting
// to jump to next match
@@ -115,10 +117,9 @@ typedef struct command_line_state {
incsearch_state_T is_state;
int did_wild_list; // did wild_list() recently
int wim_index; // index in wim_flags[]
- int res;
int save_msg_scroll;
int save_State; // remember State when called
- char_u *save_p_icm;
+ char *save_p_icm;
int some_key_typed; // one of the keys was typed
// mouse drag and release events are ignored, unless they are
// preceded with a mouse down event
@@ -138,6 +139,7 @@ typedef struct cmdpreview_win_info {
typedef struct cmdpreview_buf_info {
buf_T *buf;
+ bool save_b_u_synced;
time_t save_b_u_time_cur;
long save_b_u_seq_cur;
u_header_T *save_b_u_newhead;
@@ -154,6 +156,14 @@ typedef struct cmdpreview_info {
garray_T save_view;
} CpInfo;
+/// Return value when handling keys in command-line mode.
+enum {
+ CMDLINE_NOT_CHANGED = 1,
+ CMDLINE_CHANGED = 2,
+ GOTO_NORMAL_MODE = 3,
+ 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
/// to be saved with save_cmdline() and restored with restore_cmdline().
@@ -170,6 +180,8 @@ static Array cmdline_block = ARRAY_DICT_INIT;
/// user interrupting highlight function to not interrupt command-line.
static bool getln_interrupted_highlight = false;
+static int cedit_key = -1; ///< key value of 'cedit' option
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_getln.c.generated.h"
#endif
@@ -206,7 +218,7 @@ static void init_incsearch_state(incsearch_state_T *s)
s->match_start = curwin->w_cursor;
s->did_incsearch = false;
s->incsearch_postponed = false;
- s->magic_save = p_magic;
+ s->magic_overruled_save = magic_overruled;
clearpos(&s->match_end);
s->save_cursor = curwin->w_cursor; // may be restored later
s->search_start = curwin->w_cursor;
@@ -229,6 +241,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
pos_T save_cursor;
bool use_last_pat;
bool retval = false;
+ magic_T magic = 0;
*skiplen = 0;
*patlen = ccline.cmdlen;
@@ -253,7 +266,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
exarg_T ea = {
.line1 = 1,
.line2 = 1,
- .cmd = (char *)ccline.cmdbuff,
+ .cmd = ccline.cmdbuff,
.addr_type = ADDR_LINES,
};
@@ -261,7 +274,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
parse_command_modifiers(&ea, &dummy, &dummy_cmdmod, true);
cmd = skip_range(ea.cmd, NULL);
- if (vim_strchr("sgvl", *cmd) == NULL) {
+ if (vim_strchr("sgvl", (uint8_t)(*cmd)) == NULL) {
goto theend;
}
@@ -271,16 +284,16 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
goto theend;
}
- if (STRNCMP(cmd, "substitute", p - cmd) == 0
- || STRNCMP(cmd, "smagic", p - cmd) == 0
- || STRNCMP(cmd, "snomagic", MAX(p - cmd, 3)) == 0
- || STRNCMP(cmd, "vglobal", p - cmd) == 0) {
+ if (strncmp(cmd, "substitute", (size_t)(p - cmd)) == 0
+ || strncmp(cmd, "smagic", (size_t)(p - cmd)) == 0
+ || strncmp(cmd, "snomagic", (size_t)MAX(p - cmd, 3)) == 0
+ || strncmp(cmd, "vglobal", (size_t)(p - cmd)) == 0) {
if (*cmd == 's' && cmd[1] == 'm') {
- p_magic = true;
+ magic_overruled = OPTION_MAGIC_ON;
} else if (*cmd == 's' && cmd[1] == 'n') {
- p_magic = false;
+ magic_overruled = OPTION_MAGIC_OFF;
}
- } else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) {
+ } else if (strncmp(cmd, "sort", (size_t)MAX(p - cmd, 3)) == 0) {
// skip over ! and flags
if (*p == '!') {
p = skipwhite(p + 1);
@@ -291,11 +304,11 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
if (*p == NUL) {
goto theend;
}
- } else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0
- || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0
- || STRNCMP(cmd, "lvimgrep", MAX(p - cmd, 2)) == 0
- || STRNCMP(cmd, "lvimgrepadd", MAX(p - cmd, 9)) == 0
- || STRNCMP(cmd, "global", p - cmd) == 0) {
+ } else if (strncmp(cmd, "vimgrep", (size_t)MAX(p - cmd, 3)) == 0
+ || strncmp(cmd, "vimgrepadd", (size_t)MAX(p - cmd, 8)) == 0
+ || strncmp(cmd, "lvimgrep", (size_t)MAX(p - cmd, 2)) == 0
+ || strncmp(cmd, "lvimgrepadd", (size_t)MAX(p - cmd, 9)) == 0
+ || strncmp(cmd, "global", (size_t)(p - cmd)) == 0) {
// skip over "!/".
if (*p == '!') {
p++;
@@ -311,9 +324,9 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
}
p = skipwhite(p);
- delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
+ delim = (delim_optional && vim_isIDc((uint8_t)(*p))) ? ' ' : *p++;
*search_delim = delim;
- end = (char *)skip_regexp((char_u *)p, delim, p_magic, NULL);
+ end = skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic);
use_last_pat = end == p && *end == delim;
if (end == p && !use_last_pat) {
@@ -323,10 +336,8 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
// Don't do 'hlsearch' highlighting if the pattern matches everything.
if (!use_last_pat) {
char c = *end;
- int empty;
-
*end = NUL;
- empty = empty_pattern((char_u *)p);
+ bool empty = empty_pattern_magic(p, strlen(p), magic);
*end = c;
if (empty) {
goto theend;
@@ -334,7 +345,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
}
// found a non-empty pattern or //
- *skiplen = (int)((char_u *)p - ccline.cmdbuff);
+ *skiplen = (int)(p - ccline.cmdbuff);
*patlen = (int)(end - p);
// parse the address range
@@ -369,8 +380,8 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
pos_T end_pos;
proftime_T tm;
int skiplen, patlen;
- char_u next_char;
- char_u use_last_pat;
+ char next_char;
+ bool use_last_pat;
int search_delim;
// Parsing range may already set the last search pattern.
@@ -415,7 +426,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
if (patlen == 0 && !use_last_pat) {
found = 0;
set_no_hlsearch(true); // turn off previous highlight
- redraw_all_later(SOME_VALID);
+ redraw_all_later(UPD_SOME_VALID);
} else {
int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK;
ui_busy_start();
@@ -481,14 +492,14 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
} else {
end_pos = curwin->w_cursor; // shutup gcc 4
}
- //
+
// Disable 'hlsearch' highlighting if the pattern matches
// everything. Avoids a flash when typing "foo\|".
if (!use_last_pat) {
next_char = ccline.cmdbuff[skiplen + patlen];
ccline.cmdbuff[skiplen + patlen] = NUL;
- if (empty_pattern(ccline.cmdbuff) && !no_hlsearch) {
- redraw_all_later(SOME_VALID);
+ if (empty_pattern(ccline.cmdbuff + skiplen, search_delim) && !no_hlsearch) {
+ redraw_all_later(UPD_SOME_VALID);
set_no_hlsearch(true);
}
ccline.cmdbuff[skiplen + patlen] = next_char;
@@ -500,7 +511,8 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
curwin->w_redr_status = true;
}
- update_screen(SOME_VALID);
+ redraw_later(curwin, UPD_SOME_VALID);
+ update_screen();
highlight_match = false;
restore_last_search_pattern();
@@ -550,7 +562,7 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
*c = mb_tolower(*c);
}
if (*c == search_delim
- || vim_strchr((p_magic ? "\\~^$.*[" : "\\^$"), *c) != NULL) {
+ || vim_strchr((magic_isset() ? "\\~^$.*[" : "\\^$"), *c) != NULL) {
// put a backslash before special characters
stuffcharReadbuff(*c);
*c = '\\';
@@ -563,60 +575,74 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool call_update_screen)
{
- if (s->did_incsearch) {
- s->did_incsearch = false;
- if (gotesc) {
+ if (!s->did_incsearch) {
+ return;
+ }
+
+ s->did_incsearch = false;
+ if (gotesc) {
+ curwin->w_cursor = s->save_cursor;
+ } else {
+ if (!equalpos(s->save_cursor, s->search_start)) {
+ // put the '" mark at the original position
curwin->w_cursor = s->save_cursor;
- } else {
- if (!equalpos(s->save_cursor, s->search_start)) {
- // put the '" mark at the original position
- curwin->w_cursor = s->save_cursor;
- setpcmark();
- }
- curwin->w_cursor = s->search_start; // -V519
+ setpcmark();
}
- restore_viewstate(curwin, &s->old_viewstate);
- highlight_match = false;
+ curwin->w_cursor = s->search_start; // -V519
+ }
+ restore_viewstate(curwin, &s->old_viewstate);
+ highlight_match = false;
- // by default search all lines
- search_first_line = 0;
- search_last_line = MAXLNUM;
+ // by default search all lines
+ search_first_line = 0;
+ search_last_line = MAXLNUM;
- p_magic = s->magic_save;
+ magic_overruled = s->magic_overruled_save;
- validate_cursor(); // needed for TAB
- redraw_all_later(SOME_VALID);
- if (call_update_screen) {
- update_screen(SOME_VALID);
- }
+ validate_cursor(); // needed for TAB
+ redraw_all_later(UPD_SOME_VALID);
+ if (call_update_screen) {
+ update_screen();
}
}
-/// Internal entry point for cmdline mode.
-///
-/// @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)
+/// Initialize the current command-line info.
+static void init_ccline(int firstc, int indent)
{
- const bool cmdheight0 = !ui_has_messages();
+ ccline.overstrike = false; // always start in insert mode
- if (cmdheight0) {
- const long save_so = lastwin->w_p_so;
+ assert(indent >= 0);
- // If cmdheight is 0, cmdheight must be set to 1 when we enter the
- // command line. Set "made_cmdheight_nonzero" and reset 'scrolloff' to
- // avoid scrolling the last window.
- made_cmdheight_nonzero = true;
+ // set some variables for redrawcmd()
+ ccline.cmdfirstc = (firstc == '@' ? 0 : firstc);
+ ccline.cmdindent = (firstc > 0 ? indent : 0);
- lastwin->w_p_so = 0;
- set_option_value("ch", 1L, NULL, 0);
- update_screen(VALID); // redraw the screen NOW
+ // alloc initial ccline.cmdbuff
+ alloc_cmdbuff(indent + 50);
+ ccline.cmdlen = ccline.cmdpos = 0;
+ ccline.cmdbuff[0] = NUL;
- made_cmdheight_nonzero = false;
- lastwin->w_p_so = save_so;
+ ccline.last_colors = (ColoredCmdline){ .cmdbuff = NULL,
+ .colors = KV_INITIAL_VALUE };
+ sb_text_start_cmdline();
+
+ // autoindent for :insert and :append
+ if (firstc <= 0) {
+ memset(ccline.cmdbuff, ' ', (size_t)indent);
+ ccline.cmdbuff[indent] = NUL;
+ ccline.cmdpos = indent;
+ ccline.cmdspos = indent;
+ ccline.cmdlen = indent;
}
+}
+/// Internal entry point for cmdline mode.
+///
+/// @param count only used for incremental search
+/// @param indent indent for inside conditionals
+/// @param clear_ccline clear ccline first
+static uint8_t *command_line_enter(int firstc, long count, int indent, bool clear_ccline)
+{
// can be invoked recursively, identify each level
static int cmdline_level = 0;
cmdline_level++;
@@ -632,20 +658,20 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
.ignore_drag_release = true,
};
CommandLineState *s = &state;
- s->save_p_icm = vim_strsave(p_icm);
+ s->save_p_icm = xstrdup(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.
+ // Currently ccline can never be in use if clear_ccline is false.
// Some changes will be needed if this is no longer the case.
- assert(init_ccline);
+ assert(clear_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) {
+ } else if (clear_ccline) {
CLEAR_FIELD(ccline);
}
@@ -659,33 +685,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
cmd_hkmap = 0;
}
+ init_ccline(s->firstc, s->indent);
ccline.prompt_id = last_prompt_id++;
ccline.level = cmdline_level;
- ccline.overstrike = false; // always start in insert mode
-
- assert(indent >= 0);
-
- // set some variables for redrawcmd()
- ccline.cmdfirstc = (s->firstc == '@' ? 0 : s->firstc);
- ccline.cmdindent = (s->firstc > 0 ? s->indent : 0);
-
- // alloc initial ccline.cmdbuff
- alloc_cmdbuff(indent + 50);
- ccline.cmdlen = ccline.cmdpos = 0;
- ccline.cmdbuff[0] = NUL;
-
- ccline.last_colors = (ColoredCmdline){ .cmdbuff = NULL,
- .colors = KV_INITIAL_VALUE };
- sb_text_start_cmdline();
-
- // autoindent for :insert and :append
- if (s->firstc <= 0) {
- memset(ccline.cmdbuff, ' ', (size_t)s->indent);
- ccline.cmdbuff[s->indent] = NUL;
- ccline.cmdpos = s->indent;
- ccline.cmdspos = s->indent;
- ccline.cmdlen = s->indent;
- }
if (cmdline_level == 50) {
// Somehow got into a loop recursively calling getcmdline(), bail out.
@@ -722,8 +724,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
if (ccline.input_fn) {
s->xpc.xp_context = ccline.xp_context;
- s->xpc.xp_pattern = (char *)ccline.cmdbuff;
- s->xpc.xp_arg = (char *)ccline.xp_arg;
+ s->xpc.xp_pattern = ccline.cmdbuff;
+ s->xpc.xp_arg = ccline.xp_arg;
}
// Avoid scrolling when called by a recursive do_cmdline(), e.g. when
@@ -751,13 +753,14 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
TryState tstate;
Error err = ERROR_INIT;
bool tl_ret = true;
- 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;
if (has_event(EVENT_CMDLINEENTER)) {
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
+
// set v:event to a dictionary with information about the commandline
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
@@ -770,7 +773,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
tl_ret = try_leave(&tstate, &err);
if (!tl_ret && ERROR_SET(&err)) {
msg_putchar('\n');
- msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg);
+ msg_scroll = true;
+ msg_puts_attr(err.msg, HL_ATTR(HLF_E)|MSG_HIST);
api_clear_error(&err);
redrawcmd();
}
@@ -791,11 +795,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
// Redraw the statusline in case it uses the current mode using the mode()
// function.
- if (!cmd_silent && msg_scrolled == 0) {
+ if (!cmd_silent) {
bool found_one = false;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (*p_stl != NUL || *wp->w_p_stl != NUL) {
+ if (*p_stl != NUL || *wp->w_p_stl != NUL || *p_wbr != NUL || *wp->w_p_wbr != NUL) {
wp->w_redr_status = true;
found_one = true;
}
@@ -819,6 +823,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
state_enter(&s->state);
if (has_event(EVENT_CMDLINELEAVE)) {
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
+
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
tv_dict_set_keys_readonly(dict);
@@ -852,7 +859,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
s->histype == HIST_SEARCH ? s->firstc : NUL);
if (s->firstc == ':') {
xfree(new_last_cmdline);
- new_last_cmdline = vim_strsave(ccline.cmdbuff);
+ new_last_cmdline = xstrdup(ccline.cmdbuff);
}
}
@@ -865,12 +872,18 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
// If the line is too long, clear it, so ruler and shown command do
// not get printed in the middle of it.
msg_check();
+ if (p_ch == 0 && !ui_has(kUIMessages)) {
+ if (must_redraw < UPD_VALID) {
+ must_redraw = UPD_VALID;
+ }
+ }
msg_scroll = s->save_msg_scroll;
redir_off = false;
if (!tl_ret && ERROR_SET(&err)) {
msg_putchar('\n');
- msg_printf_attr(HL_ATTR(HLF_E)|MSG_HIST, (char *)e_autocmd_err, err.msg);
+ emsg(err.msg);
+ did_emsg = false;
api_clear_error(&err);
}
@@ -879,11 +892,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
need_wait_return = false;
}
- set_string_option_direct("icm", -1, (char *)s->save_p_icm, OPT_FREE, SID_NONE);
+ set_string_option_direct("icm", -1, s->save_p_icm, OPT_FREE, SID_NONE);
State = s->save_State;
if (cmdpreview != save_cmdpreview) {
cmdpreview = save_cmdpreview; // restore preview state
- redraw_all_later(SOME_VALID);
+ redraw_all_later(UPD_SOME_VALID);
}
may_trigger_modechanged();
setmouse();
@@ -895,7 +908,7 @@ theend:
xfree(ccline.last_colors.cmdbuff);
kv_destroy(ccline.last_colors.colors);
- char_u *p = ccline.cmdbuff;
+ char *p = ccline.cmdbuff;
if (ui_has(kUICmdline)) {
ui_call_cmdline_hide(ccline.level);
@@ -910,18 +923,7 @@ theend:
ccline.cmdbuff = NULL;
}
- if (cmdheight0) {
- made_cmdheight_nonzero = true;
-
- // Restore cmdheight
- set_option_value("ch", 0L, NULL, 0);
- // Redraw is needed for command line completion
- redraw_all_later(CLEAR);
-
- made_cmdheight_nonzero = false;
- }
-
- return p;
+ return (uint8_t *)p;
}
static int command_line_check(VimState *state)
@@ -940,6 +942,191 @@ static int command_line_check(VimState *state)
return 1;
}
+/// Handle CTRL-\ pressed in Command-line mode:
+/// - CTRL-\ CTRL-N or CTRL-\ CTRL-G goes to Normal mode.
+/// - CTRL-\ e prompts for an expression.
+static int command_line_handle_ctrl_bsl(CommandLineState *s)
+{
+ no_mapping++;
+ allow_keys++;
+ s->c = plain_vgetc();
+ no_mapping--;
+ allow_keys--;
+
+ // CTRL-\ e doesn't work when obtaining an expression, unless it
+ // is in a mapping.
+ if (s->c != Ctrl_N
+ && s->c != Ctrl_G
+ && (s->c != 'e'
+ || (ccline.cmdfirstc == '=' && KeyTyped)
+ || cmdline_star > 0)) {
+ vungetc(s->c);
+ return PROCESS_NEXT_KEY;
+ }
+
+ if (s->c == 'e') {
+ // Replace the command line with the result of an expression.
+ // This will call getcmdline() recursively in get_expr_register().
+ if (ccline.cmdpos == ccline.cmdlen) {
+ new_cmdpos = 99999; // keep it at the end
+ } else {
+ new_cmdpos = ccline.cmdpos;
+ }
+
+ s->c = get_expr_register();
+ if (s->c == '=') {
+ // Evaluate the expression. Set "textlock" to avoid nasty things
+ // like going to another buffer.
+ textlock++;
+ char *p = get_expr_line();
+ textlock--;
+
+ if (p != NULL) {
+ int len = (int)strlen(p);
+ realloc_cmdbuff(len + 1);
+ ccline.cmdlen = len;
+ STRCPY(ccline.cmdbuff, p);
+ xfree(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;
+ }
+ }
+ beep_flush();
+ got_int = false; // don't abandon the command line
+ did_emsg = false;
+ emsg_on_display = false;
+ redrawcmd();
+ return CMDLINE_NOT_CHANGED;
+ }
+
+ s->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
+/// @return CMDLINE_CHANGED if command line is changed or CMDLINE_NOT_CHANGED.
+static int command_line_wildchar_complete(CommandLineState *s)
+{
+ int res;
+ 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)
+ || (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) {
+ res = nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@');
+ } else if (wim_flags[s->wim_index] & WIM_FULL) {
+ res = nextwild(&s->xpc, WILD_NEXT, options, s->firstc != '@');
+ } else {
+ res = OK; // don't insert 'wildchar' now
+ }
+ } else { // typed p_wc first time
+ s->wim_index = 0;
+ int j = ccline.cmdpos;
+
+ // if 'wildmode' first contains "longest", get longest
+ // common part
+ if (wim_flags[0] & WIM_LONGEST) {
+ res = nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@');
+ } else {
+ res = nextwild(&s->xpc, WILD_EXPAND_KEEP, options, s->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(&s->xpc, NULL, NULL, 0, WILD_FREE);
+ s->xpc.xp_context = EXPAND_NOTHING;
+ 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 && s->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) {
+ s->wim_index = 1;
+ }
+ if ((wim_flags[s->wim_index] & WIM_LIST)
+ || (p_wmnu && (wim_flags[s->wim_index] & WIM_FULL) != 0)) {
+ if (!(wim_flags[0] & WIM_LONGEST)) {
+ int p_wmnu_save = p_wmnu;
+ p_wmnu = 0;
+ // remove match
+ nextwild(&s->xpc, WILD_PREV, 0, s->firstc != '@');
+ p_wmnu = p_wmnu_save;
+ }
+
+ (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) {
+ nextwild(&s->xpc, WILD_LONGEST, options, s->firstc != '@');
+ } else if (wim_flags[s->wim_index] & WIM_FULL) {
+ nextwild(&s->xpc, WILD_NEXT, options, s->firstc != '@');
+ }
+ } else {
+ vim_beep(BO_WILD);
+ }
+ } else if (s->xpc.xp_numfiles == -1) {
+ s->xpc.xp_context = EXPAND_NOTHING;
+ }
+ }
+
+ if (s->wim_index < 3) {
+ s->wim_index++;
+ }
+
+ if (s->c == ESC) {
+ s->gotesc = true;
+ }
+
+ return (res == OK) ? CMDLINE_CHANGED : CMDLINE_NOT_CHANGED;
+}
+
+static void command_line_end_wildmenu(CommandLineState *s)
+{
+ if (cmdline_pum_active()) {
+ cmdline_pum_remove();
+ }
+ if (s->xpc.xp_numfiles != -1) {
+ (void)ExpandOne(&s->xpc, NULL, NULL, 0, WILD_FREE);
+ }
+ s->did_wild_list = false;
+ if (!p_wmnu || (s->c != K_UP && s->c != K_DOWN)) {
+ s->xpc.xp_context = EXPAND_NOTHING;
+ }
+ s->wim_index = 0;
+ wildmenu_cleanup(&ccline);
+}
+
static int command_line_execute(VimState *state, int key)
{
if (key == K_IGNORE || key == K_NOP) {
@@ -958,6 +1145,19 @@ static int command_line_execute(VimState *state, int key)
map_execute_lua();
}
+ // nvim_select_popupmenu_item() can be called from the handling of
+ // K_EVENT, K_COMMAND, or K_LUA.
+ if (pum_want.active) {
+ if (cmdline_pum_active()) {
+ nextwild(&s->xpc, WILD_PUM_WANT, 0, s->firstc != '@');
+ if (pum_want.finish) {
+ nextwild(&s->xpc, WILD_APPLY, WILD_NO_BEEP, s->firstc != '@');
+ command_line_end_wildmenu(s);
+ }
+ }
+ pum_want.active = false;
+ }
+
if (!cmdline_was_last_drawn) {
redrawcmdline();
}
@@ -1026,100 +1226,49 @@ static int command_line_execute(VimState *state, int key)
}
if (cmdline_pum_active() || s->did_wild_list) {
+ // Ctrl-Y: Accept the current selection and close the popup menu.
+ // Ctrl-E: cancel the cmdline popup menu and return the original text.
if (s->c == Ctrl_E || s->c == Ctrl_Y) {
const int wild_type = (s->c == Ctrl_E) ? WILD_CANCEL : WILD_APPLY;
- s->res = nextwild(&s->xpc, wild_type, WILD_NO_BEEP, s->firstc != '@');
+ (void)nextwild(&s->xpc, wild_type, WILD_NO_BEEP, s->firstc != '@');
s->c = Ctrl_E;
}
}
+ // The wildmenu is cleared if the pressed key is not used for
+ // navigating the wild menu (i.e. the key is not 'wildchar' or
+ // 'wildcharm' or Ctrl-N or Ctrl-P or Ctrl-A or Ctrl-L).
+ // If the popup menu is displayed, then PageDown and PageUp keys are
+ // also used to navigate the menu.
+ bool end_wildmenu = (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z
+ && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A
+ && s->c != Ctrl_L);
+ end_wildmenu = end_wildmenu && (!cmdline_pum_active()
+ || (s->c != K_PAGEDOWN && s->c != K_PAGEUP
+ && s->c != K_KPAGEDOWN && s->c != K_KPAGEUP));
+
// free expanded names when finished walking through matches
- if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z
- && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A
- && s->c != Ctrl_L) {
- if (cmdline_pum_active()) {
- cmdline_pum_remove();
- }
- if (s->xpc.xp_numfiles != -1) {
- (void)ExpandOne(&s->xpc, NULL, NULL, 0, WILD_FREE);
- }
- s->did_wild_list = false;
- if (!p_wmnu || (s->c != K_UP && s->c != K_DOWN)) {
- s->xpc.xp_context = EXPAND_NOTHING;
- }
- s->wim_index = 0;
- wildmenu_cleanup(&ccline);
+ if (end_wildmenu) {
+ command_line_end_wildmenu(s);
}
if (p_wmnu) {
s->c = wildmenu_process_key(&ccline, s->c, &s->xpc);
}
- // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ e prompts for an expression.
+ // CTRL-\ CTRL-N or CTRL-\ CTRL-G goes to Normal mode,
+ // CTRL-\ e prompts for an expression.
if (s->c == Ctrl_BSL) {
- no_mapping++;
- allow_keys++;
- s->c = plain_vgetc();
- no_mapping--;
- allow_keys--;
- // CTRL-\ e doesn't work when obtaining an expression, unless it
- // is in a mapping.
- if (s->c != Ctrl_N
- && s->c != Ctrl_G
- && (s->c != 'e'
- || (ccline.cmdfirstc == '=' && KeyTyped)
- || cmdline_star > 0)) {
- vungetc(s->c);
- s->c = Ctrl_BSL;
- } else if (s->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;
- }
-
- s->c = get_expr_register();
- if (s->c == '=') {
- textlock++;
- p = get_expr_line();
- textlock--;
-
- if (p != NULL) {
- len = (int)STRLEN(p);
- realloc_cmdbuff(len + 1);
- ccline.cmdlen = len;
- STRCPY(ccline.cmdbuff, p);
- xfree(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 command_line_changed(s);
- }
- }
- beep_flush();
- got_int = false; // don't abandon the command line
- did_emsg = false;
- emsg_on_display = false;
- redrawcmd();
+ switch (command_line_handle_ctrl_bsl(s)) {
+ case CMDLINE_CHANGED:
+ return command_line_changed(s);
+ case CMDLINE_NOT_CHANGED:
return command_line_not_changed(s);
- } else {
- s->gotesc = true; // will free ccline.cmdbuff after putting it
- // in history
- return 0; // back to Normal mode
+ case GOTO_NORMAL_MODE:
+ return 0; // back to cmd mode
+ default:
+ s->c = Ctrl_BSL; // backslash key not processed by
+ // command_line_handle_ctrl_bsl()
}
}
@@ -1167,107 +1316,8 @@ static int command_line_execute(VimState *state, int key)
}
// 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 ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm
- || s->c == Ctrl_Z) {
- 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)
- || (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, options,
- s->firstc != '@');
- } else if (wim_flags[s->wim_index] & WIM_FULL) {
- s->res = nextwild(&s->xpc, WILD_NEXT, options,
- s->firstc != '@');
- } else {
- s->res = OK; // don't insert 'wildchar' now
- }
- } else { // typed p_wc first time
- s->wim_index = 0;
- int j = ccline.cmdpos;
-
- // if 'wildmode' first contains "longest", get longest
- // common part
- if (wim_flags[0] & WIM_LONGEST) {
- s->res = nextwild(&s->xpc, WILD_LONGEST, options,
- s->firstc != '@');
- } else {
- s->res = nextwild(&s->xpc, WILD_EXPAND_KEEP, options,
- s->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(&s->xpc, NULL, NULL, 0, WILD_FREE);
- s->xpc.xp_context = EXPAND_NOTHING;
- return command_line_changed(s);
- }<