summaryrefslogtreecommitdiffstats
path: root/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/pack/dist/opt/termdebug/plugin/termdebug.vim')
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim212
1 files changed, 132 insertions, 80 deletions
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 1d4e338e17..ee77008492 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 22
+# 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,12 +42,15 @@ 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
@@ -87,7 +90,7 @@ var varbufname: string
var asmbufnr: number
var asmbufname: string
var promptbufnr: number
-# This is for the "debugged-program" thing
+# 'pty' refers to the "debugged-program" pty
var ptybufnr: number
var ptybufname: string
var commbufnr: number
@@ -220,6 +223,11 @@ 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.
@@ -227,11 +235,11 @@ def SanityCheck(): bool
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(gdb_cmd))
+ 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(asmbufname))
+ 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(varbufname))
+ 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}'"
@@ -244,6 +252,43 @@ def SanityCheck(): bool
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
+
+ # 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
@@ -313,13 +358,14 @@ def StartDebug_internal(dict: dict<any>)
if !SanityCheck()
return
endif
+ DeprecationWarnings()
if exists('#User#TermdebugStartPre')
doauto <nomodeline> User TermdebugStartPre
endif
# Uncomment this line to write logging in "debuglog".
- # call ch_logfile('debuglog', 'w')
+ # ch_logfile('debuglog', 'w')
# Assume current window is the source code window
sourcewin = win_getid()
@@ -410,7 +456,7 @@ def CreateCommunicationPty(): string
# Create a hidden terminal window to communicate with gdb
commbufnr = term_start('NONE', {
term_name: commbufname,
- out_cb: function('CommOutput'),
+ out_cb: CommOutput,
hidden: 1
})
if commbufnr == 0
@@ -455,9 +501,9 @@ def CreateGdbConsole(dict: dict<any>, pty: string, commpty: string): string
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
return 'Failed to open the gdb terminal window'
endif
@@ -493,7 +539,7 @@ def CreateGdbConsole(dict: dict<any>, pty: string, commpty: string): string
# ---- 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
@@ -569,7 +615,7 @@ def StartDebug_term(dict: dict<any>)
return
endif
- job_setoptions(term_getjob(gdbbufnr), {exit_cb: function('EndDebug')})
+ job_setoptions(term_getjob(gdbbufnr), {exit_cb: EndDebug})
# Set the filetype, this can be used to add mappings.
set filetype=termdebug
@@ -593,8 +639,8 @@ def StartDebug_prompt(dict: dict<any>)
set buftype=prompt
exe $"file {gdbbufname}"
- prompt_setcallback(promptbufnr, function('PromptCallback'))
- prompt_setinterrupt(promptbufnr, function('PromptInterrupt'))
+ prompt_setcallback(promptbufnr, PromptCallback)
+ prompt_setinterrupt(promptbufnr, PromptInterrupt)
if vvertical
# Assuming the source code window will get a signcolumn, use two more
@@ -621,8 +667,8 @@ def StartDebug_prompt(dict: dict<any>)
ch_log($'executing "{join(gdb_cmd)}"')
gdbjob = job_start(gdb_cmd, {
- exit_cb: function('EndDebug'),
- out_cb: function('GdbOutCallback'),
+ exit_cb: EndDebug,
+ out_cb: GdbOutCallback
})
if job_status(gdbjob) != "run"
Echoerr('Failed to start gdb')
@@ -630,7 +676,7 @@ def StartDebug_prompt(dict: dict<any>)
return
endif
exe $'au BufUnload <buffer={promptbufnr}> ++once ' ..
- 'call job_stop(gdbjob, ''kill'')'
+ 'call job_stop(gdbjob, ''kill'')'
# Mark the buffer modified so that it's not easy to close.
set modified
gdb_channel = job_getchannel(gdbjob)
@@ -671,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
@@ -813,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
@@ -856,18 +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('\\\\', '\', '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')
@@ -1005,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)
@@ -1085,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'
@@ -1191,10 +1237,10 @@ def InstallCommands()
if pup
&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
@@ -1277,7 +1323,6 @@ def DeleteCommands()
endif
endfor
win_gotoid(curwinid)
- # winbar_winids = []
&mousemodel = saved_mousemodel
try
@@ -1292,14 +1337,15 @@ def DeleteCommands()
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)
@@ -1310,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')
@@ -1329,7 +1375,7 @@ def SetBreakpoint(at: string, tbreak=false)
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}'
@@ -1491,18 +1537,18 @@ 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}'
@@ -1564,14 +1610,17 @@ def GotoSourcewinOrCreateIt()
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
@@ -1634,14 +1683,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
@@ -1775,7 +1827,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())
@@ -1822,7 +1874,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='