aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_cmds2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_cmds2.c')
-rw-r--r--src/nvim/ex_cmds2.c132
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;
}