diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:23:01 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:23:01 +0000 |
commit | 142d9041391780ac15b89886a54015fdc5c73995 (patch) | |
tree | 0f6b5cac1a60810a03f52826c9e67c9e2780b033 /src/nvim/ex_getln.c | |
parent | ad86b5db74922285699ab2a1dbb2ff20e6268a33 (diff) | |
parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
download | rneovim-142d9041391780ac15b89886a54015fdc5c73995.tar.gz rneovim-142d9041391780ac15b89886a54015fdc5c73995.tar.bz2 rneovim-142d9041391780ac15b89886a54015fdc5c73995.zip |
Merge remote-tracking branch 'upstream/master' into userreg
Diffstat (limited to 'src/nvim/ex_getln.c')
-rw-r--r-- | src/nvim/ex_getln.c | 1361 |
1 files changed, 758 insertions, 603 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 031226c5a1..76c3680742 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -5,44 +5,45 @@ #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/log.h" -#include "nvim/main.h" +#include "nvim/macros.h" #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/mbyte.h" @@ -51,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" @@ -94,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 { @@ -113,7 +117,6 @@ 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 *save_p_icm; @@ -153,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(). @@ -207,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; @@ -230,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; @@ -262,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; } @@ -272,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); @@ -292,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++; @@ -312,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 = skip_regexp(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) { @@ -324,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(p); + bool empty = empty_pattern_magic(p, strlen(p), magic); *end = c; if (empty) { goto theend; @@ -370,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. @@ -408,7 +418,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat int found; // do_search() result // Use the previous pattern for ":s//". - next_char = (char_u)ccline.cmdbuff[skiplen + patlen]; + next_char = ccline.cmdbuff[skiplen + patlen]; use_last_pat = patlen == 0 && skiplen > 0 && ccline.cmdbuff[skiplen - 1] == next_char; @@ -435,9 +445,9 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat .sa_tm = &tm, }; found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, - (char_u *)ccline.cmdbuff + skiplen, count, + ccline.cmdbuff + skiplen, count, search_flags, &sia); - ccline.cmdbuff[skiplen + patlen] = (char)next_char; + ccline.cmdbuff[skiplen + patlen] = next_char; emsg_off--; if (curwin->w_cursor.lnum < search_first_line || curwin->w_cursor.lnum > search_last_line) { @@ -482,17 +492,17 @@ 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 = (char_u)ccline.cmdbuff[skiplen + patlen]; + next_char = ccline.cmdbuff[skiplen + patlen]; ccline.cmdbuff[skiplen + patlen] = NUL; - if (empty_pattern(ccline.cmdbuff) && !no_hlsearch) { + if (empty_pattern(ccline.cmdbuff + skiplen, search_delim) && !no_hlsearch) { redraw_all_later(UPD_SOME_VALID); set_no_hlsearch(true); } - ccline.cmdbuff[skiplen + patlen] = (char)next_char; + ccline.cmdbuff[skiplen + patlen] = next_char; } validate_cursor(); @@ -548,11 +558,11 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s) // command line has no uppercase characters, convert // the character to lowercase if (p_ic && p_scs - && !pat_has_uppercase((char_u *)ccline.cmdbuff + skiplen)) { + && !pat_has_uppercase(ccline.cmdbuff + skiplen)) { *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 = '\\'; @@ -565,32 +575,64 @@ 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(UPD_SOME_VALID); - if (call_update_screen) { - update_screen(); - } + validate_cursor(); // needed for TAB + redraw_all_later(UPD_SOME_VALID); + if (call_update_screen) { + update_screen(); + } +} + +/// Initialize the current command-line info. +static void init_ccline(int firstc, int indent) +{ + ccline.overstrike = false; // always start in insert mode + + assert(indent >= 0); + + // set some variables for redrawcmd() + ccline.cmdfirstc = (firstc == '@' ? 0 : firstc); + ccline.cmdindent = (firstc > 0 ? 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 (firstc <= 0) { + memset(ccline.cmdbuff, ' ', (size_t)indent); + ccline.cmdbuff[indent] = NUL; + ccline.cmdpos = indent; + ccline.cmdspos = indent; + ccline.cmdlen = indent; } } @@ -598,8 +640,8 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool /// /// @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) +/// @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; @@ -622,14 +664,14 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init 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); } @@ -643,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. @@ -707,7 +725,7 @@ 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 = ccline.cmdbuff; - s->xpc.xp_arg = (char *)ccline.xp_arg; + s->xpc.xp_arg = ccline.xp_arg; } // Avoid scrolling when called by a recursive do_cmdline(), e.g. when @@ -735,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); @@ -754,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(); } @@ -803,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); @@ -859,7 +882,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init if (!tl_ret && ERROR_SET(&err)) { msg_putchar('\n'); - semsg(e_autocmd_err, err.msg); + emsg(err.msg); did_emsg = false; api_clear_error(&err); } @@ -885,7 +908,7 @@ theend: xfree(ccline.last_colors.cmdbuff); kv_destroy(ccline.last_colors.colors); - char_u *p = (char_u *)ccline.cmdbuff; + char *p = ccline.cmdbuff; if (ui_has(kUICmdline)) { ui_call_cmdline_hide(ccline.level); @@ -900,7 +923,7 @@ theend: ccline.cmdbuff = NULL; } - return p; + return (uint8_t *)p; } static int command_line_check(VimState *state) @@ -919,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) { @@ -937,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(); } @@ -1005,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 = (char_u *)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() } } @@ -1146,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); - } - - // when more than one match, and 'wildmode' first contains - // "list", or no change and 'wildmode' contains "longest,list", - // list all matches - if (s->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; - } - - if (s->res == OK) { + if ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm || s->c == Ctrl_Z) { + if (command_line_wildchar_complete(s) == CMDLINE_CHANGED) { return command_line_changed(s); } } @@ -1303,9 +1374,9 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ ui_flush(); pos_T t; - char_u *pat; + char *pat; int search_flags = SEARCH_NOOF; - char_u save; + char save; if (search_delim == ccline.cmdbuff[skiplen]) { pat = last_search_pattern(); @@ -1314,9 +1385,9 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ return FAIL; } skiplen = 0; - patlen = (int)STRLEN(pat); + patlen = (int)strlen(pat); } else { - pat = (char_u *)ccline.cmdbuff + skiplen; + pat = ccline.cmdbuff + skiplen; } if (next_match) { @@ -1389,6 +1460,199 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ return FAIL; } +/// Handle backspace, delete and CTRL-W keys in the command-line mode. +static int command_line_erase_chars(CommandLineState *s) +{ + if (s->c == K_KDEL) { + s->c = K_DEL; + } + + // Delete current character is the same as backspace on next + // character, except at end of line + if (s->c == K_DEL && ccline.cmdpos != ccline.cmdlen) { + ccline.cmdpos++; + } + + if (s->c == K_DEL) { + ccline.cmdpos += mb_off_next(ccline.cmdbuff, + ccline.cmdbuff + ccline.cmdpos); + } + + if (ccline.cmdpos > 0) { + char *p; + + int j = ccline.cmdpos; + p = mb_prevptr(ccline.cmdbuff, ccline.cmdbuff + j); + + if (s->c == Ctrl_W) { + while (p > ccline.cmdbuff && ascii_isspace(*p)) { + p = mb_prevptr(ccline.cmdbuff, p); + } + + int 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 += utfc_ptr2len(p); + } + } + + ccline.cmdpos = (int)(p - ccline.cmdbuff); + ccline.cmdlen -= j - ccline.cmdpos; + int 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; + if (ccline.cmdlen == 0) { + s->is_state.search_start = s->is_state.save_cursor; + // save view settings, so that the screen won't be restored at the + // wrong position + s->is_state.old_viewstate = s->is_state.init_viewstate; + } + redrawcmd(); + } else if (ccline.cmdlen == 0 && s->c != Ctrl_W + && ccline.cmdprompt == NULL && s->indent == 0) { + // In ex and debug mode it doesn't make sense to return. + if (exmode_active || ccline.cmdfirstc == '>') { + return CMDLINE_NOT_CHANGED; + } + + XFREE_CLEAR(ccline.cmdbuff); // no commandline to return + if (!cmd_silent && !ui_has(kUICmdline)) { + if (cmdmsg_rl) { + msg_col = Columns; + } else { + msg_col = 0; + } + msg_putchar(' '); // delete ':' + } + s->is_state.search_start = s->is_state.save_cursor; + redraw_cmdline = true; + return GOTO_NORMAL_MODE; + } + return CMDLINE_CHANGED; +} + +/// Handle the CTRL-^ key in the command-line mode and toggle the use of the +/// language :lmap mappings and/or Input Method. +static void command_line_toggle_langmap(CommandLineState *s) +{ + if (map_to_exists_mode("", MODE_LANGMAP, false)) { + // ":lmap" mappings exists, toggle use of mappings. + State ^= MODE_LANGMAP; + if (s->b_im_ptr != NULL) { + if (State & MODE_LANGMAP) { + *s->b_im_ptr = B_IMODE_LMAP; + } else { + *s->b_im_ptr = B_IMODE_NONE; + } + } + } + + if (s->b_im_ptr != NULL) { + if (s->b_im_ptr == &curbuf->b_p_iminsert) { + set_iminsert_global(curbuf); + } else { + set_imsearch_global(curbuf); + } + } + ui_cursor_shape(); // may show different cursor shape + // Show/unshow value of 'keymap' in status lines later. + status_redraw_curbuf(); +} + +/// Handle the CTRL-R key in the command-line mode and insert the contents of a +/// numbered or named register. +static int command_line_insert_reg(CommandLineState *s) +{ + const int save_new_cmdpos = new_cmdpos; + + putcmdline('"', true); + no_mapping++; + allow_keys++; + int i = s->c = plain_vgetc(); // CTRL-R <char> + if (i == Ctrl_O) { + i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R + } + + if (i == Ctrl_R) { + s->c = plain_vgetc(); // CTRL-R CTRL-R <char> + } + no_mapping--; + allow_keys--; + // Insert the result of an expression. + new_cmdpos = -1; + if (s->c == '=') { + if (ccline.cmdfirstc == '=' // can't do this recursively + || cmdline_star > 0) { // or when typing a password + beep_flush(); + s->c = ESC; + } else { + s->c = get_expr_register(); + } + } + + if (s->c != ESC) { // use ESC to cancel inserting register + cmdline_paste(s->c, i == Ctrl_R, false); + + // When there was a serious error abort getting the + // command line. + if (aborting()) { + s->gotesc = true; // will free ccline.cmdbuff after + // putting it in history + return GOTO_NORMAL_MODE; + } + KeyTyped = false; // Don't do p_wc completion. + if (new_cmdpos >= 0) { + // set_cmdline_pos() was used + if (new_cmdpos > ccline.cmdlen) { + ccline.cmdpos = ccline.cmdlen; + } else { + ccline.cmdpos = new_cmdpos; + } + } + } + new_cmdpos = save_new_cmdpos; + + // remove the double quote + ccline.special_char = NUL; + redrawcmd(); + + // The text has been stuffed, the command line didn't change yet. + return CMDLINE_NOT_CHANGED; +} + +/// Handle the Left and Right mouse clicks in the command-line mode. +static void command_line_left_right_mouse(CommandLineState *s) +{ + if (s->c == K_LEFTRELEASE || s->c == K_RIGHTRELEASE) { + s->ignore_drag_release = true; + } else { + s->ignore_drag_release = false; + } + + ccline.cmdspos = cmd_startcol(); + for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen; + ccline.cmdpos++) { + int cells = cmdline_charsize(ccline.cmdpos); + if (mouse_row <= cmdline_row + ccline.cmdspos / Columns + && mouse_col < ccline.cmdspos % Columns + cells) { + break; + } + + // Count ">" for double-wide char that doesn't fit. + correct_screencol(ccline.cmdpos, cells, &ccline.cmdspos); + ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1; + ccline.cmdspos += cells; + } +} + static void command_line_next_histidx(CommandLineState *s, bool next_match) { int j = (int)strlen(s->lookfor); @@ -1434,96 +1698,118 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match) if ((s->c != K_UP && s->c != K_DOWN) || s->hiscnt == s->save_hiscnt - || STRNCMP(get_histentry(s->histype)[s->hiscnt].hisstr, + || strncmp(get_histentry(s->histype)[s->hiscnt].hisstr, s->lookfor, (size_t)j) == 0) { break; } } } -static int command_line_handle_key(CommandLineState *s) +/// Handle the Up, Down, Page Up, Page down, CTRL-N and CTRL-P key in the +/// command-line mode. +static int command_line_browse_history(CommandLineState *s) { - // Big switch for a typed command line character. - switch (s->c) { - case K_BS: - case Ctrl_H: - case K_DEL: - case K_KDEL: - case Ctrl_W: - if (s->c == K_KDEL) { - s->c = K_DEL; - } + if (s->histype == HIST_INVALID || get_hislen() == 0 || s->firstc == NUL) { + // no history + return CMDLINE_NOT_CHANGED; + } - // delete current character is the same as backspace on next - // character, except at end of line - if (s->c == K_DEL && ccline.cmdpos != ccline.cmdlen) { - ccline.cmdpos++; - } + s->save_hiscnt = s->hiscnt; - if (s->c == K_DEL) { - ccline.cmdpos += mb_off_next((char_u *)ccline.cmdbuff, - (char_u *)ccline.cmdbuff + ccline.cmdpos); - } + // save current command string so it can be restored later + if (s->lookfor == NULL) { + s->lookfor = xstrdup(ccline.cmdbuff); + s->lookfor[ccline.cmdpos] = NUL; + } - if (ccline.cmdpos > 0) { - char_u *p; + bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N + || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN); + command_line_next_histidx(s, next_match); - int j = ccline.cmdpos; - p = mb_prevptr((char_u *)ccline.cmdbuff, (char_u *)ccline.cmdbuff + j); + if (s->hiscnt != s->save_hiscnt) { + // jumped to other entry + char *p; + int len = 0; + int old_firstc; - if (s->c == Ctrl_W) { - while (p > (char_u *)ccline.cmdbuff && ascii_isspace(*p)) { - p = mb_prevptr((char_u *)ccline.cmdbuff, p); - } + XFREE_CLEAR(ccline.cmdbuff); + s->xpc.xp_context = EXPAND_NOTHING; + if (s->hiscnt == get_hislen()) { + p = s->lookfor; // back to the old one + } else { + p = get_histentry(s->histype)[s->hiscnt].hisstr; + } + + if (s->histype == HIST_SEARCH + && p != s->lookfor + && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) { + // Correct for the separator character used when + // adding the history entry vs the one used now. + // First loop: count length. + // Second loop: copy the characters. + for (int i = 0; i <= 1; i++) { + len = 0; + for (int j = 0; p[j] != NUL; j++) { + // Replace old sep with new sep, unless it is + // escaped. + if (p[j] == old_firstc + && (j == 0 || p[j - 1] != '\\')) { + if (i > 0) { + ccline.cmdbuff[len] = (char)s->firstc; + } + } else { + // Escape new sep, unless it is already + // escaped. + if (p[j] == s->firstc + && (j == 0 || p[j - 1] != '\\')) { + if (i > 0) { + ccline.cmdbuff[len] = '\\'; + } + len++; + } - int i = mb_get_class(p); - while (p > (char_u *)ccline.cmdbuff && mb_get_class(p) == i) { - p = mb_prevptr((char_u *)ccline.cmdbuff, p); + if (i > 0) { + ccline.cmdbuff[len] = p[j]; + } + } + len++; } - if (mb_get_class(p) != i) { - p += utfc_ptr2len((char *)p); + if (i == 0) { + alloc_cmdbuff(len); } } + ccline.cmdbuff[len] = NUL; + } else { + alloc_cmdbuff((int)strlen(p)); + STRCPY(ccline.cmdbuff, p); + } - ccline.cmdpos = (int)(p - (char_u *)ccline.cmdbuff); - ccline.cmdlen -= j - ccline.cmdpos; - int 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; - if (ccline.cmdlen == 0) { - s->is_state.search_start = s->is_state.save_cursor; - // save view settings, so that the screen won't be restored at the - // wrong position - s->is_state.old_viewstate = s->is_state.init_viewstate; - } - redrawcmd(); - } else if (ccline.cmdlen == 0 && s->c != Ctrl_W - && ccline.cmdprompt == NULL && s->indent == 0) { - // In ex and debug mode it doesn't make sense to return. - if (exmode_active || ccline.cmdfirstc == '>') { - return command_line_not_changed(s); - } + ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff); + redrawcmd(); + return CMDLINE_CHANGED; + } + beep_flush(); + return CMDLINE_NOT_CHANGED; +} - XFREE_CLEAR(ccline.cmdbuff); // no commandline to return - if (!cmd_silent && !ui_has(kUICmdline)) { - if (cmdmsg_rl) { - msg_col = Columns; - } else { - msg_col = 0; - } - msg_putchar(' '); // delete ':' - } - s->is_state.search_start = s->is_state.save_cursor; - redraw_cmdline = true; - return 0; // back to cmd mode +static int command_line_handle_key(CommandLineState *s) +{ + // Big switch for a typed command line character. + switch (s->c) { + case K_BS: + case Ctrl_H: + case K_DEL: + case K_KDEL: + case Ctrl_W: + switch (command_line_erase_chars(s)) { + case CMDLINE_NOT_CHANGED: + return command_line_not_changed(s); + case GOTO_NORMAL_MODE: + return 0; // back to cmd mode + default: + return command_line_changed(s); } - return command_line_changed(s); case K_INS: case K_KINS: @@ -1533,28 +1819,7 @@ static int command_line_handle_key(CommandLineState *s) return command_line_not_changed(s); case Ctrl_HAT: - if (map_to_exists_mode("", MODE_LANGMAP, false)) { - // ":lmap" mappings exists, toggle use of mappings. - State ^= MODE_LANGMAP; - if (s->b_im_ptr != NULL) { - if (State & MODE_LANGMAP) { - *s->b_im_ptr = B_IMODE_LMAP; - } else { - *s->b_im_ptr = B_IMODE_NONE; - } - } - } - - if (s->b_im_ptr != NULL) { - if (s->b_im_ptr == &curbuf->b_p_iminsert) { - set_iminsert_global(); - } else { - set_imsearch_global(); - } - } - ui_cursor_shape(); // may show different cursor shape - // Show/unshow value of 'keymap' in status lines later. - status_redraw_curbuf(); + command_line_toggle_langmap(s); return command_line_not_changed(s); case Ctrl_U: { @@ -1590,58 +1855,15 @@ static int command_line_handle_key(CommandLineState *s) // putting it in history return 0; // back to cmd mode - case Ctrl_R: { // insert register - putcmdline('"', true); - no_mapping++; - allow_keys++; - int i = s->c = plain_vgetc(); // CTRL-R <char> - if (i == Ctrl_O) { - i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R - } - - if (i == Ctrl_R) { - s->c = plain_vgetc(); // CTRL-R CTRL-R <char> - } - no_mapping--; - allow_keys--; - // 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 (s->c == '=') { - if (ccline.cmdfirstc == '=' // can't do this recursively - || cmdline_star > 0) { // or when typing a password - beep_flush(); - s->c = ESC; - } else { - s->c = get_expr_register(); - } - } - - if (s->c != ESC) { // use ESC to cancel inserting register - cmdline_paste(s->c, i == Ctrl_R, false); - - // When there was a serious error abort getting the - // command line. - if (aborting()) { - s->gotesc = true; // will free ccline.cmdbuff after - // putting it in history - return 0; // back to cmd mode - } - KeyTyped = false; // Don't do p_wc completion. - if (new_cmdpos >= 0) { - // set_cmdline_pos() was used - if (new_cmdpos > ccline.cmdlen) { - ccline.cmdpos = ccline.cmdlen; - } else { - ccline.cmdpos = new_cmdpos; - } - } + case Ctrl_R: // insert register + switch (command_line_insert_reg(s)) { + case CMDLINE_NOT_CHANGED: + return command_line_not_changed(s); + case GOTO_NORMAL_MODE: + return 0; // back to cmd mode + default: + return command_line_changed(s); } - ccline.special_char = NUL; - redrawcmd(); - return command_line_changed(s); - } case Ctrl_D: if (showmatches(&s->xpc, false) == EXPAND_NOTHING) { @@ -1722,26 +1944,7 @@ static int command_line_handle_key(CommandLineState *s) FALLTHROUGH; case K_LEFTMOUSE: case K_RIGHTMOUSE: - if (s->c == K_LEFTRELEASE || s->c == K_RIGHTRELEASE) { - s->ignore_drag_release = true; - } else { - s->ignore_drag_release = false; - } - - ccline.cmdspos = cmd_startcol(); - for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen; - ccline.cmdpos++) { - int cells = cmdline_charsize(ccline.cmdpos); - if (mouse_row <= cmdline_row + ccline.cmdspos / Columns - && mouse_col < ccline.cmdspos % Columns + cells) { - break; - } - - // Count ">" for double-wide char that doesn't fit. - correct_screencol(ccline.cmdpos, cells, &ccline.cmdspos); - ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1; - ccline.cmdspos += cells; - } + command_line_left_right_mouse(s); return command_line_not_changed(s); // Mouse scroll wheel: ignored here @@ -1808,8 +2011,8 @@ static int command_line_handle_key(CommandLineState *s) case Ctrl_N: // next match case Ctrl_P: // previous match if (s->xpc.xp_numfiles > 0) { - if (nextwild(&s->xpc, (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT, - 0, s->firstc != '@') == FAIL) { + const int wild_type = (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT; + if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } return command_line_not_changed(s); @@ -1824,88 +2027,27 @@ static int command_line_handle_key(CommandLineState *s) case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: - if (s->histype == HIST_INVALID || get_hislen() == 0 || s->firstc == NUL) { - // no history - return command_line_not_changed(s); - } - - s->save_hiscnt = s->hiscnt; - - // save current command string so it can be restored later - if (s->lookfor == NULL) { - s->lookfor = xstrdup(ccline.cmdbuff); - s->lookfor[ccline.cmdpos] = NUL; - } - - bool next_match = (s->c == K_DOWN || s->c == K_S_DOWN || s->c == Ctrl_N - || s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN); - command_line_next_histidx(s, next_match); - - if (s->hiscnt != s->save_hiscnt) { - // jumped to other entry - char_u *p; - int len = 0; - int old_firstc; - - XFREE_CLEAR(ccline.cmdbuff); - s->xpc.xp_context = EXPAND_NOTHING; - if (s->hiscnt == get_hislen()) { - p = (char_u *)s->lookfor; // back to the old one - } else { - p = (char_u *)get_histentry(s->histype)[s->hiscnt].hisstr; + if (cmdline_pum_active() + && (s->c == K_PAGEUP || s->c == K_PAGEDOWN + || s->c == K_KPAGEUP || s->c == K_KPAGEDOWN)) { + // If the popup menu is displayed, then PageUp and PageDown + // are used to scroll the menu. + const int wild_type = + (s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN) ? WILD_PAGEDOWN : WILD_PAGEUP; + if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { + break; } - - if (s->histype == HIST_SEARCH - && p != (char_u *)s->lookfor - && (old_firstc = p[STRLEN(p) + 1]) != s->firstc) { - // Correct for the separator character used when - // adding the history entry vs the one used now. - // First loop: count length. - // Second loop: copy the characters. - for (int i = 0; i <= 1; i++) { - len = 0; - for (int j = 0; p[j] != NUL; j++) { - // Replace old sep with new sep, unless it is - // escaped. - if (p[j] == old_firstc - && (j == 0 || p[j - 1] != '\\')) { - if (i > 0) { - ccline.cmdbuff[len] = (char)s->firstc; - } - } else { - // Escape new sep, unless it is already - // escaped. - if (p[j] == s->firstc - && (j == 0 || p[j - 1] != '\\')) { - if (i > 0) { - ccline.cmdbuff[len] = '\\'; - } - len++; - } - - if (i > 0) { - ccline.cmdbuff[len] = (char)p[j]; - } - } - len++; - } - - if (i == 0) { - alloc_cmdbuff(len); - } - } - ccline.cmdbuff[len] = NUL; - } else { - alloc_cmdbuff((int)STRLEN(p)); - STRCPY(ccline.cmdbuff, p); + return command_line_not_changed(s); + } else { + switch (command_line_browse_history(s)) { + case CMDLINE_CHANGED: + return command_line_changed(s); + case GOTO_NORMAL_MODE: + return 0; + default: + return command_line_not_changed(s); } - - ccline.cmdpos = ccline.cmdlen = (int)strlen(ccline.cmdbuff); - redrawcmd(); - return command_line_changed(s); } - beep_flush(); - return command_line_not_changed(s); case Ctrl_G: // next match case Ctrl_T: // previous match @@ -1981,11 +2123,11 @@ static int command_line_handle_key(CommandLineState *s) // put the character in the command line if (IS_SPECIAL(s->c) || mod_mask != 0) { - put_on_cmdline(get_special_key_name(s->c, mod_mask), -1, true); + put_on_cmdline((char *)get_special_key_name(s->c, mod_mask), -1, true); } else { - int j = utf_char2bytes(s->c, (char *)IObuff); + int j = utf_char2bytes(s->c, IObuff); IObuff[j] = NUL; // exclude composing chars - put_on_cmdline((char_u *)IObuff, j, true); + put_on_cmdline(IObuff, j, true); } return command_line_changed(s); } @@ -2005,16 +2147,35 @@ static int command_line_not_changed(CommandLineState *s) /// Guess that the pattern matches everything. Only finds specific cases, such /// as a trailing \|, which can happen while typing a pattern. -static int empty_pattern(char *p) +static bool empty_pattern(char *p, int delim) { size_t n = strlen(p); + magic_T magic_val = MAGIC_ON; - // remove trailing \v and the like - while (n >= 2 && p[n - 2] == '\\' - && vim_strchr("mMvVcCZ", p[n - 1]) != NULL) { - n -= 2; + if (n > 0) { + (void)skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val); + } else { + return true; } - return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|'); + + return empty_pattern_magic(p, n, magic_val); +} + +static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val) +{ + // remove trailing \v and the like + while (len >= 2 && p[len - 2] == '\\' + && vim_strchr("mMvVcCZ", (uint8_t)p[len - 1]) != NULL) { + len -= 2; + } + + // true, if the pattern is empty, or the pattern ends with \| and magic is + // set (or it ends with '|' and very magic is set) + return len == 0 || (len > 1 + && ((p[len - 2] == '\\' + && p[len - 1] == '|' && magic_val == MAGIC_ON) + || (p[len - 2] != '\\' + && p[len - 1] == '|' && magic_val == MAGIC_ALL))); } handle_T cmdpreview_get_bufnr(void) @@ -2384,7 +2545,8 @@ static void do_autocmd_cmdlinechanged(int firstc) bool 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(); } @@ -2463,9 +2625,9 @@ static void abandon_cmdline(void) /// /// @param count only used for incremental search /// @param indent indent for inside conditionals -char_u *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED) +char *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED) { - return command_line_enter(firstc, count, indent, true); + return (char *)command_line_enter(firstc, count, indent, true); } /// Get a command line with a prompt @@ -2498,10 +2660,10 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at CLEAR_FIELD(ccline); } ccline.prompt_id = last_prompt_id++; - ccline.cmdprompt = (char_u *)prompt; + ccline.cmdprompt = (char *)prompt; ccline.cmdattr = attr; ccline.xp_context = xp_context; - ccline.xp_arg = (char_u *)xp_arg; + ccline.xp_arg = (char *)xp_arg; ccline.input_fn = (firstc == '@'); ccline.highlight_callback = highlight_callback; @@ -2525,12 +2687,6 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at return ret; } -// Return current cmdline prompt -char_u *get_cmdprompt(void) -{ - return ccline.cmdprompt; -} - /// Read the 'wildmode' option, fill wim_flags[]. int check_opt_wim(void) { @@ -2547,13 +2703,13 @@ int check_opt_wim(void) if (p[i] != NUL && p[i] != ',' && p[i] != ':') { return FAIL; } - if (i == 7 && STRNCMP(p, "longest", 7) == 0) { + if (i == 7 && strncmp(p, "longest", 7) == 0) { new_wim_flags[idx] |= WIM_LONGEST; - } else if (i == 4 && STRNCMP(p, "full", 4) == 0) { + } else if (i == 4 && strncmp(p, "full", 4) == 0) { new_wim_flags[idx] |= WIM_FULL; - } else if (i == 4 && STRNCMP(p, "list", 4) == 0) { + } else if (i == 4 && strncmp(p, "list", 4) == 0) { new_wim_flags[idx] |= WIM_LIST; - } else if (i == 8 && STRNCMP(p, "lastused", 8) == 0) { + } else if (i == 8 && strncmp(p, "lastused", 8) == 0) { new_wim_flags[idx] |= WIM_BUFLASTUSED; } else { return FAIL; @@ -2710,7 +2866,7 @@ char *getexline(int c, void *cookie, int indent, bool do_concat) (void)vgetc(); } - return (char *)getcmdline(c, 1L, indent, do_concat); + return getcmdline(c, 1L, indent, do_concat); } bool cmdline_overstrike(void) @@ -2748,7 +2904,7 @@ void realloc_cmdbuff(int len) return; // no need to resize } - char_u *p = (char_u *)ccline.cmdbuff; + char *p = ccline.cmdbuff; alloc_cmdbuff(len); // will get some more // There isn't always a NUL after the command, but it may need to be // there, thus copy up to the NUL and add a NUL. @@ -2760,7 +2916,7 @@ void realloc_cmdbuff(int len) && ccline.xpc->xp_pattern != NULL && ccline.xpc->xp_context != EXPAND_NOTHING && ccline.xpc->xp_context != EXPAND_UNSUCCESSFUL) { - int i = (int)((char_u *)ccline.xpc->xp_pattern - p); + int i = (int)(ccline.xpc->xp_pattern - p); // If xp_pattern points inside the old cmdbuff it needs to be adjusted // to point into the newly allocated memory. @@ -3095,10 +3251,10 @@ static void draw_cmdline(int start, int len) bool do_arabicshape = false; int mb_l; for (int i = start; i < start + len; i += mb_l) { - char_u *p = (char_u *)ccline.cmdbuff + i; + char *p = ccline.cmdbuff + i; int u8cc[MAX_MCO]; int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len((char *)p, start + len - i); + mb_l = utfc_ptr2len_len(p, start + len - i); if (ARABIC_CHAR(u8c)) { do_arabicshape = true; break; @@ -3131,10 +3287,10 @@ static void draw_cmdline(int start, int len) int prev_c = 0; int prev_c1 = 0; for (int i = start; i < start + len; i += mb_l) { - char_u *p = (char_u *)ccline.cmdbuff + i; + char *p = ccline.cmdbuff + i; int u8cc[MAX_MCO]; int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len((char *)p, start + len - i); + mb_l = utfc_ptr2len_len(p, start + len - i); if (ARABIC_CHAR(u8c)) { int pc; int pc1 = 0; @@ -3148,7 +3304,7 @@ static void draw_cmdline(int start, int len) if (i + mb_l >= start + len) { nc = NUL; } else { - nc = utf_ptr2char((char *)p + mb_l); + nc = utf_ptr2char(p + mb_l); } } else { // Displaying from left to right. @@ -3207,7 +3363,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) if (cmdline_star) { content = arena_array(&arena, 1); size_t len = 0; - for (char_u *p = (char_u *)ccline.cmdbuff; *p; MB_PTR_ADV(p)) { + for (char *p = ccline.cmdbuff; *p; MB_PTR_ADV(p)) { len++; } char *buf = arena_alloc(&arena, len, false); @@ -3238,7 +3394,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) char charbuf[2] = { (char)line->cmdfirstc, 0 }; ui_call_cmdline_show(content, line->cmdpos, cstr_as_string(charbuf), - cstr_as_string((char *)(line->cmdprompt)), + cstr_as_string((line->cmdprompt)), line->cmdindent, line->level); if (line->special_char) { @@ -3374,14 +3530,14 @@ void unputcmdline(void) // part will be redrawn, otherwise it will not. If this function is called // twice in a row, then 'redraw' should be false and redrawcmd() should be // called afterwards. -void put_on_cmdline(char_u *str, int len, int redraw) +void put_on_cmdline(char *str, int len, int redraw) { int i; int m; int c; if (len < 0) { - len = (int)STRLEN(str); + len = (int)strlen(str); } realloc_cmdbuff(ccline.cmdlen + len + 1); @@ -3394,7 +3550,7 @@ void put_on_cmdline(char_u *str, int len, int redraw) } else { // Count nr of characters in the new string. m = 0; - for (i = 0; i < len; i += utfc_ptr2len((char *)str + i)) { + for (i = 0; i < len; i += utfc_ptr2len(str + i)) { m++; } // Count nr of bytes in cmdline that are overwritten by these @@ -3520,7 +3676,7 @@ static void restore_cmdline(CmdlineInfo *ccp) static bool cmdline_paste(int regname, bool literally, bool remcr) { char *arg; - char_u *p; + char *p; bool allocated; // check for valid regname; also accept special characters for CTRL-R in @@ -3552,21 +3708,21 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) // When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate // part of the word. - p = (char_u *)arg; + p = arg; if (p_is && regname == Ctrl_W) { - char_u *w; + char *w; int len; // Locate start of last word in the cmd buffer. - for (w = (char_u *)ccline.cmdbuff + ccline.cmdpos; w > (char_u *)ccline.cmdbuff;) { - len = utf_head_off(ccline.cmdbuff, (char *)w - 1) + 1; - if (!vim_iswordc(utf_ptr2char((char *)w - len))) { + for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff;) { + len = utf_head_off(ccline.cmdbuff, w - 1) + 1; + if (!vim_iswordc(utf_ptr2char(w - len))) { break; } w -= len; } - len = (int)(((char_u *)ccline.cmdbuff + ccline.cmdpos) - w); - if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0) { + len = (int)((ccline.cmdbuff + ccline.cmdpos) - w); + if (p_ic ? STRNICMP(w, arg, len) == 0 : strncmp(w, arg, (size_t)len) == 0) { p += len; } } @@ -3585,7 +3741,7 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) // When "literally" is true, insert literally. // When "literally" is false, insert as typed, but don't leave the command // line. -void cmdline_paste_str(char_u *s, int literally) +void cmdline_paste_str(char *s, int literally) { int c, cv; @@ -3593,11 +3749,11 @@ void cmdline_paste_str(char_u *s, int literally) put_on_cmdline(s, -1, true); } else { while (*s != NUL) { - cv = *s; + cv = (uint8_t)(*s); if (cv == Ctrl_V && s[1]) { s++; } - c = mb_cptr2char_adv((const char_u **)&s); + c = mb_cptr2char_adv((const char **)&s); if (cv == Ctrl_V || c == ESC || c == Ctrl_C || c == CAR || c == NL || c == Ctrl_L || (c == Ctrl_BSL && *s == Ctrl_N)) { @@ -3638,7 +3794,7 @@ static void redrawcmdprompt(void) msg_putchar(ccline.cmdfirstc); } if (ccline.cmdprompt != NULL) { - msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr); + msg_puts_attr(ccline.cmdprompt, ccline.cmdattr); ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns; // do the reverse of cmd_startcol() if (ccline.cmdfirstc != NUL) { @@ -3708,7 +3864,7 @@ void compute_cmdrow(void) cmdline_row = wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height + global_stl_height(); } - if (cmdline_row == Rows) { + if (cmdline_row == Rows && p_ch > 0) { cmdline_row--; } lines_left = cmdline_row; @@ -3796,7 +3952,7 @@ static int ccheck_abbr(int c) spos = 0; } - return check_abbr(c, (char_u *)ccline.cmdbuff, ccline.cmdpos, spos); + return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos); } /// Escape special characters in "fname", depending on "what": @@ -3813,34 +3969,31 @@ char *vim_strsave_fnameescape(const char *const fname, const int what) { #ifdef BACKSLASH_IN_FILENAME # define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<" -# define BUFFER_ESC_CHARS ((char_u *)" \t\n*?[`%#'\"|!<") - char_u buf[sizeof(PATH_ESC_CHARS)]; +# define BUFFER_ESC_CHARS (" \t\n*?[`%#'\"|!<") + char buf[sizeof(PATH_ESC_CHARS)]; int j = 0; // Don't escape '[', '{' and '!' if they are in 'isfname' and for the // ":buffer" command. for (const char *p = what == VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS; *p != NUL; p++) { - if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p)) { + if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec((uint8_t)(*p))) { buf[j++] = *p; } } buf[j] = NUL; - char *p = (char *)vim_strsave_escaped((const char_u *)fname, - (const char_u *)buf); + char *p = vim_strsave_escaped(fname, buf); #else -# define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<") -# define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&") -# define BUFFER_ESC_CHARS ((char_u *)" \t\n*?[`$\\%#'\"|!<") - char *p = - (char *)vim_strsave_escaped((const char_u *)fname, - what == VSE_SHELL ? SHELL_ESC_CHARS - : what == VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS); +# define PATH_ESC_CHARS " \t\n*?[{`$\\%#'\"|!<" +# define SHELL_ESC_CHARS " \t\n*?[{`$\\%#'\"|!<>();&" +# define BUFFER_ESC_CHARS " \t\n*?[`$\\%#'\"|!<" + char *p = vim_strsave_escaped(fname, + what == VSE_SHELL ? SHELL_ESC_CHARS : what == + VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS); if (what == VSE_SHELL && csh_like_shell()) { // For csh and similar shells need to put two backslashes before '!'. // One is taken by Vim, one by the shell. - char *s = (char *)vim_strsave_escaped((const char_u *)p, - (const char_u *)"!"); + char *s = vim_strsave_escaped(p, "!"); xfree(p); p = s; } @@ -3858,16 +4011,16 @@ char *vim_strsave_fnameescape(const char *const fname, const int what) /// Put a backslash before the file name in "pp", which is in allocated memory. void escape_fname(char **pp) { - char_u *p = xmalloc(strlen(*pp) + 2); + char *p = xmalloc(strlen(*pp) + 2); p[0] = '\\'; STRCPY(p + 1, *pp); xfree(*pp); - *pp = (char *)p; + *pp = p; } /// For each file name in files[num_files]: /// If 'orig_pat' starts with "~/", replace the home directory with "~". -void tilde_replace(char_u *orig_pat, int num_files, char **files) +void tilde_replace(char *orig_pat, int num_files, char **files) { char *p; @@ -3948,12 +4101,14 @@ static char *get_cmdline_completion(void) } CmdlineInfo *p = get_ccline_ptr(); - if (p != NULL && p->xpc != NULL) { - set_expand_context(p->xpc); - char *cmd_compl = get_user_cmd_complete(p->xpc, p->xpc->xp_context); - if (cmd_compl != NULL) { - return xstrdup(cmd_compl); - } + if (p == NULL || p->xpc == NULL) { + return NULL; + } + + set_expand_context(p->xpc); + char *cmd_compl = get_user_cmd_complete(p->xpc, p->xpc->xp_context); + if (cmd_compl != NULL) { + return xstrdup(cmd_compl); } return NULL; @@ -4134,7 +4289,7 @@ char *check_cedit(void) if (*p_cedit == NUL) { cedit_key = -1; } else { - n = string_to_key((char_u *)p_cedit); + n = string_to_key(p_cedit); if (vim_isprintc(n)) { return e_invarg; } |