]> granicus.if.org Git - vim/commitdiff
patch 8.2.1297: when a test fails it's often not easy to see where v8.2.1297
authorBram Moolenaar <Bram@vim.org>
Sun, 26 Jul 2020 13:37:02 +0000 (15:37 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 26 Jul 2020 13:37:02 +0000 (15:37 +0200)
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.

runtime/doc/cmdline.txt
src/debugger.c
src/ex_docmd.c
src/ex_eval.c
src/message.c
src/proto/scriptfile.pro
src/scriptfile.c
src/testdir/test_expand_func.vim
src/testing.c
src/version.c

index ecaa73e894974b016ff084674a7f0db204181c8e..8e4e2a0180d30913e9ffb9a5bb799ef0b32dc092 100644 (file)
@@ -876,7 +876,7 @@ Also see |`=|.
                               *:<cword>* *<cword>* *:<cWORD>* *<cWORD>*
                               *:<cexpr>* *<cexpr>* *:<cfile>* *<cfile>*
                               *:<afile>* *<afile>* *:<abuf>* *<abuf>*
-                              *:<amatch>* *<amatch>*
+                              *:<amatch>* *<amatch>* *:<stack>* *<stack>*
                               *:<sfile>* *<sfile>* *:<slnum>* *<slnum>*
                               *:<sflnum>* *<sflnum>* *E499* *E500*
 Note: these are typed literally, they are not special keys!
@@ -903,12 +903,16 @@ Note: these are typed literally, they are not special keys!
                   events).
        <sfile>    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:
-                  "function {function-name1}[{lnum}]..{function-name2}[{lnum}]"
+                  When executing a function, is replaced with the call stack,
+                  as with <stack> (this is for backwards compatibility, using
+                  <stack> is preferred).
                   Note that filename-modifiers are useless when <sfile> is
-                  used inside a function.
+                  not used inside a script.
+       <stack>    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}]"
        <slnum>    When executing a ":source" command, is replaced with the
                   line number.  *E842*
                   When executing a function it's the line number relative to
index 91ab5ee1fa26dd4313963f8db84f81e7a84277d6..00fb9c8f8bc09d42a529560428e61b6e949fde72 100644 (file)
@@ -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)
     {
index 04c3b465a7dd4073d7d88a0a3a54da9aec4f47e6..987e92dea9c85d9bcf83858108945ae907cc7f27 100644 (file)
@@ -8268,8 +8268,10 @@ find_cmdline_var(char_u *src, int *usedlen)
 #define SPEC_SFILE  (SPEC_CFILE + 1)
                    "<slnum>",          // ":so" file line number
 #define SPEC_SLNUM  (SPEC_SFILE + 1)
+                   "<stack>",          // call stack
+#define SPEC_STACK  (SPEC_SLNUM + 1)
                    "<afile>",          // autocommand file name
-#define SPEC_AFILE  (SPEC_SLNUM + 1)
+#define SPEC_AFILE  (SPEC_STACK + 1)
                    "<abuf>",           // autocommand buffer number
 #define SPEC_ABUF   (SPEC_AFILE + 1)
                    "<amatch>",         // 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 \"<sfile>\"");
+                   *errormsg = spec_idx == SPEC_SFILE
+                       ? _("E498: no :source file name to substitute for \"<sfile>\"")
+                       : _("E489: no call stack to substitute for \"<stack>\"");
                    return NULL;
                }
                resultbuf = result;         // remember allocated string
index f0ffaffdde8c227eab87b452ab179b688a086766..58088a0706f43be41b53826aa030e802dbbaf47e 100644 (file)
@@ -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_T type, char_u *cmdname)
     }
     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)
index 76ec456795273ba02b478b06a968821ad567ce7b..91b2fe23721b8d8a5b0574f13aba485e8ed062ee 100644 (file)
@@ -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)
index fd4c104738961289c752c9d51b4d8b5977aea434..00f1301eeeefb60fbf50646b42fc26f20e6a1d95 100644 (file)
@@ -4,7 +4,7 @@ estack_T *estack_push(etype_T type, char_u *name, long lnum);
 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);
index ce269a1cd2ac270db75b60b2d3316ec8d9fe0620..ce9c15d31bb0aa9c1dba4f4b74606ca1f86dc65a 100644 (file)
@@ -111,58 +111,68 @@ estack_pop(void)
 
 /*
  * Get the current value for <sfile> in allocated memory.
+ * "is_sfile" is TRUE for <sfile> 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 <slnum>.  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
 }
 
index 18437b75880b8dd8923bff4cef8518e2a39f35d2..41673e50afd9858ec035877b8001ad5c80af6f7d 100644 (file)
@@ -16,17 +16,47 @@ func s:expand_sflnum()
   return str2nr(expand('<sflnum>'))  
 endfunc
 
-func Test_expand_sfile()
+" 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('<sflnum>')))
+
+  " Line-continuation
+  call assert_equal(
+        \ 25,
+        \ str2nr(expand('<sflnum>')))
+
+  " Call in script-local function
+  call assert_equal(16, s:expand_sflnum())
+
+  " Call in command
+  command Flnum echo expand('<sflnum>')
+  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)
-  call assert_match('^function .*\.\.Test_expand_sfile$', expand('<sfile>'))
+  let expected = 'script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack$'
+  call assert_match(expected , expand('<sfile>'))
+  call assert_match(expected , expand('<stack>'))
 
   " Call in script-local function
-  call assert_match('^function .*\.\.Test_expand_sfile\[5\]\.\.<SNR>\d\+_expand_sfile$', s:expand_sfile())
+  call assert_match('script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack\[7\]\.\.<SNR>\d\+_expand_sfile$', s:expand_sfile())
 
   " Call in command
   command Sfile echo expand('<sfile>')
-  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 <stack> from sourced script.
+  let lines =<< trim END
+    let g:stack_value = expand('<stack>')
+  END
+  call writefile(lines, 'Xstack')
+  source Xstack
+  call assert_match('\<Xstack$', g:stack_value)
+  call delete('Xstack')
 endfunc
 
 func Test_expand_slnum()
@@ -47,24 +77,6 @@ func Test_expand_slnum()
   delcommand Slnum
 endfunc
 
-func Test_expand_sflnum()
-  call assert_equal(5, s:sflnum)
-  call assert_equal(52, str2nr(expand('<sflnum>')))
-
-  " Line-continuation
-  call assert_equal(
-        \ 55,
-        \ str2nr(expand('<sflnum>')))
-
-  " Call in script-local function
-  call assert_equal(16, s:expand_sflnum())
-
-  " Call in command
-  command Flnum echo expand('<sflnum>')
-  call assert_equal(64, str2nr(trim(execute('Flnum'))))
-  delcommand Flnum
-endfunc
-
 func Test_expand()
   new
   call assert_equal("",  expand('%:S'))
index de89bd9fd7fe9811bfbfb3d68a03c5191ec6f3da..137d5fe9f708ef8e5e3288e8c1e7c12039e4fddf 100644 (file)
@@ -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)
index 6a5f19951e5e8923daf90e08007767c0d18cc453..c45c15519c501c2500af4951975ec42b2fcabcd0 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1297,
 /**/
     1296,
 /**/