# HG changeset patch # User Bram Moolenaar # Date 1595771104 -7200 # Node ID 7449921216bc187f39bc3763e13bd363f482e561 # Parent fb81749507a455556457ea55740224e0a5fc16c0 patch 8.2.1297: when a test fails it's often not easy to see where Commit: https://github.com/vim/vim/commit/a5d0423fa16f18b4576a2a07e50034e489587a7d Author: Bram Moolenaar Date: Sun Jul 26 15:37:02 2020 +0200 patch 8.2.1297: when a test fails it's often not easy to see where Problem: When a test fails it's often not easy to see what the call stack is. Solution: Add more entries from the call stack in the exception message. diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -876,7 +876,7 @@ Also see |`=|. *:* ** *:* ** *:* ** *:* ** *:* ** *:* ** - *:* ** + *:* ** *:* ** *:* ** *:* ** *:* ** *E499* *E500* Note: these are typed literally, they are not special keys! @@ -903,12 +903,16 @@ Note: these are typed literally, they ar events). When executing a ":source" command, is replaced with the file name of the sourced file. *E498* - When executing a function, is replaced with: - "function {function-name}[{lnum}]" - function call nesting is indicated like this: + When executing a function, is replaced with the call stack, + as with (this is for backwards compatibility, using + is preferred). + Note that filename-modifiers are useless when is + not used inside a script. + is replaced with the call stack, using + "function {function-name}[{lnum}]" for a function line + and "script {file-name}[{lnum}]" for a script line, and + ".." in between items. E.g.: "function {function-name1}[{lnum}]..{function-name2}[{lnum}]" - Note that filename-modifiers are useless when is - used inside a function. When executing a ":source" command, is replaced with the line number. *E842* When executing a function it's the line number relative to diff --git a/src/debugger.c b/src/debugger.c --- a/src/debugger.c +++ b/src/debugger.c @@ -105,7 +105,7 @@ do_debug(char_u *cmd) vim_free(debug_newval); debug_newval = NULL; } - sname = estack_sfile(); + sname = estack_sfile(FALSE); if (sname != NULL) msg((char *)sname); vim_free(sname); @@ -344,7 +344,7 @@ do_checkbacktracelevel(void) } else { - char_u *sname = estack_sfile(); + char_u *sname = estack_sfile(FALSE); int max = get_maxbacktrace_level(sname); if (debug_backtrace_level > max) @@ -365,7 +365,7 @@ do_showbacktrace(char_u *cmd) int i = 0; int max; - sname = estack_sfile(); + sname = estack_sfile(FALSE); max = get_maxbacktrace_level(sname); if (sname != NULL) { diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -8268,8 +8268,10 @@ find_cmdline_var(char_u *src, int *usedl #define SPEC_SFILE (SPEC_CFILE + 1) "", // ":so" file line number #define SPEC_SLNUM (SPEC_SFILE + 1) + "", // call stack +#define SPEC_STACK (SPEC_SLNUM + 1) "", // autocommand file name -#define SPEC_AFILE (SPEC_SLNUM + 1) +#define SPEC_AFILE (SPEC_STACK + 1) "", // autocommand buffer number #define SPEC_ABUF (SPEC_AFILE + 1) "", // autocommand match name @@ -8520,10 +8522,13 @@ eval_vars( break; case SPEC_SFILE: // file name for ":so" command - result = estack_sfile(); + case SPEC_STACK: // call stack + result = estack_sfile(spec_idx == SPEC_SFILE); if (result == NULL) { - *errormsg = _("E498: no :source file name to substitute for \"\""); + *errormsg = spec_idx == SPEC_SFILE + ? _("E498: no :source file name to substitute for \"\"") + : _("E489: no call stack to substitute for \"\""); return NULL; } resultbuf = result; // remember allocated string diff --git a/src/ex_eval.c b/src/ex_eval.c --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -290,7 +290,7 @@ cause_errthrow( // Get the source name and lnum now, it may change before // reaching do_errthrow(). - elem->sfile = estack_sfile(); + elem->sfile = estack_sfile(FALSE); elem->slnum = SOURCING_LNUM; } } @@ -549,7 +549,7 @@ throw_exception(void *value, except_type } else { - excp->throw_name = estack_sfile(); + excp->throw_name = estack_sfile(FALSE); if (excp->throw_name == NULL) excp->throw_name = vim_strsave((char_u *)""); if (excp->throw_name == NULL) diff --git a/src/message.c b/src/message.c --- a/src/message.c +++ b/src/message.c @@ -461,7 +461,7 @@ get_emsg_source(void) if (SOURCING_NAME != NULL && other_sourcing_name()) { - char_u *sname = estack_sfile(); + char_u *sname = estack_sfile(FALSE); char_u *tofree = sname; if (sname == NULL) diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro --- a/src/proto/scriptfile.pro +++ b/src/proto/scriptfile.pro @@ -4,7 +4,7 @@ estack_T *estack_push(etype_T type, char estack_T *estack_push_ufunc(ufunc_T *ufunc, long lnum); int estack_top_is_ufunc(ufunc_T *ufunc, long lnum); estack_T *estack_pop(void); -char_u *estack_sfile(void); +char_u *estack_sfile(int is_sfile); void ex_runtime(exarg_T *eap); int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie); int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie); diff --git a/src/scriptfile.c b/src/scriptfile.c --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -111,58 +111,68 @@ estack_pop(void) /* * Get the current value for in allocated memory. + * "is_sfile" is TRUE for itself. */ char_u * -estack_sfile(void) +estack_sfile(int is_sfile) { estack_T *entry; #ifdef FEAT_EVAL + garray_T ga; size_t len; int idx; - char *res; - size_t done; + etype_T last_type = ETYPE_SCRIPT; + char *type_name; #endif entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; - if (entry->es_name == NULL) - return NULL; #ifdef FEAT_EVAL - if (entry->es_info.ufunc == NULL) + if (is_sfile && entry->es_type != ETYPE_UFUNC) #endif + { + if (entry->es_name == NULL) + return NULL; return vim_strsave(entry->es_name); - + } #ifdef FEAT_EVAL + // Give information about each stack entry up to the root. // For a function we compose the call stack, as it was done in the past: // "function One[123]..Two[456]..Three" - len = STRLEN(entry->es_name) + 10; - for (idx = exestack.ga_len - 2; idx >= 0; --idx) + ga_init2(&ga, sizeof(char), 100); + for (idx = 0; idx < exestack.ga_len; ++idx) { entry = ((estack_T *)exestack.ga_data) + idx; - if (entry->es_name == NULL || entry->es_info.ufunc == NULL) + if (entry->es_name != NULL) { - ++idx; - break; + len = STRLEN(entry->es_name) + 15; + type_name = ""; + if (entry->es_type != last_type) + { + switch (entry->es_type) + { + case ETYPE_SCRIPT: type_name = "script "; break; + case ETYPE_UFUNC: type_name = "function "; break; + default: type_name = ""; break; + } + last_type = entry->es_type; + } + len += STRLEN(type_name); + if (ga_grow(&ga, len) == FAIL) + break; + if (idx == exestack.ga_len - 1 || entry->es_lnum == 0) + // For the bottom entry: do not add the line number, it is used + // in . Also leave it out when the number is not set. + vim_snprintf(ga.ga_data + ga.ga_len, len, "%s%s%s", + type_name, entry->es_name, + idx == exestack.ga_len - 1 ? "" : ".."); + else + vim_snprintf(ga.ga_data + ga.ga_len, len, "%s%s[%ld]..", + type_name, entry->es_name, entry->es_lnum); + ga.ga_len += STRLEN(ga.ga_data + ga.ga_len); } - len += STRLEN(entry->es_name) + 15; } - res = (char *)alloc((int)len); - if (res != NULL) - { - STRCPY(res, "function "); - while (idx < exestack.ga_len - 1) - { - done = STRLEN(res); - entry = ((estack_T *)exestack.ga_data) + idx; - vim_snprintf(res + done, len - done, "%s[%ld]..", - entry->es_name, entry->es_lnum); - ++idx; - } - done = STRLEN(res); - entry = ((estack_T *)exestack.ga_data) + idx; - vim_snprintf(res + done, len - done, "%s", entry->es_name); - } - return (char_u *)res; + return (char_u *)ga.ga_data; #endif } diff --git a/src/testdir/test_expand_func.vim b/src/testdir/test_expand_func.vim --- a/src/testdir/test_expand_func.vim +++ b/src/testdir/test_expand_func.vim @@ -16,17 +16,47 @@ func s:expand_sflnum() return str2nr(expand('')) endfunc -func Test_expand_sfile() - call assert_match('test_expand_func\.vim$', s:sfile) - call assert_match('^function .*\.\.Test_expand_sfile$', expand('')) +" This test depends on the location in the test file, put it first. +func Test_expand_sflnum() + call assert_equal(5, s:sflnum) + call assert_equal(22, str2nr(expand(''))) + + " Line-continuation + call assert_equal( + \ 25, + \ str2nr(expand(''))) " Call in script-local function - call assert_match('^function .*\.\.Test_expand_sfile\[5\]\.\.\d\+_expand_sfile$', s:expand_sfile()) + call assert_equal(16, s:expand_sflnum()) + + " Call in command + command Flnum echo expand('') + call assert_equal(34, str2nr(trim(execute('Flnum')))) + delcommand Flnum +endfunc + +func Test_expand_sfile_and_stack() + call assert_match('test_expand_func\.vim$', s:sfile) + let expected = 'script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack$' + call assert_match(expected , expand('')) + call assert_match(expected , expand('')) + + " Call in script-local function + call assert_match('script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack\[7\]\.\.\d\+_expand_sfile$', s:expand_sfile()) " Call in command command Sfile echo expand('') - call assert_match('^function .*\.\.Test_expand_sfile$', trim(execute('Sfile'))) + call assert_match('script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack$', trim(execute('Sfile'))) delcommand Sfile + + " Use from sourced script. + let lines =<< trim END + let g:stack_value = expand('') + END + call writefile(lines, 'Xstack') + source Xstack + call assert_match('\'))) - - " Line-continuation - call assert_equal( - \ 55, - \ str2nr(expand(''))) - - " Call in script-local function - call assert_equal(16, s:expand_sflnum()) - - " Call in command - command Flnum echo expand('') - call assert_equal(64, str2nr(trim(execute('Flnum')))) - delcommand Flnum -endfunc - func Test_expand() new call assert_equal("", expand('%:S')) diff --git a/src/testing.c b/src/testing.c --- a/src/testing.c +++ b/src/testing.c @@ -22,7 +22,7 @@ prepare_assert_error(garray_T *gap) { char buf[NUMBUFLEN]; - char_u *sname = estack_sfile(); + char_u *sname = estack_sfile(FALSE); ga_init2(gap, 1, 100); if (sname != NULL) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1297, +/**/ 1296, /**/ 1295,