diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 2bcb62571b..46aae00ad3 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -422,12 +422,16 @@ gdb: :Tbreak main < - *:Clear* delete the breakpoint at the cursor position +- *:ToggleBreak* set a breakpoint at the cursor position or delete all + breakpoints at the cursor positoin - *:Step* execute the gdb "step" command - *:Over* execute the gdb "next" command (`:Next` is a Vim command) - *:Until* execute the gdb "until" command - *:Finish* execute the gdb "finish" command - *:Continue* execute the gdb "continue" command +- *:RunOrContinue* execute the gdb "continue" command if program is running, + otherwise run the program - *:Stop* interrupt the program If gdb stops at a source line and there is no window currently showing the diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 093e9cb388..619d56a9cc 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -583,6 +583,25 @@ func s:SendCommand(cmd) endif endfunc +func s:StopCommand() + if s:way == 'prompt' + call s:PromptInterrupt() + else + call s:SendCommand('-exec-interrupt') + endif +endfunc + +func s:ContinueCommand() + if s:way == 'prompt' + call s:SendCommand('continue') + else + " using -exec-continue results in CTRL-C in the gdb window not working, + " communicating via commbuf (= use of SendCommand) has the same result + " call s:SendCommand('-exec-continue') + call chansend(s:gdb_job_id, "continue\r") + endif +endfunc + " This is global so that a user can create their mappings with this. func TermDebugSendCommand(cmd) if s:way == 'prompt' @@ -987,6 +1006,7 @@ func s:InstallCommands() command -nargs=? Break call s:SetBreakpoint() command -nargs=? Tbreak call s:SetBreakpoint(, v:true) + command ToggleBreak call s:ToggleBreak() command Clear call s:ClearBreakpoint() command Step call s:SendResumingCommand('-exec-step') command Over call s:SendResumingCommand('-exec-next') @@ -994,17 +1014,9 @@ func s:InstallCommands() command Finish call s:SendResumingCommand('-exec-finish') command -nargs=* Run call s:Run() command -nargs=* Arguments call s:SendResumingCommand('-exec-arguments ' . ) - - if s:way == 'prompt' - command Stop call s:PromptInterrupt() - command Continue call s:SendCommand('continue') - else - command Stop call s:SendCommand('-exec-interrupt') - " using -exec-continue results in CTRL-C in the gdb window not working, - " communicating via commbuf (= use of SendCommand) has the same result - "command Continue call s:SendCommand('-exec-continue') - command Continue call chansend(s:gdb_job_id, "continue\r") - endif + command Stop call s:StopCommand() + command Continue call s:ContinueCommand() + command RunOrContinue call s:RunOrContinue() command -nargs=* Frame call s:Frame() command -count=1 Up call s:Up() @@ -1115,6 +1127,8 @@ func s:DeleteCommands() delcommand Asm delcommand Var delcommand Winbar + delcommand RunOrContinue + delcommand ToggleBreak if exists('s:saved_K_map') if !empty(s:saved_K_map) && !s:saved_K_map.buffer @@ -1335,6 +1349,19 @@ func s:ClearBreakpoint() endif endfunc +func s:ToggleBreak() + let fname = fnameescape(expand('%:p')) + let lnum = line('.') + let bploc = printf('%s:%d', fname, lnum) + if has_key(s:breakpoint_locations, bploc) + while has_key(s:breakpoint_locations, bploc) + call s:ClearBreakpoint() + endwhile + else + call s:SetBreakpoint("") + endif +endfunc + func s:Run(args) if a:args != '' call s:SendResumingCommand($'-exec-arguments {a:args}') @@ -1342,6 +1369,14 @@ func s:Run(args) call s:SendResumingCommand('-exec-run') endfunc +func s:RunOrContinue() + if s:running + call s:ContinueCommand() + else + call s:Run('') + endif +endfunc + " :Frame - go to a specific frame in the stack func s:Frame(arg) " Note: we explicit do not use mi's command @@ -1839,7 +1874,10 @@ func s:HandleNewBreakpoint(msg, modifiedFlag) if !has_key(s:breakpoint_locations, bploc) let s:breakpoint_locations[bploc] = [] endif - let s:breakpoint_locations[bploc] += [id] + if s:breakpoint_locations[bploc]->index(id) == -1 + " Make sure all ids are unique + let s:breakpoint_locations[bploc] += [id] + endif if bufloaded(fname) call s:PlaceSign(id, subid, entry) diff --git a/test/old/testdir/test_plugin_termdebug.vim b/test/old/testdir/test_plugin_termdebug.vim index 3fbcd8937d..0dbd16abe4 100644 --- a/test/old/testdir/test_plugin_termdebug.vim +++ b/test/old/testdir/test_plugin_termdebug.vim @@ -182,10 +182,10 @@ func Test_termdebug_basic() Break 9 call Nterm_wait(gdb_buf) redraw! - call assert_equal([ + call WaitForAssert({-> assert_equal([ \ {'lnum': 9, 'id': 1014, 'name': 'debugBreakpoint1.0', \ 'priority': 110, 'group': 'TermDebug'}], - \ sign_getplaced('', #{group: 'TermDebug'})[0].signs) + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)}) Run call Nterm_wait(gdb_buf, 400) redraw! @@ -344,12 +344,12 @@ func Test_termdebug_tbreak() call Nterm_wait(gdb_buf) redraw! " both temporary and normal breakpoint signs were displayed... - call assert_equal([ + call WaitForAssert({-> assert_equal([ \ {'lnum': temp_bp_line, 'id': 1014, 'name': 'debugBreakpoint1.0', \ 'priority': 110, 'group': 'TermDebug'}, \ {'lnum': bp_line, 'id': 2014, 'name': 'debugBreakpoint2.0', \ 'priority': 110, 'group': 'TermDebug'}], - \ sign_getplaced('', #{group: 'TermDebug'})[0].signs) + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)}) Run call Nterm_wait(gdb_buf, 400) @@ -578,4 +578,87 @@ function Test_termdebug_save_restore_variables() endfunction +func Test_termdebug_toggle_break() + let g:test_is_flaky = 1 + let bin_name = 'XTD_tbreak' + let src_name = bin_name .. '.c' + + eval s:generate_files(bin_name) + + execute 'edit ' .. src_name + execute 'Termdebug ./' .. bin_name + + call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))}) + call WaitForAssert({-> assert_equal(3, winnr('$'))}) + let gdb_buf = winbufnr(1) + wincmd b + + let bp_line = 22 " 'return' statement in main + execute "normal! " .. bp_line .. "G" + execute "ToggleBreak" + + call Nterm_wait(gdb_buf) + redraw! + call WaitForAssert({-> assert_equal([ + \ {'lnum': bp_line, 'id': 1014, 'name': 'debugBreakpoint1.0', + \ 'priority': 110, 'group': 'TermDebug'}], + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)}) + + RunOrContinue + call Nterm_wait(gdb_buf, 400) + redraw! + call WaitForAssert({-> assert_equal([ + \ {'lnum': bp_line, 'id': 12, 'name': 'debugPC', 'priority': 110, + \ 'group': 'TermDebug'}, + \ {'lnum': bp_line, 'id': 1014, 'name': 'debugBreakpoint1.0', + \ 'priority': 110, 'group': 'TermDebug'}], + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs->reverse())}) + + " Add one break point + execute "normal! " .. bp_line .. "G" + execute "ToggleBreak" + call Nterm_wait(gdb_buf) + redraw! + call WaitForAssert({-> assert_equal([ + \ {'lnum': bp_line, 'id': 12, 'name': 'debugPC', 'priority': 110, + \ 'group': 'TermDebug'}], + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)}) + + " Remove one break point + execute "normal! " .. bp_line .. "G" + execute "ToggleBreak" + call Nterm_wait(gdb_buf) + redraw! + call WaitForAssert({-> assert_equal([ + \ {'lnum': bp_line, 'id': 2014, 'name': 'debugBreakpoint2.0', + \ 'priority': 110, 'group': 'TermDebug'}, + \ {'lnum': bp_line, 'id': 12, 'name': 'debugPC', 'priority': 110, + \ 'group': 'TermDebug'}], + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)}) + + " Remove multiple break points + execute "Break" + execute "Break" + execute "Break" + execute "Break" + call Nterm_wait(gdb_buf, 400) + execute "ToggleBreak" + call Nterm_wait(gdb_buf) + redraw! + call WaitForAssert({-> assert_equal([ + \ {'lnum': bp_line, 'id': 12, 'name': 'debugPC', 'priority': 110, + \ 'group': 'TermDebug'}], + \ sign_getplaced('', #{group: 'TermDebug'})[0].signs)}) + + + wincmd t + quit! + redraw! + call WaitForAssert({-> assert_equal(1, winnr('$'))}) + call assert_equal([], sign_getplaced('', #{group: 'TermDebug'})[0].signs) + + eval s:cleanup_files(bin_name) + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab