diff options
Diffstat (limited to 'runtime/pack/dist/opt/termdebug/plugin/termdebug.vim')
-rw-r--r-- | runtime/pack/dist/opt/termdebug/plugin/termdebug.vim | 212 |
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=' |