Skip to content

Commit

Permalink
feat(:source, nvim_exec): line numbers in :verbose output
Browse files Browse the repository at this point in the history
Support showing line numbers for Vim script sourced anonymously via :source (no
args) and nvim_exec.

Do not offset the line number shown from anonymous scripts with the line number
of an enclosing script. For example, this could produce incorrect numbers in
situations where we have escaped NLs:

```vim
echo "hi"
call nvim_exec("\n\n\nset cul", 1)
verbose set cul?
```
Would print "line 6" (preferably "line 5"), but it's actually on line 2...

TODO: ideally, we should say something instead, like:
"Last set from anonymous :source (script id X) line 4 in script.vim line 2"

TODO: see verbose_spec.lua comment, anonymous sources in Lua need to be fixed so
they can be <SID>ed like regular anon sources, but neovim#15079 broke that...
  • Loading branch information
seandewar committed Mar 28, 2022
1 parent 88b6545 commit edb5314
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 16 deletions.
18 changes: 13 additions & 5 deletions src/nvim/ex_cmds2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1790,6 +1790,7 @@ static FILE *fopen_noinh_readbin(char *filename)
typedef struct {
char_u *buf;
size_t offset;
linenr_T sourcing_lnum;
} GetStrLineCookie;

/// Get one full line from a sourced string (in-memory, no file).
Expand All @@ -1799,7 +1800,7 @@ typedef struct {
/// some error.
static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
{
GetStrLineCookie *p = cookie;
GetStrLineCookie *const p = cookie;
if (STRLEN(p->buf) <= p->offset) {
return NULL;
}
Expand All @@ -1808,13 +1809,15 @@ static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
garray_T ga;
ga_init(&ga, sizeof(char_u), 400);
ga_concat_len(&ga, (const char *)line, (size_t)(eol - line));
sourcing_lnum = ++p->sourcing_lnum;
if (do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL) {
while (eol[0] != NUL) {
line = eol + 1;
const char_u *const next_eol = skip_to_newline(line);
if (!concat_continued_line(&ga, 400, line, (size_t)(next_eol - line))) {
break;
}
p->sourcing_lnum++;
eol = next_eol;
}
}
Expand Down Expand Up @@ -1875,7 +1878,7 @@ static int source_using_linegetter(void *cookie, LineGetter fgetline, const char
const sctx_T save_current_sctx = current_sctx;
current_sctx.sc_sid = sid;
current_sctx.sc_seq = sid > 0 ? ++last_current_SID_seq : 0;
current_sctx.sc_lnum = save_sourcing_lnum;
current_sctx.sc_lnum = 0;
funccal_entry_T entry;
save_funccal(&entry);
const int retval
Expand Down Expand Up @@ -1911,6 +1914,7 @@ static void cmd_source_buffer(const exarg_T *const eap)
const GetStrLineCookie cookie = {
.buf = ga.ga_data,
.offset = 0,
.sourcing_lnum = 0,
};
if (curbuf->b_fname && path_with_extension((const char *)curbuf->b_fname, "lua")) {
nlua_source_using_linegetter(get_str_line, (void *)&cookie, ":source (no file)");
Expand All @@ -1934,6 +1938,7 @@ int do_source_str(const char *cmd, const char *traceback_name)
GetStrLineCookie cookie = {
.buf = (char_u *)cmd,
.offset = 0,
.sourcing_lnum = 0,
};
const scid_T sid = current_sctx.sc_sid == SID_LUA ? SID_LUA : ++last_current_SID;
return source_using_linegetter((void *)&cookie, get_str_line, traceback_name, sid);
Expand Down Expand Up @@ -2344,9 +2349,12 @@ void free_scriptnames(void)

linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie)
{
return fgetline == getsourceline
? ((struct source_cookie *)cookie)->sourcing_lnum
: sourcing_lnum;
if (fgetline == getsourceline) {
return ((struct source_cookie *)cookie)->sourcing_lnum;
} else if (fgetline == get_str_line) {
return ((GetStrLineCookie *)cookie)->sourcing_lnum;
}
return sourcing_lnum;
}


Expand Down
54 changes: 48 additions & 6 deletions test/functional/api/vim_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ describe('API', function()

it(':verbose set {option}?', function()
nvim('exec', 'set nowrap', false)
eq('nowrap\n\tLast set from anonymous :source (script id 1)',
nvim('exec', 'verbose set wrap?', true))
eq('nowrap\n\tLast set from anonymous :source (script id 1) line 1',
nvim('exec', 'verbose set wrap?', true))
end)

it('multiline input', function()
Expand Down Expand Up @@ -240,13 +240,13 @@ describe('API', function()
local sourcing_fname = tmpname()
write_file(sourcing_fname, 'call nvim_exec("source '..fname..'", v:false)\n')
meths.exec('set verbose=2', false)
local traceback_output = 'line 0: sourcing "'..sourcing_fname..'"\n'..
'line 0: sourcing "'..fname..'"\n'..
local traceback_output = 'line 1: sourcing "'..sourcing_fname..'"\n'..
'line 1: sourcing "'..fname..'"\n'..
'hello\n'..
'finished sourcing '..fname..'\n'..
'continuing in nvim_exec() called at '..sourcing_fname..':1\n'..
'finished sourcing '..sourcing_fname..'\n'..
'continuing in nvim_exec() called at nvim_exec():0'
'continuing in nvim_exec() called at nvim_exec():1'
eq(traceback_output,
meths.exec('call nvim_exec("source '..sourcing_fname..'", v:false)', true))
os.remove(fname)
Expand Down Expand Up @@ -279,7 +279,7 @@ describe('API', function()
]]}
end)

it('does\'t display messages when output=true', function()
it('doesn\'t display messages when output=true', function()
local screen = Screen.new(40, 8)
screen:attach()
screen:set_default_attr_ids({
Expand All @@ -297,6 +297,48 @@ describe('API', function()
|
]]}
end)

it(':verbose shows correct line numbers', function()
-- should work like test_vimscript's Test_function_defined_line()
local 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()
]]
meths.exec(code, false)
matches('line 2\n', meths.exec('verbose func F1', true))
matches('line 4\n', meths.exec('verbose func F2', true))
matches('line 11\n', meths.exec('verbose func F3', true))
matches('line 13\n', meths.exec('verbose func F4', true))
matches('line 21\n', meths.exec('verbose func F5', true))
matches('line 23\n', meths.exec('verbose func F6', true))
end)
end)

describe('nvim_command', function()
Expand Down
4 changes: 3 additions & 1 deletion test/functional/ex_cmds/verbose_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ test_group FileType

it('"Last set" works with anonymous sid', function()
local result = exec_capture(':verbose set tw?')
-- TODO(seandewar): should be 27, but ideally should display something like
-- "Last set from anonymous :source (script id <blah>) line 5 in <script_location> line 23"
eq(string.format([[
textwidth=80
Last set from %s line 23]],
Last set from %s line 28]],
script_location), result)

-- Different anon execs in the same file should have unique SIDs as usual.
Expand Down
8 changes: 4 additions & 4 deletions test/functional/legacy/assert_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ describe('assert function:', function()
call assert_true('', 'file two')
]])
expected_errors({
"nvim_exec(): equal assertion failed: Expected 1 but got 100",
"nvim_exec(): true assertion failed: Expected False but got 'true'",
"nvim_exec(): false assertion failed: Expected True but got 'false'",
"nvim_exec(): file two: Expected True but got ''",
"nvim_exec() line 1: equal assertion failed: Expected 1 but got 100",
"nvim_exec() line 2: true assertion failed: Expected False but got 'true'",
"nvim_exec() line 3: false assertion failed: Expected True but got 'false'",
"nvim_exec() line 1: file two: Expected True but got ''",
})
end)
end)
Expand Down

0 comments on commit edb5314

Please sign in to comment.