diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 22:39:54 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 22:39:54 +0000 |
commit | 21cb7d04c387e4198ca8098a884c78b56ffcf4c2 (patch) | |
tree | 84fe5690df1551f0bb2bdfe1a13aacd29ebc1de7 /src/nvim/ex_getln.c | |
parent | d9c904f85a23a496df4eb6be42aa43f007b22d50 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-colorcolchar.tar.gz rneovim-colorcolchar.tar.bz2 rneovim-colorcolchar.zip |
Merge remote-tracking branch 'upstream/master' into colorcolcharcolorcolchar
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_ccline->cmdbuff, (size_t)colored_ccline->cmdlen); } tv_clear(&tv); return ret; @@ -3247,98 +3304,7 @@ static void draw_cmdline(int start, int len) msg_putchar('*'); i += utfc_ptr2len(ccline.cmdbuff + start + i) - 1; } - } else if (p_arshape && !p_tbidi && len > 0) { - bool do_arabicshape = false; - int mb_l; - for (int i = start; i < start + len; i += mb_l) { - char *p = ccline.cmdbuff + i; - int u8cc[MAX_MCO]; - int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len(p, start + len - i); - if (ARABIC_CHAR(u8c)) { - do_arabicshape = true; - break; - } - } - if (!do_arabicshape) { - goto draw_cmdline_no_arabicshape; - } - - static size_t buflen = 0; - assert(len >= 0); - - // Do arabic shaping into a temporary buffer. This is very - // inefficient! - if ((size_t)len * 2 + 2 > buflen) { - // Re-allocate the buffer. We keep it around to avoid a lot of - // alloc()/free() calls. - xfree(arshape_buf); - buflen = (size_t)len * 2 + 2; - arshape_buf = xmalloc(buflen); - } - - int newlen = 0; - if (utf_iscomposing(utf_ptr2char(ccline.cmdbuff + start))) { - // Prepend a space to draw the leading composing char on. - arshape_buf[0] = ' '; - newlen = 1; - } - - int prev_c = 0; - int prev_c1 = 0; - for (int i = start; i < start + len; i += mb_l) { - char *p = ccline.cmdbuff + i; - int u8cc[MAX_MCO]; - int u8c = utfc_ptr2char_len(p, u8cc, start + len - i); - mb_l = utfc_ptr2len_len(p, start + len - i); - if (ARABIC_CHAR(u8c)) { - int pc; - int pc1 = 0; - int nc = 0; - // Do Arabic shaping. - if (cmdmsg_rl) { - // Displaying from right to left. - pc = prev_c; - pc1 = prev_c1; - prev_c1 = u8cc[0]; - if (i + mb_l >= start + len) { - nc = NUL; - } else { - nc = utf_ptr2char(p + mb_l); - } - } else { - // Displaying from left to right. - if (i + mb_l >= start + len) { - pc = NUL; - } else { - int pcc[MAX_MCO]; - - pc = utfc_ptr2char_len(p + mb_l, pcc, start + len - i - mb_l); - pc1 = pcc[0]; - } - nc = prev_c; - } - prev_c = u8c; - - u8c = arabic_shape(u8c, NULL, &u8cc[0], pc, pc1, nc); - - newlen += utf_char2bytes(u8c, arshape_buf + newlen); - if (u8cc[0] != 0) { - newlen += utf_char2bytes(u8cc[0], arshape_buf + newlen); - if (u8cc[1] != 0) { - newlen += utf_char2bytes(u8cc[1], arshape_buf + newlen); - } - } - } else { - prev_c = u8c; - memmove(arshape_buf + newlen, p, (size_t)mb_l); - newlen += mb_l; - } - } - - msg_outtrans_len(arshape_buf, newlen); } else { -draw_cmdline_no_arabicshape: if (kv_size(ccline.last_colors.colors)) { for (size_t i = 0; i < kv_size(ccline.last_colors.colors); i++) { CmdlineColorChunk chunk = kv_A(ccline.last_colors.colors, i); @@ -3346,12 +3312,10 @@ draw_cmdline_no_arabicshape: continue; } const int chunk_start = MAX(chunk.start, start); - msg_outtrans_len_attr(ccline.cmdbuff + chunk_start, - chunk.end - chunk_start, - chunk.attr); + msg_outtrans_len(ccline.cmdbuff + chunk_start, chunk.end - chunk_start, chunk.attr); } } else { - msg_outtrans_len(ccline.cmdbuff + start, len); + msg_outtrans_len(ccline.cmdbuff + start, len, 0); } } } @@ -3380,14 +3344,14 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) ADD_C(item, INTEGER_OBJ(chunk.attr)); assert(chunk.end >= chunk.start); - ADD_C(item, STRING_OBJ(cbuf_as_string((char *)line->cmdbuff + chunk.start, + ADD_C(item, STRING_OBJ(cbuf_as_string(line->cmdbuff + chunk.start, (size_t)(chunk.end - chunk.start)))); ADD_C(content, ARRAY_OBJ(item)); } } else { Array item = arena_array(&arena, 2); ADD_C(item, INTEGER_OBJ(0)); - ADD_C(item, STRING_OBJ(cstr_as_string((char *)(line->cmdbuff)))); + ADD_C(item, CSTR_AS_OBJ(line->cmdbuff)); content = arena_array(&arena, 1); ADD_C(content, ARRAY_OBJ(item)); } @@ -3410,11 +3374,11 @@ void ui_ext_cmdline_block_append(size_t indent, const char *line) { char *buf = xmallocz(indent + strlen(line)); memset(buf, ' ', indent); - memcpy(buf + indent, line, strlen(line)); // -V575 + memcpy(buf + indent, line, strlen(line)); Array item = ARRAY_DICT_INIT; ADD(item, INTEGER_OBJ(0)); - ADD(item, STRING_OBJ(cstr_as_string(buf))); + ADD(item, CSTR_AS_OBJ(buf)); Array content = ARRAY_DICT_INIT; ADD(content, ARRAY_OBJ(item)); ADD(cmdline_block, ARRAY_OBJ(content)); @@ -3530,7 +3494,7 @@ 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 *str, int len, int redraw) +void put_on_cmdline(const char *str, int len, int redraw) { int i; int m; @@ -3676,7 +3640,6 @@ static void restore_cmdline(CmdlineInfo *ccp) static bool cmdline_paste(int regname, bool literally, bool remcr) { char *arg; - char *p; bool allocated; // check for valid regname; also accept special characters for CTRL-R in @@ -3708,7 +3671,7 @@ 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 = arg; + char *p = arg; if (p_is && regname == Ctrl_W) { char *w; int len; @@ -3741,19 +3704,17 @@ 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 *s, int literally) +void cmdline_paste_str(const char *s, int literally) { - int c, cv; - if (literally) { put_on_cmdline(s, -1, true); } else { while (*s != NUL) { - cv = (uint8_t)(*s); + int cv = (uint8_t)(*s); if (cv == Ctrl_V && s[1]) { s++; } - c = mb_cptr2char_adv((const char **)&s); + int c = mb_cptr2char_adv(&s); if (cv == Ctrl_V || c == ESC || c == Ctrl_C || c == CAR || c == NL || c == Ctrl_L || (c == Ctrl_BSL && *s == Ctrl_N)) { @@ -3781,8 +3742,6 @@ void redrawcmdline(void) static void redrawcmdprompt(void) { - int i; - if (cmd_silent) { return; } @@ -3801,7 +3760,7 @@ static void redrawcmdprompt(void) ccline.cmdindent--; } } else { - for (i = ccline.cmdindent; i > 0; i--) { + for (int i = ccline.cmdindent; i > 0; i--) { msg_putchar(' '); } } @@ -3821,7 +3780,7 @@ void redrawcmd(void) // when 'incsearch' is set there may be no command line while redrawing if (ccline.cmdbuff == NULL) { - cmd_cursor_goto(cmdline_row, 0); + msg_cursor_goto(cmdline_row, 0); msg_clr_eos(); return; } @@ -3884,28 +3843,13 @@ void cursorcmd(void) return; } - if (cmdmsg_rl) { - msg_row = cmdline_row + (ccline.cmdspos / (Columns - 1)); - msg_col = Columns - (ccline.cmdspos % (Columns - 1)) - 1; - if (msg_row <= 0) { - msg_row = Rows - 1; - } - } else { - msg_row = cmdline_row + (ccline.cmdspos / Columns); - msg_col = ccline.cmdspos % Columns; - if (msg_row >= Rows) { - msg_row = Rows - 1; - } + msg_row = cmdline_row + (ccline.cmdspos / Columns); + msg_col = ccline.cmdspos % Columns; + if (msg_row >= Rows) { + msg_row = Rows - 1; } - cmd_cursor_goto(msg_row, msg_col); -} - -static void cmd_cursor_goto(int row, int col) -{ - ScreenGrid *grid = &msg_grid_adj; - grid_adjust(&grid, &row, &col); - ui_grid_cursor_goto(grid->handle, row, col); + msg_cursor_goto(msg_row, msg_col); } void gotocmdline(bool clr) @@ -3914,15 +3858,11 @@ void gotocmdline(bool clr) return; } msg_start(); - if (cmdmsg_rl) { - msg_col = Columns - 1; - } else { - msg_col = 0; // always start in column 0 - } + msg_col = 0; // always start in column 0 if (clr) { // clear the bottom line(s) msg_clr_eos(); // will reset clear_cmdline } - cmd_cursor_goto(cmdline_row, 0); + msg_cursor_goto(cmdline_row, 0); } // Check the word in front of the cursor for an abbreviation. @@ -4022,11 +3962,9 @@ void escape_fname(char **pp) /// If 'orig_pat' starts with "~/", replace the home directory with "~". void tilde_replace(char *orig_pat, int num_files, char **files) { - char *p; - if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1])) { for (int i = 0; i < num_files; i++) { - p = home_replace_save(NULL, files[i]); + char *p = home_replace_save(NULL, files[i]); xfree(files[i]); files[i] = p; } @@ -4106,12 +4044,24 @@ static char *get_cmdline_completion(void) } set_expand_context(p->xpc); + if (p->xpc->xp_context == EXPAND_UNSUCCESSFUL) { + return NULL; + } + char *cmd_compl = get_user_cmd_complete(p->xpc, p->xpc->xp_context); - if (cmd_compl != NULL) { - return xstrdup(cmd_compl); + if (cmd_compl == NULL) { + return NULL; } - return NULL; + if (p->xpc->xp_context == EXPAND_USER_LIST + || p->xpc->xp_context == EXPAND_USER_DEFINED) { + size_t buflen = strlen(cmd_compl) + strlen(p->xpc->xp_arg) + 2; + char *buffer = xmalloc(buflen); + snprintf(buffer, buflen, "%s,%s", cmd_compl, p->xpc->xp_arg); + return buffer; + } + + return xstrdup(cmd_compl); } /// "getcmdcompltype()" function @@ -4219,7 +4169,8 @@ void f_setcmdline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } - rettv->vval.v_number = set_cmdline_str(argvars[0].vval.v_string, pos); + // Use tv_get_string() to handle a NULL string like an empty string. + rettv->vval.v_number = set_cmdline_str(tv_get_string(&argvars[0]), pos); } /// "setcmdpos()" function @@ -4254,18 +4205,28 @@ int get_list_range(char **str, int *num1, int *num2) *str = skipwhite((*str)); if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range - vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false); + vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false, NULL); *str += len; + // overflow + if (num > INT_MAX) { + return FAIL; + } + *num1 = (int)num; first = true; } *str = skipwhite((*str)); if (**str == ',') { // parse "to" part of range *str = skipwhite((*str) + 1); - vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false); + vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false, NULL); if (len > 0) { - *num2 = (int)num; *str = skipwhite((*str) + len); + // overflow + if (num > INT_MAX) { + return FAIL; + } + + *num2 = (int)num; } else if (!first) { // no number given at all return FAIL; } @@ -4282,14 +4243,12 @@ void cmdline_init(void) /// Check value of 'cedit' and set cedit_key. /// Returns NULL if value is OK, error message otherwise. -char *check_cedit(void) +const char *did_set_cedit(optset_T *args) { - int n; - if (*p_cedit == NUL) { cedit_key = -1; } else { - n = string_to_key(p_cedit); + int n = string_to_key(p_cedit); if (vim_isprintc(n)) { return e_invarg; } @@ -4309,9 +4268,7 @@ static int open_cmdwin(void) bufref_T old_curbuf; bufref_T bufref; win_T *old_curwin = curwin; - win_T *wp; int i; - linenr_T lnum; garray_T winsizes; char typestr[2]; int save_restart_edit = restart_edit; @@ -4351,6 +4308,7 @@ static int open_cmdwin(void) // Set "cmdwin_type" before any autocommands may mess things up. cmdwin_type = get_cmdline_type(); cmdwin_level = ccline.level; + cmdwin_old_curwin = old_curwin; // Create empty command-line buffer. if (buf_open_scratch(0, _("[Command Line]")) == FAIL) { @@ -4358,10 +4316,11 @@ static int open_cmdwin(void) win_close(curwin, true, false); ga_clear(&winsizes); cmdwin_type = 0; + cmdwin_old_curwin = NULL; return Ctrl_C; } // Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer. - set_option_value_give_err("bh", 0L, "wipe", OPT_LOCAL); + set_option_value_give_err("bh", STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL); curbuf->b_p_ma = true; curwin->w_p_fen = false; curwin->w_p_rl = cmdmsg_rl; @@ -4379,7 +4338,7 @@ static int open_cmdwin(void) add_map("<Tab>", "<C-X><C-V>", MODE_INSERT, true); add_map("<Tab>", "a<C-X><C-V>", MODE_NORMAL, true); } - set_option_value_give_err("ft", 0L, "vim", OPT_LOCAL); + set_option_value_give_err("ft", STATIC_CSTR_AS_OPTVAL("vim"), OPT_LOCAL); } curbuf->b_ro_locked--; @@ -4392,13 +4351,13 @@ static int open_cmdwin(void) if (get_hislen() > 0 && histtype != HIST_INVALID) { i = *get_hisidx(histtype); if (i >= 0) { - lnum = 0; + linenr_T lnum = 0; do { if (++i == get_hislen()) { i = 0; } if (get_histentry(histtype)[i].hisstr != NULL) { - ml_append(lnum++, get_histentry(histtype)[i].hisstr, (colnr_T)0, false); + ml_append(lnum++, get_histentry(histtype)[i].hisstr, 0, false); } } while (i != *get_hisidx(histtype)); } @@ -4410,7 +4369,7 @@ static int open_cmdwin(void) curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; curwin->w_cursor.col = ccline.cmdpos; changed_line_abv_curs(); - invalidate_botline(); + invalidate_botline(curwin); if (ui_has(kUICmdline)) { ccline.redraw_state = kCmdRedrawNone; ui_call_cmdline_hide(ccline.level); @@ -4454,6 +4413,7 @@ static int open_cmdwin(void) cmdwin_type = 0; cmdwin_level = 0; + cmdwin_old_curwin = NULL; exmode_active = save_exmode; @@ -4463,6 +4423,7 @@ static int open_cmdwin(void) cmdwin_result = Ctrl_C; emsg(_("E199: Active window or buffer deleted")); } else { + win_T *wp; // autocmds may abort script processing if (aborting() && cmdwin_result != K_IGNORE) { cmdwin_result = Ctrl_C; @@ -4500,7 +4461,8 @@ static int open_cmdwin(void) ccline.cmdlen = (int)strlen(ccline.cmdbuff); ccline.cmdbufflen = ccline.cmdlen + 1; ccline.cmdpos = curwin->w_cursor.col; - if (ccline.cmdpos > ccline.cmdlen) { + // If the cursor is on the last character, it probably should be after it. + if (ccline.cmdpos == ccline.cmdlen - 1 || ccline.cmdpos > ccline.cmdlen) { ccline.cmdpos = ccline.cmdlen; } if (cmdwin_result == K_IGNORE) { @@ -4569,39 +4531,37 @@ bool is_in_cmdwin(void) char *script_get(exarg_T *const eap, size_t *const lenp) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC { - const char *const cmd = (const char *)eap->arg; + char *cmd = eap->arg; if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL) { *lenp = strlen(eap->arg); return eap->skip ? NULL : xmemdupz(eap->arg, *lenp); } + cmd += 2; garray_T ga = { .ga_data = NULL, .ga_len = 0 }; + + list_T *const l = heredoc_get(eap, cmd, true); + if (l == NULL) { + return NULL; + } + if (!eap->skip) { ga_init(&ga, 1, 0x400); } - const char *const end_pattern = (cmd[2] != NUL ? (const char *)skipwhite(cmd + 2) : "."); - for (;;) { - char *const theline = eap->getline(eap->cstack->cs_looplevel > 0 ? -1 : NUL, eap->cookie, 0, - true); - - if (theline == NULL || strcmp(end_pattern, theline) == 0) { - xfree(theline); - break; - } - + TV_LIST_ITER_CONST(l, li, { if (!eap->skip) { - ga_concat(&ga, theline); + ga_concat(&ga, tv_get_string(TV_LIST_ITEM_TV(li))); ga_append(&ga, '\n'); } - xfree(theline); - } + }); *lenp = (size_t)ga.ga_len; // Set length without trailing NUL. if (!eap->skip) { ga_append(&ga, NUL); } + tv_list_free(l); return (char *)ga.ga_data; } |