aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/runtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/runtime.c')
-rw-r--r--src/nvim/runtime.c151
1 files changed, 100 insertions, 51 deletions
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 3f00b74e61..cdedf86977 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -43,6 +43,7 @@
#include "nvim/mbyte_defs.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
+#include "nvim/memory_defs.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/option_defs.h"
@@ -159,10 +160,7 @@ char *estack_sfile(estack_arg_T which)
{
const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) {
- if (entry->es_name == NULL) {
- return NULL;
- }
- return xstrdup(entry->es_name);
+ return entry->es_name != NULL ? xstrdup(entry->es_name) : NULL;
}
// If evaluated in a function or autocommand, return the path of the script
@@ -230,6 +228,72 @@ char *estack_sfile(estack_arg_T which)
return (char *)ga.ga_data;
}
+static void stacktrace_push_item(list_T *const l, ufunc_T *const fp, const char *const event,
+ const linenr_T lnum, char *const filepath,
+ const bool filepath_alloced)
+{
+ dict_T *const d = tv_dict_alloc_lock(VAR_FIXED);
+ typval_T tv = {
+ .v_type = VAR_DICT,
+ .v_lock = VAR_LOCKED,
+ .vval.v_dict = d,
+ };
+
+ if (fp != NULL) {
+ tv_dict_add_func(d, S_LEN("funcref"), fp);
+ }
+ if (event != NULL) {
+ tv_dict_add_str(d, S_LEN("event"), event);
+ }
+ tv_dict_add_nr(d, S_LEN("lnum"), lnum);
+ if (filepath_alloced) {
+ tv_dict_add_allocated_str(d, S_LEN("filepath"), filepath);
+ } else {
+ tv_dict_add_str(d, S_LEN("filepath"), filepath);
+ }
+
+ tv_list_append_tv(l, &tv);
+}
+
+/// Create the stacktrace from exestack.
+list_T *stacktrace_create(void)
+{
+ list_T *const l = tv_list_alloc(exestack.ga_len);
+
+ for (int i = 0; i < exestack.ga_len; i++) {
+ estack_T *const entry = &((estack_T *)exestack.ga_data)[i];
+ linenr_T lnum = entry->es_lnum;
+
+ if (entry->es_type == ETYPE_SCRIPT) {
+ stacktrace_push_item(l, NULL, NULL, lnum, entry->es_name, false);
+ } else if (entry->es_type == ETYPE_UFUNC) {
+ ufunc_T *const fp = entry->es_info.ufunc;
+ const sctx_T sctx = fp->uf_script_ctx;
+ bool filepath_alloced = false;
+ char *filepath = sctx.sc_sid > 0
+ ? get_scriptname((LastSet){ .script_ctx = sctx },
+ &filepath_alloced) : "";
+ lnum += sctx.sc_lnum;
+ stacktrace_push_item(l, fp, NULL, lnum, filepath, filepath_alloced);
+ } else if (entry->es_type == ETYPE_AUCMD) {
+ const sctx_T sctx = entry->es_info.aucmd->script_ctx;
+ bool filepath_alloced = false;
+ char *filepath = sctx.sc_sid > 0
+ ? get_scriptname((LastSet){ .script_ctx = sctx },
+ &filepath_alloced) : "";
+ lnum += sctx.sc_lnum;
+ stacktrace_push_item(l, NULL, entry->es_name, lnum, filepath, filepath_alloced);
+ }
+ }
+ return l;
+}
+
+/// getstacktrace() function
+void f_getstacktrace(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_set_ret(rettv, stacktrace_create());
+}
+
static bool runtime_search_path_valid = false;
static int *runtime_search_path_ref = NULL;
static RuntimeSearchPath runtime_search_path;
@@ -499,7 +563,6 @@ static void runtime_search_path_unref(RuntimeSearchPath path, const int *ref)
/// return FAIL when no file could be sourced, OK otherwise.
static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *cookie)
{
- char *tail;
bool did_one = false;
char buf[MAXPATHL];
@@ -533,7 +596,7 @@ static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback,
} else if (buflen + strlen(name) + 2 < MAXPATHL) {
STRCPY(buf, item.path);
add_pathsep(buf);
- tail = buf + strlen(buf);
+ char *tail = buf + strlen(buf);
// Loop over all patterns in "name"
char *np = name;
@@ -935,7 +998,6 @@ static int gen_expand_wildcards_and_cb(int num_pat, char **pats, int flags, bool
/// @param is_pack whether the added dir is a "pack/*/start/*/" style package
static int add_pack_dir_to_rtp(char *fname, bool is_pack)
{
- char *p;
char *afterdir = NULL;
int retval = FAIL;
@@ -943,7 +1005,7 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
char *p2 = p1;
char *p3 = p1;
char *p4 = p1;
- for (p = p1; *p; MB_PTR_ADV(p)) {
+ for (char *p = p1; *p; MB_PTR_ADV(p)) {
if (vim_ispathsep_nocolon(*p)) {
p4 = p3;
p3 = p2;
@@ -970,21 +1032,21 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
// Also stop at the first "after" directory
size_t fname_len = strlen(ffname);
- char *buf = try_malloc(MAXPATHL);
- if (buf == NULL) {
- goto theend;
- }
+ char buf[MAXPATHL];
const char *insp = NULL;
const char *after_insp = NULL;
- for (const char *entry = p_rtp; *entry != NUL;) {
+ const char *entry = p_rtp;
+ while (*entry != NUL) {
const char *cur_entry = entry;
-
copy_option_part((char **)&entry, buf, MAXPATHL, ",");
- if ((p = strstr(buf, "after")) != NULL
- && p > buf
- && vim_ispathsep(p[-1])
- && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',')) {
+ char *p = strstr(buf, "after");
+ bool is_after = p != NULL
+ && p > buf
+ && vim_ispathsep(p[-1])
+ && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ',');
+
+ if (is_after) {
if (insp == NULL) {
// Did not find "ffname" before the first "after" directory,
// insert it before this entry.
@@ -1000,12 +1062,11 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
if (rtp_ffname == NULL) {
goto theend;
}
- bool match = path_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
- xfree(rtp_ffname);
- if (match) {
+ if (path_fnamencmp(rtp_ffname, ffname, fname_len) == 0) {
// Insert "ffname" after this entry (and comma).
insp = entry;
}
+ xfree(rtp_ffname);
}
}
@@ -1075,7 +1136,6 @@ static int add_pack_dir_to_rtp(char *fname, bool is_pack)
retval = OK;
theend:
- xfree(buf);
xfree(ffname);
xfree(afterdir);
return retval;
@@ -1123,7 +1183,7 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
bool did_one = false;
if (cookie != &APP_LOAD) {
- char *buf = xmalloc(MAXPATHL);
+ char buf[MAXPATHL];
for (int i = 0; i < num_fnames; i++) {
bool found = false;
@@ -1138,7 +1198,6 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
if (!found) {
// directory is not yet in 'runtimepath', add it
if (add_pack_dir_to_rtp(fnames[i], false) == FAIL) {
- xfree(buf);
return;
}
}
@@ -1147,7 +1206,6 @@ static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all,
break;
}
}
- xfree(buf);
}
if (!all && did_one) {
@@ -1276,25 +1334,23 @@ void ex_packadd(exarg_T *eap)
static const char plugpat[] = "pack/*/%s/%s"; // NOLINT
int res = OK;
- // Round 1: use "start", round 2: use "opt".
- for (int round = 1; round <= 2; round++) {
- // Only look under "start" when loading packages wasn't done yet.
- if (round == 1 && did_source_packages) {
- continue;
- }
+ const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
+ char *pat = xmallocz(len);
+ void *cookie = eap->forceit ? &APP_ADD_DIR : &APP_BOTH;
- const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5;
- char *pat = xmallocz(len);
- vim_snprintf(pat, len, plugpat, round == 1 ? "start" : "opt", eap->arg);
- // The first round don't give a "not found" error, in the second round
- // only when nothing was found in the first round.
- res =
- do_in_path(p_pp, "", pat,
- DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0),
- round == 1 ? add_start_pack_plugins : add_opt_pack_plugins,
- eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
- xfree(pat);
+ // Only look under "start" when loading packages wasn't done yet.
+ if (!did_source_packages) {
+ vim_snprintf(pat, len, plugpat, "start", eap->arg);
+ res = do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR,
+ add_start_pack_plugins, cookie);
}
+
+ // Give a "not found" error if nothing was found in 'start' or 'opt'.
+ vim_snprintf(pat, len, plugpat, "opt", eap->arg);
+ do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR + (res == FAIL ? DIP_ERR : 0),
+ add_opt_pack_plugins, cookie);
+
+ xfree(pat);
}
static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap,
@@ -2726,22 +2782,15 @@ retry:
/// Without the multi-byte feature it's simply ignored.
void ex_scriptencoding(exarg_T *eap)
{
- source_cookie_T *sp;
- char *name;
-
if (!getline_equal(eap->ea_getline, eap->cookie, getsourceline)) {
emsg(_("E167: :scriptencoding used outside of a sourced file"));
return;
}
- if (*eap->arg != NUL) {
- name = enc_canonize(eap->arg);
- } else {
- name = eap->arg;
- }
+ char *name = (*eap->arg != NUL) ? enc_canonize(eap->arg) : eap->arg;
// Setup for conversion from the specified encoding to 'encoding'.
- sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
+ source_cookie_T *sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie);
convert_setup(&sp->conv, name, p_enc);
if (name != eap->arg) {