vim-patch:partial:9.1.0482: termdebug plugin needs more love (#29329)

Problem:  termdebug plugin needs more love
Solution: start with some more Vim9 refactoring
          to improve maintenance and readability
          (Ubaldo Tiberi)

List of Changes and the Reasoning Behind Them:

1) Introduction of InitScriptVariables() Function:

Reasoning: This function has been introduced to ensure that when you open and
close Termdebug, and then open it again, there are no leftover script variable
values from the previous session. Leftover values could potentially cause
issues. The goal is for each Termdebug session to be independent of previous
sessions. At startup, all script variables are initialized. The only exception
is g:termdebug_loaded located at the very beginning of the script to prevent
sourcing the script twice. The variables are declared at script level and
defined in InitScriptVariables().

2) More Descriptive Variable Names:

Reasoning: The names of variables have been made more comprehensive. Almost
every Termdebug buffer now has a variable to indicate its name and another
variable to indicate its number, improving code readability and
maintainability. Due to the latest discussion around the &mousemodel option
save/restore mechanism, perhaps some other variables shall be prepended with
saved_.

3) Consistent Naming for GDB Terminal Buffers:

Reasoning: The name of the GDB terminal buffer now matches the name of the GDB
program being used, e.g., 'gdb', 'mygdb', 'arm-eabi-none-gdb', etc. This
ensures clarity and consistency in identifying buffers.

4) Other minor improvements:
Moved EchoErr() on top, added another test, some refactoring, mainly changed
several 0 and 1 to true and false

closes: vim/vim#14980

ef8eab86e2

Co-authored-by: Ubaldo Tiberi <ubaldo.tiberi@volvo.com>
This commit is contained in:
Yinzuo Jiang 2024-06-14 16:37:38 +08:00 committed by GitHub
parent 874869321a
commit 29e05cfb7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 74 additions and 62 deletions

View File

@ -44,8 +44,13 @@
" - job_info && term_getjob -> nvim_get_chan_info " - job_info && term_getjob -> nvim_get_chan_info
" - balloon -> vim.lsp.util.open_floating_preview " - balloon -> vim.lsp.util.open_floating_preview
func s:Echoerr(msg)
echohl ErrorMsg | echom '[termdebug] ' .. a:msg | echohl None
endfunc
" In case this gets sourced twice. " In case this gets sourced twice.
if exists(':Termdebug') if exists(':Termdebug')
call s:Echoerr('Termdebug already loaded.')
finish finish
endif endif
@ -67,8 +72,8 @@ command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(
let s:pc_id = 12 let s:pc_id = 12
let s:asm_id = 13 let s:asm_id = 13
let s:break_id = 14 " breakpoint number is added to this let s:break_id = 14 " breakpoint number is added to this
let s:stopped = 1 let s:stopped = v:true
let s:running = 0 let s:running = v:false
let s:parsing_disasm_msg = 0 let s:parsing_disasm_msg = 0
let s:asm_lines = [] let s:asm_lines = []
@ -121,10 +126,6 @@ func s:GetCommand()
return type(cmd) == v:t_list ? copy(cmd) : [cmd] return type(cmd) == v:t_list ? copy(cmd) : [cmd]
endfunc endfunc
func s:Echoerr(msg)
echohl ErrorMsg | echom '[termdebug] ' .. a:msg | echohl None
endfunc
func s:StartDebug(bang, ...) func s:StartDebug(bang, ...)
" First argument is the command to debug, second core file or process ID. " First argument is the command to debug, second core file or process ID.
call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang}) call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang})
@ -149,9 +150,9 @@ func s:StartDebug_internal(dict)
let s:ptywin = 0 let s:ptywin = 0
let s:pid = 0 let s:pid = 0
let s:asmwin = 0 let s:asmwin = 0
let s:asmbuf = 0 let s:asmbufnr = 0
let s:varwin = 0 let s:varwin = 0
let s:varbuf = 0 let s:varbufnr = 0
if exists('#User#TermdebugStartPre') if exists('#User#TermdebugStartPre')
doauto <nomodeline> User TermdebugStartPre doauto <nomodeline> User TermdebugStartPre
@ -168,7 +169,7 @@ func s:StartDebug_internal(dict)
let s:signcolumn_buflist = [bufnr()] let s:signcolumn_buflist = [bufnr()]
let s:save_columns = 0 let s:save_columns = 0
let s:allleft = 0 let s:allleft = v:false
let wide = 0 let wide = 0
if exists('g:termdebug_config') if exists('g:termdebug_config')
let wide = get(g:termdebug_config, 'wide', 0) let wide = get(g:termdebug_config, 'wide', 0)
@ -181,11 +182,11 @@ func s:StartDebug_internal(dict)
let &columns = wide let &columns = wide
" If we make the Vim window wider, use the whole left half for the debug " If we make the Vim window wider, use the whole left half for the debug
" windows. " windows.
let s:allleft = 1 let s:allleft = v:true
endif endif
let s:vertical = 1 let s:vertical = v:true
else else
let s:vertical = 0 let s:vertical = v:false
endif endif
" Override using a terminal window by setting g:termdebug_use_prompt to 1. " Override using a terminal window by setting g:termdebug_use_prompt to 1.
@ -226,24 +227,24 @@ endfunc
" Use when debugger didn't start or ended. " Use when debugger didn't start or ended.
func s:CloseBuffers() func s:CloseBuffers()
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybufnr
if s:asmbuf > 0 && bufexists(s:asmbuf) if s:asmbufnr > 0 && bufexists(s:asmbufnr)
exe 'bwipe! ' . s:asmbuf exe 'bwipe! ' . s:asmbufnr
endif endif
if s:varbuf > 0 && bufexists(s:varbuf) if s:varbufnr > 0 && bufexists(s:varbufnr)
exe 'bwipe! ' . s:varbuf exe 'bwipe! ' . s:varbufnr
endif endif
let s:running = 0 let s:running = v:false
unlet! s:gdbwin unlet! s:gdbwin
endfunc endfunc
func s:CheckGdbRunning() func s:IsGdbStarted()
if !s:gdb_running if !s:gdb_running
call s:Echoerr(string(s:GetCommand()[0]) . ' exited unexpectedly') call s:Echoerr(string(s:GetCommand()[0]) . ' exited unexpectedly')
call s:CloseBuffers() call s:CloseBuffers()
return '' return v:false
endif endif
return 'ok' return v:true
endfunc endfunc
" Open a terminal window without a job, to run the debugged program in. " Open a terminal window without a job, to run the debugged program in.
@ -258,7 +259,7 @@ func s:StartDebug_term(dict)
return return
endif endif
let pty_job_info = nvim_get_chan_info(s:pty_job_id) let pty_job_info = nvim_get_chan_info(s:pty_job_id)
let s:ptybuf = pty_job_info['buffer'] let s:ptybufnr = pty_job_info['buffer']
let pty = pty_job_info['pty'] let pty = pty_job_info['pty']
let s:ptywin = win_getid() let s:ptywin = win_getid()
if s:vertical if s:vertical
@ -279,11 +280,11 @@ func s:StartDebug_term(dict)
" hide terminal buffer " hide terminal buffer
if s:comm_job_id == 0 if s:comm_job_id == 0
call s:Echoerr('Invalid argument (or job table is full) while opening communication terminal window') call s:Echoerr('Invalid argument (or job table is full) while opening communication terminal window')
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybufnr
return return
elseif s:comm_job_id == -1 elseif s:comm_job_id == -1
call s:Echoerr('Failed to open the communication terminal window') call s:Echoerr('Failed to open the communication terminal window')
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybufnr
return return
endif endif
let comm_job_info = nvim_get_chan_info(s:comm_job_id) let comm_job_info = nvim_get_chan_info(s:comm_job_id)
@ -324,7 +325,7 @@ func s:StartDebug_term(dict)
let s:gdb_job_id = termopen(gdb_cmd, {'on_exit': function('s:EndTermDebug')}) let s:gdb_job_id = termopen(gdb_cmd, {'on_exit': function('s:EndTermDebug')})
if s:gdb_job_id == 0 if s:gdb_job_id == 0
call s:Echoerr('Invalid argument (or job table is full) while opening gdb terminal window') call s:Echoerr('Invalid argument (or job table is full) while opening gdb terminal window')
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybufnr
return return
elseif s:gdb_job_id == -1 elseif s:gdb_job_id == -1
call s:Echoerr('Failed to open the gdb terminal window') call s:Echoerr('Failed to open the gdb terminal window')
@ -334,18 +335,18 @@ func s:StartDebug_term(dict)
let s:gdb_running = v:true let s:gdb_running = v:true
let s:starting = v:true let s:starting = v:true
let gdb_job_info = nvim_get_chan_info(s:gdb_job_id) let gdb_job_info = nvim_get_chan_info(s:gdb_job_id)
let s:gdbbuf = gdb_job_info['buffer'] let s:gdbbufnr = gdb_job_info['buffer']
let s:gdbwin = win_getid() let s:gdbwin = win_getid()
" Wait for the "startupdone" message before sending any commands. " Wait for the "startupdone" message before sending any commands.
let try_count = 0 let try_count = 0
while 1 while 1
if s:CheckGdbRunning() != 'ok' if !s:IsGdbStarted()
return return
endif endif
for lnum in range(1, 200) for lnum in range(1, 200)
if get(getbufline(s:gdbbuf, lnum), 0, '') =~ 'startupdone' if get(getbufline(s:gdbbufnr, lnum), 0, '') =~ 'startupdone'
let try_count = 9999 let try_count = 9999
break break
endif endif
@ -371,14 +372,14 @@ func s:StartDebug_term(dict)
" why the debugger doesn't work. " why the debugger doesn't work.
let try_count = 0 let try_count = 0
while 1 while 1
if s:CheckGdbRunning() != 'ok' if !s:IsGdbStarted()
return return
endif endif
let response = '' let response = ''
for lnum in range(1, 200) for lnum in range(1, 200)
let line1 = get(getbufline(s:gdbbuf, lnum), 0, '') let line1 = get(getbufline(s:gdbbufnr, lnum), 0, '')
let line2 = get(getbufline(s:gdbbuf, lnum + 1), 0, '') let line2 = get(getbufline(s:gdbbufnr, lnum + 1), 0, '')
if line1 =~ 'new-ui mi ' if line1 =~ 'new-ui mi '
" response can be in the same line or the next line " response can be in the same line or the next line
let response = line1 . line2 let response = line1 . line2
@ -472,7 +473,7 @@ func s:StartDebug_prompt(dict)
\ }) \ })
if s:gdbjob == 0 if s:gdbjob == 0
call s:Echoerr('Invalid argument (or job table is full) while starting gdb job') call s:Echoerr('Invalid argument (or job table is full) while starting gdb job')
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybufnr
return return
elseif s:gdbjob == -1 elseif s:gdbjob == -1
call s:Echoerr('Failed to start the gdb job') call s:Echoerr('Failed to start the gdb job')
@ -481,7 +482,7 @@ func s:StartDebug_prompt(dict)
endif endif
exe $'au BufUnload <buffer={s:promptbuf}> ++once call jobstop(s:gdbjob)' exe $'au BufUnload <buffer={s:promptbuf}> ++once call jobstop(s:gdbjob)'
let s:ptybuf = 0 let s:ptybufnr = 0
if has('win32') if has('win32')
" MS-Windows: run in a new console window for maximum compatibility " MS-Windows: run in a new console window for maximum compatibility
call s:SendCommand('set new-console on') call s:SendCommand('set new-console on')
@ -498,7 +499,7 @@ func s:StartDebug_prompt(dict)
return return
endif endif
let pty_job_info = nvim_get_chan_info(s:pty_job_id) let pty_job_info = nvim_get_chan_info(s:pty_job_id)
let s:ptybuf = pty_job_info['buffer'] let s:ptybufnr = pty_job_info['buffer']
let pty = pty_job_info['pty'] let pty = pty_job_info['pty']
let s:ptywin = win_getid() let s:ptywin = win_getid()
call s:SendCommand('tty ' . pty) call s:SendCommand('tty ' . pty)
@ -602,7 +603,7 @@ endfunc
func s:SendResumingCommand(cmd) func s:SendResumingCommand(cmd)
if s:stopped if s:stopped
" reset s:stopped here, it may take a bit of time before we get a response " reset s:stopped here, it may take a bit of time before we get a response
let s:stopped = 0 let s:stopped = v:false
" call ch_log('assume that program is running after this command') " call ch_log('assume that program is running after this command')
call s:SendCommand(a:cmd) call s:SendCommand(a:cmd)
" else " else
@ -776,16 +777,16 @@ endfunc
func s:EndDebugCommon() func s:EndDebugCommon()
let curwinid = win_getid() let curwinid = win_getid()
if exists('s:ptybuf') && s:ptybuf if exists('s:ptybufnr') && s:ptybufnr
exe 'bwipe! ' . s:ptybuf exe 'bwipe! ' . s:ptybufnr
endif endif
if s:asmbuf > 0 && bufexists(s:asmbuf) if s:asmbufnr > 0 && bufexists(s:asmbufnr)
exe 'bwipe! ' . s:asmbuf exe 'bwipe! ' . s:asmbufnr
endif endif
if s:varbuf > 0 && bufexists(s:varbuf) if s:varbufnr > 0 && bufexists(s:varbufnr)
exe 'bwipe! ' . s:varbuf exe 'bwipe! ' . s:varbufnr
endif endif
let s:running = 0 let s:running = v:false
" Restore 'signcolumn' in all buffers for which it was set. " Restore 'signcolumn' in all buffers for which it was set.
call win_gotoid(s:sourcewin) call win_gotoid(s:sourcewin)
@ -1186,7 +1187,7 @@ endfunc
func s:Until(at) func s:Until(at)
if s:stopped if s:stopped
" reset s:stopped here, it may take a bit of time before we get a response " reset s:stopped here, it may take a bit of time before we get a response
let s:stopped = 0 let s:stopped = v:false
" call ch_log('assume that program is running after this command') " call ch_log('assume that program is running after this command')
" Use the fname:lnum format " Use the fname:lnum format
let at = empty(a:at) ? let at = empty(a:at) ?
@ -1322,9 +1323,9 @@ func s:Evaluate(range, arg)
return return
endif endif
let expr = s:GetEvaluationExpression(a:range, a:arg) let expr = s:GetEvaluationExpression(a:range, a:arg)
let s:evalFromBalloonExpr = 1 let s:evalFromBalloonExpr = v:true
let s:evalFromBalloonExprResult = '' let s:evalFromBalloonExprResult = ''
let s:ignoreEvalError = 0 let s:ignoreEvalError = v:false
call s:SendEval(expr) call s:SendEval(expr)
endfunc endfunc
@ -1343,12 +1344,12 @@ func s:GetEvaluationExpression(range, arg)
let expr = s:CleanupExpr(@v) let expr = s:CleanupExpr(@v)
call setpos('.', pos) call setpos('.', pos)
call setreg('v', reg, regt) call setreg('v', reg, regt)
let s:evalFromBalloonExpr = 1 let s:evalFromBalloonExpr = v:true
else else
" no evaluation provided: get from C-expression under cursor " no evaluation provided: get from C-expression under cursor
" TODO: allow filetype specific lookup #9057 " TODO: allow filetype specific lookup #9057
let expr = expand('<cexpr>') let expr = expand('<cexpr>')
let s:evalFromBalloonExpr = 1 let s:evalFromBalloonExpr = v:true
endif endif
return expr return expr
endfunc endfunc
@ -1376,8 +1377,8 @@ func s:CleanupExpr(expr)
return expr return expr
endfunc endfunc
let s:ignoreEvalError = 0 let s:ignoreEvalError = v:false
let s:evalFromBalloonExpr = 0 let s:evalFromBalloonExpr = v:false
let s:evalFromBalloonExprResult = '' let s:evalFromBalloonExprResult = ''
let s:eval_float_win_id = -1 let s:eval_float_win_id = -1
@ -1419,7 +1420,7 @@ func s:HandleEvaluate(msg)
if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$' if s:evalexpr[0] != '*' && value =~ '^0x' && value != '0x0' && value !~ '"$'
" Looks like a pointer, also display what it points to. " Looks like a pointer, also display what it points to.
let s:ignoreEvalError = 1 let s:ignoreEvalError = v:true
call s:SendEval('*' . s:evalexpr) call s:SendEval('*' . s:evalexpr)
endif endif
endfunc endfunc
@ -1428,8 +1429,8 @@ endfunc
func s:HandleError(msg) func s:HandleError(msg)
if s:ignoreEvalError if s:ignoreEvalError
" Result of s:SendEval() failed, ignore. " Result of s:SendEval() failed, ignore.
let s:ignoreEvalError = 0 let s:ignoreEvalError = v:false
let s:evalFromBalloonExpr = 0 let s:evalFromBalloonExpr = v:false
return return
endif endif
let msgVal = substitute(a:msg, '.*msg="\(.*\)"', '\1', '') let msgVal = substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
@ -1489,11 +1490,11 @@ func s:GotoAsmwinOrCreateIt()
setlocal signcolumn=no setlocal signcolumn=no
setlocal modifiable setlocal modifiable
if s:asmbuf > 0 && bufexists(s:asmbuf) if s:asmbufnr > 0 && bufexists(s:asmbufnr)
exe 'buffer' . s:asmbuf exe 'buffer' . s:asmbufnr
elseif empty(glob('Termdebug-asm-listing')) elseif empty(glob('Termdebug-asm-listing'))
silent file Termdebug-asm-listing silent file Termdebug-asm-listing
let s:asmbuf = bufnr('Termdebug-asm-listing') let s:asmbufnr = bufnr('Termdebug-asm-listing')
else else
call s:Echoerr("You have a file/folder named 'Termdebug-asm-listing'. call s:Echoerr("You have a file/folder named 'Termdebug-asm-listing'.
\ Please exit and rename it because Termdebug may not work as expected.") \ Please exit and rename it because Termdebug may not work as expected.")
@ -1561,11 +1562,11 @@ func s:GotoVariableswinOrCreateIt()
setlocal signcolumn=no setlocal signcolumn=no
setlocal modifiable setlocal modifiable
if s:varbuf > 0 && bufexists(s:varbuf) if s:varbufnr > 0 && bufexists(s:varbufnr)
exe 'buffer' . s:varbuf exe 'buffer' . s:varbufnr
elseif empty(glob('Termdebug-variables-listing')) elseif empty(glob('Termdebug-variables-listing'))
silent file Termdebug-variables-listing silent file Termdebug-variables-listing
let s:varbuf = bufnr('Termdebug-variables-listing') let s:varbufnr = bufnr('Termdebug-variables-listing')
else else
call s:Echoerr("You have a file/folder named 'Termdebug-variables-listing'. call s:Echoerr("You have a file/folder named 'Termdebug-variables-listing'.
\ Please exit and rename it because Termdebug may not work as expected.") \ Please exit and rename it because Termdebug may not work as expected.")
@ -1588,14 +1589,14 @@ func s:HandleCursor(msg)
if a:msg =~ '^\*stopped' if a:msg =~ '^\*stopped'
"call ch_log('program stopped') "call ch_log('program stopped')
let s:stopped = 1 let s:stopped = v:true
if a:msg =~ '^\*stopped,reason="exited-normally"' if a:msg =~ '^\*stopped,reason="exited-normally"'
let s:running = 0 let s:running = v:false
endif endif
elseif a:msg =~ '^\*running' elseif a:msg =~ '^\*running'
"call ch_log('program running') "call ch_log('program running')
let s:stopped = 0 let s:stopped = v:false
let s:running = 1 let s:running = v:true
endif endif
if a:msg =~ 'fullname=' if a:msg =~ 'fullname='

View File

@ -340,5 +340,16 @@ func Test_termdebug_bufnames()
unlet g:termdebug_config unlet g:termdebug_config
endfunc endfunc
function Test_termdebug_save_restore_variables()
let &mousemodel=''
Termdebug
call WaitForAssert({-> assert_equal(3, winnr('$'))})
call WaitForAssert({-> assert_match(&mousemodel, 'popup_setpos')})
wincmd t
quit!
call WaitForAssert({-> assert_equal(1, winnr('$'))})
call WaitForAssert({-> assert_true(empty(&mousemodel))})
endfunction
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab