summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUbaldo Tiberi <ubaldo.tiberi@volvo.com>2024-06-05 21:27:38 +0200
committerChristian Brabandt <cb@256bit.org>2024-06-05 21:37:53 +0200
commit23f29ffc64276dd790581f98b86a0a6435b7eb22 (patch)
treeb77405ee6ecc98b14ea0e111e7fc505250cbfc2b
parent7cbed350f840b7ff96a5be6102f26ad57929b8b6 (diff)
runtime(termdebug): convert termdebug plugin to Vim9 script
closes: #14903 Signed-off-by: Ubaldo Tiberi <ubaldo.tiberi@volvo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--runtime/doc/terminal.txt24
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim2432
2 files changed, 1266 insertions, 1190 deletions
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index c99b882cf9..d7749ff262 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -1,4 +1,4 @@
-*terminal.txt* For Vim version 9.1. Last change: 2024 Mar 17
+*terminal.txt* For Vim version 9.1. Last change: 2024 Jun 05
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1332,8 +1332,8 @@ Put focus on the gdb window to type commands there. Some common ones are:
*:Run* *:Arguments*
In the window showing the source code these commands can be used to control
gdb:
- `:Run` [args] run the program with [args] or the previous arguments
- `:Arguments` {args} set arguments for the next `:Run`
+ :Run [args] run the program with [args] or the previous arguments
+ :Arguments {args} set arguments for the next `:Run`
*:Break* set a breakpoint at the cursor position
:Break {position}
@@ -1379,10 +1379,10 @@ breakpoint, or use the "Clear breakpoint" right-click menu entry.
Inspecting variables ~
*termdebug-variables* *:Evaluate*
- `:Evaluate` evaluate the expression under the cursor
- `K` same (see |termdebug_map_K| to disable)
- `:Evaluate` {expr} evaluate {expr}
- `:'<,'>Evaluate` evaluate the Visually selected text
+ :Evaluate evaluate the expression under the cursor
+ K same (see |termdebug_map_K| to disable)
+ :Evaluate {expr} evaluate {expr}
+ :'<,'>Evaluate evaluate the Visually selected text
This is similar to using "print" in the gdb window.
You can usually shorten `:Evaluate` to `:Ev`.
@@ -1390,14 +1390,14 @@ You can usually shorten `:Evaluate` to `:Ev`.
Navigating stack frames ~
*termdebug-frames* *:Frame* *:Up* *:Down*
- `:Frame` [frame] select frame [frame], which is a frame number,
+ :Frame [frame] select frame [frame], which is a frame number,
address, or function name (default: current frame)
- `:Up` [count] go up [count] frames (default: 1; the frame that
+ :Up [count] go up [count] frames (default: 1; the frame that
called the current)
- `+` same (see |termdebug_map_plus| to disable)
- `:Down` [count] go down [count] frames (default: 1; the frame called
+ + same (see |termdebug_map_plus| to disable)
+ :Down [count] go down [count] frames (default: 1; the frame called
by the current)
- `-` same (see |termdebug_map_minus| to disable)
+ - same (see |termdebug_map_minus| to disable)
Other commands ~
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 8eb3fff694..9d987e350a 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -1,419 +1,480 @@
-" Debugger plugin using gdb.
-"
-" Author: Bram Moolenaar
-" Copyright: Vim license applies, see ":help license"
-" Last Change: 2023 Nov 02
-"
-" 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
-" Not used when g:termdebug_use_prompt is set to 1.
-" - 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
-" current statement from gdb.
-"
-" USING A TERMINAL WINDOW
-"
-" Opens two visible terminal windows:
-" 1. runs a pty for the debugged program, as with ":term NONE"
-" 2. runs gdb, passing the pty of the debugged program
-" A third terminal window is hidden, it is used for communication with gdb.
-"
-" USING A PROMPT BUFFER
-"
-" Opens a window with a prompt buffer to communicate with gdb.
-" Gdb is run as a job with callbacks for I/O.
-" On Unix another terminal window is opened to run the debugged program
-" On MS-Windows a separate console is opened to run the debugged program
-"
-" The communication with gdb uses GDB/MI. See:
-" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
-
-" In case this gets sourced twice.
-if exists(':Termdebug')
+vim9script
+
+# Debugger plugin using gdb.
+
+# Author: Bram Moolenaar
+# Copyright: Vim license applies, see ":help license"
+# Last Change: 2024 Jun 03
+# Converted to Vim9: Ubaldo Tiberi <ubaldo.tiberi@volvo.com>
+
+# 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
+# Not used when g:termdebug_use_prompt is set to 1.
+# - 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
+# current statement from gdb.
+
+# USING A TERMINAL WINDOW
+
+# Opens two visible terminal windows:
+# 1. runs a pty for the debugged program, as with ":term NONE"
+# 2. runs gdb, passing the pty of the debugged program
+# A third terminal window is hidden, it is used for communication with gdb.
+
+# USING A PROMPT BUFFER
+
+# Opens a window with a prompt buffer to communicate with gdb.
+# Gdb is run as a job with callbacks for I/O.
+# On Unix another terminal window is opened to run the debugged program
+# On MS-Windows a separate console is opened to run the debugged program
+
+# The communication with gdb uses GDB/MI. See:
+# https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
+
+# In case this gets sourced twice.
+if exists('g:termdebug_loaded')
finish
endif
-
-" Need either the +terminal feature or +channel and the prompt buffer.
-" The terminal feature does not work with gdb on win32.
+g:termdebug_loaded = true
+
+var way = 'terminal'
+var err = 'no errors'
+
+var pc_id = 12
+var asm_id = 13
+var break_id = 14 # breakpoint number is added to this
+var stopped = 1
+var running = 0
+
+var parsing_disasm_msg = 0
+var asm_lines = []
+var asm_addr = ''
+
+# These shall be constants but cannot be initialized here
+# They indicate the buffer numbers of the main buffers used
+var gdbbuf = 0
+var varbuf = 0
+var asmbuf = 0
+var promptbuf = 0
+# This is for the "debugged program" thing
+var ptybuf = 0
+var commbuf = 0
+
+var gdbjob = null_job
+var gdb_channel = null_channel
+# These changes because they relate to windows
+var pid = 0
+var gdbwin = 0
+var varwin = 0
+var asmwin = 0
+var ptywin = 0
+var sourcewin = 0
+
+# Contains breakpoints that have been placed, key is a string with the GDB
+# breakpoint number.
+# Each entry is a dict, containing the sub-breakpoints. Key is the subid.
+# For a breakpoint that is just a number the subid is zero.
+# For a breakpoint "123.4" the id is "123" and subid is "4".
+# Example, when breakpoint "44", "123", "123.1" and "123.2" exist:
+# {'44': {'0': entry}, '123': {'0': entry, '1': entry, '2': entry}}
+var breakpoints = {}
+
+# Contains breakpoints by file/lnum. The key is "fname:lnum".
+# Each entry is a list of breakpoint IDs at that position.
+var breakpoint_locations = {}
+var BreakpointSigns: list<string> = []
+
+
+var evalFromBalloonExpr = 0
+var evalFromBalloonExprResult = ''
+var ignoreEvalError = 0
+var evalexpr = ''
+# 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 = [bufnr()]
+var save_columns = 0
+
+var allleft = 0
+# This was s:vertical but I cannot use vertical as variable name
+var vvertical = 0
+
+var winbar_winids = []
+var plus_map_saved = {}
+var minus_map_saved = {}
+var k_map_saved = {}
+var saved_mousemodel = ''
+
+
+# Need either the +terminal feature or +channel and the prompt buffer.
+# The terminal feature does not work with gdb on win32.
if has('terminal') && !has('win32')
- let s:way = 'terminal'
+ way = 'terminal'
elseif has('channel') && exists('*prompt_setprompt')
- let s:way = 'prompt'
+ way = 'prompt'
else
if has('terminal')
- let s:err = 'Cannot debug, missing prompt buffer support'
+ err = 'Cannot debug, missing prompt buffer support'
else
- let s:err = 'Cannot debug, +channel feature is not supported'
+ err = 'Cannot debug, +channel feature is not supported'
endif
- command -nargs=* -complete=file -bang Termdebug echoerr s:err
- command -nargs=+ -complete=file -bang TermdebugCommand echoerr s:err
+ command -nargs=* -complete=file -bang Termdebug echoerr err
+ command -nargs=+ -complete=file -bang TermdebugCommand echoerr err
finish
endif
-let s:keepcpo = &cpo
-set cpo&vim
-
-" The command that starts debugging, e.g. ":Termdebug vim".
-" To end type "quit" in the gdb window.
-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:running = 0
-
-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.
-func s:Breakpoint2SignNumber(id, subid)
- return s:break_id + a:id * 1000 + a:subid
-endfunction
-
-" Define or adjust the default highlighting, using background "new".
-" When the 'background' option is set then "old" has the old value.
-func s:Highlight(init, old, new)
- let default = a:init ? 'default ' : ''
- if a:new ==# 'light' && a:old !=# 'light'
- exe "hi " . default . "debugPC term=reverse ctermbg=lightblue guibg=lightblue"
- elseif a:new ==# 'dark' && a:old !=# 'dark'
- exe "hi " . default . "debugPC term=reverse ctermbg=darkblue guibg=darkblue"
- endif
-endfunc
-
-" Define the default highlighting, using the current 'background' value.
-func s:InitHighlight()
- call s:Highlight(1, '', &background)
+
+# 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>)
+
+
+# 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.
+def Breakpoint2SignNumber(id: number, subid: number): number
+ return break_id + id * 1000 + subid
+enddef
+
+# Define or adjust the default highlighting, using background "new".
+# When the 'background' option is set then "old" has the old value.
+def Highlight(init: bool, old: string, new: string)
+ var default = init ? 'default ' : ''
+ if new ==# 'light' && old !=# 'light'
+ exe "hi " .. default .. "debugPC term=reverse ctermbg=lightblue guibg=lightblue"
+ elseif new ==# 'dark' && old !=# 'dark'
+ exe "hi " .. default .. "debugPC term=reverse ctermbg=darkblue guibg=darkblue"
+ endif
+enddef
+
+# Define the default highlighting, using the current 'background' value.
+def InitHighlight()
+ Highlight(1, '', &background)
hi default debugBreakpoint term=reverse ctermbg=red guibg=red
hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
-endfunc
+enddef
-" Setup an autocommand to redefine the default highlight when the colorscheme
-" is changed.
-func s:InitAutocmd()
+# Setup an autocommand to redefine the default highlight when the colorscheme
+# is changed.
+def InitAutocmd()
augroup TermDebug
autocmd!
- autocmd ColorScheme * call s:InitHighlight()
+ autocmd ColorScheme * InitHighlight()
augroup END
-endfunc
+enddef
-" Get the command to execute the debugger as a list, defaults to ["gdb"].
-func s:GetCommand()
+# Get the command to execute the debugger as a list, defaults to ["gdb"].
+def GetCommand(): list<string>
+ var cmd = 'gdb'
if exists('g:termdebug_config')
- let cmd = get(g:termdebug_config, 'command', 'gdb')
+ cmd = get(g:termdebug_config, 'command', 'gdb')
elseif exists('g:termdebugger')
- let cmd = g:termdebugger
- else
- let cmd = 'gdb'
+ cmd = g:termdebugger
endif
return type(cmd) == v:t_list ? copy(cmd) : [cmd]
-endfunc
+enddef
+
+def Echoerr(msg: string)
+ echohl ErrorMsg | echom '[termdebug] ' .. msg | echohl None
+enddef
-func s:Echoerr(msg)
- echohl ErrorMsg | echom '[termdebug] ' .. a:msg | echohl None
-endfunc
+def StartDebug(bang: bool, ...gdb_args: list<string>)
+ # First argument is the command to debug, second core file or process ID.
+ StartDebug_internal({'gdb_args': gdb_args, 'bang': bang})
+enddef
-func s:StartDebug(bang, ...)
- " First argument is the command to debug, second core file or process ID.
- call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang})
-endfunc
+def StartDebugCommand(bang: bool, ...args: list<string>)
+ # First argument is the command to debug, rest are run arguments.
+ StartDebug_internal({'gdb_args': [args[0]], 'proc_args': args[1:], 'bang': bang})
+enddef
-func s:StartDebugCommand(bang, ...)
- " First argument is the command to debug, rest are run arguments.
- call s:StartDebug_internal({'gdb_args': [a:1], 'proc_args': a:000[1:], 'bang': a:bang})
-endfunc
-func s:StartDebug_internal(dict)
- if exists('s:gdbwin')
- call s:Echoerr('Terminal debugger already running, cannot run two')
+def StartDebug_internal(dict: dict<any>)
+ if gdbwin > 0
+ Echoerr('Terminal debugger already running, cannot run two')
return
endif
- let gdbcmd = s:GetCommand()
+ var gdbcmd = GetCommand()
if !executable(gdbcmd[0])
- call s:Echoerr('Cannot execute debugger program "' .. gdbcmd[0] .. '"')
+ Echoerr('Cannot execute debugger program "' .. gdbcmd[0] .. '"')
return
endif
- let s:ptywin = 0
- let s:pid = 0
- let s:asmwin = 0
- let s:asmbuf = 0
- let s:varwin = 0
- let s:varbuf = 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()
+ # Assume current window is the source code window
+ sourcewin = win_getid()
+ var wide = 0
- " 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)
+ wide = get(g:termdebug_config, 'wide', 0)
elseif exists('g:termdebug_wide')
- let wide = g:termdebug_wide
+ 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
+ save_columns = &columns
+ &columns = wide
+ # If we make the Vim window wider, use the whole left half for the debug
+ # windows.
+ allleft = 1
endif
- let s:vertical = 1
+ vvertical = 1
else
- let s:vertical = 0
+ vvertical = 0
endif
- " Override using a terminal window by setting g:termdebug_use_prompt to 1.
- let use_prompt = 0
+ # Override using a terminal window by setting g:termdebug_use_prompt to 1.
+ var use_prompt = 0
if exists('g:termdebug_config')
- let use_prompt = get(g:termdebug_config, 'use_prompt', 0)
+ use_prompt = get(g:termdebug_config, 'use_prompt', 0)
elseif exists('g:termdebug_use_prompt')
- let use_prompt = g:termdebug_use_prompt
+ use_prompt = g:termdebug_use_prompt
endif
if has('terminal') && !has('win32') && !use_prompt
- let s:way = 'terminal'
+ way = 'terminal'
else
- let s:way = 'prompt'
+ way = 'prompt'
endif
- if s:way == 'prompt'
- call s:StartDebug_prompt(a:dict)
+ if way == 'prompt'
+ StartDebug_prompt(dict)
else
- call s:StartDebug_term(a:dict)
+ StartDebug_term(dict)
endif
- if s:GetDisasmWindow()
- let curwinid = win_getid()
- call s:GotoAsmwinOrCreateIt()
- call win_gotoid(curwinid)
+ if GetDisasmWindow()
+ var curwinid = win_getid()
+ GotoAsmwinOrCreateIt()
+ win_gotoid(curwinid)
endif
- if s:GetVariablesWindow()
- let curwinid = win_getid()
- call s:GotoVariableswinOrCreateIt()
- call win_gotoid(curwinid)
+ if GetVariablesWindow()
+ var curwinid = win_getid()
+ GotoVariableswinOrCreateIt()
+ win_gotoid(curwinid)
endif
if exists('#User#TermdebugStartPost')
doauto <nomodeline> User TermdebugStartPost
endif
-endfunc
+enddef
-" Use when debugger didn't start or ended.
-func s:CloseBuffers()
- exe 'bwipe! ' . s:ptybuf
- exe 'bwipe! ' . s:commbuf
- if s:asmbuf > 0 && bufexists(s:asmbuf)
- exe 'bwipe! ' . s:asmbuf
+# Use when debugger didn't start or ended.
+def CloseBuffers()
+ exe 'bwipe! ' .. ptybuf
+ exe 'bwipe! ' .. commbuf
+ if asmbuf > 0 && bufexists(asmbuf)
+ exe 'bwipe! ' .. asmbuf
endif
- if s:varbuf > 0 && bufexists(s:varbuf)
- exe 'bwipe! ' . s:varbuf
+ if varbuf > 0 && bufexists(varbuf)
+ exe 'bwipe! ' .. varbuf
endif
- let s:running = 0
- unlet! s:gdbwin
-endfunc
+ running = 0
+ gdbwin = 0
+enddef
-func s:CheckGdbRunning()
- let gdbproc = term_getjob(s:gdbbuf)
- if gdbproc == v:null || job_status(gdbproc) !=# 'run'
- call s:Echoerr(string(s:GetCommand()[0]) . ' exited unexpectedly')
- call s:CloseBuffers()
+# IsGdbRunning(): bool may be a better name?
+def CheckGdbRunning(): string
+ var gdbproc = term_getjob(gdbbuf)
+ var gdbproc_status = 'unknown'
+ if type(gdbproc) == v:t_job
+ gdbproc_status = job_status(gdbproc)
+ endif
+ if gdbproc == v:null || gdbproc_status !=# 'run'
+ Echoerr(string(GetCommand()[0]) .. ' exited unexpectedly')
+ 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,
- \ })
- if s:ptybuf == 0
- call s:Echoerr('Failed to open the program terminal window')
+enddef
+
+# Open a terminal window without a job, to run the debugged program in.
+def StartDebug_term(dict: dict<any>)
+ ptybuf = term_start('NONE', {
+ \ 'term_name': 'debugged program',
+ \ 'vertical': vvertical,
+ \ })
+ if ptybuf == 0
+ Echoerr('Failed to open the program terminal window')
return
endif
- let pty = job_info(term_getjob(s:ptybuf))['tty_out']
- let s:ptywin = win_getid()
- if s:vertical
- " Assuming the source code window will get a signcolumn, use two more
- " columns for that, thus one less for the terminal window.
- exe (&columns / 2 - 1) . "wincmd |"
- if s:allleft
- " use the whole left column
+ var pty = job_info(term_getjob(ptybuf))['tty_out']
+ ptywin = win_getid()
+ if vvertical
+ # Assuming the source code window will get a signcolumn, use two more
+ # columns for that, thus one less for the terminal window.
+ exe ":" .. (&columns / 2 - 1) .. "wincmd |"
+ if allleft
+ # use the whole left column
wincmd H
endif
endif
- " Create a hidden terminal window to communicate with gdb
- let s:commbuf = term_start('NONE', {
- \ 'term_name': 'gdb communication',
- \ 'out_cb': function('s:CommOutput'),
- \ 'hidden': 1,
- \ })
- if s:commbuf == 0
- call s:Echoerr('Failed to open the communication terminal window')
- exe 'bwipe! ' . s:ptybuf
+ # Create a hidden terminal window to communicate with gdb
+ commbuf = term_start('NONE', {
+ \ 'term_name': 'gdb communication',
+ \ 'out_cb': function('CommOutput'),
+ \ 'hidden': 1,
+ \ })
+ if commbuf == 0
+ Echoerr('Failed to open the communication terminal window')
+ exe 'bwipe! ' .. ptybuf
return
endif
- let commpty = job_info(term_getjob(s:commbuf))['tty_out']
+ var commpty = job_info(term_getjob(commbuf))['tty_out']
- let gdb_args = get(a:dict, 'gdb_args', [])
- let proc_args = get(a:dict, 'proc_args', [])
+ var gdb_args = get(dict, 'gdb_args', [])
+ var proc_args = get(dict, 'proc_args', [])
- let gdb_cmd = s:GetCommand()
+ var gdb_cmd = 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)
+ 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']
+ # 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
+ 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).
+ gdb_cmd += ['-iex', 'set mi-async on']
+ # Open a terminal window to run the debugger.
+ gdb_cmd += ['-tty', pty]
+ # Command executed _after_ startup is done, provides us with the necessary
+ # feedback
+ 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)
+ gdb_cmd = g:termdebug_config.command_filter(gdb_cmd)
endif
- " Adding arguments requested by the user
- let gdb_cmd += gdb_args
+ # Adding arguments requested by the user
+ 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
- call s:Echoerr('Failed to open the gdb terminal window')
- call s:CloseBuffers()
+ ch_log('executing "' .. join(gdb_cmd) .. '"')
+ gdbbuf = term_start(gdb_cmd, {
+ \ 'term_name': 'gdb',
+ \ 'term_finish': 'close',
+ \ })
+ if gdbbuf == 0
+ Echoerr('Failed to open the gdb terminal window')
+ CloseBuffers()
return
endif
- let s:gdbwin = win_getid()
+ gdbwin = win_getid()
- " Wait for the "startupdone" message before sending any commands.
- let try_count = 0
- while 1
- if s:CheckGdbRunning() != 'ok'
+ # Wait for the "startupdone" message before sending any commands.
+ var counter = 0
+ var counter_max = 300
+ var success = false
+ while success == false && counter < counter_max
+ if CheckGdbRunning() != 'ok'
+ # Failure. If NOK just return.
return
endif
for lnum in range(1, 200)
- if term_getline(s:gdbbuf, lnum) =~ 'startupdone'
- let try_count = 9999
- break
+ if term_getline(gdbbuf, lnum) =~ 'startupdone'
+ success = true
endif
endfor
- let try_count += 1
- if try_count > 300
- " done or give up after five seconds
- break
- endif
+
+ # Each count is 10ms
+ counter += 1
sleep 10m
endwhile
- " Set arguments to be run.
+ if success == false
+ Echoerr('Failed to startup the gdb program.')
+ CloseBuffers()
+ return
+ endif
+
+ # ---- gdb started. Next, let's set the MI interface. ---
+ # Set arguments to be run.
if len(proc_args)
- call term_sendkeys(s:gdbbuf, 'server set args ' . join(proc_args) . "\r")
+ term_sendkeys(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")
+ # Connect gdb to the communication pty, using the GDB/MI interface.
+ # Prefix "server" to avoid adding this to the history.
+ term_sendkeys(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'
+ # Wait for the response to show up, users may not notice the error and wonder
+ # why the debugger doesn't work.
+ counter = 0
+ counter_max = 300
+ success = false
+ while success == false && counter < counter_max
+ if CheckGdbRunning() != 'ok'
return
endif
- let response = ''
+ var response = ''
for lnum in range(1, 200)
- let line1 = term_getline(s:gdbbuf, lnum)
- let line2 = term_getline(s:gdbbuf, lnum + 1)
+ var line1 = term_getline(gdbbuf, lnum)
+ var line2 = term_getline(gdbbuf, lnum + 1)
if line1 =~ 'new-ui mi '
- " response can be in the same line or the next line
- let response = line1 . line2
+ # response can be in the same line or the next line
+ response = line1 .. line2
if response =~ 'Undefined command'
- call s:Echoerr('Sorry, your gdb is too old, gdb 7.12 is required')
- " CHECKME: possibly send a "server show version" here
- call s:CloseBuffers()
+ Echoerr('Sorry, your gdb is too old, gdb 7.12 is required')
+ # CHECKME: possibly send a "server show version" here
+ CloseBuffers()
return
endif
if response =~ 'New UI allocated'
- " Success!
- break
+ # Success!
+ success = true
endif
elseif line1 =~ 'Reading symbols from' && line2 !~ 'new-ui mi '
- " Reading symbols might take a while, try more times
- let try_count -= 1
+ # Reading symbols might take a while, try more times
+ counter -= 1
endif
endfor
if response =~ 'New UI allocated'
break
endif
- let try_count += 1
- if try_count > 100
- call s:Echoerr('Cannot check if your gdb works, continuing anyway')
- break
- endif
+ counter += 1
sleep 10m
endwhile
- call job_setoptions(term_getjob(s:gdbbuf), {'exit_cb': function('s:EndTermDebug')})
+ if success == false
+ Echoerr('Cannot check if your gdb works, continuing anyway')
+ return
+ endif
+
+ job_setoptions(term_getjob(gdbbuf), {'exit_cb': function('EndTermDebug')})
- " Set the filetype, this can be used to add mappings.
+ # Set the filetype, this can be used to add mappings.
set filetype=termdebug
- call s:StartDebugCommon(a:dict)
-endfunc
+ StartDebugCommon(dict)
+enddef
-" Open a window with a prompt buffer to run gdb in.
-func s:StartDebug_prompt(dict)
- if s:vertical
+# Open a window with a prompt buffer to run gdb in.
+def StartDebug_prompt(dict: dict<any>)
+ if vvertical
vertical new
else
new
endif
- let s:gdbwin = win_getid()
- let s:promptbuf = bufnr('')
- call prompt_setprompt(s:promptbuf, 'gdb> ')
+ gdbwin = win_getid()
+ promptbuf = bufnr('')
+ prompt_setprompt(promptbuf, 'gdb> ')
set buftype=prompt
if empty(glob('gdb'))
@@ -421,108 +482,108 @@ func s:StartDebug_prompt(dict)
elseif empty(glob('Termdebug-gdb-console'))
file Termdebug-gdb-console
else
- call s:Echoerr("You have a file/folder named 'gdb'
+ 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
- call prompt_setcallback(s:promptbuf, function('s:PromptCallback'))
- call prompt_setinterrupt(s:promptbuf, function('s:PromptInterrupt'))
-
- if s:vertical
- " Assuming the source code window will get a signcolumn, use two more
- " columns for that, thus one less for the terminal window.
- 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'),
- \ })
- if job_status(s:gdbjob) != "run"
- call s:Echoerr('Failed to start gdb')
- exe 'bwipe! ' . s:promptbuf
+ prompt_setcallback(promptbuf, function('PromptCallback'))
+ prompt_setinterrupt(promptbuf, function('PromptInterrupt'))
+
+ if vvertical
+ # Assuming the source code window will get a signcolumn, use two more
+ # columns for that, thus one less for the terminal window.
+ exe ":" .. (&columns / 2 - 1) .. "wincmd |"
+ endif
+
+ 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
+ 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).
+ gdb_cmd += ['-iex', 'set mi-async on']
+ # directly communicate via mi2
+ gdb_cmd += ['--interpreter=mi2']
+
+ # Adding arguments requested by the user
+ gdb_cmd += gdb_args
+
+ ch_log('executing "' .. join(gdb_cmd) .. '"')
+ gdbjob = job_start(gdb_cmd, {
+ \ 'exit_cb': function('EndPromptDebug'),
+ \ 'out_cb': function('GdbOutCallback'),
+ \ })
+ if job_status(gdbjob) != "run"
+ Echoerr('Failed to start gdb')
+ exe 'bwipe! ' .. promptbuf
return
endif
- exe $'au BufUnload <buffer={s:promptbuf}> ++once ' ..
- \ 'call job_stop(s:gdbjob, ''kill'')'
- " Mark the buffer modified so that it's not easy to close.
+ exe $'au BufUnload <buffer={promptbuf}> ++once ' ..
+ \ 'call job_stop(gdbjob, ''kill'')'
+ # Mark the buffer modified so that it's not easy to close.
set modified
- let s:gdb_channel = job_getchannel(s:gdbjob)
+ gdb_channel = job_getchannel(gdbjob)
- let s:ptybuf = 0
+ ptybuf = 0
if has('win32')
- " MS-Windows: run in a new console window for maximum compatibility
- call s:SendCommand('set new-console on')
+ # MS-Windows: run in a new console window for maximum compatibility
+ SendCommand('set new-console on')
elseif has('terminal')
- " Unix: Run the debugged program in a terminal window. Open it below the
- " gdb window.
- belowright let s:ptybuf = term_start('NONE', {
- \ 'term_name': 'debugged program',
- \ })
- if s:ptybuf == 0
- call s:Echoerr('Failed to open the program terminal window')
- call job_stop(s:gdbjob)
+ # Unix: Run the debugged program in a terminal window. Open it below the
+ # gdb window.
+ belowright ptybuf = term_start('NONE', {
+ \ 'term_name': 'debugged program',
+ \ })
+ if ptybuf == 0
+ Echoerr('Failed to open the program terminal window')
+ job_stop(gdbjob)
return
endif
- let s:ptywin = win_getid()
- let pty = job_info(term_getjob(s:ptybuf))['tty_out']
- call s:SendCommand('tty ' . pty)
-
- " Since GDB runs in a prompt window, the environment has not been set to
- " match a terminal window, need to do that now.
- call s:SendCommand('set env TERM = xterm-color')
- call s:SendCommand('set env ROWS = ' . winheight(s:ptywin))
- call s:SendCommand('set env LINES = ' . winheight(s:ptywin))
- call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin))
- call s:SendCommand('set env COLORS = ' . &t_Co)
- call s:SendCommand('set env VIM_TERMINAL = ' . v:version)
+ ptywin = win_getid()
+ var pty = job_info(term_getjob(ptybuf))['tty_out']
+ SendCommand('tty ' .. pty)
+
+ # Since GDB runs in a prompt window, the environment has not been set to
+ # match a terminal window, need to do that now.
+ SendCommand('set env TERM = xterm-color')
+ SendCommand('set env ROWS = ' .. winheight(ptywin))
+ SendCommand('set env LINES = ' .. winheight(ptywin))
+ SendCommand('set env COLUMNS = ' .. winwidth(ptywin))
+ SendCommand('set env COLORS = ' .. &t_Co)
+ 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')
+ # TODO: open a new terminal, get the tty name, pass on to gdb
+ SendCommand('show inferior-tty')
endif
- call s:SendCommand('set print pretty on')
- call s:SendCommand('set breakpoint pending on')
+ SendCommand('set print pretty on')
+ SendCommand('set breakpoint pending on')
- " Set arguments to be run
+ # Set arguments to be run
if len(proc_args)
- call s:SendCommand('set args ' . join(proc_args))
+ SendCommand('set args ' .. join(proc_args))
endif
- call s:StartDebugCommon(a:dict)
+ StartDebugCommon(dict)
startinsert
-endfunc
+enddef
-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'})
+def StartDebugCommon(dict: dict<any>)
+ # 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)
- call s:InstallCommands()
- call win_gotoid(s:gdbwin)
+ # Install debugger commands in the text window.
+ win_gotoid(sourcewin)
+ InstallCommands()
+ win_gotoid(gdbwin)
- " Enable showing a balloon with eval info
+ # Enable showing a balloon with eval info
if has("balloon_eval") || has("balloon_eval_term")
set balloonexpr=TermDebugBalloonExpr()
if has("balloon_eval")
@@ -533,243 +594,238 @@ func s:StartDebugCommon(dict)
endif
endif
- " Contains breakpoints that have been placed, key is a string with the GDB
- " breakpoint number.
- " Each entry is a dict, containing the sub-breakpo