summaryrefslogtreecommitdiffstats
path: root/runtime/pack/dist/opt/termdebug
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-19 04:05:15 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-09-19 04:05:15 +0000
commit6e9cd6b491267e6dff3e3f3f37d8af5f28e40672 (patch)
tree35661af16c4a0ef2a9a8e225d2d5cc82605ea289 /runtime/pack/dist/opt/termdebug
parentAdding upstream version 2:9.1.0496. (diff)
downloadvim-6e9cd6b491267e6dff3e3f3f37d8af5f28e40672.tar.xz
vim-6e9cd6b491267e6dff3e3f3f37d8af5f28e40672.zip
Adding upstream version 2:9.1.0698.upstream/2%9.1.0698
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'runtime/pack/dist/opt/termdebug')
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim625
1 files changed, 334 insertions, 291 deletions
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index d24ae57..377827e 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -4,7 +4,7 @@ vim9script
# Author: Bram Moolenaar
# Copyright: Vim license applies, see ":help license"
-# Last Change: 2024 Jun 16
+# Last Change: 2024 Jul 04
# Converted to Vim9: Ubaldo Tiberi <ubaldo.tiberi@gmail.com>
# WORK IN PROGRESS - The basics works stable, more to come
@@ -15,7 +15,7 @@ vim9script
# There are two ways to run gdb:
# - In a terminal window; used if possible, does not work on MS-Windows
-# Not used when g:termdebug_use_prompt is set to 1.
+# Not used when g:termdebug_use_prompt is set to true.
# - Using a "prompt" buffer; may use a terminal window for the program
# For both the current window is used to view source code and shows the
@@ -42,18 +42,33 @@ def Echoerr(msg: string)
echohl ErrorMsg | echom $'[termdebug] {msg}' | echohl None
enddef
+def Echowarn(msg: string)
+ echohl WarningMsg | echom $'[termdebug] {msg}' | echohl None
+enddef
# Variables to keep their status among multiple instances of Termdebug
# Avoid to source the script twice.
if exists('g:termdebug_loaded')
- Echoerr('Termdebug already loaded.')
- finish
+ Echoerr('Termdebug already loaded.')
+ finish
endif
g:termdebug_loaded = true
+g:termdebug_is_running = false
+
+
+# The command that starts debugging, e.g. ":Termdebug vim".
+# To end type "quit" in the gdb window.
+command -nargs=* -complete=file -bang Termdebug StartDebug(<bang>0, <f-args>)
+command -nargs=+ -complete=file -bang TermdebugCommand StartDebugCommand(<bang>0, <f-args>)
+
+enum Way
+ Prompt,
+ Terminal
+endenum
# Script variables declaration. These variables are re-initialized at every
# Termdebug instance
-var way: string
+var way: Way
var err: string
var pc_id: number
@@ -74,10 +89,12 @@ var varbufnr: number
var varbufname: string
var asmbufnr: number
var asmbufname: string
-var promptbuf: number
-# This is for the "debugged program" thing
+var promptbufnr: number
+# 'pty' refers to the "debugged-program" pty
var ptybufnr: number
+var ptybufname: string
var commbufnr: number
+var commbufname: string
var gdbjob: job
var gdb_channel: channel
@@ -110,7 +127,7 @@ var evalexpr: string
# Remember the old value of 'signcolumn' for each buffer that it's set in, so
# that we can restore the value for all buffers.
var signcolumn_buflist: list<number>
-var save_columns: number
+var saved_columns: number
var allleft: bool
# This was s:vertical but I cannot use vertical as variable name
@@ -120,20 +137,19 @@ var winbar_winids: list<number>
var saved_mousemodel: string
-var k_map_saved: dict<any>
-var plus_map_saved: dict<any>
-var minus_map_saved: dict<any>
-
+var saved_K_map: dict<any>
+var saved_plus_map: dict<any>
+var saved_minus_map: dict<any>
def InitScriptVariables()
if exists('g:termdebug_config') && has_key(g:termdebug_config, 'use_prompt')
- way = g:termdebug_config['use_prompt'] ? 'prompt' : 'terminal'
+ way = g:termdebug_config['use_prompt'] ? Way.Prompt : Way.Terminal
elseif exists('g:termdebug_use_prompt')
- way = g:termdebug_use_prompt
+ way = g:termdebug_use_prompt ? Way.Prompt : Way.Terminal
elseif has('terminal') && !has('win32')
- way = 'terminal'
+ way = Way.Terminal
else
- way = 'prompt'
+ way = Way.Prompt
endif
err = ''
@@ -154,9 +170,11 @@ def InitScriptVariables()
varbufname = 'Termdebug-variables-listing'
asmbufnr = 0
asmbufname = 'Termdebug-asm-listing'
- promptbuf = 0
- # This is for the "debugged program" thing
+ promptbufnr = 0
+ # This is for the "debugged-program" thing
+ ptybufname = "debugged-program"
ptybufnr = 0
+ commbufname = "gdb-communication"
commbufnr = 0
gdbjob = null_job
@@ -190,23 +208,87 @@ def InitScriptVariables()
# Remember the old value of 'signcolumn' for each buffer that it's set in, so
# that we can restore the value for all buffers.
signcolumn_buflist = [bufnr()]
- save_columns = 0
+ saved_columns = &columns
winbar_winids = []
- k_map_saved = null_dict
- plus_map_saved = null_dict
- minus_map_saved = null_dict
+ saved_K_map = maparg('K', 'n', false, true)
+ saved_plus_map = maparg('+', 'n', false, true)
+ saved_minus_map = maparg('-', 'n', false, true)
if has('menu')
- saved_mousemodel = null_string
+ saved_mousemodel = &mousemodel
+ endif
+enddef
+
+def SanityCheck(): bool
+ var gdb_cmd = GetCommand()[0]
+ var cwd = $'{getcwd()}/'
+ if exists('+shellslash') && !&shellslash
+ # on windows, need to handle backslash
+ cwd->substitute('\\', '/', 'g')
+ endif
+ var is_check_ok = true
+ # Need either the +terminal feature or +channel and the prompt buffer.
+ # The terminal feature does not work with gdb on win32.
+ if (way is Way.Prompt) && !has('channel')
+ err = 'Cannot debug, +channel feature is not supported'
+ elseif (way is Way.Prompt) && !exists('*prompt_setprompt')
+ err = 'Cannot debug, missing prompt buffer support'
+ elseif (way is Way.Prompt) && !empty(glob($'{cwd}{gdb_cmd}'))
+ err = $"You have a file/folder named '{gdb_cmd}' in the current directory Termdebug may not work properly. Please exit and rename such a file/folder."
+ elseif !empty(glob($'{cwd}{asmbufname}'))
+ err = $"You have a file/folder named '{asmbufname}' in the current directory Termdebug may not work properly. Please exit and rename such a file/folder."
+ elseif !empty(glob($'{cwd}{varbufname}'))
+ err = $"You have a file/folder named '{varbufname}' in the current directory Termdebug may not work properly. Please exit and rename such a file/folder."
+ elseif !executable(gdb_cmd)
+ err = $"Cannot execute debugger program '{gdb_cmd}'"
+ endif
+
+ if !empty(err)
+ Echoerr(err)
+ is_check_ok = false
+ endif
+ return is_check_ok
+enddef
+
+def DeprecationWarnings()
+ # TODO Remove the deprecated features after 1 Jan 2025.
+ var config_param = ''
+ if exists('g:termdebug_wide')
+ config_param = 'g:termdebug_wide'
+ elseif exists('g:termdebug_popup')
+ config_param = 'g:termdebug_popup'
+ elseif exists('g:termdebugger')
+ config_param = 'g:termdebugger'
+ elseif exists('g:termdebug_variables_window')
+ config_param = 'g:termdebug_variables_window'
+ elseif exists('g:termdebug_disasm_window')
+ config_param = 'g:termdebug_disasm_window'
+ elseif exists('g:termdebug_map_K')
+ config_param = 'g:termdebug_map_K'
+ elseif exists('g:termdebug_use_prompt')
+ config_param = 'g:termdebug_use_prompt'
+ endif
+
+ if !empty(config_param)
+ Echowarn($"Deprecation Warning: '{config_param}' parameter
+ \ is deprecated and will be removed in the future. See ':h g:termdebug_config' for alternatives.")
endif
-enddef
-# The command that starts debugging, e.g. ":Termdebug vim".
-# To end type "quit" in the gdb window.
-command -nargs=* -complete=file -bang Termdebug StartDebug(<bang>0, <f-args>)
-command -nargs=+ -complete=file -bang TermdebugCommand StartDebugCommand(<bang>0, <f-args>)
+ # termdebug config types
+ if exists('g:termdebug_config') && !empty(g:termdebug_config)
+ for key in keys(g:termdebug_config)
+ if index(['disasm_window', 'variables_window', 'use_prompt', 'map_K', 'map_minus', 'map_plus'], key) != -1
+ if typename(g:termdebug_config[key]) == 'number'
+ var val = g:termdebug_config[key]
+ Echowarn($"Deprecation Warning: 'g:termdebug_config[\"{key}\"] = {val}' will be deprecated.
+ \ Please use 'g:termdebug_config[\"{key}\"] = {val != 0}'" )
+ endif
+ endif
+ endfor
+ endif
+enddef
# Take a breakpoint number as used by GDB and turn it into an integer.
# The breakpoint may contain a dot: 123.4 -> 123004
@@ -228,7 +310,7 @@ enddef
# Define the default highlighting, using the current 'background' value.
def InitHighlight()
- Highlight(1, '', &background)
+ Highlight(true, '', &background)
hi default debugBreakpoint term=reverse ctermbg=red guibg=red
hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
enddef
@@ -244,18 +326,19 @@ enddef
# Get the command to execute the debugger as a list, defaults to ["gdb"].
def GetCommand(): list<string>
- var cmd = 'gdb'
+ var cmd: any
if exists('g:termdebug_config')
cmd = get(g:termdebug_config, 'command', 'gdb')
elseif exists('g:termdebugger')
cmd = g:termdebugger
+ else
+ cmd = 'gdb'
endif
return type(cmd) == v:t_list ? copy(cmd) : [cmd]
enddef
def StartDebug(bang: bool, ...gdb_args: list<string>)
- InitScriptVariables()
# First argument is the command to debug, second core file or process ID.
StartDebug_internal({gdb_args: gdb_args, bang: bang})
enddef
@@ -265,22 +348,25 @@ def StartDebugCommand(bang: bool, ...args: list<string>)
StartDebug_internal({gdb_args: [args[0]], proc_args: args[1 : ], bang: bang})
enddef
-
def StartDebug_internal(dict: dict<any>)
- if gdbwin > 0
+ if g:termdebug_is_running
Echoerr('Terminal debugger already running, cannot run two')
return
endif
- var gdbcmd = GetCommand()
- if !executable(gdbcmd[0])
- Echoerr($'Cannot execute debugger program "{gdbcmd[0]}"')
+
+ InitScriptVariables()
+ if !SanityCheck()
return
endif
+ DeprecationWarnings()
if exists('#User#TermdebugStartPre')
doauto <nomodeline> User TermdebugStartPre
endif
+ # Uncomment this line to write logging in "debuglog".
+ # ch_logfile('debuglog', 'w')
+
# Assume current window is the source code window
sourcewin = win_getid()
var wide = 0
@@ -292,7 +378,6 @@ def StartDebug_internal(dict: dict<any>)
endif
if wide > 0
if &columns < wide
- save_columns = &columns
&columns = wide
# If we make the Vim window wider, use the whole left half for the debug
# windows.
@@ -303,7 +388,7 @@ def StartDebug_internal(dict: dict<any>)
vvertical = false
endif
- if way == 'prompt'
+ if way is Way.Prompt
StartDebug_prompt(dict)
else
StartDebug_term(dict)
@@ -324,44 +409,34 @@ def StartDebug_internal(dict: dict<any>)
if exists('#User#TermdebugStartPost')
doauto <nomodeline> User TermdebugStartPost
endif
+ g:termdebug_is_running = true
enddef
# Use when debugger didn't start or ended.
def CloseBuffers()
- var bufnames = ['debugged\ program', 'gdb\ communication', asmbufname, varbufname]
- for bufname in bufnames
- var buf_nr = bufnr(bufname)
+ var buf_numbers = [promptbufnr, ptybufnr, commbufnr, asmbufnr, varbufnr]
+ for buf_nr in buf_numbers
if buf_nr > 0 && bufexists(buf_nr)
- exe $'bwipe! {bufname}'
+ exe $'bwipe! {buf_nr}'
endif
endfor
-
- running = 0
- gdbwin = 0
enddef
-# IsGdbRunning(): bool may be a better name?
def IsGdbStarted(): bool
var gdbproc_status = job_status(term_getjob(gdbbufnr))
if gdbproc_status !=# 'run'
- var cmd_name = string(GetCommand()[0])
- Echoerr($'{cmd_name} exited unexpectedly')
- CloseBuffers()
return false
endif
return true
enddef
-# Open a terminal window without a job, to run the debugged program in.
-def StartDebug_term(dict: dict<any>)
+def CreateProgramPty(): string
ptybufnr = term_start('NONE', {
- term_name: 'debugged program',
+ term_name: ptybufname,
vertical: vvertical})
if ptybufnr == 0
- Echoerr('Failed to open the program terminal window')
- return
+ return null_string
endif
- var pty = job_info(term_getjob(ptybufnr))['tty_out']
ptywin = win_getid()
if vvertical
@@ -374,19 +449,23 @@ def StartDebug_term(dict: dict<any>)
endif
endif
+ return job_info(term_getjob(ptybufnr))['tty_out']
+enddef
+
+def CreateCommunicationPty(): string
# Create a hidden terminal window to communicate with gdb
commbufnr = term_start('NONE', {
- term_name: 'gdb communication',
- out_cb: function('CommOutput'),
+ term_name: commbufname,
+ out_cb: CommOutput,
hidden: 1
})
if commbufnr == 0
- Echoerr('Failed to open the communication terminal window')
- exe $'bwipe! {ptybufnr}'
- return
+ return null_string
endif
- var commpty = job_info(term_getjob(commbufnr))['tty_out']
+ return job_info(term_getjob(commbufnr))['tty_out']
+enddef
+def CreateGdbConsole(dict: dict<any>, pty: string, commpty: string): string
# Start the gdb buffer
var gdb_args = get(dict, 'gdb_args', [])
var proc_args = get(dict, 'proc_args', [])
@@ -422,24 +501,25 @@ def StartDebug_term(dict: dict<any>)
ch_log($'executing "{join(gdb_cmd)}"')
gdbbufnr = term_start(gdb_cmd, {
- term_name: gdbbufname,
- term_finish: 'close',
- })
+ term_name: gdbbufname,
+ term_finish: 'close',
+ })
if gdbbufnr == 0
- Echoerr('Failed to open the gdb terminal window')
- CloseBuffers()
- return
+ return 'Failed to open the gdb terminal window'
endif
gdbwin = win_getid()
# Wait for the "startupdone" message before sending any commands.
var counter = 0
var counter_max = 300
+ if exists('g:termdebug_config') && has_key(g:termdebug_config, 'timeout')
+ counter_max = g:termdebug_config['timeout']
+ endif
+
var success = false
while !success && counter < counter_max
if !IsGdbStarted()
- CloseBuffers()
- return
+ return $'{gdbbufname} exited unexpectedly'
endif
for lnum in range(1, 200)
@@ -454,14 +534,12 @@ def StartDebug_term(dict: dict<any>)
endwhile
if !success
- Echoerr('Failed to startup the gdb program.')
- CloseBuffers()
- return
+ return 'Failed to startup the gdb program.'
endif
# ---- gdb started. Next, let's set the MI interface. ---
# Set arguments to be run.
- if len(proc_args)
+ if !empty(proc_args)
term_sendkeys(gdbbufnr, $"server set args {join(proc_args)}\r")
endif
@@ -476,7 +554,7 @@ def StartDebug_term(dict: dict<any>)
success = false
while !success && counter < counter_max
if !IsGdbStarted()
- return
+ return $'{gdbbufname} exited unexpectedly'
endif
var response = ''
@@ -487,10 +565,8 @@ def StartDebug_term(dict: dict<any>)
# response can be in the same line or the next line
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
- CloseBuffers()
- return
+ return 'Sorry, your gdb is too old, gdb 7.12 is required'
endif
if response =~ 'New UI allocated'
# Success!
@@ -509,11 +585,37 @@ def StartDebug_term(dict: dict<any>)
endwhile
if !success
- Echoerr('Cannot check if your gdb works, continuing anyway')
+ return 'Cannot check if your gdb works, continuing anyway'
+ endif
+ return ''
+enddef
+
+
+# Open a terminal window without a job, to run the debugged program in.
+def StartDebug_term(dict: dict<any>)
+
+ var programpty = CreateProgramPty()
+ if programpty is null_string
+ Echoerr('Failed to open the program terminal window')
+ CloseBuffers()
+ return
+ endif
+
+ var commpty = CreateCommunicationPty()
+ if commpty is null_string
+ Echoerr('Failed to open the communication terminal window')
+ CloseBuffers()
+ return
+ endif
+
+ var err_message = CreateGdbConsole(dict, programpty, commpty)
+ if !empty(err_message)
+ Echoerr(err_message)
+ CloseBuffers()
return
endif
- job_setoptions(term_getjob(gdbbufnr), {exit_cb: function('EndTermDebug')})
+ job_setoptions(term_getjob(gdbbufnr), {exit_cb: EndDebug})
# Set the filetype, this can be used to add mappings.
set filetype=termdebug
@@ -523,29 +625,22 @@ enddef
# Open a window with a prompt buffer to run gdb in.
def StartDebug_prompt(dict: dict<any>)
+ var gdb_cmd = GetCommand()
+ gdbbufname = gdb_cmd[0]
+
if vvertical
vertical new
else
new
endif
gdbwin = win_getid()
- promptbuf = bufnr('')
- prompt_setprompt(promptbuf, 'gdb> ')
+ promptbufnr = bufnr('')
+ prompt_setprompt(promptbufnr, 'gdb> ')
set buftype=prompt
+ exe $"file {gdbbufname}"
- if empty(glob('gdb'))
- file gdb
- elseif empty(glob('Termdebug-gdb-console'))
- file Termdebug-gdb-console
- else
- Echoerr("You have a file/folder named 'gdb' " ..
- "or 'Termdebug-gdb-console'. " ..
- "Please exit and rename them because Termdebug may not work " ..
- "as expected.")
- endif
-
- prompt_setcallback(promptbuf, function('PromptCallback'))
- prompt_setinterrupt(promptbuf, function('PromptInterrupt'))
+ prompt_setcallback(promptbufnr, PromptCallback)
+ prompt_setinterrupt(promptbufnr, PromptInterrupt)
if vvertical
# Assuming the source code window will get a signcolumn, use two more
@@ -556,7 +651,6 @@ def StartDebug_prompt(dict: dict<any>)
var gdb_args = get(dict, 'gdb_args', [])
var proc_args = get(dict, 'proc_args', [])
- var gdb_cmd = GetCommand()
# Add -quiet to avoid the intro message causing a hit-enter prompt.
gdb_cmd += ['-quiet']
# Disable pagination, it causes everything to stop at the gdb, needs to be run early
@@ -573,16 +667,16 @@ def StartDebug_prompt(dict: dict<any>)
ch_log($'executing "{join(gdb_cmd)}"')
gdbjob = job_start(gdb_cmd, {
- exit_cb: function('EndPromptDebug'),
- out_cb: function('GdbOutCallback'),
+ exit_cb: EndDebug,
+ out_cb: GdbOutCallback
})
if job_status(gdbjob) != "run"
Echoerr('Failed to start gdb')
- exe $'bwipe! {promptbuf}'
+ exe $'bwipe! {promptbufnr}'
return
endif
- exe $'au BufUnload <buffer={promptbuf}> ++once ' ..
- 'call job_stop(gdbjob, ''kill'')'
+ exe $'au BufUnload <buffer={promptbufnr}> ++once ' ..
+ 'call job_stop(gdbjob, ''kill'')'
# Mark the buffer modified so that it's not easy to close.
set modified
gdb_channel = job_getchannel(gdbjob)
@@ -623,7 +717,7 @@ def StartDebug_prompt(dict: dict<any>)
SendCommand('set breakpoint pending on')
# Set arguments to be run
- if len(proc_args)
+ if !empty(proc_args)
SendCommand($'set args {join(proc_args)}')
endif
@@ -669,7 +763,7 @@ enddef
# Send a command to gdb. "cmd" is the string without line terminator.
def SendCommand(cmd: string)
ch_log($'sending to gdb: {cmd}')
- if way == 'prompt'
+ if way is Way.Prompt
ch_sendraw(gdb_channel, $"{cmd}\n")
else
term_sendkeys(commbufnr, $"{cmd}\r")
@@ -678,7 +772,7 @@ enddef
# Interrupt or stop the program
def StopCommand()
- if way == 'prompt'
+ if way is Way.Prompt
PromptInterrupt()
else
SendCommand('-exec-interrupt')
@@ -687,7 +781,7 @@ enddef
# Continue the program
def ContinueCommand()
- if way == 'prompt'
+ if way is Way.Prompt
SendCommand('continue')
else
# using -exec-continue results in CTRL-C in the gdb window not working,
@@ -699,12 +793,12 @@ enddef
# This is global so that a user can create their mappings with this.
def g:TermDebugSendCommand(cmd: string)
- if way == 'prompt'
+ if way is Way.Prompt
ch_sendraw(gdb_channel, $"{cmd}\n")
else
- var do_continue = 0
+ var do_continue = false
if !stopped
- do_continue = 1
+ do_continue = true
StopCommand()
sleep 10m
endif
@@ -765,7 +859,7 @@ def GdbOutCallback(channel: channel, text: string)
# Drop the gdb prompt, we have our own.
# Drop status and echo'd commands.
if text == '(gdb) ' || text == '^done' ||
- (text[0] == '&' && text !~ '^&"disassemble')
+ (text[0] == '&' && text !~ '^&"disassemble')
return
endif
@@ -808,20 +902,18 @@ def DecodeMessage(quotedText: string, literal: bool): string
return ''
endif
var msg = quotedText
- ->substitute('^"\|[^\\]\zs".*', '', 'g')
- ->substitute('\\"', '"', 'g')
- #\ multi-byte characters arrive in octal form
- #\ NULL-values must be kept encoded as those break the string otherwise
- ->substitute('\\000', NullRepl, 'g')
- ->substitute('\\\(\o\o\o\)', (m) => nr2char(str2nr(m[1], 8)), 'g')
- # You could also use ->substitute('\\\\\(\o\o\o\)', '\=nr2char(str2nr(submatch(1), 8))', "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', NullRepl, 'g')
- ->substitute('\\\\', '\', 'g')
- ->substitute(NullRepl, '\\000', 'g')
+ ->substitute('^"\|[^\\]\zs".*', '', 'g')
+ ->substitute('\\"', '"', 'g')
+ #\ multi-byte characters arrive in octal form
+ #\ NULL-values must be kept encoded as those break the string otherwise
+ ->substitute('\\000', NullRepl, 'g')
+ ->substitute('\\\(\o\o\o\)', (m) => nr2char(str2nr(m[1], 8)), 'g')
+ # You could also use ->substitute('\\\\\(\o\o\o\)', '\=nr2char(str2nr(submatch(1), 8))', "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('\\\\', '\', 'g')
+ ->substitute(NullRepl, '\\000', 'g')
if !literal
return msg
->substitute('\\t', "\t", 'g')
@@ -857,32 +949,17 @@ def GetAsmAddr(msg: string): string
return addr
enddef
-
-def EndTermDebug(job: any, status: any)
+def EndDebug(job: any, status: any)
if exists('#User#TermdebugStopPre')
doauto <nomodeline> User TermdebugStopPre
endif
- if commbufnr > 0 && bufexists(commbufnr)
- exe $'bwipe! {commbufnr}'
+ if way is Way.Prompt
+ ch_log("Returning from EndDebug()")
endif
- gdbwin = 0
- EndDebugCommon()
-enddef
-def EndDebugCommon()
var curwinid = win_getid()
-
- if ptybufnr > 0 && bufexists(ptybufnr)
- exe $'bwipe! {ptybufnr}'
- endif
- if asmbufnr > 0 && bufexists(asmbufnr)
- exe $'bwipe! {asmbufnr}'
- endif
- if varbufnr > 0 && bufexists(varbufnr)
- exe $'bwipe! {varbufnr}'
- endif
- running = false
+ CloseBuffers()
# Restore 'signcolumn' in all buffers for which it was set.
win_gotoid(sourcewin)
@@ -904,9 +981,7 @@ def EndDebugCommon()
win_gotoid(curwinid)
- if save_columns > 0
- &columns = save_columns
- endif
+ &columns = saved_columns
if has("balloon_eval") || has("balloon_eval_term")
set balloonexpr=
@@ -923,23 +998,9 @@ def EndDebugCommon()
endif
au! TermDebug
+ g:termdebug_is_running = false
enddef
-def EndPromptDebug(job: any, status: any)
- if exists('#User#TermdebugStopPre')
- doauto <nomodeline> User TermdebugStopPre
- endif
-
- if bufexists(promptbuf)
- exe $'bwipe! {promptbuf}'
- endif
-
- EndDebugCommon()
- gdbwin = 0
- ch_log("Returning from EndPromptDebug()")
-enddef
-
-
# Disassembly window - added by Michael Sartain
#
# - CommOutput: &"disassemble $pc\n"
@@ -990,11 +1051,11 @@ def HandleDisasmMsg(msg: string)
endif
elseif msg !~ '^&"disassemble'
var value = substitute(msg, '^\~\"[ ]*', '', '')
- ->substitute('^=>[ ]*', '', '')
- ->substitute('\\n\"\r$', '', '')
- ->substitute('\\n\"$', '', '')
- ->substitute('\r', '', '')
- ->substitute('\\t', ' ', 'g')
+ ->substitute('^=>[ ]*', '', '')
+ ->substitute('\\n\"\r$', '', '')
+ ->substitute('\\n\"$', '', '')
+ ->substitute('\r', '', '')
+ ->substitute('\\t', ' ', 'g')
if value != '' || !empty(asm_lines)
add(asm_lines, value)
@@ -1070,9 +1131,9 @@ def CommOutput(chan: channel, message: string)
if msg =~ '^\(\*stopped\|\*running\|=thread-selected\)'
HandleCursor(msg)
elseif msg =~ '^\^done,bkpt=' || msg =~ '^=breakpoint-created,'
- HandleNewBreakpoint(msg, 0)
+ HandleNewBreakpoint(msg, false)
elseif msg =~ '^=breakpoint-modified,'
- HandleNewBreakpoint(msg, 1)
+ HandleNewBreakpoint(msg, true)
elseif msg =~ '^=breakpoint-deleted,'
HandleBreakpointDelete(msg)
elseif msg =~ '^=thread-group-started'
@@ -1127,74 +1188,70 @@ def InstallCommands()
command Source GotoSourcewinOrCreateIt()
command Asm GotoAsmwinOrCreateIt()
command Var GotoVariableswinOrCreateIt()
- command Winbar InstallWinbar(1)
+ command Winbar InstallWinbar(true)
- var map = 1
+ var map = true
if exists('g:termdebug_config')
- map = get(g:termdebug_config, 'map_K', 1)
+ map = get(g:termdebug_config, 'map_K', true)
elseif exists('g:termdebug_map_K')
map = g:termdebug_map_K
endif
if map
- k_map_saved = maparg('K', 'n', 0, 1)
- if !empty(k_map_saved) && !k_map_saved.buffer || empty(k_map_saved)
+ if !empty(saved_K_map) && !saved_K_map.buffer || empty(saved_K_map)
nnoremap K :Evaluate<CR>
endif
endif
- map = 1
+ map = true
if exists('g:termdebug_config')
- map = get(g:termdebug_config, 'map_plus', 1)
+ map = get(g:termdebug_config, 'map_plus', true)
endif
if map
- plus_map_saved = maparg('+', 'n', 0, 1)
- if !empty(plus_map_saved) && !plus_map_saved.buffer || empty(plus_map_saved)
+ if !empty(saved_plus_map) && !saved_plus_map.buffer || empty(saved_plus_map)
nnoremap <expr> + $'<Cmd>{v:count1}Up<CR>'
endif
endif
- map = 1
+ map = true
if exists('g:termdebug_config')
- map = get(g:termdebug_config, 'map_minus', 1)
+ map = get(g:termdebug_config, 'map_minus', true)
endif
if map
- minus_map_saved = maparg('-', 'n', 0, 1)
- if !empty(minus_map_saved) && !minus_map_saved.buffer || empty(minus_map_saved)
+ if !empty(saved_minus_map) && !saved_minus_map.buffer || empty(saved_minus_map)
nnoremap <expr> - $'<Cmd>{v:count1}Down<CR>'
endif
endif
if has('menu') && &mouse != ''
- InstallWinbar(0)
+ InstallWinbar(false)
- var pup = 1
+ var pup = true
if exists('g:termdebug_config')
- pup = get(g:termdebug_config, 'popup', 1)
+ pup = get(g:termdebug_config, 'popup', true)
elseif exists('g:termdebug_popup')
pup = g:termdebug_popup
endif
if pup
- saved_mousemodel = &mousemodel
&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>
+ an 1.210 PopUp.Set\ breakpoint <cmd>Break<CR>
+ an 1.220 PopUp.Clear\ breakpoint <cmd>Clear<CR>
+ an 1.230 PopUp.Run\ until <cmd>Until<CR>
+ an 1.240 PopUp.Evaluate <cmd>Evaluate<CR>
endif
endif
enddef
# Install the window toolbar in the current window.
-def InstallWinbar(force: number)
+def InstallWinbar(force: bool)
# install the window toolbar by default, can be disabled in the config
- var winbar = 1
+ var winbar = true
if exists('g:termdebug_config')
- winbar = get(g:termdebug_config, 'winbar', 1)
+ winbar = get(g:termdebug_config, 'winbar', true)
endif
if has('menu') && &mouse != '' && (winbar || force)
@@ -1232,40 +1289,26 @@ def DeleteCommands()
delcommand Var
delcommand Winbar
- if k_map_saved isnot null_dict
- if !empty(k_map_saved) && k_map_saved.buffer
- # pass
- elseif !empty(k_map_saved) && !k_map_saved.buffer
- nunmap K
- mapset(k_map_saved)
- elseif empty(k_map_saved)
- silent! nunmap K
- endif
- k_map_saved = null_dict
- endif
- if plus_map_saved isnot null_dict
- if !empty(plus_map_saved) && plus_map_saved.buffer
- # pass
- elseif !empty(plus_map_saved) && !plus_map_saved.buffer
- nunmap +
- mapset(plus_map_saved)
- elseif empty(plus_map_saved)
- silent! nunmap +
- endif
- plus_map_saved = null_dict
- endif
- if minus_map_saved isnot null_dict
- if !empty(minus_map_saved) && minus_map_saved.buffer
- # pass
- elseif !empty(minus_map_saved) && !minus_map_saved.buffer
- nunmap -
- mapset(minus_map_saved)
- elseif empty(minus_map_saved)
- silent! nunmap -
- endif
- minus_map_saved = null_dict
+
+ if !empty(saved_K_map) && !saved_K_map.buffer
+ mapset(saved_K_map)
+ elseif empty(saved_K_map)
+ silent! nunmap K
+ endif
+
+ if !empty(saved_plus_map) && !saved_plus_map.buffer
+ mapset(saved_plus_map)
+ elseif empty(saved_plus_map)
+ silent! nunmap +
+ endif
+
+ if !empty(saved_minus_map) && !saved_minus_map.buffer
+ mapset(saved_minus_map)
+ elseif empty(saved_minus_map)
+ silent! nunmap -
endif
+
if has('menu')
# Remove the WinBar entries from all windows where it was added.
var curwinid = win_getid()
@@ -1280,32 +1323,29 @@ def DeleteCommands()
endif
endfor
win_gotoid(curwinid)
- winbar_winids = []
-
- if saved_mousemodel isnot null_string
- &mousemodel = saved_mousemodel
- saved_mousemodel = null_string
- try
- aunmenu PopUp.-SEP3-
- aunmenu PopUp.Set\ breakpoint
- aunmenu PopUp.Clear\ breakpoint
- aunmenu PopUp.Run\ until
- aunmenu PopUp.Evaluate
- catch
- # ignore any errors in removing the PopUp menu
- endtry
- endif
+
+ &mousemodel = saved_mousemodel
+ try
+ aunmenu PopUp.-SEP3-
+ aunmenu PopUp.Set\ breakpoint
+ aunmenu PopUp.Clear\ breakpoint
+ aunmenu PopUp.Run\ until
+ aunmenu PopUp.Evaluate
+ catch
+ # ignore any errors in removing the PopUp menu
+ endtry
endif
sign_unplace('TermDebug')
- breakpoints = {}
- breakpoint_locations = {}
-
sign_undefine('debugPC')
sign_undefine(BreakpointSigns->map("'debugBreakpoint' .. v:val"))
- BreakpointSigns = []
enddef
+def QuoteArg(x: string): string
+ # Find all the occurrences of " and \ and escape them and double quote
+ # the resulting string.
+ return printf('"%s"', x ->substitute('[\\"]', '\\&', 'g'))
+enddef
# :Until - Execute until past a specified position or current line
def Until(at: string)
@@ -1316,7 +1356,7 @@ def Until(at: string)
ch_log('assume that program is running after this command')
# Use the fname:lnum format
- var AT = empty(at) ? $"{fnameescape(expand('%:p'))}:{line('.')}" : at
+ var AT = empty(at) ? QuoteArg($"{expand('%:p')}:{line('.')}") : at
SendCommand($'-exec-until {AT}')
else
ch_log('dropping command, program is running: exec-until')
@@ -1327,23 +1367,21 @@ enddef
def SetBreakpoint(at: string, tbreak=false)
# Setting a breakpoint may not work while the program is running.
# Interrupt to make it work.
- var do_continue = 0
+ var do_continue = false
if !stopped
- do_continue = 1
+ do_continue = true
StopCommand()
sleep 10m
endif
# Use the fname:lnum format, older gdb can't handle --source.
- var AT = empty(at) ? $"{fnameescape(expand('%:p'))}:{line('.')}" : at
+ var AT = empty(at) ? QuoteArg($"{expand('%:p')}:{line('.')}") : at
var cmd = ''
if tbreak
cmd = $'-break-insert -t {AT}'
else
cmd = $'-break-insert {AT}'
endif
- # OK
- # echom $"cmsd: {cmd}"
SendCommand(cmd)
if do_continue
ContinueCommand()
@@ -1497,27 +1535,33 @@ def CleanupExpr(passed_expr: string): string
return expr
enddef
+def Balloon_show(expr: string)
+ if has("balloon_eval") || has("balloon_eval_term")
+ balloon_show(expr)
+ endif
+enddef
+
def HandleEvaluate(msg: string)
var value = msg
- ->substitute('.*value="\(.*\)"', '\1', '')
- ->substitute('\\"', '"', 'g')
- ->substitute('\\\\', '\\', 'g')
- #\ multi-byte characters arrive in octal form, replace everything but NULL values
- ->substitute('\\000', NullRepl, 'g')
- ->substitute('\\\(\o\o\o\)', (m) => nr2char(str2nr(m[1], 8)), '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', NullRep, 'g')
- #\ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
- ->substitute(NullRepl, '\\000', 'g')
+ ->substitute('.*value="\(.*\)"', '\1', '')
+ ->substitute('\\"', '"', 'g')
+ ->substitute('\\\\', '\\', 'g')
+ #\ multi-byte characters arrive in octal form, replace everything but NULL values
+ ->substitute('\\000', NullRepl, 'g')
+ ->substitute('\\\(\o\o\o\)', (m) => nr2char(str2nr(m[1], 8)), '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', NullRep, 'g')
+ #\ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
+ ->substitute(NullRepl, '\\000', 'g')
if evalFromBalloonExpr
if empty(evalFromBalloonExprResult)
evalFromBalloonExprResult = $'{evalexpr}: {value}'
else
evalFromBalloonExprResult ..= $' = {value}'
endif
- balloon_show(evalFromBalloonExprResult)
+ Balloon_show(evalFromBalloonExprResult)
else
echomsg $'"{evalexpr}": {value}'
endif
@@ -1567,19 +1611,22 @@ def GotoSourcewinOrCreateIt()
if !win_gotoid(sourcewin)
new
sourcewin = win_getid()
- InstallWinbar(0)
+ InstallWinbar(false)
endif
enddef
-def GetDisasmWindow(): number
- 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
+def GetDisasmWindow(): bool
+ # TODO Remove the deprecated features after 1 Jan 2025.
+ var val: any
+ if exists('g:termdebug_config') && has_key(g:termdebug_config, 'disasm_window')
+ val = g:termdebug_config['disasm_window']
+ elseif exists('g:termdebug_disasm_window')
+ val = g:termdebug_disasm_window
+ else
+ val = false
endif
- return 0
+ return typename(val) == 'number' ? val != 0 : val
enddef
def GetDisasmWindowHeight(): number
@@ -1619,13 +1666,9 @@ def GotoAsmwinOrCreateIt()
if asmbufnr > 0 && bufexists(asmbufnr)
exe $'buffer {asmbufnr}'
- elseif empty(glob('Termdebug-asm-listing'))
- silent file Termdebug-asm-listing
- asmbufnr = bufnr('Termdebug-asm-listing')
else
- Echoerr("You have a file/folder named 'Termdebug-asm-listing'. " ..
- "Please exit and rename it because Termdebug may not work " ..
- "as expected.")
+ exe $"silent file {asmbufname}"
+ asmbufnr = bufnr(asmbufname)
endif
if mdf != 'vert' && GetDisasmWindowHeight() > 0
@@ -1646,14 +1689,17 @@ def GotoAsmwinOrCreateIt()
endif
enddef
-def GetVariablesWindow(): number
- if exists('g:termdebug_config')
- return get(g:termdebug_config, 'variables_window', 0)
- endif
- if exists('g:termdebug_disasm_window')
- return g:termdebug_variables_window
+def GetVariablesWindow(): bool
+ # TODO Remove the deprecated features after 1 Jan 2025.
+ var val: any
+ if exists('g:termdebug_config') && has_key(g:termdebug_config, 'variables_window')
+ val = g:termdebug_config['variables_window']
+ elseif exists('g:termdebug_variables_window')
+ val = g:termdebug_variables_window
+ else
+ val = false
endif
- return 0
+ return typename(val) == 'number' ? val != 0 : val
enddef
def GetVariablesWindowHeight(): number
@@ -1691,15 +1737,12 @@ def GotoVariableswinOrCreateIt()
setlocal signcolumn=no
setlocal modifiable
+ # If exists, then open, otherwise create
if varbufnr > 0 && bufexists(varbufnr)
exe $'buffer {varbufnr}'
- elseif empty(glob('Termdebug-variables-listing'))
- silent file Termdebug-variables-listing
- varbufnr = bufnr('Termdebug-variables-listing')
else
- Echoerr("You have a file/folder named 'Termdebug-variables-listing'. " ..
- "Please exit and rename it because Termdebug may not work " ..
- "as expected.")
+ exe $"silent file {varbufname}"
+ varbufnr = bufnr(varbufname)
endif
if mdf != 'vert' && GetVariablesWindowHeight() > 0
@@ -1719,7 +1762,7 @@ def HandleCursor(msg: string)
if msg =~ '^\*stopped'
ch_log('program stopped')
- stopped = 1
+ stopped = true
if msg =~ '^\*stopped,reason="exited-normally"'
running = false
endif
@@ -1778,7 +1821,7 @@ def HandleCursor(msg: string)
# TODO: find existing window
exe $'split {fnameescape(fname)}'
sourcewin = win_getid()
- InstallWinbar(0)
+ InstallWinbar(false)
else
exe $'edit {fnameescape(fname)}'
endif
@@ -1790,7 +1833,7 @@ def HandleCursor(msg: string)
normal! zv
sign_unplace('TermDebug', {id: pc_id})
sign_place(pc_id, 'TermDebug', 'debugPC', fname,
- {lnum: str2nr(lnum), priority: 110})
+ {lnum: str2nr(lnum), priority: 110})
if !exists('b:save_signcolumn')
b:save_signcolumn = &signcolumn
add(signcolumn_buflist, bufnr())
@@ -1837,7 +1880,7 @@ enddef
# Handle setting a breakpoint
# Will update the sign that shows the breakpoint
-def HandleNewBreakpoint(msg: string, modifiedFlag: any)
+def HandleNewBreakpoint(msg: string, modifiedFlag: bool)
var nr = ''
if msg !~ 'fullname='