Patch 8.2.5010
Problem: The terminal debugger uses various global variables.
Solution: Add a dictionary to hold the terminal debugger preferences.
Files: runtime/doc/terminal.txt,
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
*** ../vim-8.2.5009/runtime/doc/terminal.txt 2022-05-22 14:48:26.339247289 +0100
--- runtime/doc/terminal.txt 2022-05-23 21:33:55.141039199 +0100
***************
*** 1367,1373 ****
*TermdebugStartPre*
TermdebugStartPre Before starting debugging.
Not triggered if the debugger is already
! running or |g:termdebugger| cannot be
executed.
*TermdebugStartPost*
TermdebugStartPost After debugging has initialized.
--- 1367,1373 ----
*TermdebugStartPre*
TermdebugStartPre Before starting debugging.
Not triggered if the debugger is already
! running or the debugger command cannot be
executed.
*TermdebugStartPost*
TermdebugStartPost After debugging has initialized.
***************
*** 1398,1415 ****
*termdebug_use_prompt*
Prompt mode can be used even when the |+terminal| feature is present with: >
let g:termdebug_use_prompt = 1
<
*termdebug_map_K*
The K key is normally mapped to :Evaluate. If you do not want this use: >
let g:termdebug_map_K = 0
-
<
*termdebug_disasm_window*
! If you want the Asm window shown by default, set this to 1. Setting to
! any value greater than 1 will set the Asm window height to that value: >
let g:termdebug_disasm_window = 15
! <
Communication ~
*termdebug-communication*
--- 1398,1421 ----
*termdebug_use_prompt*
Prompt mode can be used even when the |+terminal| feature is present with: >
+ let g:termdebug_config['use_prompt'] = 1
+ Or if there is no g:termdebug_config: >
let g:termdebug_use_prompt = 1
<
*termdebug_map_K*
The K key is normally mapped to :Evaluate. If you do not want this use: >
+ let g:termdebug_config['map_K'] = 0
+ Or if there is no g:termdebug_config: >
let g:termdebug_map_K = 0
<
*termdebug_disasm_window*
! If you want the Asm window shown by default, set the flag to 1.
! the "disasm_window_height" entry can be used to set the window height: >
! let g:termdebug_config['disasm_window'] = 1
! let g:termdebug_config['disasm_window_height'] = 15
! or, if there is no g:termdebug_config: >
let g:termdebug_disasm_window = 15
! Any value greater than 1 will set the Asm window height to that value: >
Communication ~
*termdebug-communication*
***************
*** 1426,1440 ****
Customizing ~
! GDB command *termdebug-customizing*
*g:termdebugger*
! To change the name of the gdb command, set the "g:termdebugger" variable before
! invoking `:Termdebug`: >
let g:termdebugger = "mygdb"
If the command needs an argument use a List: >
let g:termdebugger = ['rr', 'replay', '--']
! < *gdb-version*
Only debuggers fully compatible with gdb will work. Vim uses the GDB/MI
interface. The "new-ui" command requires gdb version 7.12 or later. if you
get this error:
--- 1432,1467 ----
Customizing ~
+ *termdebug-customizing* *g:termdebug_config*
+ In the past several global variables were used for configuration. These are
+ deprecated, using the g:termdebug_config dictionary is preferred. When
+ g:termdebug_config exists the other global variables will not be used.
+
! GDB command ~
*g:termdebugger*
! To change the name of the gdb command, set "debugger" entry in
! g:termdebug_config or the "g:termdebugger" variable before invoking
! `:Termdebug`: >
! let g:termdebug_config['command'] = "mygdb"
! Or if there is no g:termdebug_config: >
let g:termdebugger = "mygdb"
+
If the command needs an argument use a List: >
+ let g:termdebug_config['command'] = ['rr', 'replay', '--']
+ Or if there is no g:termdebug_config: >
let g:termdebugger = ['rr', 'replay', '--']
!
! Several arguments will be added to make gdb work well for the debugger.
! If you want to modify them, add a function to filter the argument list: >
! let g:termdebug_config['command_filter'] = MyDebugFilter
!
! If you do not want the arguments to be added, but you do need to set the
! "pty", use a function to add the necessary arguments: >
! let g:termdebug_config['command_add_args'] = MyAddArguments
! The function will be called with the list of arguments so far, and a second
! argument that is the name of the pty.
! *gdb-version*
Only debuggers fully compatible with gdb will work. Vim uses the GDB/MI
interface. The "new-ui" command requires gdb version 7.12 or later. if you
get this error:
***************
*** 1442,1449 ****
Then your gdb is too old.
! Colors *hl-debugPC* *hl-debugBreakpoint*
!
The color of the signs can be adjusted with these highlight groups:
- debugPC the current position
- debugBreakpoint a breakpoint
--- 1469,1476 ----
Then your gdb is too old.
! Colors~
! *hl-debugPC* *hl-debugBreakpoint*
The color of the signs can be adjusted with these highlight groups:
- debugPC the current position
- debugBreakpoint a breakpoint
***************
*** 1473,1478 ****
--- 1500,1507 ----
Clear breakpoint `:Clear`
Evaluate `:Evaluate`
If you don't want this then disable it with: >
+ let g:termdebug_config['popup'] = 0
+ or if there is no g:termdebug_config: >
let g:termdebug_popup = 0
***************
*** 1480,1494 ****
To change the width of the Vim window when debugging starts and use a vertical
split: >
let g:termdebug_wide = 163
This will set 'columns' to 163 when `:Termdebug` is used. The value is
restored when quitting the debugger.
! If g:termdebug_wide is set and 'columns' is already a greater value, then a
vertical split will be used without modifying 'columns'.
! Set g:termdebug_wide to 1 to use a vertical split without ever changing
'columns'. This is useful when the terminal can't be resized by Vim.
--- 1509,1525 ----
To change the width of the Vim window when debugging starts and use a vertical
split: >
+ let g:termdebug_config['wide'] = 163
+ Or if there is no g:termdebug_config: >
let g:termdebug_wide = 163
This will set 'columns' to 163 when `:Termdebug` is used. The value is
restored when quitting the debugger.
! If the wide value is set and 'columns' is already a greater value, then a
vertical split will be used without modifying 'columns'.
! Set the wide value to 1 to use a vertical split without ever changing
'columns'. This is useful when the terminal can't be resized by Vim.
*** ../vim-8.2.5009/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim 2020-08-31 20:58:36.115898718 +0100
--- runtime/pack/dist/opt/termdebug/plugin/termdebug.vim 2022-05-23 21:37:12.244652273 +0100
***************
*** 2,13 ****
"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"
! " Last Change: 2020 Aug 31
"
! " WORK IN PROGRESS - Only the basics work
! " Note: On MS-Windows you need a recent version of gdb. The one included with
! " MingW is too old (7.6.1).
! " I used version 7.12 from
http://www.equation.com/servlet/equation.cmd?fa=gdb
"
" There are two ways to run gdb:
" - In a terminal window; used if possible, does not work on MS-Windows
--- 2,14 ----
"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"
! " Last Change: 2022 May 23
"
! " WORK IN PROGRESS - The basics works stable, more to come
! " Note: In general you need at least GDB 7.12 because this provides the
! " frame= response in MI thread-selected events we need to sync stack to file.
! " The one included with "old" MingW is too old (7.6.1), you may upgrade it or
! " use a newer version from
http://www.equation.com/servlet/equation.cmd?fa=gdb
"
" There are two ways to run gdb:
" - In a terminal window; used if possible, does not work on MS-Windows
***************
*** 64,78 ****
command -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>)
command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>)
- " Name of the gdb command, defaults to "gdb".
- if !exists('g:termdebugger')
- let g:termdebugger = 'gdb'
- endif
-
let s:pc_id = 12
! let s:break_id = 13 " breakpoint number is added to this
let s:stopped = 1
" Take a breakpoint number as used by GDB and turn it into an integer.
" The breakpoint may contain a dot: 123.4 -> 123004
" The main breakpoint has a zero subid.
--- 65,79 ----
command -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-args>)
command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>)
let s:pc_id = 12
! let s:asm_id = 13
! let s:break_id = 14 " breakpoint number is added to this
let s:stopped = 1
+ let s:parsing_disasm_msg = 0
+ let s:asm_lines = []
+ let s:asm_addr = ''
+
" Take a breakpoint number as used by GDB and turn it into an integer.
" The breakpoint may contain a dot: 123.4 -> 123004
" The main breakpoint has a zero subid.
***************
*** 91,96 ****
--- 92,111 ----
call s:Highlight(1, '', &background)
hi default debugBreakpoint term=reverse ctermbg=red guibg=red
+ hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
+
+ " Get the command to execute the debugger as a list, defaults to ["gdb"].
+ func s:GetCommand()
+ if exists('g:termdebug_config')
+ let cmd = get(g:termdebug_config, 'command', 'gdb')
+ elseif exists('g:termdebugger')
+ let cmd = g:termdebugger
+ else
+ let cmd = 'gdb'
+ endif
+
+ return type(cmd) == v:t_list ? copy(cmd) : [cmd]
+ endfunc
func s:StartDebug(bang, ...)
" First argument is the command to debug, second core file or process ID.
***************
*** 107,133 ****
echoerr 'Terminal debugger already running, cannot run two'
return
endif
! if !executable(g:termdebugger)
! echoerr 'Cannot execute debugger program "' .. g:termdebugger .. '"'
return
endif
let s:ptywin = 0
let s:pid = 0
" Uncomment this line to write logging in "debuglog".
" call ch_logfile('debuglog', 'w')
let s:sourcewin = win_getid(winnr())
! let s:startsigncolumn = &signcolumn
let s:save_columns = 0
let s:allleft = 0
! if exists('g:termdebug_wide')
! if &columns < g:termdebug_wide
let s:save_columns = &columns
! let &columns = g:termdebug_wide
! " If we make the Vim window wider, use the whole left halve for the debug
" windows.
let s:allleft = 1
endif
--- 122,164 ----
echoerr 'Terminal debugger already running, cannot run two'
return
endif
! let gdbcmd = s:GetCommand()
! if !executable(gdbcmd[0])
! echoerr 'Cannot execute debugger program "' .. gdbcmd[0] .. '"'
return
endif
let s:ptywin = 0
let s:pid = 0
+ let s:asmwin = 0
+
+ if exists('#User#TermdebugStartPre')
+ doauto <nomodeline> User TermdebugStartPre
+ endif
" Uncomment this line to write logging in "debuglog".
" call ch_logfile('debuglog', 'w')
let s:sourcewin = win_getid(winnr())
!
! " Remember the old value of 'signcolumn' for each buffer that it's set in, so
! " that we can restore the value for all buffers.
! let b:save_signcolumn = &signcolumn
! let s:signcolumn_buflist = [bufnr()]
let s:save_columns = 0
let s:allleft = 0
! let wide = 0
! if exists('g:termdebug_config')
! let wide = get(g:termdebug_config, 'wide', 0)
! elseif exists('g:termdebug_wide')
! let wide = g:termdebug_wide
! endif
! if wide > 0
! if &columns < wide
let s:save_columns = &columns
! let &columns = wide
! " If we make the Vim window wider, use the whole left half for the debug
" windows.
let s:allleft = 1
endif
***************
*** 137,143 ****
endif
" Override using a terminal window by setting g:termdebug_use_prompt to 1.
! let use_prompt = exists('g:termdebug_use_prompt') && g:termdebug_use_prompt
if has('terminal') && !has('win32') && !use_prompt
let s:way = 'terminal'
else
--- 168,179 ----
endif
" Override using a terminal window by setting g:termdebug_use_prompt to 1.
! let use_prompt = 0
! if exists('g:termdebug_config')
! let use_prompt = get(g:termdebug_config, 'use_prompt', 0)
! elseif exists('g:termdebug_use_prompt')
! let use_prompt = g:termdebug_use_prompt
! endif
if has('terminal') && !has('win32') && !use_prompt
let s:way = 'terminal'
else
***************
*** 149,154 ****
--- 185,200 ----
else
call s:StartDebug_term(a:dict)
endif
+
+ if s:GetDisasmWindow()
+ let curwinid = win_getid(winnr())
+ call s:GotoAsmwinOrCreateIt()
+ call win_gotoid(curwinid)
+ endif
+
+ if exists('#User#TermdebugStartPost')
+ doauto <nomodeline> User TermdebugStartPost
+ endif
endfunc
" Use when debugger didn't start or ended.
***************
*** 158,165 ****
unlet! s:gdbwin
endfunc
func s:StartDebug_term(dict)
- " Open a terminal window without a job, to run the debugged program in.
let s:ptybuf = term_start('NONE', {
\ 'term_name': 'debugged program',
\ 'vertical': s:vertical,
--- 204,221 ----
unlet! s:gdbwin
endfunc
+ func s:CheckGdbRunning()
+ let gdbproc = term_getjob(s:gdbbuf)
+ if gdbproc == v:null || job_status(gdbproc) !=# 'run'
+ echoerr string(s:GetCommand()[0]) . ' exited unexpectedly'
+ call s:CloseBuffers()
+ return ''
+ endif
+ return 'ok'
+ endfunc
+
+ " Open a terminal window without a job, to run the debugged program in.
func s:StartDebug_term(dict)
let s:ptybuf = term_start('NONE', {
\ 'term_name': 'debugged program',
\ 'vertical': s:vertical,
***************
*** 193,206 ****
endif
let commpty = job_info(term_getjob(s:commbuf))['tty_out']
- " Open a terminal window to run the debugger.
- " Add -quiet to avoid the intro message causing a hit-enter prompt.
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
! let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args
! call ch_log('executing "' . join(cmd) . '"')
! let s:gdbbuf = term_start(cmd, {
\ 'term_finish': 'close',
\ })
if s:gdbbuf == 0
--- 249,286 ----
endif
let commpty = job_info(term_getjob(s:commbuf))['tty_out']
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
! let gdb_cmd = s:GetCommand()
!
! if exists('g:termdebug_config') && has_key(g:termdebug_config, 'command_add_args')
! let gdb_cmd = g:termdebug_config.command_add_args(gdb_cmd, pty)
! else
! " Add -quiet to avoid the intro message causing a hit-enter prompt.
! let gdb_cmd += ['-quiet']
! " Disable pagination, it causes everything to stop at the gdb
! let gdb_cmd += ['-iex', 'set pagination off']
! " Interpret commands while the target is running. This should usually only
! " be exec-interrupt, since many commands don't work properly while the
! " target is running (so execute during startup).
! let gdb_cmd += ['-iex', 'set mi-async on']
! " Open a terminal window to run the debugger.
! let gdb_cmd += ['-tty', pty]
! " Command executed _after_ startup is done, provides us with the necessary
! " feedback
! let gdb_cmd += ['-ex', 'echo startupdone\n']
! endif
!
! if exists('g:termdebug_config') && has_key(g:termdebug_config, 'command_filter')
! let gdb_cmd = g:termdebug_config.command_filter(gdb_cmd)
! endif
!
! " Adding arguments requested by the user
! let gdb_cmd += gdb_args
!
! call ch_log('executing "' . join(gdb_cmd) . '"')
! let s:gdbbuf = term_start(gdb_cmd, {
\ 'term_finish': 'close',
\ })
if s:gdbbuf == 0
***************
*** 210,231 ****
endif
let s:gdbwin = win_getid(winnr())
! " Set arguments to be run
if len(proc_args)
! call term_sendkeys(s:gdbbuf, 'set args ' . join(proc_args) . "\r")
endif
! " Connect gdb to the communication pty, using the GDB/MI interface
! call term_sendkeys(s:gdbbuf, 'new-ui mi ' . commpty . "\r")
" Wait for the response to show up, users may not notice the error and wonder
" why the debugger doesn't work.
let try_count = 0
while 1
! let gdbproc = term_getjob(s:gdbbuf)
! if gdbproc == v:null || job_status(gdbproc) !=# 'run'
! echoerr string(g:termdebugger) . ' exited unexpectedly'
! call s:CloseBuffers()
return
endif
--- 290,330 ----
endif
let s:gdbwin = win_getid(winnr())
! " Wait for the "startupdone" message before sending any commands.
! let try_count = 0
! while 1
! if s:CheckGdbRunning() != 'ok'
! return
! endif
!
! for lnum in range(1, 200)
! if term_getline(s:gdbbuf, lnum) =~ 'startupdone'
! let try_count = 9999
! break
! endif
! endfor
! let try_count += 1
! if try_count > 300
! " done or give up after five seconds
! break
! endif
! sleep 10m
! endwhile
!
! " Set arguments to be run.
if len(proc_args)
! call term_sendkeys(s:gdbbuf, 'server set args ' . join(proc_args) . "\r")
endif
! " Connect gdb to the communication pty, using the GDB/MI interface.
! " Prefix "server" to avoid adding this to the history.
! call term_sendkeys(s:gdbbuf, 'server new-ui mi ' . commpty . "\r")
" Wait for the response to show up, users may not notice the error and wonder
" why the debugger doesn't work.
let try_count = 0
while 1
! if s:CheckGdbRunning() != 'ok'
return
endif
***************
*** 234,253 ****
let line1 = term_getline(s:gdbbuf, lnum)
let line2 = term_getline(s:gdbbuf, lnum + 1)
if line1 =~ 'new-ui mi '
! " response can be in the same line or the next line
! let response = line1 . line2
! if response =~ 'Undefined command'
! echoerr 'Sorry, your gdb is too old, gdb 7.12 is required'
! call s:CloseBuffers()
! return
! endif
! if response =~ 'New UI allocated'
! " Success!
! break
! endif
elseif line1 =~ 'Reading symbols from' && line2 !~ 'new-ui mi '
! " Reading symbols might take a while, try more times
! let try_count -= 1
endif
endfor
if response =~ 'New UI allocated'
--- 333,353 ----
let line1 = term_getline(s:gdbbuf, lnum)
let line2 = term_getline(s:gdbbuf, lnum + 1)
if line1 =~ 'new-ui mi '
! " response can be in the same line or the next line
! let response = line1 . line2
! if response =~ 'Undefined command'
! echoerr 'Sorry, your gdb is too old, gdb 7.12 is required'
! " CHECKME: possibly send a "server show version" here
! call s:CloseBuffers()
! return
! endif
! if response =~ 'New UI allocated'
! " Success!
! break
! endif
elseif line1 =~ 'Reading symbols from' && line2 !~ 'new-ui mi '
! " Reading symbols might take a while, try more times
! let try_count -= 1
endif
endfor
if response =~ 'New UI allocated'
***************
*** 261,283 ****
sleep 10m
endwhile
! " Interpret commands while the target is running. This should usually only be
! " exec-interrupt, since many commands don't work properly while the target is
! " running.
! call s:SendCommand('-gdb-set mi-async on')
! " Older gdb uses a different command.
! call s:SendCommand('-gdb-set target-async on')
!
! " Disable pagination, it causes everything to stop at the gdb
! " "Type <return> to continue" prompt.
! call s:SendCommand('set pagination off')
- call job_setoptions(gdbproc, {'exit_cb': function('s:EndTermDebug')})
call s:StartDebugCommon(a:dict)
endfunc
func s:StartDebug_prompt(dict)
- " Open a window with a prompt buffer to run gdb in.
if s:vertical
vertical new
else
--- 361,376 ----
sleep 10m
endwhile
! call job_setoptions(term_getjob(s:gdbbuf), {'exit_cb': function('s:EndTermDebug')})
!
! " Set the filetype, this can be used to add mappings.
! set filetype=termdebug
call s:StartDebugCommon(a:dict)
endfunc
+ " Open a window with a prompt buffer to run gdb in.
func s:StartDebug_prompt(dict)
if s:vertical
vertical new
else
***************
*** 297,310 ****
exe (&columns / 2 - 1) . "wincmd |"
endif
- " Add -quiet to avoid the intro message causing a hit-enter prompt.
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
! let cmd = [g:termdebugger, '-quiet', '--interpreter=mi2'] + gdb_args
! call ch_log('executing "' . join(cmd) . '"')
! let s:gdbjob = job_start(cmd, {
\ 'exit_cb': function('s:EndPromptDebug'),
\ 'out_cb': function('s:GdbOutCallback'),
\ })
--- 390,415 ----
exe (&columns / 2 - 1) . "wincmd |"
endif
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
! let gdb_cmd = s:GetCommand()
! " Add -quiet to avoid the intro message causing a hit-enter prompt.
! let gdb_cmd += ['-quiet']
! " Disable pagination, it causes everything to stop at the gdb, needs to be run early
! let gdb_cmd += ['-iex', 'set pagination off']
! " Interpret commands while the target is running. This should usually only
! " be exec-interrupt, since many commands don't work properly while the
! " target is running (so execute during startup).
! let gdb_cmd += ['-iex', 'set mi-async on']
! " directly communicate via mi2
! let gdb_cmd += ['--interpreter=mi2']
!
! " Adding arguments requested by the user
! let gdb_cmd += gdb_args
! call ch_log('executing "' . join(gdb_cmd) . '"')
! let s:gdbjob = job_start(gdb_cmd, {
\ 'exit_cb': function('s:EndPromptDebug'),
\ 'out_cb': function('s:GdbOutCallback'),
\ })
***************
*** 315,328 ****
endif
" Mark the buffer modified so that it's not easy to close.
set modified
! let s:gdb_channel = job_getchannel(s:gdbjob)
!
! " Interpret commands while the target is running. This should usually only
! " be exec-interrupt, since many commands don't work properly while the
! " target is running.
! call s:SendCommand('-gdb-set mi-async on')
! " Older gdb uses a different command.
! call s:SendCommand('-gdb-set target-async on')
let s:ptybuf = 0
if has('win32')
--- 420,426 ----
endif
" Mark the buffer modified so that it's not easy to close.
set modified
! let s:gdb_channel = job_getchannel(s:gdbjob)
let s:ptybuf = 0
if has('win32')
***************
*** 352,364 ****
call s:SendCommand('set env COLORS = ' . &t_Co)
call s:SendCommand('set env VIM_TERMINAL = ' . v:version)
else
! " TODO: open a new terminal get get the tty name, pass on to gdb
call s:SendCommand('show inferior-tty')
endif
call s:SendCommand('set print pretty on')
call s:SendCommand('set breakpoint pending on')
- " Disable pagination, it causes everything to stop at the gdb
- call s:SendCommand('set pagination off')
" Set arguments to be run
if len(proc_args)
--- 450,460 ----
call s:SendCommand('set env COLORS = ' . &t_Co)
call s:SendCommand('set env VIM_TERMINAL = ' . v:version)
else
! " TODO: open a new terminal, get the tty name, pass on to gdb
call s:SendCommand('show inferior-tty')
endif
call s:SendCommand('set print pretty on')
call s:SendCommand('set breakpoint pending on')
" Set arguments to be run
if len(proc_args)
***************
*** 372,378 ****
func s:StartDebugCommon(dict)
" Sign used to highlight the line where the program has stopped.
" There can be only one.
! sign define debugPC linehl=debugPC
" Install debugger commands in the text window.
call win_gotoid(s:sourcewin)
--- 468,474 ----
func s:StartDebugCommon(dict)
" Sign used to highlight the line where the program has stopped.
" There can be only one.
! call sign_define('debugPC', #{linehl: 'debugPC'})
" Install debugger commands in the text window.
call win_gotoid(s:sourcewin)
***************
*** 412,418 ****
" Run the command if the bang attribute was given and got to the debug
" window.
if get(a:dict, 'bang', 0)
! call s:SendCommand('-exec-run')
call win_gotoid(s:ptywin)
endif
endfunc
--- 508,514 ----
" Run the command if the bang attribute was given and got to the debug
" window.
if get(a:dict, 'bang', 0)
! call s:SendResumingCommand('-exec-run')
call win_gotoid(s:ptywin)
endif
endfunc
***************
*** 435,441 ****
let do_continue = 0
if !s:stopped
let do_continue = 1
! call s:SendCommand('-exec-interrupt')
sleep 10m
endif
call term_sendkeys(s:gdbbuf, a:cmd . "\r")
--- 531,537 ----
let do_continue = 0
if !s:stopped
let do_continue = 1
! Stop
sleep 10m
endif
call term_sendkeys(s:gdbbuf, a:cmd . "\r")
***************
*** 445,450 ****
--- 541,560 ----
endif
endfunc
+ " Send a command that resumes the program. If the program isn't stopped the
+ " command is not sent (to avoid a repeated command to cause trouble).
+ " If the command is sent then reset s:stopped.
+ func s:SendResumingCommand(cmd)
+ if s:stopped
+ " reset s:stopped here, it may take a bit of time before we get a response
+ let s:stopped = 0
+ call ch_log('assume that program is running after this command')
+ call s:SendCommand(a:cmd)
+ else
+ call ch_log('dropping command, program is running: ' . a:cmd)
+ endif
+ endfunc
+
" Function called when entering a line in the prompt buffer.
func s:PromptCallback(text)
call s:SendCommand(a:text)
***************
*** 476,482 ****
if a:text == '(gdb) ' || a:text == '^done' || a:text[0] == '&'
return
endif
! if a:text =~ '^^error,msg='
let text = s:DecodeMessage(a:text[11:])
if exists('s:evalexpr') && text =~ 'A syntax error in expression, near\|No symbol .* in current context'
" Silently drop evaluation errors.
--- 586,592 ----
if a:text == '(gdb) ' || a:text == '^done' || a:text[0] == '&'
return
endif
! if a:text =~ '^\^error,msg='
let text = s:DecodeMessage(a:text[11:])
if exists('s:evalexpr') && text =~ 'A syntax error in expression, near\|No symbol .* in current context'
" Silently drop evaluation errors.
***************
*** 501,533 ****
endfunc
" Decode a message from gdb. quotedText starts with a ", return the text up
! " to the next ", unescaping characters.
func s:DecodeMessage(quotedText)
if a:quotedText[0] != '"'
echoerr 'DecodeMessage(): missing quote in ' . a:quotedText
return
endif
! let result = ''
! let i = 1
! while a:quotedText[i] != '"' && i < len(a:quotedText)
! if a:quotedText[i] == '\'
! let i += 1
! if a:quotedText[i] == 'n'
! " drop \n
! let i += 1
! continue
! elseif a:quotedText[i] == 't'
! " append \t
! let i += 1
! let result .= "\t"
! continue
! endif
! endif
! let result .= a:quotedText[i]
! let i += 1
! endwhile
! return result
endfunc
" Extract the "name" value from a gdb message with fullname="name".
func s:GetFullname(msg)
--- 611,643 ----
endfunc
" Decode a message from gdb. quotedText starts with a ", return the text up
! " to the next ", unescaping characters:
! " - remove line breaks
! " - change \\t to \t
! " - change \0xhh to \xhh (disabled for now)
! " - change \ooo to octal
! " - change \\ to \
func s:DecodeMessage(quotedText)
if a:quotedText[0] != '"'
echoerr 'DecodeMessage(): missing quote in ' . a:quotedText
return
endif
! return a:quotedText
! \ ->substitute('^"\|".*\|\\n', '', 'g')
! \ ->substitute('\\t', "\t", 'g')
! " multi-byte characters arrive in octal form
! " NULL-values must be kept encoded as those break the string otherwise
! \ ->substitute('\\000', s:NullRepl, 'g')
! \ ->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
! " Note: GDB docs also mention hex encodings - the translations below work
! " but we keep them out for performance-reasons until we actually see
! " those in mi-returns
! " \ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
! " \ ->substitute('\\0x00', s:NullRepl, 'g')
! \ ->substitute('\\\\', '\', 'g')
! \ ->substitute(s:NullRepl, '\\000', 'g')
endfunc
+ const s:NullRepl = 'XXXNULLXXX'
" Extract the "name" value from a gdb message with fullname="name".
func s:GetFullname(msg)
***************
*** 542,548 ****
--- 652,671 ----
return name
endfunc
+ " Extract the "addr" value from a gdb message with addr="0x0001234".
+ func s:GetAsmAddr(msg)
+ if a:msg !~ 'addr='
+ return ''
+ endif
+ let addr = s:DecodeMessage(substitute(a:msg, '.*addr=', '', ''))
+ return addr
+ endfunc
+
func s:EndTermDebug(job, status)
+ if exists('#User#TermdebugStopPre')
+ doauto <nomodeline> User TermdebugStopPre
+ endif
+
exe 'bwipe! ' . s:commbuf
unlet s:gdbwin
***************
*** 556,563 ****
exe 'bwipe! ' . s:ptybuf
endif
call win_gotoid(s:sourcewin)
! let &signcolumn = s:startsigncolumn
call s:DeleteCommands()
call win_gotoid(curwinid)
--- 679,700 ----
exe 'bwipe! ' . s:ptybuf
endif
+ " Restore 'signcolumn' in all buffers for which it was set.
call win_gotoid(s:sourcewin)
! let was_buf = bufnr()
! for bufnr in s:signcolumn_buflist
! if bufexists(bufnr)
! exe bufnr .. "buf"
! if exists('b:save_signcolumn')
! let &signcolumn = b:save_signcolumn
! unlet b:save_signcolumn
! endif
! endif
! endfor
! if bufexists(was_buf)
! exe was_buf .. "buf"
! endif
!
call s:DeleteCommands()
call win_gotoid(curwinid)
***************
*** 576,585 ****
--- 713,730 ----
endif
endif
+ if exists('#User#TermdebugStopPost')
+ doauto <nomodeline> User TermdebugStopPost
+ endif
+
au! TermDebug
endfunc
func s:EndPromptDebug(job, status)
+ if exists('#User#TermdebugStopPre')
+ doauto <nomodeline> User TermdebugStopPre
+ endif
+
let curwinid = win_getid(winnr())
call win_gotoid(s:gdbwin)
set nomodified
***************
*** 593,598 ****
--- 738,806 ----
call ch_log("Returning from EndPromptDebug()")
endfunc
+ " Disassembly window - added by Michael Sartain
+ "
+ " - CommOutput: disassemble $pc
+ " - CommOutput: &"disassemble $pc\n"
+ " - CommOutput: ~"Dump of assembler code for function main(int, char**):\n"
+ " - CommOutput: ~" 0x0000555556466f69 <+0>:\tpush rbp\n"
+ " ...
+ " - CommOutput: ~" 0x0000555556467cd0:\tpop rbp\n"
+ " - CommOutput: ~" 0x0000555556467cd1:\tret \n"
+ " - CommOutput: ~"End of assembler dump.\n"
+ " - CommOutput: ^done
+
+ " - CommOutput: disassemble $pc
+ " - CommOutput: &"disassemble $pc\n"
+ " - CommOutput: &"No function contains specified address.\n"
+ " - CommOutput: ^error,msg="No function contains specified address."
+ func s:HandleDisasmMsg(msg)
+ if a:msg =~ '^\^done'
+ let curwinid = win_getid(winnr())
+ if win_gotoid(s:asmwin)
+ silent normal! gg0"_dG
+ call setline(1, s:asm_lines)
+ set nomodified
+ set filetype=asm
+
+ let lnum = search('^' . s:asm_addr)
+ if lnum != 0
+ call sign_unplace('TermDebug', #{id: s:asm_id})
+ call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum})
+ endif
+
+ call win_gotoid(curwinid)
+ endif
+
+ let s:parsing_disasm_msg = 0
+ let s:asm_lines = []
+ elseif a:msg =~ '^\^error,msg='
+ if s:parsing_disasm_msg == 1
+ " Disassemble call ran into an error. This can happen when gdb can't
+ " find the function frame address, so let's try to disassemble starting
+ " at current PC
+ call s:SendCommand('disassemble $pc,+100')
+ endif
+ let s:parsing_disasm_msg = 0
+ elseif a:msg =~ '\&\"disassemble \$pc'
+ if a:msg =~ '+100'
+ " This is our second disasm attempt
+ let s:parsing_disasm_msg = 2
+ endif
+ else
+ let value = substitute(a:msg, '^\~\"[ ]*', '', '')
+ let value = substitute(value, '^=>[ ]*', '', '')
+ let value = substitute(value, '\\n\"\r$', '', '')
+ let value = substitute(value, '\\n\"$', '', '')
+ let value = substitute(value, '\r', '', '')
+ let value = substitute(value, '\\t', ' ', 'g')
+
+ if value != '' || !empty(s:asm_lines)
+ call add(s:asm_lines, value)
+ endif
+ endif
+ endfunc
+
" Handle a message received from gdb on the GDB/MI interface.
func s:CommOutput(chan, msg)
let msgs = split(a:msg, "\r")
***************
*** 602,620 ****
if msg[0] == "\n"
let msg = msg[1:]
endif
! if msg != ''
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
! call s:HandleCursor(msg)
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
! call s:HandleNewBreakpoint(msg)
elseif msg =~ '^=breakpoint-deleted,'
! call s:HandleBreakpointDelete(msg)
elseif msg =~ '^=thread-group-started'
! call s:HandleProgramRun(msg)
elseif msg =~ '^\^done,value='
! call s:HandleEvaluate(msg)
elseif msg =~ '^\^error,msg='
! call s:HandleError(msg)
endif
endif
endfor
--- 810,836 ----
if msg[0] == "\n"
let msg = msg[1:]
endif
!
! if s:parsing_disasm_msg
! call s:HandleDisasmMsg(msg)
! elseif msg != ''
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
! call s:HandleCursor(msg)
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
! call s:HandleNewBreakpoint(msg, 0)
! elseif msg =~ '^=breakpoint-modified,'
! call s:HandleNewBreakpoint(msg, 1)
elseif msg =~ '^=breakpoint-deleted,'
! call s:HandleBreakpointDelete(msg)
elseif msg =~ '^=thread-group-started'
! call s:HandleProgramRun(msg)
elseif msg =~ '^\^done,value='
! call s:HandleEvaluate(msg)
elseif msg =~ '^\^error,msg='
! call s:HandleError(msg)
! elseif msg =~ '^disassemble'
! let s:parsing_disasm_msg = 1
! let s:asm_lines = []
endif
endif
endfor
***************
*** 637,653 ****
command -nargs=? Break call s:SetBreakpoint(<q-args>)
command Clear call s:ClearBreakpoint()
! command Step call s:SendCommand('-exec-step')
! command Over call s:SendCommand('-exec-next')
! command Finish call s:SendCommand('-exec-finish')
command -nargs=* Run call s:Run(<q-args>)
! command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . <q-args>)
! command Stop call s:SendCommand('-exec-interrupt')
- " using -exec-continue results in CTRL-C in gdb window not working
if s:way == 'prompt'
command Continue call s:SendCommand('continue')
else
command Continue call term_sendkeys(s:gdbbuf, "continue\r")
endif
--- 853,873 ----
command -nargs=? Break call s:SetBreakpoint(<q-args>)
command Clear call s:ClearBreakpoint()
! command Step call s:SendResumingCommand('-exec-step')
! command Over call s:SendResumingCommand('-exec-next')
! command -nargs=? Until call s:Until(<q-args>)
! command Finish call s:SendResumingCommand('-exec-finish')
command -nargs=* Run call s:Run(<q-args>)
! command -nargs=* Arguments call s:SendResumingCommand('-exec-arguments ' . <q-args>)
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 term_sendkeys(s:gdbbuf, "continue\r")
endif
***************
*** 655,663 ****
command Gdb call win_gotoid(s:gdbwin)
command Program call s:GotoProgram()
command Source call s:GotoSourcewinOrCreateIt()
command Winbar call s:InstallWinbar()
! if !exists('g:termdebug_map_K') || g:termdebug_map_K
let s:k_map_saved = maparg('K', 'n', 0, 1)
nnoremap K :Evaluate<CR>
endif
--- 875,890 ----
command Gdb call win_gotoid(s:gdbwin)
command Program call s:GotoProgram()
command Source call s:GotoSourcewinOrCreateIt()
+ command Asm call s:GotoAsmwinOrCreateIt()
command Winbar call s:InstallWinbar()
! let map = 1
! if exists('g:termdebug_config')
! let map = get(g:termdebug_config, 'map_K', 1)
! elseif exists('g:termdebug_map_K')
! let map = g:termdebug_map_K
! endif
! if map
let s:k_map_saved = maparg('K', 'n', 0, 1)
nnoremap K :Evaluate<CR>
endif
***************
*** 665,677 ****
if has('menu') && &mouse != ''
call s:InstallWinbar()
! if !exists('g:termdebug_popup') || g:termdebug_popup != 0
let s:saved_mousemodel = &mousemodel
let &mousemodel = 'popup_setpos'
an 1.200 PopUp.-SEP3- <Nop>
an 1.210 PopUp.Set\ breakpoint :Break<CR>
an 1.220 PopUp.Clear\ breakpoint :Clear<CR>
! an 1.230 PopUp.Evaluate :Evaluate<CR>
endif
endif
--- 892,911 ----
if has('menu') && &mouse != ''
call s:InstallWinbar()
! let popup = 1
! if exists('g:termdebug_config')
! let popup = get(g:termdebug_config, 'popup', 1)
! elseif exists('g:termdebug_popup')
! let popup = g:termdebug_popup
! endif
! if popup
let s:saved_mousemodel = &mousemodel
let &mousemodel = 'popup_setpos'
an 1.200 PopUp.-SEP3- <Nop>
an 1.210 PopUp.Set\ breakpoint :Break<CR>
an 1.220 PopUp.Clear\ breakpoint :Clear<CR>
! an 1.230 PopUp.Run\ until :Until<CR>
! an 1.240 PopUp.Evaluate :Evaluate<CR>
endif
endif
***************
*** 699,704 ****
--- 933,939 ----
delcommand Clear
delcommand Step
delcommand Over
+ delcommand Until
delcommand Finish
delcommand Run
delcommand Arguments
***************
*** 708,717 ****
delcommand Gdb
delcommand Program
delcommand Source
delcommand Winbar
! if exists('s:k_map_saved') && !empty(s:k_map_saved)
! call mapset('n', 0, s:k_map_saved)
unlet s:k_map_saved
endif
--- 943,957 ----
delcommand Gdb
delcommand Program
delcommand Source
+ delcommand Asm
delcommand Winbar
! if exists('s:k_map_saved')
! if empty(s:k_map_saved)
! nunmap K
! else
! call mapset(s:k_map_saved)
! endif
unlet s:k_map_saved
endif
***************
*** 737,762 ****
aunmenu PopUp.-SEP3-
aunmenu PopUp.Set\ breakpoint
aunmenu PopUp.Clear\ breakpoint
aunmenu PopUp.Evaluate
endif
endif
! exe 'sign unplace ' . s:pc_id
! for [id, entries] in items(s:breakpoints)
! for subid in keys(entries)
! exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid)
! endfor
! endfor
unlet s:breakpoints
unlet s:breakpoint_locations
! sign undefine debugPC
! for val in s:BreakpointSigns
! exe "sign undefine debugBreakpoint" . val
! endfor
let s:BreakpointSigns = []
endfunc
" :Break - Set a breakpoint at the cursor position.
func s:SetBreakpoint(at)
" Setting a breakpoint may not work while the program is running.
--- 977,1011 ----
aunmenu PopUp.-SEP3-
aunmenu PopUp.Set\ breakpoint
aunmenu PopUp.Clear\ breakpoint
+ aunmenu PopUp.Run\ until
aunmenu PopUp.Evaluate
endif
endif
! call sign_unplace('TermDebug')
unlet s:breakpoints
unlet s:breakpoint_locations
! call sign_undefine('debugPC')
! call sign_undefine(s:BreakpointSigns->map("'debugBreakpoint' .. v:val"))
let s:BreakpointSigns = []
endfunc
+ " :Until - Execute until past a specified position or current line
+ func s:Until(at)
+ if s:stopped
+ " reset s:stopped here, it may take a bit of time before we get a response
+ let s:stopped = 0
+ call ch_log('assume that program is running after this command')
+ " Use the fname:lnum format
+ let at = empty(a:at) ?
+ \ fnameescape(expand('%:p')) . ':' . line('.') : a:at
+ call s:SendCommand('-exec-until ' . at)
+ else
+ call ch_log('dropping command, program is running: exec-until')
+ endif
+ endfunc
+
" :Break - Set a breakpoint at the cursor position.
func s:SetBreakpoint(at)
" Setting a breakpoint may not work while the program is running.
***************
*** 764,783 ****
let do_continue = 0
if !s:stopped
let do_continue = 1
! if s:way == 'prompt'
! call s:PromptInterrupt()
! else
! call s:SendCommand('-exec-interrupt')
! endif
sleep 10m
endif
" Use the fname:lnum format, older gdb can't handle --source.
let at = empty(a:at) ?
! \ fnameescape(expand('%:p')) . ':' . line('.') : a:at
call s:SendCommand('-break-insert ' . at)
if do_continue
! call s:SendCommand('-exec-continue')
endif
endfunc
--- 1013,1028 ----
let do_continue = 0
if !s:stopped
let do_continue = 1
! Stop
sleep 10m
endif
" Use the fname:lnum format, older gdb can't handle --source.
let at = empty(a:at) ?
! \ fnameescape(expand('%:p')) . ':' . line('.') : a:at
call s:SendCommand('-break-insert ' . at)
if do_continue
! Continue
endif
endfunc
***************
*** 788,842 ****
let bploc = printf('%s:%d', fname, lnum)
if has_key(s:breakpoint_locations, bploc)
let idx = 0
for id in s:breakpoint_locations[bploc]
if has_key(s:breakpoints, id)
! " Assume this always works, the reply is simply "^done".
! call s:SendCommand('-break-delete ' . id)
! for subid in keys(s:breakpoints[id])
! exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid)
! endfor
! unlet s:breakpoints[id]
! unlet s:breakpoint_locations[bploc][idx]
! break
else
! let idx += 1
endif
endfor
! if empty(s:breakpoint_locations[bploc])
! unlet s:breakpoint_locations[bploc]
endif
endif
endfunc
func s:Run(args)
if a:args != ''
! call s:SendCommand('-exec-arguments ' . a:args)
endif
! call s:SendCommand('-exec-run')
endfunc
func s:SendEval(expr)
! call s:SendCommand('-data-evaluate-expression "' . a:expr . '"')
! let s:evalexpr = a:expr
endfunc
! " :Evaluate - evaluate what is under the cursor
func s:Evaluate(range, arg)
if a:arg != ''
! let expr = a:arg
elseif a:range == 2
let pos = getcurpos()
let reg = getreg('v', 1, 1)
let regt = getregtype('v')
normal! gv"vy
! let expr = @v
call setpos('.', pos)
call setreg('v', reg, regt)
else
let expr = expand('<cexpr>')
endif
! let s:ignoreEvalError = 0
! call s:SendEval(expr)
endfunc
let s:ignoreEvalError = 0
--- 1033,1144 ----
let bploc = printf('%s:%d', fname, lnum)
if has_key(s:breakpoint_locations, bploc)
let idx = 0
+ let nr = 0
for id in s:breakpoint_locations[bploc]
if has_key(s:breakpoints, id)
! " Assume this always works, the reply is simply "^done".
! call s:SendCommand('-break-delete ' . id)
! for subid in keys(s:breakpoints[id])
! call sign_unplace('TermDebug',
! \ #{id: s:Breakpoint2SignNumber(id, subid)})
! endfor
! unlet s:breakpoints[id]
! unlet s:breakpoint_locations[bploc][idx]
! let nr = id
! break
else
! let idx += 1
endif
endfor
! if nr != 0
! if empty(s:breakpoint_locations[bploc])
! unlet s:breakpoint_locations[bploc]
! endif
! echomsg 'Breakpoint ' . id . ' cleared from line ' . lnum . '.'
! else
! echoerr 'Internal error trying to remove breakpoint at line ' . lnum . '!'
endif
+ else
+ echomsg 'No breakpoint to remove at line ' . lnum . '.'
endif
endfunc
func s:Run(args)
if a:args != ''
! call s:SendResumingCommand('-exec-arguments ' . a:args)
endif
! call s:SendResumingCommand('-exec-run')
endfunc
func s:SendEval(expr)
! " check for "likely" boolean expressions, in which case we take it as lhs
! if a:expr =~ "[=!<>]="
! let exprLHS = a:expr
! else
! " remove text that is likely an assignment
! let exprLHS = substitute(a:expr, ' *=.*', '', '')
! endif
!
! " encoding expression to prevent bad errors
! let expr = a:expr
! let expr = substitute(expr, '\\', '\\\\', 'g')
! let expr = substitute(expr, '"', '\\"', 'g')
! call s:SendCommand('-data-evaluate-expression "' . expr . '"')
! let s:evalexpr = exprLHS
endfunc
! " :Evaluate - evaluate what is specified / under the cursor
func s:Evaluate(range, arg)
+ let expr = s:GetEvaluationExpression(a:range, a:arg)
+ let s:ignoreEvalError = 0
+ call s:SendEval(expr)
+ endfunc
+
+ " get what is specified / under the cursor
+ func s:GetEvaluationExpression(range, arg)
if a:arg != ''
! " user supplied evaluation
! let expr = s:CleanupExpr(a:arg)
! " DSW: replace "likely copy + paste" assignment
! let expr = substitute(expr, '"\([^"]*\)": *', '\1=', 'g')
elseif a:range == 2
+ " no evaluation but provided but range set
let pos = getcurpos()
let reg = getreg('v', 1, 1)
let regt = getregtype('v')
normal! gv"vy
! let expr = s:CleanupExpr(@v)
call setpos('.', pos)
call setreg('v', reg, regt)
else
+ " no evaluation provided: get from C-expression under cursor
+ " TODO: allow filetype specific lookup #9057
let expr = expand('<cexpr>')
endif
! return expr
! endfunc
!
! " clean up expression that may get in because of range
! " (newlines and surrounding whitespace)
! " As it can also be specified via ex-command for assignments this function
! " may not change the "content" parts (like replacing contained spaces)
! func s:CleanupExpr(expr)
! " replace all embedded newlines/tabs/...
! let expr = substitute(a:expr, '\_s', ' ', 'g')
!
! if &filetype ==# 'cobol'
! " extra cleanup for COBOL:
! " - a semicolon nmay be used instead of a space
! " - a trailing comma or period is ignored as it commonly separates/ends
! " multiple expr
! let expr = substitute(expr, ';', ' ', 'g')
! let expr = substitute(expr, '[,.]\+ *$', '', '')
! endif
!
! " get rid of leading and trailing spaces
! let expr = substitute(expr, '^ *', '', '')
! let expr = substitute(expr, ' *$', '', '')
! return expr
endfunc
let s:ignoreEvalError = 0
***************
*** 844,851 ****
" Handle the result of data-evaluate-expression
func s:HandleEvaluate(msg)
! let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '')
! let value = substitute(value, '\\"', '"', 'g')
if s:evalFromBalloonExpr
if s:evalFromBalloonExprResult == ''
let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value
--- 1146,1164 ----
" Handle the result of data-evaluate-expression
func s:HandleEvaluate(msg)
! let value = a:msg
! \ ->substitute('.*value="\(.*\)"', '\1', '')
! \ ->substitute('\\"', '"', 'g')
! \ ->substitute('\\\\', '\\', 'g')
! "\ multi-byte characters arrive in octal form, replace everything but NULL values
! \ ->substitute('\\000', s:NullRepl, 'g')
! \ ->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
! "\ Note: GDB docs also mention hex encodings - the translations below work
! "\ but we keep them out for performance-reasons until we actually see
! "\ those in mi-returns
! "\ ->substitute('\\0x00', s:NullRep, 'g')
! "\ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
! \ ->substitute(s:NullRepl, '\\000', 'g')
if s:evalFromBalloonExpr
if s:evalFromBalloonExprResult == ''
let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value
***************
*** 880,886 ****
let s:evalFromBalloonExpr = 1
let s:evalFromBalloonExprResult = ''
let s:ignoreEvalError = 1
! call s:SendEval(v:beval_text)
return ''
endfunc
--- 1193,1200 ----
let s:evalFromBalloonExpr = 1
let s:evalFromBalloonExprResult = ''
let s:ignoreEvalError = 1
! let expr = s:CleanupExpr(v:beval_text)
! call s:SendEval(expr)
return ''
endfunc
***************
*** 892,898 ****
let s:evalFromBalloonExpr = 0
return
endif
! echoerr substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
endfunc
func s:GotoSourcewinOrCreateIt()
--- 1206,1213 ----
let s:evalFromBalloonExpr = 0
return
endif
! let msgVal = substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
! echoerr substitute(msgVal, '\\"', '"', 'g')
endfunc
func s:GotoSourcewinOrCreateIt()
***************
*** 903,908 ****
--- 1218,1284 ----
endif
endfunc
+ func s:GetDisasmWindow()
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'disasm_window', 0)
+ endif
+ if exists('g:termdebug_disasm_window')
+ return g:termdebug_disasm_window
+ endif
+ return 0
+ endfunc
+
+ func s:GetDisasmWindowHeight()
+ if exists('g:termdebug_config')
+ return get(g:termdebug_config, 'disasm_window_height', 0)
+ endif
+ if exists('g:termdebug_disasm_window') && g:termdebug_disasm_window > 1
+ return g:termdebug_disasm_window
+ endif
+ return 0
+ endfunc
+
+ func s:GotoAsmwinOrCreateIt()
+ if !win_gotoid(s:asmwin)
+ if win_gotoid(s:sourcewin)
+ exe 'rightbelow new'
+ else
+ exe 'new'
+ endif
+
+ let s:asmwin = win_getid(winnr())
+
+ setlocal nowrap
+ setlocal number
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal modifiable
+
+ let asmbuf = bufnr('Termdebug-asm-listing')
+ if asmbuf > 0
+ exe 'buffer' . asmbuf
+ else
+ exe 'file Termdebug-asm-listing'
+ endif
+
+ if s:GetDisasmWindowHeight() > 0
+ exe 'resize ' .. s:GetDisasmWindowHeight()
+ endif
+ endif
+
+ if s:asm_addr != ''
+ let lnum = search('^' . s:asm_addr)
+ if lnum == 0
+ if s:stopped
+ call s:SendCommand('disassemble $pc')
+ endif
+ else
+ call sign_unplace('TermDebug', #{id: s:asm_id})
+ call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum})
+ endif
+ endif
+ endfunc
+
" Handle stopping and running message from gdb.
" Will update the sign that shows the current position.
func s:HandleCursor(msg)
***************
*** 921,947 ****
else
let fname = ''
endif
if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$'
! call s:GotoSourcewinOrCreateIt()
if expand('%:p') != fnamemodify(fname, ':p')
! if &modified
! " TODO: find existing window
! exe 'split ' . fnameescape(fname)
! let s:sourcewin = win_getid(winnr())
! call s:InstallWinbar()
! else
! exe 'edit ' . fnameescape(fname)
! endif
endif
exe lnum
! exe 'sign unplace ' . s:pc_id
! exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC priority=110 file=' . fname
setlocal signcolumn=yes
endif
elseif !s:stopped || fname != ''
! exe 'sign unplace ' . s:pc_id
endif
call win_gotoid(wid)
--- 1297,1363 ----
else
let fname = ''
endif
+
+ if a:msg =~ 'addr='
+ let asm_addr = s:GetAsmAddr(a:msg)
+ if asm_addr != ''
+ let s:asm_addr = asm_addr
+
+ let curwinid = win_getid(winnr())
+ if win_gotoid(s:asmwin)
+ let lnum = search('^' . s:asm_addr)
+ if lnum == 0
+ call s:SendCommand('disassemble $pc')
+ else
+ call sign_unplace('TermDebug', #{id: s:asm_id})
+ call sign_place(s:asm_id, 'TermDebug', 'debugPC', '%', #{lnum: lnum})
+ endif
+
+ call win_gotoid(curwinid)
+ endif
+ endif
+ endif
+
if a:msg =~ '^\(\*stopped\|=thread-selected\)' && filereadable(fname)
let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$'
! call s:GotoSourcewinOrCreateIt()
if expand('%:p') != fnamemodify(fname, ':p')
! echomsg 'different fname: "' .. expand('%:p') .. '" vs "' .. fnamemodify(fname, ':p') .. '"'
! augroup Termdebug
! " Always open a file read-only instead of showing the ATTENTION
! " prompt, since we are unlikely to want to edit the file.
! " The file may be changed but not saved, warn for that.
! au SwapExists * echohl WarningMsg
! \ | echo 'Warning: file is being edited elsewhere'
! \ | echohl None
! \ | let v:swapchoice = '0'
! augroup END
! if &modified
! " TODO: find existing window
! exe 'split ' . fnameescape(fname)
! let s:sourcewin = win_getid(winnr())
! call s:InstallWinbar()
! else
! exe 'edit ' . fnameescape(fname)
! endif
! augroup Termdebug
! au! SwapExists
! augroup END
endif
exe lnum
! normal! zv
! call sign_unplace('TermDebug', #{id: s:pc_id})
! call sign_place(s:pc_id, 'TermDebug', 'debugPC', fname,
! \ #{lnum: lnum, priority: 110})
! if !exists('b:save_signcolumn')
! let b:save_signcolumn = &signcolumn
! call add(s:signcolumn_buflist, bufnr())
! endif
setlocal signcolumn=yes
endif
elseif !s:stopped || fname != ''
! call sign_unplace('TermDebug', #{id: s:pc_id})
endif
call win_gotoid(wid)
***************
*** 949,959 ****
let s:BreakpointSigns = []
! func s:CreateBreakpoint(id, subid)
let nr = printf('%d.%d', a:id, a:subid)
if index(s:BreakpointSigns, nr) == -1
call add(s:BreakpointSigns, nr)
! exe "sign define debugBreakpoint" . nr . " text=" . substitute(nr, '\..*', '', '') . " texthl=debugBreakpoint"
endif
endfunc
--- 1365,1382 ----
let s:BreakpointSigns = []
! func s:CreateBreakpoint(id, subid, enabled)
let nr = printf('%d.%d', a:id, a:subid)
if index(s:BreakpointSigns, nr) == -1
call add(s:BreakpointSigns, nr)
! if a:enabled == "n"
! let hiName = "debugBreakpointDisabled"
! else
! let hiName = "debugBreakpoint"
! endif
! call sign_define('debugBreakpoint' .. nr,
! \ #{text: substitute(nr, '\..*', '', ''),
! \ texthl: hiName})
endif
endfunc
***************
*** 963,971 ****
" Handle setting a breakpoint
" Will update the sign that shows the breakpoint
! func s:HandleNewBreakpoint(msg)
if a:msg !~ 'fullname='
! " a watch does not have a file name
return
endif
for msg in s:SplitMsg(a:msg)
--- 1386,1399 ----
" Handle setting a breakpoint
" Will update the sign that shows the breakpoint
! func s:HandleNewBreakpoint(msg, modifiedFlag)
if a:msg !~ 'fullname='
! " a watch or a pending breakpoint does not have a file name
! if a:msg =~ 'pending='
! let nr = substitute(a:msg, '.*number=\"\([0-9.]*\)\".*', '\1', '')
! let target = substitute(a:msg, '.*pending=\"\([^"]*\)\".*', '\1', '')
! echomsg 'Breakpoint ' . nr . ' (' . target . ') pending.'
! endif
return
endif
for msg in s:SplitMsg(a:msg)
***************
*** 981,987 ****
" If "nr" is 123 it becomes "123.0" and subid is "0".
" If "nr" is 123.4 it becomes "123.4.0" and subid is "4"; "0" is discarded.
let [id, subid; _] = map(split(nr . '.0', '\.'), 'v:val + 0')
! call s:CreateBreakpoint(id, subid)
if has_key(s:breakpoints, id)
let entries = s:breakpoints[id]
--- 1409,1416 ----
" If "nr" is 123 it becomes "123.0" and subid is "0".
" If "nr" is 123.4 it becomes "123.4.0" and subid is "4"; "0" is discarded.
let [id, subid; _] = map(split(nr . '.0', '\.'), 'v:val + 0')
! let enabled = substitute(msg, '.*enabled="\([yn]\)".*', '\1', '')
! call s:CreateBreakpoint(id, subid, enabled)
if has_key(s:breakpoints, id)
let entries = s:breakpoints[id]
***************
*** 1008,1020 ****
if bufloaded(fname)
call s:PlaceSign(id, subid, entry)
endif
endfor
endfunc
func s:PlaceSign(id, subid, entry)
let nr = printf('%d.%d', a:id, a:subid)
! exe 'sign place ' . s:Breakpoint2SignNumber(a:id, a:subid) . ' line=' . a:entry['lnum'] . ' name=debugBreakpoint' . nr . ' file=' . a:entry['fname']
let a:entry['placed'] = 1
endfunc
--- 1437,1462 ----
if bufloaded(fname)
call s:PlaceSign(id, subid, entry)
+ let posMsg = ' at line ' . lnum . '.'
+ else
+ let posMsg = ' in ' . fname . ' at line ' . lnum . '.'
+ endif
+ if !a:modifiedFlag
+ let actionTaken = 'created'
+ elseif enabled == 'n'
+ let actionTaken = 'disabled'
+ else
+ let actionTaken = 'enabled'
endif
+ echomsg 'Breakpoint ' . nr . ' ' . actionTaken . posMsg
endfor
endfunc
func s:PlaceSign(id, subid, entry)
let nr = printf('%d.%d', a:id, a:subid)
! call sign_place(s:Breakpoint2SignNumber(a:id, a:subid), 'TermDebug',
! \ 'debugBreakpoint' .. nr, a:entry['fname'],
! \ #{lnum: a:entry['lnum'], priority: 110})
let a:entry['placed'] = 1
endfunc
***************
*** 1028,1038 ****
if has_key(s:breakpoints, id)
for [subid, entry] in items(s:breakpoints[id])
if has_key(entry, 'placed')
! exe 'sign unplace ' . s:Breakpoint2SignNumber(id, subid)
! unlet entry['placed']
endif
endfor
unlet s:breakpoints[id]
endif
endfunc
--- 1470,1482 ----
if has_key(s:breakpoints, id)
for [subid, entry] in items(s:breakpoints[id])
if has_key(entry, 'placed')
! call sign_unplace('TermDebug',
! \ #{id: s:Breakpoint2SignNumber(id, subid)})
! unlet entry['placed']
endif
endfor
unlet s:breakpoints[id]
+ echomsg 'Breakpoint ' . id . ' cleared.'
endif
endfunc
***************
*** 1053,1059 ****
for [id, entries] in items(s:breakpoints)
for [subid, entry] in items(entries)
if entry['fname'] == fname
! call s:PlaceSign(id, subid, entry)
endif
endfor
endfor
--- 1497,1503 ----
for [id, entries] in items(s:breakpoints)
for [subid, entry] in items(entries)
if entry['fname'] == fname
! call s:PlaceSign(id, subid, entry)
endif
endfor
endfor
***************
*** 1065,1071 ****
for [id, entries] in items(s:breakpoints)
for [subid, entry] in items(entries)
if entry['fname'] == fname
! let entry['placed'] = 0
endif
endfor
endfor
--- 1509,1515 ----
for [id, entries] in items(s:breakpoints)
for [subid, entry] in items(entries)
if entry['fname'] == fname
! let entry['placed'] = 0
endif
endfor
endfor
*** ../vim-8.2.5009/src/version.c 2022-05-23 15:33:03.077095124 +0100
--- src/version.c 2022-05-23 21:44:10.675925972 +0100
***************
*** 736,737 ****
--- 736,739 ----
{ /* Add new patch number below this line */
+ /**/
+ 5010,
/**/
--
Life would be so much easier if we could just look at the source code.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///