Mercurial > vim
comparison runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @ 12411:5d4d744151c2 v8.0.1085
patch 8.0.1085: terminal debugger can't set breakpoints
commit https://github.com/vim/vim/commit/e09ba7bae5c867f6d3abc184709dd27488318e97
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Sep 9 22:19:47 2017 +0200
patch 8.0.1085: terminal debugger can't set breakpoints
Problem: The terminal debugger can't set breakpoints.
Solution: Add :Break and :Delete commands. Also commands for stepping
through code.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 09 Sep 2017 22:30:04 +0200 |
parents | 39e1087e7094 |
children | 29d21591ad6b |
comparison
equal
deleted
inserted
replaced
12410:ba632a9ed948 | 12411:5d4d744151c2 |
---|---|
18 " The command that starts debugging, e.g. ":Termdebug vim". | 18 " The command that starts debugging, e.g. ":Termdebug vim". |
19 " To end type "quit" in the gdb window. | 19 " To end type "quit" in the gdb window. |
20 command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>) | 20 command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>) |
21 | 21 |
22 " Name of the gdb command, defaults to "gdb". | 22 " Name of the gdb command, defaults to "gdb". |
23 if !exists('debugger') | 23 if !exists('termdebugger') |
24 let debugger = 'gdb' | 24 let termdebugger = 'gdb' |
25 endif | 25 endif |
26 | 26 |
27 " Sign used to highlight the line where the program has stopped. | 27 " Sign used to highlight the line where the program has stopped. |
28 " There can be only one. | |
28 sign define debugPC linehl=debugPC | 29 sign define debugPC linehl=debugPC |
30 let s:pc_id = 12 | |
31 let s:break_id = 13 | |
32 | |
33 " Sign used to indicate a breakpoint. | |
34 " Can be used multiple times. | |
35 sign define debugBreakpoint text=>> texthl=debugBreakpoint | |
36 | |
29 if &background == 'light' | 37 if &background == 'light' |
30 hi debugPC term=reverse ctermbg=lightblue guibg=lightblue | 38 hi default debugPC term=reverse ctermbg=lightblue guibg=lightblue |
31 else | 39 else |
32 hi debugPC term=reverse ctermbg=darkblue guibg=darkblue | 40 hi default debugPC term=reverse ctermbg=darkblue guibg=darkblue |
33 endif | 41 endif |
34 let s:pc_id = 12 | 42 hi default debugBreakpoint term=reverse ctermbg=red guibg=red |
35 | 43 |
36 func s:StartDebug(cmd) | 44 func s:StartDebug(cmd) |
37 let s:startwin = win_getid(winnr()) | 45 let s:startwin = win_getid(winnr()) |
38 let s:startsigncolumn = &signcolumn | 46 let s:startsigncolumn = &signcolumn |
39 | 47 |
59 return | 67 return |
60 endif | 68 endif |
61 let commpty = job_info(term_getjob(s:commbuf))['tty_out'] | 69 let commpty = job_info(term_getjob(s:commbuf))['tty_out'] |
62 | 70 |
63 " Open a terminal window to run the debugger. | 71 " Open a terminal window to run the debugger. |
64 let cmd = [g:debugger, '-tty', pty, a:cmd] | 72 let cmd = [g:termdebugger, '-tty', pty, a:cmd] |
65 echomsg 'executing "' . join(cmd) . '"' | 73 echomsg 'executing "' . join(cmd) . '"' |
66 let gdbbuf = term_start(cmd, { | 74 let gdbbuf = term_start(cmd, { |
67 \ 'exit_cb': function('s:EndDebug'), | 75 \ 'exit_cb': function('s:EndDebug'), |
68 \ 'term_finish': 'close', | 76 \ 'term_finish': 'close', |
69 \ }) | 77 \ }) |
74 return | 82 return |
75 endif | 83 endif |
76 | 84 |
77 " Connect gdb to the communication pty, using the GDB/MI interface | 85 " Connect gdb to the communication pty, using the GDB/MI interface |
78 call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r") | 86 call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r") |
87 | |
88 " Install debugger commands. | |
89 call s:InstallCommands() | |
90 | |
91 let s:breakpoints = {} | |
79 endfunc | 92 endfunc |
80 | 93 |
81 func s:EndDebug(job, status) | 94 func s:EndDebug(job, status) |
82 exe 'bwipe! ' . s:ptybuf | 95 exe 'bwipe! ' . s:ptybuf |
83 exe 'bwipe! ' . s:commbuf | 96 exe 'bwipe! ' . s:commbuf |
84 call setwinvar(s:startwin, '&signcolumn', s:startsigncolumn) | 97 |
98 let curwinid = win_getid(winnr()) | |
99 | |
100 call win_gotoid(s:startwin) | |
101 let &signcolumn = s:startsigncolumn | |
102 call s:DeleteCommands() | |
103 | |
104 call win_gotoid(curwinid) | |
85 endfunc | 105 endfunc |
86 | 106 |
87 " Handle a message received from gdb on the GDB/MI interface. | 107 " Handle a message received from gdb on the GDB/MI interface. |
88 func s:CommOutput(chan, msg) | 108 func s:CommOutput(chan, msg) |
89 let msgs = split(a:msg, "\r") | 109 let msgs = split(a:msg, "\r") |
93 if msg[0] == "\n" | 113 if msg[0] == "\n" |
94 let msg = msg[1:] | 114 let msg = msg[1:] |
95 endif | 115 endif |
96 if msg != '' | 116 if msg != '' |
97 if msg =~ '^\*\(stopped\|running\)' | 117 if msg =~ '^\*\(stopped\|running\)' |
98 let wid = win_getid(winnr()) | 118 call s:HandleCursor(msg) |
99 | 119 elseif msg =~ '^\^done,bkpt=' |
100 if win_gotoid(s:startwin) | 120 call s:HandleNewBreakpoint(msg) |
101 if msg =~ '^\*stopped' | 121 elseif msg =~ '^=breakpoint-deleted,' |
102 " TODO: proper parsing | 122 call s:HandleBreakpointDelete(msg) |
103 let fname = substitute(msg, '.*fullname="\([^"]*\)".*', '\1', '') | 123 endif |
104 let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '') | 124 endif |
105 if lnum =~ '^[0-9]*$' | 125 endfor |
106 if expand('%:h') != fname | 126 endfunc |
107 if &modified | 127 |
108 " TODO: find existing window | 128 " Install commands in the current window to control the debugger. |
109 exe 'split ' . fnameescape(fname) | 129 func s:InstallCommands() |
110 let s:startwin = win_getid(winnr()) | 130 command Break call s:SetBreakpoint() |
111 else | 131 command Delete call s:DeleteBreakpoint() |
112 exe 'edit ' . fnameescape(fname) | 132 command Step call s:SendCommand('-exec-step') |
113 endif | 133 command NNext call s:SendCommand('-exec-next') |
114 endif | 134 command Finish call s:SendCommand('-exec-finish') |
115 exe lnum | 135 command Continue call s:SendCommand('-exec-continue') |
116 exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname) | 136 endfunc |
117 setlocal signcolumn=yes | 137 |
118 endif | 138 " Delete installed debugger commands in the current window. |
139 func s:DeleteCommands() | |
140 delcommand Break | |
141 delcommand Delete | |
142 delcommand Step | |
143 delcommand NNext | |
144 delcommand Finish | |
145 delcommand Continue | |
146 endfunc | |
147 | |
148 " :Break - Set a breakpoint at the cursor position. | |
149 func s:SetBreakpoint() | |
150 call term_sendkeys(s:commbuf, '-break-insert --source ' | |
151 \ . fnameescape(expand('%:p')) . ' --line ' . line('.') . "\r") | |
152 endfunc | |
153 | |
154 " :Delete - Delete a breakpoint at the cursor position. | |
155 func s:DeleteBreakpoint() | |
156 let fname = fnameescape(expand('%:p')) | |
157 let lnum = line('.') | |
158 for [key, val] in items(s:breakpoints) | |
159 if val['fname'] == fname && val['lnum'] == lnum | |
160 call term_sendkeys(s:commbuf, '-break-delete ' . key . "\r") | |
161 " Assume this always wors, the reply is simply "^done". | |
162 exe 'sign unplace ' . (s:break_id + key) | |
163 unlet s:breakpoints[key] | |
164 break | |
165 endif | |
166 endfor | |
167 endfunc | |
168 | |
169 " :Next, :Continue, etc - send a command to gdb | |
170 func s:SendCommand(cmd) | |
171 call term_sendkeys(s:commbuf, a:cmd . "\r") | |
172 endfunc | |
173 | |
174 " Handle stopping and running message from gdb. | |
175 " Will update the sign that shows the current position. | |
176 func s:HandleCursor(msg) | |
177 let wid = win_getid(winnr()) | |
178 | |
179 if win_gotoid(s:startwin) | |
180 if a:msg =~ '^\*stopped' | |
181 let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') | |
182 let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') | |
183 if lnum =~ '^[0-9]*$' | |
184 if expand('%:h') != fname | |
185 if &modified | |
186 " TODO: find existing window | |
187 exe 'split ' . fnameescape(fname) | |
188 let s:startwin = win_getid(winnr()) | |
119 else | 189 else |
120 exe 'sign unplace ' . s:pc_id | 190 exe 'edit ' . fnameescape(fname) |
121 endif | 191 endif |
122 | |
123 call win_gotoid(wid) | |
124 endif | 192 endif |
193 exe lnum | |
194 exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname) | |
195 setlocal signcolumn=yes | |
125 endif | 196 endif |
126 endif | 197 else |
127 endfor | 198 exe 'sign unplace ' . s:pc_id |
128 endfunc | 199 endif |
200 | |
201 call win_gotoid(wid) | |
202 endif | |
203 endfunc | |
204 | |
205 " Handle setting a breakpoint | |
206 " Will update the sign that shows the breakpoint | |
207 func s:HandleNewBreakpoint(msg) | |
208 let nr = substitute(a:msg, '.*number="\([0-9]\)*\".*', '\1', '') + 0 | |
209 if nr == 0 | |
210 return | |
211 endif | |
212 | |
213 if has_key(s:breakpoints, nr) | |
214 let entry = s:breakpoints[nr] | |
215 else | |
216 let entry = {} | |
217 let s:breakpoints[nr] = entry | |
218 endif | |
219 | |
220 let fname = substitute(a:msg, '.*fullname="\([^"]*\)".*', '\1', '') | |
221 let lnum = substitute(a:msg, '.*line="\([^"]*\)".*', '\1', '') | |
222 | |
223 exe 'sign place ' . (s:break_id + nr) . ' line=' . lnum . ' name=debugBreakpoint file=' . fnameescape(fname) | |
224 | |
225 let entry['fname'] = fname | |
226 let entry['lnum'] = lnum | |
227 endfunc | |
228 | |
229 " Handle deleting a breakpoint | |
230 " Will remove the sign that shows the breakpoint | |
231 func s:HandleBreakpointDelete(msg) | |
232 let nr = substitute(a:msg, '.*id="\([0-9]*\)\".*', '\1', '') + 0 | |
233 if nr == 0 | |
234 return | |
235 endif | |
236 exe 'sign unplace ' . (s:break_id + nr) | |
237 unlet s:breakpoints[nr] | |
238 endfunc |