diff options
Diffstat (limited to 'src/nvim/ex_cmds.c')
-rw-r--r-- | src/nvim/ex_cmds.c | 570 |
1 files changed, 226 insertions, 344 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index ea51cac163..437a05f61d 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -4,20 +4,27 @@ // ex_cmds.c: some functions for command line commands #include <assert.h> +#include <ctype.h> #include <float.h> #include <inttypes.h> #include <math.h> #include <stdbool.h> +#include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> -#include "nvim/api/buffer.h" -#include "nvim/api/private/defs.h" +#include "auto/config.h" +#include "klib/kvec.h" #include "nvim/arglist.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/buffer_updates.h" #include "nvim/change.h" +#include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdhist.h" #include "nvim/cursor.h" @@ -27,22 +34,27 @@ #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.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/fileio.h" #include "nvim/fold.h" -#include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/grid_defs.h" #include "nvim/help.h" -#include "nvim/highlight.h" +#include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/input.h" -#include "nvim/log.h" +#include "nvim/lua/executor.h" +#include "nvim/macros.h" #include "nvim/main.h" #include "nvim/mark.h" #include "nvim/mbyte.h" @@ -55,21 +67,22 @@ #include "nvim/ops.h" #include "nvim/option.h" #include "nvim/optionstr.h" +#include "nvim/os/fs_defs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/shell.h" #include "nvim/os/time.h" -#include "nvim/os_unix.h" #include "nvim/path.h" #include "nvim/plines.h" #include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/spell.h" #include "nvim/strings.h" -#include "nvim/syntax.h" -#include "nvim/tag.h" +#include "nvim/terminal.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/vim.h" @@ -145,14 +158,14 @@ void do_ascii(const exarg_T *const eap) char buf2[20]; buf2[0] = NUL; - dig = (char *)get_digraph_for_char(cval); + dig = get_digraph_for_char(cval); if (dig != NULL) { - iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len, + iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"), transchar(c), buf1, buf2, cval, cval, cval, dig); } else { - iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len, + iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, _("<%s>%s%s %d, Hex %02x, Octal %03o"), transchar(c), buf1, buf2, cval, cval, cval); @@ -191,18 +204,18 @@ void do_ascii(const exarg_T *const eap) if (utf_iscomposing(c)) { IObuff[iobuff_len++] = ' '; // Draw composing char on top of a space. } - iobuff_len += (size_t)utf_char2bytes(c, (char *)IObuff + iobuff_len); + iobuff_len += (size_t)utf_char2bytes(c, IObuff + iobuff_len); - dig = (char *)get_digraph_for_char(c); + dig = get_digraph_for_char(c); if (dig != NULL) { - iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len, + iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, (c < 0x10000 ? _("> %d, Hex %04x, Oct %o, Digr %s") : _("> %d, Hex %08x, Oct %o, Digr %s")), c, c, c, dig); } else { - iobuff_len += (size_t)vim_snprintf((char *)IObuff + iobuff_len, + iobuff_len += (size_t)vim_snprintf(IObuff + iobuff_len, sizeof(IObuff) - iobuff_len, (c < 0x10000 ? _("> %d, Hex %04x, Octal %o") @@ -215,10 +228,10 @@ void do_ascii(const exarg_T *const eap) c = cc[ci++]; } if (ci != MAX_MCO && c != 0) { - xstrlcpy((char *)IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len); + xstrlcpy(IObuff + iobuff_len, " ...", sizeof(IObuff) - iobuff_len); } - msg((char *)IObuff); + msg(IObuff); } /// ":left", ":center" and ":right": align text. @@ -266,13 +279,12 @@ void ex_align(exarg_T *eap) } for (curwin->w_cursor.lnum = eap->line1; - curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum) { + curwin->w_cursor.lnum <= eap->line2; curwin->w_cursor.lnum++) { if (eap->cmdidx == CMD_left) { // left align new_indent = indent; } else { has_tab = false; // avoid uninit warnings - len = linelen(eap->cmdidx == CMD_right ? &has_tab - : NULL) - get_indent(); + len = linelen(eap->cmdidx == CMD_right ? &has_tab : NULL) - get_indent(); if (len <= 0) { // skip blank lines continue; @@ -335,7 +347,7 @@ static int linelen(int *has_tab) char save = *last; *last = NUL; // Get line length. - len = linetabsize((char_u *)line); + len = linetabsize(line); // Check for embedded TAB. if (has_tab != NULL) { *has_tab = vim_strchr(first, TAB) != NULL; @@ -505,9 +517,8 @@ void ex_sort(exarg_T *eap) eap->nextcmd = check_nextcmd(p); break; } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { - s = skip_regexp(p + 1, *p, true, NULL); - if (*s != *p) { - emsg(_(e_invalpat)); + s = skip_regexp_err(p + 1, *p, true); + if (s == NULL) { goto sortend; } *s = NUL; @@ -517,7 +528,7 @@ void ex_sort(exarg_T *eap) emsg(_(e_noprevre)); goto sortend; } - regmatch.regprog = vim_regcomp((char *)last_search_pat(), RE_MAGIC); + regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); } else { regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); } @@ -708,187 +719,6 @@ sortend: } } -/// ":retab". -void ex_retab(exarg_T *eap) -{ - linenr_T lnum; - bool got_tab = false; - long num_spaces = 0; - long num_tabs; - long len; - long col; - long vcol; - long start_col = 0; // For start of white-space string - long start_vcol = 0; // For start of white-space string - long old_len; - char *ptr; - char *new_line = (char *)1; // init to non-NULL - bool did_undo; // called u_save for current line - long *new_vts_array = NULL; - char *new_ts_str; // string value of tab argument - - int save_list; - linenr_T first_line = 0; // first changed line - linenr_T last_line = 0; // last changed line - - save_list = curwin->w_p_list; - curwin->w_p_list = 0; // don't want list mode here - - new_ts_str = eap->arg; - if (!tabstop_set(eap->arg, &new_vts_array)) { - return; - } - while (ascii_isdigit(*(eap->arg)) || *(eap->arg) == ',') { - (eap->arg)++; - } - - // This ensures that either new_vts_array and new_ts_str are freshly - // allocated, or new_vts_array points to an existing array and new_ts_str - // is null. - if (new_vts_array == NULL) { - new_vts_array = curbuf->b_p_vts_array; - new_ts_str = NULL; - } else { - new_ts_str = xstrnsave(new_ts_str, (size_t)(eap->arg - new_ts_str)); - } - for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) { - ptr = ml_get(lnum); - col = 0; - vcol = 0; - did_undo = false; - for (;;) { - if (ascii_iswhite(ptr[col])) { - if (!got_tab && num_spaces == 0) { - // First consecutive white-space - start_vcol = vcol; - start_col = col; - } - if (ptr[col] == ' ') { - num_spaces++; - } else { - got_tab = true; - } - } else { - if (got_tab || (eap->forceit && num_spaces > 1)) { - // Retabulate this string of white-space - - // len is virtual length of white string - len = num_spaces = vcol - start_vcol; - num_tabs = 0; - if (!curbuf->b_p_et) { - int t, s; - - tabstop_fromto((colnr_T)start_vcol, (colnr_T)vcol, - curbuf->b_p_ts, new_vts_array, &t, &s); - num_tabs = t; - num_spaces = s; - } - if (curbuf->b_p_et || got_tab - || (num_spaces + num_tabs < len)) { - if (did_undo == false) { - did_undo = true; - if (u_save((linenr_T)(lnum - 1), - (linenr_T)(lnum + 1)) == FAIL) { - new_line = NULL; // flag out-of-memory - break; - } - } - - // len is actual number of white characters used - len = num_spaces + num_tabs; - old_len = (long)strlen(ptr); - const long new_len = old_len - col + start_col + len + 1; - if (new_len <= 0 || new_len >= MAXCOL) { - emsg(_(e_resulting_text_too_long)); - break; - } - new_line = xmalloc((size_t)new_len); - - if (start_col > 0) { - memmove(new_line, ptr, (size_t)start_col); - } - memmove(new_line + start_col + len, - ptr + col, (size_t)(old_len - col + 1)); - ptr = new_line + start_col; - for (col = 0; col < len; col++) { - ptr[col] = (col < num_tabs) ? '\t' : ' '; - } - if (ml_replace(lnum, new_line, false) == OK) { - // "new_line" may have been copied - new_line = (char *)curbuf->b_ml.ml_line_ptr; - extmark_splice_cols(curbuf, lnum - 1, 0, (colnr_T)old_len, - (colnr_T)new_len - 1, kExtmarkUndo); - } - if (first_line == 0) { - first_line = lnum; - } - last_line = lnum; - ptr = new_line; - col = start_col + len; - } - } - got_tab = false; - num_spaces = 0; - } - if (ptr[col] == NUL) { - break; - } - vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol); - if (vcol >= MAXCOL) { - emsg(_(e_resulting_text_too_long)); - break; - } - col += utfc_ptr2len(ptr + col); - } - if (new_line == NULL) { // out of memory - break; - } - line_breakcheck(); - } - if (got_int) { - emsg(_(e_interr)); - } - - // If a single value was given then it can be considered equal to - // either the value of 'tabstop' or the value of 'vartabstop'. - if (tabstop_count(curbuf->b_p_vts_array) == 0 - && tabstop_count(new_vts_array) == 1 - && curbuf->b_p_ts == tabstop_first(new_vts_array)) { - // not changed - } else if (tabstop_count(curbuf->b_p_vts_array) > 0 - && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) { - // not changed - } else { - redraw_curbuf_later(UPD_NOT_VALID); - } - if (first_line != 0) { - changed_lines(first_line, 0, last_line + 1, 0L, true); - } - - curwin->w_p_list = save_list; // restore 'list' - - if (new_ts_str != NULL) { // set the new tabstop - // If 'vartabstop' is in use or if the value given to retab has more - // than one tabstop then update 'vartabstop'. - long *old_vts_ary = curbuf->b_p_vts_array; - - if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) { - set_string_option_direct("vts", -1, new_ts_str, OPT_FREE | OPT_LOCAL, 0); - curbuf->b_p_vts_array = new_vts_array; - xfree(old_vts_ary); - } else { - // 'vartabstop' wasn't in use and a single value was given to - // retab then update 'tabstop'. - curbuf->b_p_ts = tabstop_first(new_vts_array); - xfree(new_vts_array); - } - xfree(new_ts_str); - } - coladvance(curwin->w_curswant); - - u_clearline(); -} - /// :move command - move lines line1-line2 to line dest /// /// @return FAIL for failure, OK otherwise @@ -1008,7 +838,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) ml_delete(line1 + extra, true); } if (!global_busy && num_lines > p_report) { - smsg(NGETTEXT("1 line moved", "%" PRId64 " lines moved", num_lines), (int64_t)num_lines); + smsg(NGETTEXT("%" PRId64 " line moved", + "%" PRId64 " lines moved", num_lines), + (int64_t)num_lines); } extmark_move_region(curbuf, line1 - 1, 0, start_byte, @@ -1124,8 +956,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out int scroll_save = msg_scroll; // - // Disallow shell commands from .exrc and .vimrc in current directory for - // security reasons. + // Disallow shell commands in secure mode // if (check_secure()) { return; @@ -1137,10 +968,12 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out msg_scroll = scroll_save; } - // Try to find an embedded bang, like in :!<cmd> ! [args] - // (:!! is indicated by the 'forceit' variable) + // Try to find an embedded bang, like in ":!<cmd> ! [args]" + // ":!!" is indicated by the 'forceit' variable. bool ins_prevcmd = forceit; - trailarg = arg; + + // Skip leading white space to avoid a strange error with some shells. + trailarg = skipwhite(arg); do { len = strlen(trailarg) + 1; if (newcmd != NULL) { @@ -1192,7 +1025,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out // If % or # appears in the command, it must have been escaped. // Reescape them, so that redoing them does not substitute them by the // buffername. - char *cmd = (char *)vim_strsave_escaped((char_u *)prevcmd, (char_u *)"%#"); + char *cmd = vim_strsave_escaped(prevcmd, "%#"); AppendToRedobuffLit(cmd, -1); xfree(cmd); @@ -1201,7 +1034,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out } // Add quotes around the command, for shells that need them. if (*p_shq != NUL) { - newcmd = xmalloc(strlen(prevcmd) + 2 * STRLEN(p_shq) + 1); + newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1); STRCPY(newcmd, p_shq); STRCAT(newcmd, prevcmd); STRCAT(newcmd, p_shq); @@ -1346,7 +1179,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b read_linecount = curbuf->b_ml.ml_line_count; // Pass on the kShellOptDoOut flag when the output is being redirected. - call_shell((char_u *)cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL); + call_shell(cmd_buf, (ShellOpts)(kShellOptFilter | shell_flags), NULL); xfree(cmd_buf); did_check_timestamps = false; @@ -1465,8 +1298,7 @@ filterend: /// @param flags may be SHELL_DOOUT when output is redirected void do_shell(char *cmd, int flags) { - // Disallow shell commands from .exrc and .vimrc in current directory for - // security reasons. + // Disallow shell commands in secure mode if (check_secure()) { msg_end(); return; @@ -1492,7 +1324,7 @@ void do_shell(char *cmd, int flags) // This ui_cursor_goto is required for when the '\n' resulted in a "delete line // 1" command to the terminal. ui_cursor_goto(msg_row, msg_col); - (void)call_shell((char_u *)cmd, (ShellOpts)flags, NULL); + (void)call_shell(cmd, (ShellOpts)flags, NULL); msg_didout = true; did_check_timestamps = false; need_check_timestamps = true; @@ -1512,11 +1344,11 @@ static char *find_pipe(const char *cmd) for (const char *p = cmd; *p != NUL; p++) { if (!inquote && *p == '|') { - return p; + return (char *)p; } if (*p == '"') { inquote = !inquote; - } else if (rem_backslash((const char_u *)p)) { + } else if (rem_backslash(p)) { p++; } } @@ -1535,12 +1367,13 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) { bool is_fish_shell = #if defined(UNIX) - STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "fish", 4) == 0; + strncmp((char *)invocation_path_tail(p_sh, NULL), "fish", 4) == 0; #else false; #endif - bool is_pwsh = STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "pwsh", 4) == 0 - || STRNCMP(invocation_path_tail((char_u *)p_sh, NULL), "powershell", 10) == 0; + bool is_pwsh = strncmp((char *)invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0 + || strncmp((char *)invocation_path_tail(p_sh, NULL), "powershell", + 10) == 0; size_t len = strlen(cmd) + 1; // At least enough space for cmd + NULL. @@ -1549,7 +1382,7 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) : 0; if (itmp != NULL) { - len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + len += is_pwsh ? strlen(itmp) + sizeof("& { Get-Content " " | & " " }") - 1 + 6 // +6: #20530 : strlen(itmp) + sizeof(" { " " < " " } ") - 1; } if (otmp != NULL) { @@ -1587,7 +1420,7 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp) #else // For shells that don't understand braces around commands, at least allow // the use of commands in a pipe. - xstrlcpy(buf, (char *)cmd, len); + xstrlcpy(buf, cmd, len); if (itmp != NULL) { // If there is a pipe, we have to put the '<' in front of it. // Don't do this when 'shellquote' is not empty, otherwise the @@ -1670,7 +1503,7 @@ void print_line(linenr_T lnum, int use_number, int list) msg_start(); silent_mode = false; - info_message = true; // use mch_msg(), not mch_errmsg() + info_message = true; // use os_msg(), not os_errmsg() print_line_no_prefix(lnum, use_number, list); if (save_silent) { msg_putchar('\n'); @@ -1774,12 +1607,23 @@ void ex_write(exarg_T *eap) } } -/// write current buffer to file 'eap->arg' -/// if 'eap->append' is true, append to the file +#ifdef UNIX +static int check_writable(const char *fname) +{ + if (os_nodetype(fname) == NODE_OTHER) { + semsg(_("E503: \"%s\" is not a file or writable device"), fname); + return FAIL; + } + return OK; +} +#endif + +/// Write current buffer to file "eap->arg". +/// If "eap->append" is true, append to the file. /// -/// if *eap->arg == NUL write to current file +/// If "*eap->arg == NUL" write to current file. /// -/// @return FAIL for failure, OK otherwise +/// @return FAIL for failure, OK otherwise. int do_write(exarg_T *eap) { int other; @@ -1831,7 +1675,11 @@ int do_write(exarg_T *eap) // Writing to the current file is not allowed in readonly mode // and a file name is required. // "nofile" and "nowrite" buffers cannot be written implicitly either. - if (!other && (bt_dontwrite_msg(curbuf) || check_fname() == FAIL + if (!other && (bt_dontwrite_msg(curbuf) + || check_fname() == FAIL +#ifdef UNIX + || check_writable(curbuf->b_ffname) == FAIL +#endif || check_readonly(&eap->forceit, curbuf))) { goto theend; } @@ -1909,6 +1757,13 @@ int do_write(exarg_T *eap) fname = curbuf->b_sfname; } + if (eap->mkdir_p) { + if (os_file_mkdir(fname, 0755) < 0) { + retval = FAIL; + goto theend; + } + } + name_was_missing = curbuf->b_ffname == NULL; retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2, eap, eap->append, eap->forceit, true, false); @@ -1999,7 +1854,7 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int oth p = p_dir; copy_option_part(&p, dir, MAXPATHL, ","); } - swapname = (char *)makeswapname((char_u *)fname, (char_u *)ffname, curbuf, (char_u *)dir); + swapname = makeswapname(fname, ffname, curbuf, dir); xfree(dir); if (os_path_exists(swapname)) { if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { @@ -2139,9 +1994,8 @@ static int check_readonly(int *forceit, buf_T *buf) // Set forceit, to force the writing of a readonly file *forceit = true; return false; - } else { - return true; } + return true; } else if (buf->b_p_ro) { emsg(_(e_readonly)); } else { @@ -3182,8 +3036,7 @@ void ex_z(exarg_T *eap) ex_no_reprint = true; } -/// @return true if the secure flag is set (.exrc or .vimrc in current directory) -/// and also give an error message. +/// @return true if the secure flag is set and also give an error message. /// Otherwise, return false. bool check_secure(void) { @@ -3240,7 +3093,7 @@ void sub_set_replacement(SubReplacementString sub) /// @param[in] save Save pattern to options, history /// /// @returns true if :substitute can be replaced with a join command -static bool sub_joining_lines(exarg_T *eap, char *pat, char *sub, char *cmd, bool save) +static bool sub_joining_lines(exarg_T *eap, char *pat, const char *sub, const char *cmd, bool save) FUNC_ATTR_NONNULL_ARG(1, 3, 4) { // TODO(vim): find a generic solution to make line-joining operations more @@ -3279,7 +3132,7 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, char *sub, char *cmd, boo if (save) { if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) { - save_re_pat(RE_SUBST, pat, p_magic); + save_re_pat(RE_SUBST, pat, magic_isset()); } // put pattern in history add_to_history(HIST_SEARCH, pat, true, NUL); @@ -3410,6 +3263,30 @@ static int check_regexp_delim(int c) /// @return 0, 1 or 2. See show_cmdpreview() for more information on what the return value means. static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T cmdpreview_bufnr) { +#define ADJUST_SUB_FIRSTLNUM() \ + do { \ + /* For a multi-line match, make a copy of the last matched */ \ + /* line and continue in that one. */ \ + if (nmatch > 1) { \ + sub_firstlnum += (linenr_T)nmatch - 1; \ + xfree(sub_firstline); \ + sub_firstline = xstrdup(ml_get(sub_firstlnum)); \ + /* When going beyond the last line, stop substituting. */ \ + if (sub_firstlnum <= line2) { \ + do_again = true; \ + } else { \ + subflags.do_all = false; \ + } \ + } \ + if (skip_match) { \ + /* Already hit end of the buffer, sub_firstlnum is one */ \ + /* less than what it ought to be. */ \ + xfree(sub_firstline); \ + sub_firstline = xstrdup(""); \ + copycol = 0; \ + } \ + } while (0) + long i = 0; regmmatch_T regmatch; static subflags_T subflags = { @@ -3455,7 +3332,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T } // new pattern and substitution if (eap->cmd[0] == 's' && *cmd != NUL && !ascii_iswhite(*cmd) - && vim_strchr("0123456789cegriIp|\"", *cmd) == NULL) { + && vim_strchr("0123456789cegriIp|\"", (uint8_t)(*cmd)) == NULL) { // don't accept alphanumeric for separator if (check_regexp_delim(*cmd) == FAIL) { return 0; @@ -3466,7 +3343,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // //sub/r). "\&sub&" use last substitute pattern (like //sub/). if (*cmd == '\\') { cmd++; - if (vim_strchr("/?&", *cmd) == NULL) { + if (vim_strchr("/?&", (uint8_t)(*cmd)) == NULL) { emsg(_(e_backslash)); return 0; } @@ -3474,13 +3351,13 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T which_pat = RE_SEARCH; // use last '/' pattern } pat = ""; // empty search pattern - delimiter = (char_u)(*cmd++); // remember delimiter character + delimiter = (uint8_t)(*cmd++); // remember delimiter character has_second_delim = true; } else { // find the end of the regexp which_pat = RE_LAST; // use last used regexp - delimiter = (char_u)(*cmd++); // remember delimiter character + delimiter = (uint8_t)(*cmd++); // remember delimiter character pat = cmd; // remember start of search pat - cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg); + cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delimiter) { // end delimiter found *cmd++ = NUL; // replace it with a NUL has_second_delim = true; @@ -3566,8 +3443,8 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T return 0; } - if (search_regcomp((char_u *)pat, RE_SUBST, which_pat, (cmdpreview ? 0 : SEARCH_HIS), - ®match) == FAIL) { + if (search_regcomp(pat, NULL, RE_SUBST, which_pat, + (cmdpreview ? 0 : SEARCH_HIS), ®match) == FAIL) { if (subflags.do_error) { emsg(_(e_invcmd)); } @@ -3596,7 +3473,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T sub = xstrdup(sub); sub_copy = sub; } else { - char *newsub = regtilde(sub, p_magic, cmdpreview); + char *newsub = regtilde(sub, magic_isset(), cmdpreview); if (newsub != sub) { // newsub was allocated, free it later. sub_copy = newsub; @@ -3820,7 +3697,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T msg_putchar('\n'); xfree(prompt); if (resp != NULL) { - typed = (char_u)(*resp); + typed = (uint8_t)(*resp); xfree(resp); } else { // getcmdline_prompt() returns NULL if there is no command line to return. @@ -3981,30 +3858,6 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T skip_match = true; } -#define ADJUST_SUB_FIRSTLNUM() \ - do { \ - /* For a multi-line match, make a copy of the last matched */ \ - /* line and continue in that one. */ \ - if (nmatch > 1) { \ - sub_firstlnum += (linenr_T)nmatch - 1; \ - xfree(sub_firstline); \ - sub_firstline = xstrdup(ml_get(sub_firstlnum)); \ - /* When going beyond the last line, stop substituting. */ \ - if (sub_firstlnum <= line2) { \ - do_again = true; \ - } else { \ - subflags.do_all = false; \ - } \ - } \ - if (skip_match) { \ - /* Already hit end of the buffer, sub_firstlnum is one */ \ - /* less than what it ought to be. */ \ - xfree(sub_firstline); \ - sub_firstline = xstrdup(""); \ - copycol = 0; \ - } \ - } while (0) - // Save the line numbers for the preview buffer // NOTE: If the pattern matches a final newline, the next line will // be shown also, but should not be highlighted. Intentional for now. @@ -4042,8 +3895,9 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T // When it fails sublen is zero. sublen = vim_regsub_multi(®match, sub_firstlnum - regmatch.startpos[0].lnum, - (char_u *)sub, (char_u *)sub_firstline, 0, - REGSUB_BACKSLASH | (p_magic ? REGSUB_MAGIC : 0)); + sub, sub_firstline, 0, + REGSUB_BACKSLASH + | (magic_isset() ? REGSUB_MAGIC : 0)); textlock--; // If getting the substitute string caused an error, don't do @@ -4084,8 +3938,9 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T textlock++; (void)vim_regsub_multi(®match, sub_firstlnum - regmatch.startpos[0].lnum, - (char_u *)sub, (char_u *)new_end, sublen, - REGSUB_COPY | REGSUB_BACKSLASH | (p_magic ? REGSUB_MAGIC : 0)); + sub, new_end, sublen, + REGSUB_COPY | REGSUB_BACKSLASH + | (magic_isset() ? REGSUB_MAGIC : 0)); textlock--; sub_nsubs++; did_sub = true; @@ -4517,7 +4372,7 @@ void ex_global(exarg_T *eap) // "\&": use previous substitute pattern. if (*cmd == '\\') { cmd++; - if (vim_strchr("/?&", *cmd) == NULL) { + if (vim_strchr("/?&", (uint8_t)(*cmd)) == NULL) { emsg(_(e_backslash)); return; } @@ -4537,13 +4392,15 @@ void ex_global(exarg_T *eap) delim = *cmd; // get the delimiter cmd++; // skip delimiter if there is one pat = cmd; // remember start of pattern - cmd = skip_regexp(cmd, delim, p_magic, &eap->arg); + cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delim) { // end delimiter found *cmd++ = NUL; // replace it with a NUL } } - if (search_regcomp((char_u *)pat, RE_BOTH, which_pat, SEARCH_HIS, ®match) == FAIL) { + char *used_pat; + if (search_regcomp(pat, &used_pat, RE_BOTH, which_pat, + SEARCH_HIS, ®match) == FAIL) { emsg(_(e_invcmd)); return; } @@ -4574,9 +4431,9 @@ void ex_global(exarg_T *eap) msg(_(e_interr)); } else if (ndone == 0) { if (type == 'v') { - smsg(_("Pattern found in every line: %s"), pat); + smsg(_("Pattern found in every line: %s"), used_pat); } else { - smsg(_("Pattern not found: %s"), pat); + smsg(_("Pattern not found: %s"), used_pat); } } else { global_exe(cmd); @@ -4653,32 +4510,30 @@ void free_old_sub(void) /// @return true when it was created. bool prepare_tagpreview(bool undo_sync) { + if (curwin->w_p_pvw) { + return false; + } + // If there is already a preview window open, use that one. - if (!curwin->w_p_pvw) { - bool found_win = false; - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_p_pvw) { - win_enter(wp, undo_sync); - found_win = true; - break; - } - } - if (!found_win) { - // There is no preview window open yet. Create one. - if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) - == FAIL) { - return false; - } - curwin->w_p_pvw = true; - curwin->w_p_wfh = true; - RESET_BINDING(curwin); // don't take over 'scrollbind' and 'cursorbind' - curwin->w_p_diff = false; // no 'diff' - set_string_option_direct("fdc", -1, // no 'foldcolumn' - "0", OPT_FREE, SID_NONE); - return true; + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_p_pvw) { + win_enter(wp, undo_sync); + return false; } } - return false; + + // There is no preview window open yet. Create one. + if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0) + == FAIL) { + return false; + } + curwin->w_p_pvw = true; + curwin->w_p_wfh = true; + RESET_BINDING(curwin); // don't take over 'scrollbind' and 'cursorbind' + curwin->w_p_diff = false; // no 'diff' + set_string_option_direct("fdc", -1, // no 'foldcolumn' + "0", OPT_FREE, SID_NONE); + return true; } /// Shows the effects of the :substitute command being typed ('inccommand'). @@ -4835,7 +4690,7 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags) { int c; - if (vim_isIDc(*p)) { + if (vim_isIDc((uint8_t)(*p))) { // ":vimgrep pattern fname" if (s != NULL) { *s = p; @@ -4849,8 +4704,8 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags) if (s != NULL) { *s = p + 1; } - c = (char_u)(*p); - p = skip_regexp(p + 1, c, true, NULL); + c = (uint8_t)(*p); + p = skip_regexp(p + 1, c, true); if (*p != c) { return NULL; } @@ -4886,45 +4741,72 @@ void ex_oldfiles(exarg_T *eap) if (l == NULL) { msg(_("No old files")); - } else { - msg_start(); - msg_scroll = true; - TV_LIST_ITER(l, li, { - if (got_int) { - break; - } - nr++; - const char *fname = tv_get_string(TV_LIST_ITEM_TV(li)); - if (!message_filtered((char *)fname)) { - msg_outnum(nr); - msg_puts(": "); - msg_outtrans((char *)tv_get_string(TV_LIST_ITEM_TV(li))); - msg_clr_eos(); - msg_putchar('\n'); - os_breakcheck(); - } - }); - - // Assume "got_int" was set to truncate the listing. - got_int = false; - - // File selection prompt on ":browse oldfiles" - if (cmdmod.cmod_flags & CMOD_BROWSE) { - quit_more = false; - nr = prompt_for_number(false); - msg_starthere(); - if (nr > 0 && nr <= tv_list_len(l)) { - const char *const p = tv_list_find_str(l, (int)nr - 1); - if (p == NULL) { - return; - } - char *const s = expand_env_save((char *)p); - eap->arg = s; - eap->cmdidx = CMD_edit; - cmdmod.cmod_flags &= ~CMOD_BROWSE; - do_exedit(eap, NULL); - xfree(s); + return; + } + + msg_start(); + msg_scroll = true; + TV_LIST_ITER(l, li, { + if (got_int) { + break; + } + nr++; + const char *fname = tv_get_string(TV_LIST_ITEM_TV(li)); + if (!message_filtered((char *)fname)) { + msg_outnum(nr); + msg_puts(": "); + msg_outtrans((char *)tv_get_string(TV_LIST_ITEM_TV(li))); + msg_clr_eos(); + msg_putchar('\n'); + os_breakcheck(); + } + }); + + // Assume "got_int" was set to truncate the listing. + got_int = false; + + // File selection prompt on ":browse oldfiles" + if (cmdmod.cmod_flags & CMOD_BROWSE) { + quit_more = false; + nr = prompt_for_number(false); + msg_starthere(); + if (nr > 0 && nr <= tv_list_len(l)) { + const char *const p = tv_list_find_str(l, (int)nr - 1); + if (p == NULL) { + return; } + char *const s = expand_env_save((char *)p); + eap->arg = s; + eap->cmdidx = CMD_edit; + cmdmod.cmod_flags &= ~CMOD_BROWSE; + do_exedit(eap, NULL); + xfree(s); } } } + +void ex_trust(exarg_T *eap) +{ + const char *const p = skiptowhite(eap->arg); + char *arg1 = xmemdupz(eap->arg, (size_t)(p - eap->arg)); + const char *action = "allow"; + const char *path = skipwhite(p); + + if (strcmp(arg1, "++deny") == 0) { + action = "deny"; + } else if (strcmp(arg1, "++remove") == 0) { + action = "remove"; + } else if (*arg1 != '\0') { + semsg(e_invarg2, arg1); + goto theend; + } + + if (path[0] == '\0') { + path = NULL; + } + + nlua_trust(action, path); + +theend: + xfree(arg1); +} |