diff options
-rw-r--r-- | src/nvim/debugger.c | 22 | ||||
-rw-r--r-- | test/old/testdir/test_debugger.vim | 268 | ||||
-rw-r--r-- | test/old/testdir/test_lambda.vim | 1 |
3 files changed, 275 insertions, 16 deletions
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 31aad11d60..bfb15d59f5 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -230,7 +230,7 @@ void do_debug(char *cmd) } if (last_cmd != 0) { - // Execute debug command: decided where to break next and return. + // Execute debug command: decide where to break next and return. switch (last_cmd) { case CMD_CONT: debug_break_level = -1; @@ -475,6 +475,7 @@ static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL }; #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) #define DEBUGGY(gap, idx) (((struct debuggy *)(gap)->ga_data)[idx]) static int last_breakp = 0; // nr of last defined breakpoint +static bool has_expr_breakpoint = false; // Profiling uses file and func names similar to breakpoints. static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL }; @@ -550,7 +551,7 @@ static int dbg_parsearg(char *arg, garray_T *gap) } if (bp->dbg_type == DBG_FUNC) { - bp->dbg_name = xstrdup(p); + bp->dbg_name = xstrdup(strncmp(p, "g:", 2) == 0 ? p + 2 : p); } else if (here) { bp->dbg_name = xstrdup(curbuf->b_ffname); } else if (bp->dbg_type == DBG_EXPR) { @@ -620,6 +621,9 @@ void ex_breakadd(exarg_T *eap) // DBG_EXPR DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp; debug_tick++; + if (gap == &dbg_breakp) { + has_expr_breakpoint = true; + } } } @@ -633,6 +637,17 @@ void ex_debuggreedy(exarg_T *eap) } } +static void update_has_expr_breakpoint(void) +{ + has_expr_breakpoint = false; + for (int i = 0; i < dbg_breakp.ga_len; i++) { + if (BREAKP(i).dbg_type == DBG_EXPR) { + has_expr_breakpoint = true; + break; + } + } +} + /// ":breakdel" and ":profdel". void ex_breakdel(exarg_T *eap) { @@ -708,6 +723,9 @@ void ex_breakdel(exarg_T *eap) if (GA_EMPTY(gap)) { ga_clear(gap); } + if (gap == &dbg_breakp) { + update_has_expr_breakpoint(); + } } /// ":breaklist". diff --git a/test/old/testdir/test_debugger.vim b/test/old/testdir/test_debugger.vim index ba3f4715ca..7ac45a0bd4 100644 --- a/test/old/testdir/test_debugger.vim +++ b/test/old/testdir/test_debugger.vim @@ -73,6 +73,13 @@ func Test_Debugger() endtry return var1 endfunc + def Vim9Func() + for cmd in ['confirm', 'xxxxxxx'] + for _ in [1, 2] + echo cmd + endfor + endfor + enddef END call writefile(lines, 'Xtest.vim') @@ -298,6 +305,14 @@ func Test_Debugger() \ 'line 5: catch']) call RunDbgCmd(buf, 'c') + " Test showing local variable in :def function + call RunDbgCmd(buf, ':breakadd func 2 Vim9Func') + call RunDbgCmd(buf, ':call Vim9Func()', ['line 2: for _ in [1, 2]']) + call RunDbgCmd(buf, 'next', ['line 2: for _ in [1, 2]']) + call RunDbgCmd(buf, 'echo cmd', ['confirm']) + call RunDbgCmd(buf, 'breakdel *') + call RunDbgCmd(buf, 'cont') + " Test for :quit call RunDbgCmd(buf, ':debug echo Foo()') call RunDbgCmd(buf, 'breakdel *') @@ -880,7 +895,7 @@ func Test_Backtrace_DefFunction() CheckCWD let file1 =<< trim END vim9script - import File2Function from './Xtest2.vim' + import './Xtest2.vim' as imp def SourceAnotherFile() source Xtest2.vim @@ -888,10 +903,11 @@ func Test_Backtrace_DefFunction() def CallAFunction() SourceAnotherFile() - File2Function() + imp.File2Function() enddef def g:GlobalFunction() + var some = "some var" CallAFunction() enddef @@ -923,19 +939,22 @@ func Test_Backtrace_DefFunction() \ ':debug call GlobalFunction()', \ ['cmd: call GlobalFunction()']) - " FIXME: Vim9 lines are not debugged! - call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) + call RunDbgCmd(buf, 'step', ['line 1: var some = "some var"']) + call RunDbgCmd(buf, 'step', ['line 2: CallAFunction()']) + call RunDbgCmd(buf, 'echo some', ['some var']) - " But they do appear in the backtrace call RunDbgCmd(buf, 'backtrace', [ \ '\V>backtrace', - \ '\V 2 function GlobalFunction[1]', - \ '\V 1 <SNR>\.\*_CallAFunction[1]', - \ '\V->0 <SNR>\.\*_SourceAnotherFile', - \ '\Vline 1: source Xtest2.vim'], + \ '\V->0 function GlobalFunction', + \ '\Vline 2: CallAFunction()', + \ ], \ #{match: 'pattern'}) - + call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()']) + call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) + " Repeated line, because we fist are in the compiled function before the + " EXEC and then in do_cmdline() before the :source command. + call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) call RunDbgCmd(buf, 'step', ['line 1: vim9script']) call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number']) call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()']) @@ -944,7 +963,7 @@ func Test_Backtrace_DefFunction() call RunDbgCmd(buf, 'step', ['line 14: File2Function()']) call RunDbgCmd(buf, 'backtrace', [ \ '\V>backtrace', - \ '\V 3 function GlobalFunction[1]', + \ '\V 3 function GlobalFunction[2]', \ '\V 2 <SNR>\.\*_CallAFunction[1]', \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]', \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim', @@ -952,22 +971,242 @@ func Test_Backtrace_DefFunction() \ #{match: 'pattern'}) " Don't step into compiled functions... - call RunDbgCmd(buf, 'step', ['line 15: End of sourced file']) + call RunDbgCmd(buf, 'next', ['line 15: End of sourced file']) call RunDbgCmd(buf, 'backtrace', [ \ '\V>backtrace', - \ '\V 3 function GlobalFunction[1]', + \ '\V 3 function GlobalFunction[2]', \ '\V 2 <SNR>\.\*_CallAFunction[1]', \ '\V 1 <SNR>\.\*_SourceAnotherFile[1]', \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim', \ '\Vline 15: End of sourced file'], \ #{match: 'pattern'}) - call StopVimInTerminal(buf) call delete('Xtest1.vim') call delete('Xtest2.vim') endfunc +func Test_DefFunction_expr() + CheckRunVimInTerminal + CheckCWD + let file3 =<< trim END + vim9script + g:someVar = "foo" + def g:ChangeVar() + g:someVar = "bar" + echo "changed" + enddef + defcompile + END + call writefile(file3, 'Xtest3.vim') + let buf = RunVimInTerminal('-S Xtest3.vim', {}) + + call RunDbgCmd(buf, ':breakadd expr g:someVar') + call RunDbgCmd(buf, ':call g:ChangeVar()', ['Oldval = "''foo''"', 'Newval = "''bar''"', 'function ChangeVar', 'line 2: echo "changed"']) + + call StopVimInTerminal(buf) + call delete('Xtest3.vim') +endfunc + +func Test_debug_def_and_legacy_function() + CheckRunVimInTerminal + CheckCWD + let file =<< trim END + vim9script + def g:SomeFunc() + echo "here" + echo "and" + echo "there" + breakadd func 2 LocalFunc + LocalFunc() + enddef + + def LocalFunc() + echo "first" + echo "second" + breakadd func LegacyFunc + LegacyFunc() + enddef + + func LegacyFunc() + echo "legone" + echo "legtwo" + endfunc + + breakadd func 2 g:SomeFunc + END + call writefile(file, 'XtestDebug.vim') + + let buf = RunVimInTerminal('-S XtestDebug.vim', {}) + + call RunDbgCmd(buf,':call SomeFunc()', ['line 2: echo "and"']) + call RunDbgCmd(buf,'next', ['line 3: echo "there"']) + call RunDbgCmd(buf,'next', ['line 4: breakadd func 2 LocalFunc']) + + " continue, next breakpoint is in LocalFunc() + call RunDbgCmd(buf,'cont', ['line 2: echo "second"']) + + " continue, next breakpoint is in LegacyFunc() + call RunDbgCmd(buf,'cont', ['line 1: echo "legone"']) + + call RunDbgCmd(buf, 'cont') + + call StopVimInTerminal(buf) + call delete('XtestDebug.vim') +endfunc + +func Test_debug_def_function() + CheckRunVimInTerminal + CheckCWD + let file =<< trim END + vim9script + def g:Func() + var n: number + def Closure(): number + return n + 3 + enddef + n += Closure() + echo 'result: ' .. n + enddef + + def g:FuncWithArgs(text: string, nr: number, ...items: list<number>) + echo text .. nr + for it in items + echo it + endfor + echo "done" + enddef + + def g:FuncWithDict() + var d = { + a: 1, + b: 2, + } + # comment + def Inner() + eval 1 + 2 + enddef + enddef + + def g:FuncComment() + # comment + echo "first" + .. "one" + # comment + echo "second" + enddef + + def g:FuncForLoop() + eval 1 + 2 + for i in [11, 22, 33] + eval i + 2 + endfor + echo "done" + enddef + + def g:FuncWithSplitLine() + eval 1 + 2 + | eval 2 + 3 + enddef + END + call writefile(file, 'Xtest.vim') + + let buf = RunVimInTerminal('-S Xtest.vim', {}) + + call RunDbgCmd(buf, + \ ':debug call Func()', + \ ['cmd: call Func()']) + call RunDbgCmd(buf, 'next', ['result: 3']) + call term_sendkeys(buf, "\r") + call RunDbgCmd(buf, 'cont') + + call RunDbgCmd(buf, + \ ':debug call FuncWithArgs("asdf", 42, 1, 2, 3)', + \ ['cmd: call FuncWithArgs("asdf", 42, 1, 2, 3)']) + call RunDbgCmd(buf, 'step', ['line 1: echo text .. nr']) + call RunDbgCmd(buf, 'echo text', ['asdf']) + call RunDbgCmd(buf, 'echo nr', ['42']) + call RunDbgCmd(buf, 'echo items', ['[1, 2, 3]']) + call RunDbgCmd(buf, 'step', ['asdf42', 'function FuncWithArgs', 'line 2: for it in items']) + call RunDbgCmd(buf, 'step', ['function FuncWithArgs', 'line 2: for it in items']) + call RunDbgCmd(buf, 'echo it', ['0']) + call RunDbgCmd(buf, 'step', ['line 3: echo it']) + call RunDbgCmd(buf, 'echo it', ['1']) + call RunDbgCmd(buf, 'step', ['1', 'function FuncWithArgs', 'line 4: endfor']) + call RunDbgCmd(buf, 'step', ['line 2: for it in items']) + call RunDbgCmd(buf, 'echo it', ['1']) + call RunDbgCmd(buf, 'step', ['line 3: echo it']) + call RunDbgCmd(buf, 'step', ['2', 'function FuncWithArgs', 'line 4: endfor']) + call RunDbgCmd(buf, 'step', ['line 2: for it in items']) + call RunDbgCmd(buf, 'echo it', ['2']) + call RunDbgCmd(buf, 'step', ['line 3: echo it']) + call RunDbgCmd(buf, 'step', ['3', 'function FuncWithArgs', 'line 4: endfor']) + call RunDbgCmd(buf, 'step', ['line 2: for it in items']) + call RunDbgCmd(buf, 'step', ['line 5: echo "done"']) + call RunDbgCmd(buf, 'cont') + + call RunDbgCmd(buf, + \ ':debug call FuncWithDict()', + \ ['cmd: call FuncWithDict()']) + call RunDbgCmd(buf, 'step', ['line 1: var d = { a: 1, b: 2, }']) + call RunDbgCmd(buf, 'step', ['line 6: def Inner()']) + call RunDbgCmd(buf, 'cont') + + call RunDbgCmd(buf, ':breakadd func 1 FuncComment') + call RunDbgCmd(buf, ':call FuncComment()', ['function FuncComment', 'line 2: echo "first" .. "one"']) + call RunDbgCmd(buf, ':breakadd func 3 FuncComment') + call RunDbgCmd(buf, 'cont', ['function FuncComment', 'line 5: echo "second"']) + call RunDbgCmd(buf, 'cont') + + call RunDbgCmd(buf, ':breakadd func 2 FuncForLoop') + call RunDbgCmd(buf, ':call FuncForLoop()', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]']) + call RunDbgCmd(buf, 'step', ['line 2: for i in [11, 22, 33]']) + call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 3: eval i + 2']) + call RunDbgCmd(buf, 'echo i', ['11']) + call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 4: endfor']) + call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]']) + call RunDbgCmd(buf, 'next', ['line 3: eval i + 2']) + call RunDbgCmd(buf, 'echo i', ['22']) + + call RunDbgCmd(buf, 'breakdel *') + call RunDbgCmd(buf, 'cont') + + call RunDbgCmd(buf, ':breakadd func FuncWithSplitLine') + call RunDbgCmd(buf, ':call FuncWithSplitLine()', ['function FuncWithSplitLine', 'line 1: eval 1 + 2 | eval 2 + 3']) + + call RunDbgCmd(buf, 'cont') + call StopVimInTerminal(buf) + call delete('Xtest.vim') +endfunc + +func Test_debug_def_function_with_lambda() + CheckRunVimInTerminal + CheckCWD + let lines =<< trim END + vim9script + def g:Func() + var s = 'a' + ['b']->map((_, v) => s) + echo "done" + enddef + breakadd func 2 g:Func + END + call writefile(lines, 'XtestLambda.vim') + + let buf = RunVimInTerminal('-S XtestLambda.vim', {}) + + call RunDbgCmd(buf, + \ ':call g:Func()', + \ ['function Func', 'line 2: [''b'']->map((_, v) => s)']) + call RunDbgCmd(buf, + \ 'next', + \ ['function Func', 'line 3: echo "done"']) + + call RunDbgCmd(buf, 'cont') + call StopVimInTerminal(buf) + call delete('XtestLambda.vim') +endfunc + func Test_debug_backtrace_level() CheckRunVimInTerminal CheckCWD @@ -1156,6 +1395,7 @@ func Test_debug_backtrace_level() \ [ 'E121: Undefined variable: s:file1_var' ] ) call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] ) + call RunDbgCmd(buf, 'cont') call StopVimInTerminal(buf) call delete('Xtest1.vim') call delete('Xtest2.vim') diff --git a/test/old/testdir/test_lambda.vim b/test/old/testdir/test_lambda.vim index 025eb016a8..810b41b389 100644 --- a/test/old/testdir/test_lambda.vim +++ b/test/old/testdir/test_lambda.vim @@ -329,6 +329,7 @@ func Test_closure_error() let caught_932 = 1 endtry call assert_equal(1, caught_932) + call delete('Xscript') endfunc " vim: shiftwidth=2 sts=2 expandtab |