diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
| commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
| tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/ex_getln.c | |
| parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
| parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
| download | rneovim-aucmd_textputpost.tar.gz rneovim-aucmd_textputpost.tar.bz2 rneovim-aucmd_textputpost.zip | |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/ex_getln.c')
| -rw-r--r-- | src/nvim/ex_getln.c | 616 |
1 files changed, 288 insertions, 328 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 76c3680742..64ef17b157 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1,12 +1,10 @@ -// 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. #include <assert.h> #include <inttypes.h> #include <limits.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> @@ -17,7 +15,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/arabic.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/charset.h" @@ -29,21 +27,23 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/vars.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/extmark.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/grid.h" -#include "nvim/highlight_defs.h" +#include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/keycodes.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" +#include "nvim/map_defs.h" #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/mbyte.h" @@ -55,22 +55,24 @@ #include "nvim/normal.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_defs.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/popupmenu.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.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" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/usercmd.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/viml/parser/expressions.h" #include "nvim/viml/parser/parser.h" #include "nvim/window.h" @@ -82,6 +84,7 @@ static unsigned last_prompt_id = 0; typedef struct { colnr_T vs_curswant; colnr_T vs_leftcol; + colnr_T vs_skipcol; linenr_T vs_topline; int vs_topfill; linenr_T vs_botline; @@ -104,7 +107,7 @@ typedef struct { typedef struct command_line_state { VimState state; int firstc; - long count; + int count; int indent; int c; int gotesc; // true when <ESC> just typed @@ -126,9 +129,34 @@ typedef struct command_line_state { int ignore_drag_release; int break_ctrl_c; expand_T xpc; - long *b_im_ptr; + OptInt *b_im_ptr; + buf_T *b_im_ptr_buf; ///< buffer where b_im_ptr is valid } CommandLineState; +typedef struct cmdpreview_undo_info { + u_header_T *save_b_u_oldhead; + u_header_T *save_b_u_newhead; + u_header_T *save_b_u_curhead; + int save_b_u_numhead; + bool save_b_u_synced; + int save_b_u_seq_last; + int save_b_u_save_nr_last; + int save_b_u_seq_cur; + time_t save_b_u_time_cur; + int save_b_u_save_nr_cur; + char *save_b_u_line_ptr; + linenr_T save_b_u_line_lnum; + colnr_T save_b_u_line_colnr; +} CpUndoInfo; + +typedef struct cmdpreview_buf_info { + buf_T *buf; + OptInt save_b_p_ul; + int save_b_changed; + varnumber_T save_changedtick; + CpUndoInfo undo_info; +} CpBufInfo; + typedef struct cmdpreview_win_info { win_T *win; pos_T save_w_cursor; @@ -137,17 +165,6 @@ typedef struct cmdpreview_win_info { int save_w_p_cuc; } CpWinInfo; -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; - long save_b_p_ul; - int save_b_changed; - varnumber_T save_changedtick; -} CpBufInfo; - typedef struct cmdpreview_info { kvec_t(CpWinInfo) win_info; kvec_t(CpBufInfo) buf_info; @@ -187,15 +204,14 @@ static int cedit_key = -1; ///< key value of 'cedit' option #endif static handle_T cmdpreview_bufnr = 0; -static long cmdpreview_ns = 0; - -static int cmd_hkmap = 0; // Hebrew mapping during command line +static int cmdpreview_ns = 0; static void save_viewstate(win_T *wp, viewstate_T *vs) FUNC_ATTR_NONNULL_ALL { vs->vs_curswant = wp->w_curswant; vs->vs_leftcol = wp->w_leftcol; + vs->vs_skipcol = wp->w_skipcol; vs->vs_topline = wp->w_topline; vs->vs_topfill = wp->w_topfill; vs->vs_botline = wp->w_botline; @@ -207,6 +223,7 @@ static void restore_viewstate(win_T *wp, viewstate_T *vs) { wp->w_curswant = vs->vs_curswant; wp->w_leftcol = vs->vs_leftcol; + wp->w_skipcol = vs->vs_skipcol; wp->w_topline = vs->vs_topline; wp->w_topfill = vs->vs_topfill; wp->w_botline = vs->vs_botline; @@ -232,14 +249,9 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s int *skiplen, int *patlen) FUNC_ATTR_NONNULL_ALL { - char *cmd; char *p; bool delim_optional = false; - int delim; - char *end; - char *dummy; - pos_T save_cursor; - bool use_last_pat; + const char *dummy; bool retval = false; magic_T magic = 0; @@ -273,7 +285,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s cmdmod_T dummy_cmdmod; parse_command_modifiers(&ea, &dummy, &dummy_cmdmod, true); - cmd = skip_range(ea.cmd, NULL); + char *cmd = skip_range(ea.cmd, NULL); if (vim_strchr("sgvl", (uint8_t)(*cmd)) == NULL) { goto theend; } @@ -298,7 +310,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s if (*p == '!') { p = skipwhite(p + 1); } - while (ASCII_ISALPHA(*(p = skipwhite((char *)p)))) { + while (ASCII_ISALPHA(*(p = skipwhite(p)))) { p++; } if (*p == NUL) { @@ -324,11 +336,11 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s } p = skipwhite(p); - delim = (delim_optional && vim_isIDc((uint8_t)(*p))) ? ' ' : *p++; + int delim = (delim_optional && vim_isIDc((uint8_t)(*p))) ? ' ' : *p++; *search_delim = delim; - end = skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic); + char *end = skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic); - use_last_pat = end == p && *end == delim; + bool use_last_pat = end == p && *end == delim; if (end == p && !use_last_pat) { goto theend; } @@ -349,7 +361,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s *patlen = (int)(end - p); // parse the address range - save_cursor = curwin->w_cursor; + pos_T save_cursor = curwin->w_cursor; curwin->w_cursor = s->search_start; parse_cmd_address(&ea, &dummy, true); if (ea.addr_count > 0) { @@ -375,13 +387,10 @@ theend: } // May do 'incsearch' highlighting if desired. -static void may_do_incsearch_highlighting(int firstc, long count, incsearch_state_T *s) +static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state_T *s) { pos_T end_pos; - proftime_T tm; int skiplen, patlen; - char next_char; - bool use_last_pat; int search_delim; // Parsing range may already set the last search pattern. @@ -418,9 +427,9 @@ 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 = ccline.cmdbuff[skiplen + patlen]; - use_last_pat = patlen == 0 && skiplen > 0 - && ccline.cmdbuff[skiplen - 1] == next_char; + char next_char = ccline.cmdbuff[skiplen + patlen]; + bool use_last_pat = patlen == 0 && skiplen > 0 + && ccline.cmdbuff[skiplen - 1] == next_char; // If there is no pattern, don't do anything. if (patlen == 0 && !use_last_pat) { @@ -433,7 +442,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat ui_flush(); emsg_off++; // So it doesn't beep if bad expr // Set the time limit to half a second. - tm = profile_setlimit(500L); + proftime_T tm = profile_setlimit(500); if (!p_hls) { search_flags += SEARCH_KEEP; } @@ -477,7 +486,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat // first restore the old curwin values, so the screen is // positioned in the same way as the actual search command restore_viewstate(curwin, &s->old_viewstate); - changed_cline_bef_curs(); + changed_cline_bef_curs(curwin); update_topline(curwin); if (found != 0) { @@ -506,6 +515,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat } validate_cursor(); + // May redraw the status line to show the cursor position. if (p_ru && (curwin->w_status_height > 0 || global_stl_height() > 0)) { curwin->w_redr_status = true; @@ -588,7 +598,7 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool curwin->w_cursor = s->save_cursor; setpcmark(); } - curwin->w_cursor = s->search_start; // -V519 + curwin->w_cursor = s->search_start; } restore_viewstate(curwin, &s->old_viewstate); highlight_match = false; @@ -600,6 +610,7 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool magic_overruled = s->magic_overruled_save; validate_cursor(); // needed for TAB + status_redraw_all(); redraw_all_later(UPD_SOME_VALID); if (call_update_screen) { update_screen(); @@ -641,7 +652,7 @@ static void init_ccline(int firstc, int indent) /// @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) +static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear_ccline) { // can be invoked recursively, identify each level static int cmdline_level = 0; @@ -680,11 +691,6 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea s->break_ctrl_c = true; } - // start without Hebrew mapping for a command line - if (s->firstc == ':' || s->firstc == '=' || s->firstc == '>') { - cmd_hkmap = 0; - } - init_ccline(s->firstc, s->indent); ccline.prompt_id = last_prompt_id++; ccline.level = cmdline_level; @@ -698,12 +704,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea ExpandInit(&s->xpc); ccline.xpc = &s->xpc; - if (curwin->w_p_rl && *curwin->w_p_rlc == 's' - && (s->firstc == '/' || s->firstc == '?')) { - cmdmsg_rl = true; - } else { - cmdmsg_rl = false; - } + cmdmsg_rl = (curwin->w_p_rl && *curwin->w_p_rlc == 's' + && (s->firstc == '/' || s->firstc == '?')); msg_grid_validate(); @@ -741,7 +743,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea } else { s->b_im_ptr = &curbuf->b_p_imsearch; } - + s->b_im_ptr_buf = curbuf; if (*s->b_im_ptr == B_IMODE_LMAP) { State |= MODE_LANGMAP; } @@ -795,7 +797,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea // Redraw the statusline in case it uses the current mode using the mode() // function. - if (!cmd_silent) { + if (!cmd_silent && !exmode_active) { bool found_one = false; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { @@ -844,6 +846,16 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool clea cmdmsg_rl = false; + // We could have reached here without having a chance to clean up wild menu + // if certain special keys like <Esc> or <C-\> were used as wildchar. Make + // sure to still clean up to avoid memory corruption. + if (cmdline_pum_active()) { + cmdline_pum_remove(); + } + wildmenu_cleanup(&ccline); + s->did_wild_list = false; + s->wim_index = 0; + ExpandCleanup(&s->xpc); ccline.xpc = NULL; @@ -914,6 +926,9 @@ theend: ui_call_cmdline_hide(ccline.level); msg_ext_clear_later(); } + if (!cmd_silent) { + status_redraw_all(); // redraw to show mode change + } cmdline_level--; @@ -928,6 +943,8 @@ theend: static int command_line_check(VimState *state) { + CommandLineState *s = (CommandLineState *)state; + redir_off = true; // Don't redirect the typed command. // Repeated, because a ":redir" inside // completion may switch it on. @@ -937,6 +954,9 @@ static int command_line_check(VimState *state) // that occurs while typing a command should // cause the command not to be executed. + // Trigger SafeState if nothing is pending. + may_trigger_safestate(s->xpc.xp_numfiles <= 0); + cursorcmd(); // set the cursor on the right spot ui_cursor_shape(); return 1; @@ -1142,7 +1162,7 @@ static int command_line_execute(VimState *state, int key) } else if (s->c == K_COMMAND) { do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT); } else { - map_execute_lua(); + map_execute_lua(false); } // nvim_select_popupmenu_item() can be called from the handling of @@ -1166,9 +1186,6 @@ static int command_line_execute(VimState *state, int key) if (KeyTyped) { s->some_key_typed = true; - if (cmd_hkmap) { - s->c = hkmap(s->c); - } if (cmdmsg_rl && !KeyStuffed) { // Invert horizontal movements and operations. Only when @@ -1225,13 +1242,14 @@ static int command_line_execute(VimState *state, int key) s->c = wildmenu_translate_key(&ccline, s->c, &s->xpc, s->did_wild_list); } - if (cmdline_pum_active() || s->did_wild_list) { + int wild_type = 0; + const bool key_is_wc = (s->c == p_wc && KeyTyped) || s->c == p_wcm; + if ((cmdline_pum_active() || s->did_wild_list) && !key_is_wc) { // 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; + wild_type = (s->c == Ctrl_E) ? WILD_CANCEL : WILD_APPLY; (void)nextwild(&s->xpc, wild_type, WILD_NO_BEEP, s->firstc != '@'); - s->c = Ctrl_E; } } @@ -1240,7 +1258,7 @@ static int command_line_execute(VimState *state, int key) // '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 + bool end_wildmenu = (!key_is_wc && 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() @@ -1307,7 +1325,7 @@ static int command_line_execute(VimState *state, int key) if (!cmd_silent) { if (!ui_has(kUICmdline)) { - cmd_cursor_goto(msg_row, 0); + msg_cursor_goto(msg_row, 0); } ui_flush(); } @@ -1344,13 +1362,19 @@ static int command_line_execute(VimState *state, int key) } s->do_abbr = true; // default: check for abbreviation + + // If already used to cancel/accept wildmenu, don't process the key further. + if (wild_type == WILD_CANCEL || wild_type == WILD_APPLY) { + return command_line_not_changed(s); + } + return command_line_handle_key(s); } // May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next // or previous match. // Returns FAIL when calling command_line_not_changed. -static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_state_T *s, +static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_state_T *s, bool next_match) FUNC_ATTR_NONNULL_ALL { @@ -1376,7 +1400,6 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ pos_T t; char *pat; int search_flags = SEARCH_NOOF; - char save; if (search_delim == ccline.cmdbuff[skiplen]) { pat = last_search_pattern(); @@ -1405,7 +1428,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ search_flags += SEARCH_KEEP; } emsg_off++; - save = pat[patlen]; + char save = pat[patlen]; pat[patlen] = NUL; int found = searchit(curwin, curbuf, &t, NULL, next_match ? FORWARD : BACKWARD, @@ -1443,7 +1466,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_ set_search_match(&s->match_end); curwin->w_cursor = s->match_start; - changed_cline_bef_curs(); + changed_cline_bef_curs(curwin); update_topline(curwin); validate_cursor(); highlight_match = true; @@ -1479,10 +1502,8 @@ static int command_line_erase_chars(CommandLineState *s) } if (ccline.cmdpos > 0) { - char *p; - int j = ccline.cmdpos; - p = mb_prevptr(ccline.cmdbuff, ccline.cmdbuff + j); + char *p = mb_prevptr(ccline.cmdbuff, ccline.cmdbuff + j); if (s->c == Ctrl_W) { while (p > ccline.cmdbuff && ascii_isspace(*p)) { @@ -1525,11 +1546,7 @@ static int command_line_erase_chars(CommandLineState *s) 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_col = 0; msg_putchar(' '); // delete ':' } s->is_state.search_start = s->is_state.save_cursor; @@ -1543,20 +1560,21 @@ static int command_line_erase_chars(CommandLineState *s) /// language :lmap mappings and/or Input Method. static void command_line_toggle_langmap(CommandLineState *s) { + OptInt *b_im_ptr = buf_valid(s->b_im_ptr_buf) ? s->b_im_ptr : NULL; 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 (b_im_ptr != NULL) { if (State & MODE_LANGMAP) { - *s->b_im_ptr = B_IMODE_LMAP; + *b_im_ptr = B_IMODE_LMAP; } else { - *s->b_im_ptr = B_IMODE_NONE; + *b_im_ptr = B_IMODE_NONE; } } } - if (s->b_im_ptr != NULL) { - if (s->b_im_ptr == &curbuf->b_p_iminsert) { + if (b_im_ptr != NULL) { + if (b_im_ptr == &curbuf->b_p_iminsert) { set_iminsert_global(curbuf); } else { set_imsearch_global(curbuf); @@ -1598,8 +1616,10 @@ static int command_line_insert_reg(CommandLineState *s) } } + bool literally = false; if (s->c != ESC) { // use ESC to cancel inserting register - cmdline_paste(s->c, i == Ctrl_R, false); + literally = i == Ctrl_R || is_literal_register(s->c); + cmdline_paste(s->c, literally, false); // When there was a serious error abort getting the // command line. @@ -1624,8 +1644,9 @@ static int command_line_insert_reg(CommandLineState *s) ccline.special_char = NUL; redrawcmd(); - // The text has been stuffed, the command line didn't change yet. - return CMDLINE_NOT_CHANGED; + // With "literally": the command line has already changed. + // Else: the text has been stuffed, but the command line didn't change yet. + return literally ? CMDLINE_CHANGED : CMDLINE_NOT_CHANGED; } /// Handle the Left and Right mouse clicks in the command-line mode. @@ -1656,7 +1677,7 @@ static void command_line_left_right_mouse(CommandLineState *s) static void command_line_next_histidx(CommandLineState *s, bool next_match) { int j = (int)strlen(s->lookfor); - for (;;) { + while (true) { // one step backwards if (!next_match) { if (s->hiscnt == get_hislen()) { @@ -1729,7 +1750,6 @@ static int command_line_browse_history(CommandLineState *s) if (s->hiscnt != s->save_hiscnt) { // jumped to other entry char *p; - int len = 0; int old_firstc; XFREE_CLEAR(ccline.cmdbuff); @@ -1743,6 +1763,7 @@ static int command_line_browse_history(CommandLineState *s) if (s->histype == HIST_SEARCH && p != s->lookfor && (old_firstc = (uint8_t)p[strlen(p) + 1]) != s->firstc) { + int len = 0; // Correct for the separator character used when // adding the history entry vs the one used now. // First loop: count length. @@ -1814,8 +1835,10 @@ static int command_line_handle_key(CommandLineState *s) case K_INS: case K_KINS: ccline.overstrike = !ccline.overstrike; - ui_cursor_shape(); // may show different cursor shape + may_trigger_modechanged(); + status_redraw_curbuf(); + redraw_statuslines(); return command_line_not_changed(s); case Ctrl_HAT: @@ -1857,12 +1880,12 @@ static int command_line_handle_key(CommandLineState *s) 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: + case CMDLINE_CHANGED: return command_line_changed(s); + default: + return command_line_not_changed(s); } case Ctrl_D: @@ -2015,7 +2038,7 @@ static int command_line_handle_key(CommandLineState *s) if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } - return command_line_not_changed(s); + return command_line_changed(s); } FALLTHROUGH; @@ -2037,7 +2060,7 @@ static int command_line_handle_key(CommandLineState *s) if (nextwild(&s->xpc, wild_type, 0, s->firstc != '@') == FAIL) { break; } - return command_line_not_changed(s); + return command_line_changed(s); } else { switch (command_line_browse_history(s)) { case CMDLINE_CHANGED: @@ -2098,7 +2121,6 @@ static int command_line_handle_key(CommandLineState *s) if (!p_ari) { break; } - cmd_hkmap = !cmd_hkmap; return command_line_not_changed(s); default: @@ -2123,7 +2145,7 @@ 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((char *)get_special_key_name(s->c, mod_mask), -1, true); + put_on_cmdline(get_special_key_name(s->c, mod_mask), -1, true); } else { int j = utf_char2bytes(s->c, IObuff); IObuff[j] = NUL; // exclude composing chars @@ -2183,7 +2205,7 @@ handle_T cmdpreview_get_bufnr(void) return cmdpreview_bufnr; } -long cmdpreview_get_ns(void) +int cmdpreview_get_ns(void) { return cmdpreview_ns; } @@ -2278,9 +2300,51 @@ static void cmdpreview_close_win(void) } } +/// Save the undo state of a buffer for command preview. +static void cmdpreview_save_undo(CpUndoInfo *cp_undoinfo, buf_T *buf) + FUNC_ATTR_NONNULL_ALL +{ + cp_undoinfo->save_b_u_synced = buf->b_u_synced; + cp_undoinfo->save_b_u_oldhead = buf->b_u_oldhead; + cp_undoinfo->save_b_u_newhead = buf->b_u_newhead; + cp_undoinfo->save_b_u_curhead = buf->b_u_curhead; + cp_undoinfo->save_b_u_numhead = buf->b_u_numhead; + cp_undoinfo->save_b_u_seq_last = buf->b_u_seq_last; + cp_undoinfo->save_b_u_save_nr_last = buf->b_u_save_nr_last; + cp_undoinfo->save_b_u_seq_cur = buf->b_u_seq_cur; + cp_undoinfo->save_b_u_time_cur = buf->b_u_time_cur; + cp_undoinfo->save_b_u_save_nr_cur = buf->b_u_save_nr_cur; + cp_undoinfo->save_b_u_line_ptr = buf->b_u_line_ptr; + cp_undoinfo->save_b_u_line_lnum = buf->b_u_line_lnum; + cp_undoinfo->save_b_u_line_colnr = buf->b_u_line_colnr; +} + +/// Restore the undo state of a buffer for command preview. +static void cmdpreview_restore_undo(const CpUndoInfo *cp_undoinfo, buf_T *buf) +{ + buf->b_u_oldhead = cp_undoinfo->save_b_u_oldhead; + buf->b_u_newhead = cp_undoinfo->save_b_u_newhead; + buf->b_u_curhead = cp_undoinfo->save_b_u_curhead; + buf->b_u_numhead = cp_undoinfo->save_b_u_numhead; + buf->b_u_seq_last = cp_undoinfo->save_b_u_seq_last; + buf->b_u_save_nr_last = cp_undoinfo->save_b_u_save_nr_last; + buf->b_u_seq_cur = cp_undoinfo->save_b_u_seq_cur; + buf->b_u_time_cur = cp_undoinfo->save_b_u_time_cur; + buf->b_u_save_nr_cur = cp_undoinfo->save_b_u_save_nr_cur; + buf->b_u_line_ptr = cp_undoinfo->save_b_u_line_ptr; + buf->b_u_line_lnum = cp_undoinfo->save_b_u_line_lnum; + buf->b_u_line_colnr = cp_undoinfo->save_b_u_line_colnr; + if (buf->b_u_curhead == NULL) { + buf->b_u_synced = cp_undoinfo->save_b_u_synced; + } +} + /// Save current state and prepare windows and buffers for command preview. static void cmdpreview_prepare(CpInfo *cpinfo) + FUNC_ATTR_NONNULL_ALL { + Set(ptr_t) saved_bufs = SET_INIT; + kv_init(cpinfo->buf_info); kv_init(cpinfo->win_info); @@ -2292,20 +2356,19 @@ static void cmdpreview_prepare(CpInfo *cpinfo) continue; } - CpBufInfo cp_bufinfo; - cp_bufinfo.buf = buf; + if (!set_has(ptr_t, &saved_bufs, buf)) { + CpBufInfo cp_bufinfo; + cp_bufinfo.buf = buf; + cp_bufinfo.save_b_p_ul = buf->b_p_ul; + cp_bufinfo.save_b_changed = buf->b_changed; + cp_bufinfo.save_changedtick = buf_get_changedtick(buf); + cmdpreview_save_undo(&cp_bufinfo.undo_info, buf); + kv_push(cpinfo->buf_info, cp_bufinfo); + set_put(ptr_t, &saved_bufs, buf); - cp_bufinfo.save_b_u_synced = buf->b_u_synced; - cp_bufinfo.save_b_u_time_cur = buf->b_u_time_cur; - cp_bufinfo.save_b_u_seq_cur = buf->b_u_seq_cur; - cp_bufinfo.save_b_u_newhead = buf->b_u_newhead; - cp_bufinfo.save_b_p_ul = buf->b_p_ul; - cp_bufinfo.save_b_changed = buf->b_changed; - cp_bufinfo.save_changedtick = buf_get_changedtick(buf); - - kv_push(cpinfo->buf_info, cp_bufinfo); - - buf->b_p_ul = LONG_MAX; // Make sure we can undo all changes + u_clearall(buf); + buf->b_p_ul = INT_MAX; // Make sure we can undo all changes + } CpWinInfo cp_wininfo; cp_wininfo.win = win; @@ -2324,6 +2387,8 @@ static void cmdpreview_prepare(CpInfo *cpinfo) win->w_p_cuc = false; // Disable 'cursorcolumn' so it doesn't mess up the highlights } + set_destroy(ptr_t, &saved_bufs); + cpinfo->save_hls = p_hls; cpinfo->save_cmdmod = cmdmod; win_size_save(&cpinfo->save_view); @@ -2337,8 +2402,9 @@ static void cmdpreview_prepare(CpInfo *cpinfo) u_sync(true); } -// Restore the state of buffers and windows before command preview. +/// Restore the state of buffers and windows for command preview. static void cmdpreview_restore_state(CpInfo *cpinfo) + FUNC_ATTR_NONNULL_ALL { for (size_t i = 0; i < cpinfo->buf_info.size; i++) { CpBufInfo cp_bufinfo = cpinfo->buf_info.items[i]; @@ -2346,41 +2412,40 @@ static void cmdpreview_restore_state(CpInfo *cpinfo) buf->b_changed = cp_bufinfo.save_b_changed; - if (buf->b_u_seq_cur != cp_bufinfo.save_b_u_seq_cur) { + // Clear preview highlights. + extmark_clear(buf, (uint32_t)cmdpreview_ns, 0, 0, MAXLNUM, MAXCOL); + + if (buf->b_u_seq_cur != cp_bufinfo.undo_info.save_b_u_seq_cur) { int count = 0; // Calculate how many undo steps are necessary to restore earlier state. for (u_header_T *uhp = buf->b_u_curhead ? buf->b_u_curhead : buf->b_u_newhead; - uhp != NULL && uhp->uh_seq > cp_bufinfo.save_b_u_seq_cur; + uhp != NULL; uhp = uhp->uh_next.ptr, ++count) {} aco_save_T aco; aucmd_prepbuf(&aco, buf); + // Ensure all the entries will be undone + if (curbuf->b_u_synced == false) { + u_sync(true); + } // Undo invisibly. This also moves the cursor! if (!u_undo_and_forget(count, false)) { abort(); } aucmd_restbuf(&aco); - - // Restore newhead. It is meaningless when curhead is valid, but we must - // restore it so that undotree() is identical before/after the preview. - buf->b_u_newhead = cp_bufinfo.save_b_u_newhead; - buf->b_u_time_cur = cp_bufinfo.save_b_u_time_cur; } - if (buf->b_u_curhead == NULL) { - buf->b_u_synced = cp_bufinfo.save_b_u_synced; - } + u_blockfree(buf); + cmdpreview_restore_undo(&cp_bufinfo.undo_info, buf); if (cp_bufinfo.save_changedtick != buf_get_changedtick(buf)) { buf_set_changedtick(buf, cp_bufinfo.save_changedtick); } buf->b_p_ul = cp_bufinfo.save_b_p_ul; // Restore 'undolevels' - - // Clear preview highlights. - extmark_clear(buf, (uint32_t)cmdpreview_ns, 0, 0, MAXLNUM, MAXCOL); } + for (size_t i = 0; i < cpinfo->win_info.size; i++) { CpWinInfo cp_wininfo = cpinfo->win_info.items[i]; win_T *win = cp_wininfo.win; @@ -2429,7 +2494,7 @@ static bool cmdpreview_may_show(CommandLineState *s) // Copy the command line so we can modify it. int cmdpreview_type = 0; char *cmdline = xstrdup(ccline.cmdbuff); - char *errormsg = NULL; + const char *errormsg = NULL; emsg_off++; // Block errors when parsing the command line, and don't update v:errmsg if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) { emsg_off--; @@ -2452,8 +2517,8 @@ static bool cmdpreview_may_show(CommandLineState *s) CpInfo cpinfo; bool icm_split = *p_icm == 's'; // inccommand=split - buf_T *cmdpreview_buf; - win_T *cmdpreview_win; + buf_T *cmdpreview_buf = NULL; + win_T *cmdpreview_win = NULL; emsg_silent++; // Block error reporting as the command may be incomplete, // but still update v:errmsg @@ -2579,7 +2644,7 @@ static int command_line_changed(CommandLineState *s) } } - if (cmdmsg_rl || (p_arshape && !p_tbidi)) { + if (p_arshape && !p_tbidi) { // Always redraw the whole command line to fix shaping and // right-left typing. Not efficient, but it works. // Do it only when there are no characters left to read @@ -2601,7 +2666,7 @@ static void abandon_cmdline(void) if (msg_scrolled == 0) { compute_cmdrow(); } - msg(""); + msg("", 0); redraw_cmdline = true; } @@ -2625,7 +2690,7 @@ static void abandon_cmdline(void) /// /// @param count only used for incremental search /// @param indent indent for inside conditionals -char *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED) +char *getcmdline(int firstc, int count, int indent, bool do_concat FUNC_ATTR_UNUSED) { return (char *)command_line_enter(firstc, count, indent, true); } @@ -2670,7 +2735,7 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at int msg_silent_saved = msg_silent; msg_silent = 0; - char *const ret = (char *)command_line_enter(firstc, 1L, 0, false); + char *const ret = (char *)command_line_enter(firstc, 1, 0, false); if (did_save_ccline) { restore_cmdline(&save_ccline); @@ -2690,7 +2755,7 @@ char *getcmdline_prompt(const int firstc, const char *const prompt, const int at /// Read the 'wildmode' option, fill wim_flags[]. int check_opt_wim(void) { - char_u new_wim_flags[4]; + uint8_t new_wim_flags[4]; int i; int idx = 0; @@ -2699,6 +2764,7 @@ int check_opt_wim(void) } for (char *p = p_wim; *p; p++) { + // Note: Keep this in sync with p_wim_values. for (i = 0; ASCII_ISALPHA(p[i]); i++) {} if (p[i] != NUL && p[i] != ',' && p[i] != ':') { return FAIL; @@ -2746,6 +2812,9 @@ bool text_locked(void) if (cmdwin_type != 0) { return true; } + if (expr_map_locked()) { + return true; + } return textlock != 0; } @@ -2756,7 +2825,7 @@ void text_locked_msg(void) emsg(_(get_text_locked_msg())); } -char *get_text_locked_msg(void) +const char *get_text_locked_msg(void) { if (cmdwin_type != 0) { return e_cmdwin; @@ -2866,7 +2935,7 @@ char *getexline(int c, void *cookie, int indent, bool do_concat) (void)vgetc(); } - return getcmdline(c, 1L, indent, do_concat); + return getcmdline(c, 1, indent, do_concat); } bool cmdline_overstrike(void) @@ -2926,16 +2995,6 @@ void realloc_cmdbuff(int len) } } -static char *arshape_buf = NULL; - -#if defined(EXITFREE) -void free_arshape_buf(void) -{ - xfree(arshape_buf); -} - -#endif - enum { MAX_CB_ERRORS = 1, }; /// Color expression cmdline using built-in expressions parser @@ -2950,7 +3009,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline, { ParserLine parser_lines[] = { { - .data = (const char *)colored_ccline->cmdbuff, + .data = colored_ccline->cmdbuff, .size = strlen(colored_ccline->cmdbuff), .allocated = false, }, @@ -3054,7 +3113,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) bool can_free_cb = false; TryState tstate; Error err = ERROR_INIT; - const char *err_errmsg = (const char *)e_intern2; + const char *err_errmsg = e_intern2; bool dgc_ret = true; bool tl_ret = true; @@ -3087,8 +3146,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) } if (colored_ccline->cmdbuff[colored_ccline->cmdlen] != NUL) { arg_allocated = true; - arg.vval.v_string = xmemdupz((const char *)colored_ccline->cmdbuff, - (size_t)colored_ccline->cmdlen); + arg.vval.v_string = xmemdupz(colored_ccline->cmdbuff, (size_t)colored_ccline->cmdlen); } // msg_start() called by e.g. :echo may shift command-line to the first column // even though msg_silent is here. Two ways to workaround this problem without @@ -3207,8 +3265,7 @@ color_cmdline_end: if (arg_allocated) { ccline_colors->cmdbuff = arg.vval.v_string; } else { - ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff, - (size_t)colored_ccline->cmdlen); + ccline_colors->cmdbuff = xmemdupz(colored_ccl |