changeset 17251:984eef966002 v8.1.1625

patch 8.1.1625: script line numbers are not exactly right commit https://github.com/vim/vim/commit/bc2cfe4672d370330b8698d4d025697a9a6ec569 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jul 4 14:57:12 2019 +0200 patch 8.1.1625: script line numbers are not exactly right Problem: Script line numbers are not exactly right. Solution: Handle heredoc and continuation lines better. (Ozaki Kiichi, closes #4611, closes #4511)
author Bram Moolenaar <Bram@vim.org>
date Thu, 04 Jul 2019 15:00:07 +0200
parents 62c322fcbd20
children c46563862cd9
files src/ex_cmds2.c src/proto/ex_cmds2.pro src/testdir/test_vimscript.vim src/userfunc.c src/version.c
diffstat 5 files changed, 110 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -3269,20 +3269,21 @@ cmd_source(char_u *fname, exarg_T *eap)
  */
 struct source_cookie
 {
-    FILE	*fp;		/* opened file for sourcing */
-    char_u      *nextline;      /* if not NULL: line that was read ahead */
-    int		finished;	/* ":finish" used */
+    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
 #ifdef USE_CRNL
-    int		fileformat;	/* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
-    int		error;		/* TRUE if LF found after CR-LF */
+    int		fileformat;	// EOL_UNKNOWN, EOL_UNIX or EOL_DOS
+    int		error;		// TRUE if LF found after CR-LF
 #endif
 #ifdef FEAT_EVAL
-    linenr_T	breakpoint;	/* next line with breakpoint or zero */
-    char_u	*fname;		/* name of sourced file */
-    int		dbg_tick;	/* debug_tick when breakpoint was set */
-    int		level;		/* top nesting level of sourced file */
+    linenr_T	breakpoint;	// next line with breakpoint or zero
+    char_u	*fname;		// name of sourced file
+    int		dbg_tick;	// debug_tick when breakpoint was set
+    int		level;		// top nesting level of sourced file
 #endif
-    vimconv_T	conv;		/* type of conversion */
+    vimconv_T	conv;		// type of conversion
 };
 
 #ifdef FEAT_EVAL
@@ -3346,7 +3347,6 @@ fopen_noinh_readbin(char *filename)
 }
 #endif
 
-
 /*
  * do_source: Read the file "fname" and execute its lines as EX commands.
  *
@@ -3495,6 +3495,7 @@ do_source(
 #endif
 
     cookie.nextline = NULL;
+    cookie.sourcing_lnum = 0;
     cookie.finished = FALSE;
 
 #ifdef FEAT_EVAL
@@ -3790,6 +3791,14 @@ free_scriptnames(void)
 
 #endif
 
+    linenr_T
+get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), 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().
@@ -3816,6 +3825,10 @@ getsourceline(int c UNUSED, void *cookie
 	script_line_end();
 # endif
 #endif
+
+    // 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.
@@ -3828,7 +3841,7 @@ getsourceline(int c UNUSED, void *cookie
     {
 	line = sp->nextline;
 	sp->nextline = NULL;
-	++sourcing_lnum;
+	++sp->sourcing_lnum;
     }
 #ifdef FEAT_PROFILE
     if (line != NULL && do_profiling == PROF_YES)
@@ -3840,7 +3853,7 @@ getsourceline(int c UNUSED, void *cookie
     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
@@ -3931,7 +3944,7 @@ get_one_sourceline(struct source_cookie 
     /*
      * 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 */
@@ -4001,7 +4014,7 @@ get_one_sourceline(struct source_cookie 
 		;
 	    if ((len & 1) != (c & 1))	/* escaped NL, read more */
 	    {
-		sourcing_lnum++;
+		++sp->sourcing_lnum;
 		continue;
 	    }
 
--- a/src/proto/ex_cmds2.pro
+++ b/src/proto/ex_cmds2.pro
@@ -81,6 +81,7 @@ void ex_scriptnames(exarg_T *eap);
 void scriptnames_slash_adjust(void);
 char_u *get_scriptname(scid_T id);
 void free_scriptnames(void);
+linenr_T get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void *cookie);
 char_u *getsourceline(int c, void *cookie, int indent, int do_concat);
 void script_line_start(void);
 void script_line_exec(void);
--- a/src/testdir/test_vimscript.vim
+++ b/src/testdir/test_vimscript.vim
@@ -1676,6 +1676,76 @@ func Test_funccall_garbage_collect()
     delfunc Func
 endfunc
 
+func Test_function_defined_line()
+    if has('gui_running')
+        " Can't catch the output of gvim.
+        return
+    endif
+
+    let lines =<< trim [CODE]
+    " F1
+    func F1()
+        " F2
+        func F2()
+            "
+            "
+            "
+            return
+        endfunc
+        " F3
+        execute "func F3()\n\n\n\nreturn\nendfunc"
+        " F4
+        execute "func F4()\n
+                    \\n
+                    \\n
+                    \\n
+                    \return\n
+                    \endfunc"
+    endfunc
+    " F5
+    execute "func F5()\n\n\n\nreturn\nendfunc"
+    " F6
+    execute "func F6()\n
+                \\n
+                \\n
+                \\n
+                \return\n
+                \endfunc"
+    call F1()
+    verbose func F1
+    verbose func F2
+    verbose func F3
+    verbose func F4
+    verbose func F5
+    verbose func F6
+    qall!
+    [CODE]
+
+    call writefile(lines, 'Xtest.vim')
+    let res = system(v:progpath .. ' --clean -es -X -S Xtest.vim')
+    call assert_equal(0, v:shell_error)
+
+    let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*')
+    call assert_match(' line 2$', m)
+
+    let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*')
+    call assert_match(' line 4$', m)
+
+    let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*')
+    call assert_match(' line 11$', m)
+
+    let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*')
+    call assert_match(' line 13$', m)
+
+    let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*')
+    call assert_match(' line 21$', m)
+
+    let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*')
+    call assert_match(' line 23$', m)
+
+    call delete('Xtest.vim')
+endfunc
+
 "-------------------------------------------------------------------------------
 " Modelines								    {{{1
 " vim: ts=8 sw=4 tw=80 fdm=marker
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -2008,7 +2008,8 @@ ex_function(exarg_T *eap)
     int		todo;
     hashitem_T	*hi;
     int		do_concat = TRUE;
-    int		sourcing_lnum_off;
+    linenr_T	sourcing_lnum_off;
+    linenr_T	sourcing_lnum_top;
 
     /*
      * ":function" without argument: list functions.
@@ -2275,6 +2276,9 @@ ex_function(exarg_T *eap)
 	cmdline_row = msg_row;
     }
 
+    // Save the starting line number.
+    sourcing_lnum_top = sourcing_lnum;
+
     indent = 2;
     nesting = 0;
     for (;;)
@@ -2285,7 +2289,6 @@ ex_function(exarg_T *eap)
 	    saved_wait_return = FALSE;
 	}
 	need_wait_return = FALSE;
-	sourcing_lnum_off = sourcing_lnum;
 
 	if (line_arg != NULL)
 	{
@@ -2318,8 +2321,9 @@ ex_function(exarg_T *eap)
 	}
 
 	/* Detect line continuation: sourcing_lnum increased more than one. */
-	if (sourcing_lnum > sourcing_lnum_off + 1)
-	    sourcing_lnum_off = sourcing_lnum - sourcing_lnum_off - 1;
+	sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
+	if (sourcing_lnum < sourcing_lnum_off)
+	    sourcing_lnum_off -= sourcing_lnum;
 	else
 	    sourcing_lnum_off = 0;
 
@@ -2670,7 +2674,7 @@ ex_function(exarg_T *eap)
     fp->uf_flags = flags;
     fp->uf_calls = 0;
     fp->uf_script_ctx = current_sctx;
-    fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1;
+    fp->uf_script_ctx.sc_lnum += sourcing_lnum_top;
     goto ret_free;
 
 erret:
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1625,
+/**/
     1624,
 /**/
     1623,