vim-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 vim/vim#4611, closes vim/vim#4511)
bc2cfe4672
This commit is contained in:
Jurica Bradaric 2019-10-12 22:49:21 +02:00
parent 6c012b0624
commit fcc24d0df3
3 changed files with 102 additions and 15 deletions

View File

@ -21301,7 +21301,8 @@ void ex_function(exarg_T *eap)
hashtab_T *ht;
int todo;
hashitem_T *hi;
int sourcing_lnum_off;
linenr_T sourcing_lnum_off;
linenr_T sourcing_lnum_top;
bool show_block = false;
bool do_concat = true;
@ -21550,15 +21551,17 @@ void ex_function(exarg_T *eap)
cmdline_row = msg_row;
}
// Save the starting line number.
sourcing_lnum_top = sourcing_lnum;
indent = 2;
nesting = 0;
for (;; ) {
if (KeyTyped) {
msg_scroll = TRUE;
saved_wait_return = FALSE;
msg_scroll = true;
saved_wait_return = false;
}
need_wait_return = FALSE;
sourcing_lnum_off = sourcing_lnum;
need_wait_return = false;
if (line_arg != NULL) {
/* Use eap->arg, split up in parts by line breaks. */
@ -21591,11 +21594,13 @@ void ex_function(exarg_T *eap)
ui_ext_cmdline_block_append((size_t)indent, (const char *)theline);
}
/* 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;
else
// Detect line continuation: sourcing_lnum increased more than one.
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;
}
if (skip_until != NULL) {
// Between ":append" and "." and between ":python <<EOF" and "EOF"
@ -21896,7 +21901,8 @@ void 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:

View File

@ -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
@ -3124,6 +3125,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.
@ -3375,6 +3377,13 @@ 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().
@ -3395,6 +3404,8 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
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 +3415,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
} else {
line = sp->nextline;
sp->nextline = NULL;
sourcing_lnum++;
sp->sourcing_lnum++;
}
if (line != NULL && do_profiling == PROF_YES) {
script_line_start();
@ -3414,7 +3425,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
// contain the 'C' flag.
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 +3503,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 +3570,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;
}

View File

@ -1409,6 +1409,76 @@ func Test_compound_assignment_operators()
let @/ = ''
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