diff options
Diffstat (limited to 'src/nvim/ex_cmds2.c')
-rw-r--r-- | src/nvim/ex_cmds2.c | 132 |
1 files changed, 108 insertions, 24 deletions
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 813d1a9b0b..7f4b01e306 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -20,7 +20,7 @@ #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/charset.h" -#include "nvim/eval.h" +#include "nvim/eval/userfunc.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" @@ -97,10 +97,11 @@ typedef struct sn_prl_S { struct source_cookie { FILE *fp; ///< opened file for sourcing char_u *nextline; ///< if not NULL: line that was read ahead + linenr_T sourcing_lnum; ///< line number of the source file int finished; ///< ":finish" used #if defined(USE_CRNL) int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS - bool error; ///< true if LF found after CR-LF + bool error; ///< true if LF found after CR-LF #endif linenr_T breakpoint; ///< next line with breakpoint or zero char_u *fname; ///< name of sourced file @@ -1037,16 +1038,17 @@ static void profile_reset(void) if (!HASHITEM_EMPTY(hi)) { n--; ufunc_T *uf = HI2UF(hi); - if (uf->uf_profiling) { + if (uf->uf_prof_initialized) { uf->uf_profiling = 0; uf->uf_tm_count = 0; uf->uf_tm_total = profile_zero(); uf->uf_tm_self = profile_zero(); uf->uf_tm_children = profile_zero(); - XFREE_CLEAR(uf->uf_tml_count); - XFREE_CLEAR(uf->uf_tml_total); - XFREE_CLEAR(uf->uf_tml_self); + for (int i = 0; i < uf->uf_lines.ga_len; i++) { + uf->uf_tml_count[i] = 0; + uf->uf_tml_total[i] = uf->uf_tml_self[i] = 0; + } uf->uf_tml_start = profile_zero(); uf->uf_tml_children = profile_zero(); @@ -1413,6 +1415,7 @@ bool check_changed_any(bool hidden, bool unload) size_t bufcount = 0; int *bufnrs; + // Make a list of all buffers, with the most important ones first. FOR_ALL_BUFFERS(buf) { bufcount++; } @@ -1425,14 +1428,15 @@ bool check_changed_any(bool hidden, bool unload) // curbuf bufnrs[bufnum++] = curbuf->b_fnum; - // buf in curtab + + // buffers in current tab FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer != curbuf) { add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum); } } - // buf in other tab + // buffers in other tabs FOR_ALL_TABS(tp) { if (tp != curtab) { FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -1441,7 +1445,7 @@ bool check_changed_any(bool hidden, bool unload) } } - // any other buf + // any other buffer FOR_ALL_BUFFERS(buf) { add_bufnum(bufnrs, &bufnum, buf->b_fnum); } @@ -1470,6 +1474,7 @@ bool check_changed_any(bool hidden, bool unload) goto theend; } + // Get here if "buf" cannot be abandoned. ret = true; exiting = false; // When ":confirm" used, don't give an error message. @@ -1743,7 +1748,7 @@ static bool editing_arg_idx(win_T *win) && (win->w_buffer->b_ffname == NULL || !(path_full_compare( alist_name(&WARGLIST(win)[win->w_arg_idx]), - win->w_buffer->b_ffname, true) & kEqualFiles)))); + win->w_buffer->b_ffname, true, true) & kEqualFiles)))); } /// Check if window "win" is editing the w_arg_idx file in its argument list. @@ -1761,7 +1766,7 @@ void check_arg_idx(win_T *win) && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum || (win->w_buffer->b_ffname != NULL && (path_full_compare(alist_name(&GARGLIST[GARGCOUNT - 1]), - win->w_buffer->b_ffname, true) + win->w_buffer->b_ffname, true, true) & kEqualFiles)))) { arg_had_last = true; } @@ -2390,7 +2395,7 @@ int do_in_path(char_u *path, char_u *name, int flags, char_u *rtp_copy = vim_strsave(path); char_u *buf = xmallocz(MAXPATHL); { - if (p_verbose > 1 && name != NULL) { + if (p_verbose > 10 && name != NULL) { verbose_enter(); smsg(_("Searching for \"%s\" in \"%s\""), (char *)name, (char *)path); @@ -2432,7 +2437,7 @@ int do_in_path(char_u *path, char_u *name, int flags, copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t "); - if (p_verbose > 2) { + if (p_verbose > 10) { verbose_enter(); smsg(_("Searching for \"%s\""), buf); verbose_leave(); @@ -3014,11 +3019,78 @@ static FILE *fopen_noinh_readbin(char *filename) return fdopen(fd_tmp, READBIN); } +typedef struct { + char_u *buf; + size_t offset; +} GetStrLineCookie; + +/// Get one full line from a sourced string (in-memory, no file). +/// Called by do_cmdline() when it's called from do_source_str(). +/// +/// @return pointer to allocated line, or NULL for end-of-file or +/// some error. +static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat) +{ + GetStrLineCookie *p = cookie; + size_t i = p->offset; + if (strlen((char *)p->buf) <= p->offset) { + return NULL; + } + while (!(p->buf[i] == '\n' || p->buf[i] == '\0')) { + i++; + } + char buf[2046]; + char *dst; + dst = xstpncpy(buf, (char *)p->buf + p->offset, i - p->offset); + if ((uint32_t)(dst - buf) != i - p->offset) { + smsg(_(":source error parsing command %s"), p->buf); + return NULL; + } + buf[i - p->offset] = '\0'; + p->offset = i + 1; + return (char_u *)xstrdup(buf); +} + +/// Executes lines in `src` as Ex commands. +/// +/// @see do_source() +int do_source_str(const char *cmd, const char *traceback_name) +{ + char_u *save_sourcing_name = sourcing_name; + linenr_T save_sourcing_lnum = sourcing_lnum; + char_u sourcing_name_buf[256]; + if (save_sourcing_name == NULL) { + sourcing_name = (char_u *)traceback_name; + } else { + snprintf((char *)sourcing_name_buf, sizeof(sourcing_name_buf), + "%s called at %s:%"PRIdLINENR, traceback_name, save_sourcing_name, + save_sourcing_lnum); + sourcing_name = sourcing_name_buf; + } + sourcing_lnum = 0; + + GetStrLineCookie cookie = { + .buf = (char_u *)cmd, + .offset = 0, + }; + const sctx_T save_current_sctx = current_sctx; + current_sctx.sc_sid = SID_STR; + current_sctx.sc_seq = 0; + current_sctx.sc_lnum = save_sourcing_lnum; + int retval = do_cmdline(NULL, get_str_line, (void *)&cookie, + DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT); + current_sctx = save_current_sctx; + sourcing_lnum = save_sourcing_lnum; + sourcing_name = save_sourcing_name; + return retval; +} -/// Read the file "fname" and execute its lines as EX commands. +/// Reads the file `fname` and executes its lines as Ex commands. /// /// This function may be called recursively! /// +/// @see do_source_str +/// /// @param fname /// @param check_other check for .vimrc and _vimrc /// @param is_vimrc DOSO_ value @@ -3035,7 +3107,6 @@ int do_source(char_u *fname, int check_other, int is_vimrc) int retval = FAIL; static scid_T last_current_SID = 0; static int last_current_SID_seq = 0; - void *save_funccalp; int save_debug_break_level = debug_break_level; scriptitem_T *si = NULL; proftime_T wait_start; @@ -3124,6 +3195,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc) #endif cookie.nextline = NULL; + cookie.sourcing_lnum = 0; cookie.finished = false; // Check if this script has a breakpoint. @@ -3155,7 +3227,8 @@ int do_source(char_u *fname, int check_other, int is_vimrc) // Don't use local function variables, if called from a function. // Also starts profiling timer for nested script. - save_funccalp = save_funccal(); + funccal_entry_T funccalp_entry; + save_funccal(&funccalp_entry); // Check if this script was sourced before to finds its SID. // If it's new, generate a new SID. @@ -3218,7 +3291,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc) cookie.conv.vc_type = CONV_NONE; // no conversion // Read the first line so we can check for a UTF-8 BOM. - firstline = getsourceline(0, (void *)&cookie, 0); + firstline = getsourceline(0, (void *)&cookie, 0, true); if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef && firstline[1] == 0xbb && firstline[2] == 0xbf) { // Found BOM; setup conversion, skip over BOM and recode the line. @@ -3280,7 +3353,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc) } current_sctx = save_current_sctx; - restore_funccal(save_funccalp); + restore_funccal(); if (l_do_profiling == PROF_YES) { prof_child_exit(&wait_start); // leaving a child now } @@ -3358,6 +3431,8 @@ char_u *get_scriptname(LastSet last_set, bool *should_free) _("API client (channel id %" PRIu64 ")"), last_set.channel_id); return IObuff; + case SID_STR: + return (char_u *)_("anonymous :source"); default: *should_free = true; return home_replace_save(NULL, @@ -3375,13 +3450,20 @@ void free_scriptnames(void) } # endif +linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) +{ + return fgetline == getsourceline + ? ((struct source_cookie *)cookie)->sourcing_lnum + : sourcing_lnum; +} + /// Get one full line from a sourced file. /// Called by do_cmdline() when it's called from do_source(). /// /// @return pointer to the line in allocated memory, or NULL for end-of-file or /// some error. -char_u *getsourceline(int c, void *cookie, int indent) +char_u *getsourceline(int c, void *cookie, int indent, bool do_concat) { struct source_cookie *sp = (struct source_cookie *)cookie; char_u *line; @@ -3395,6 +3477,8 @@ char_u *getsourceline(int c, void *cookie, int indent) if (do_profiling == PROF_YES) { script_line_end(); } + // Set the current sourcing line number. + sourcing_lnum = sp->sourcing_lnum + 1; // Get current line. If there is a read-ahead line, use it, otherwise get // one now. if (sp->finished) { @@ -3404,7 +3488,7 @@ char_u *getsourceline(int c, void *cookie, int indent) } else { line = sp->nextline; sp->nextline = NULL; - sourcing_lnum++; + sp->sourcing_lnum++; } if (line != NULL && do_profiling == PROF_YES) { script_line_start(); @@ -3412,9 +3496,9 @@ char_u *getsourceline(int c, void *cookie, int indent) // Only concatenate lines starting with a \ when 'cpoptions' doesn't // contain the 'C' flag. - if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) { + if (line != NULL && do_concat && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) { // compensate for the one line read-ahead - sourcing_lnum--; + sp->sourcing_lnum--; // Get the next line and concatenate it when it starts with a // backslash. We always need to read the next line, keep it in @@ -3492,7 +3576,7 @@ static char_u *get_one_sourceline(struct source_cookie *sp) ga_init(&ga, 1, 250); // Loop until there is a finished line (or end-of-file). - sourcing_lnum++; + sp->sourcing_lnum++; for (;; ) { // make room to read at least 120 (more) characters ga_grow(&ga, 120); @@ -3559,7 +3643,7 @@ retry: // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {} if ((len & 1) != (c & 1)) { // escaped NL, read more - sourcing_lnum++; + sp->sourcing_lnum++; continue; } |