Overwrite breakpoints when launching pygdb from vim, updating vim also after quit
[pygdb.git] / DbgTerminal.py
1 #!/usr/bin/python
2 #shuber, 2008-06-04
3
4 __author__ = "shuber"
5
6
7 import gobject
8 import gtk
9 import os
10 import pango
11 import pty
12 import re
13 import string
14 import sys
15 import time
16 import threading
17 import vte
18
19 import ClientIOTerminal
20
21
22
23 class DbgTerminal (vte.Terminal):
24
25 def __init__(self, clientCmd):
26
27 vte.Terminal.__init__(self)
28
29 #Set members
30 self.childpid = None
31 self.history = [""]
32 self.isactive = True
33 self.lastc, self.lastr = 0,0
34 self.gotActiveCallback = []
35 self.gotInactiveCallback = []
36 self.activityChanged = None
37
38 #Start debugger
39 self.clientCmd = clientCmd
40 #Open pseudo-terminal where to-be-debugged process reads/writes to
41 self.client_ptymaster, self.client_ptyslave = pty.openpty()
42
43 #Set up terminal window and initialize debugger
44 self.connect("cursor-moved", self.contents_changed)
45 self.connect("child-exited", quitHandler)
46 gobject.timeout_add(50, self.checkActivityChanged)
47
48 #font description
49 fontdesc = pango.FontDescription("monospace 9")
50 self.set_font(fontdesc)
51
52
53 def initialize(self):
54 self.childpid = self.fork_command( self.getCommand(), self.getArgv())
55 self.waitForPrompt(0)
56 self.setPty(self.client_ptyslave)
57
58 def stopDbg(self):
59
60 if self.childpid != None:
61 #9=KILL, 15=TERM
62 os.kill(self.childpid, 15);
63 self.childpid = None
64
65 def getClientExecuteable(self):
66 return string.split(self.clientCmd)[0]
67
68
69 def toAbsPath(self, path):
70 """convert path to an absolute path relative to the client
71 executable we debug."""
72
73 #Current working dir
74 pwd = os.getcwd() + "/"
75
76 #executeable path
77 client = self.getClientExecuteable()
78 client = relToAbsPath(pwd, client)
79
80 return relToAbsPath(client, path)
81
82
83 def checkActivityChanged(self):
84
85 try:
86
87 #There was activity
88 if self.activityChanged != None:
89
90 res = self.activityChanged
91 self.activityChanged = None
92
93 status, param = res
94 if self.isActive():
95 print "got active: ", res
96 for cb in self.gotActiveCallback:
97 cb(status, param)
98 else:
99 print "got inactive: ", res
100 for cb in self.gotInactiveCallback:
101 cb(status, param)
102 except Exception, e:
103 print e
104
105 return True
106
107
108
109 def contents_changed(self, term):
110 assert( self.getHistoryLen()>0 )
111
112 c,r = term.get_cursor_position()
113 text = self.get_text_range(self.lastr,0,r,c,lambda *w:True)
114 self.lastc, self.lastr = c,r
115
116 #Remove annoying \n at the end
117 assert(text[-1] == "\n")
118 text = text[:-1]
119
120 #Get the lines and remove empty lines
121 lines = string.split(text, "\n")
122
123 #Remove the incomplete line
124 len = max(0,self.getHistoryLen())
125 self.history[-1] = lines[0]
126 self.history += lines[1:]
127
128
129 #Check if activity status has been changed
130 for i in range(len, self.getHistoryLen()):
131 line = self.history[i]
132
133 res = self.testForInactivity(i)
134 if res != None:
135 while self.activityChanged != None:
136 print "wait for pending activity"
137 gtk.main_iteration()
138
139 self.setActive(False)
140 self.activityChanged = res
141
142 res = self.testForActivity(i)
143 if res != None:
144 while self.activityChanged != None:
145 print "wait for pending activity"
146 gtk.main_iteration()
147
148 self.setActive(True)
149 self.activityChanged = res
150
151
152
153
154 def waitForNewline(self):
155 l = self.getHistoryLen()
156 while not self.getHistoryLen() > l:
157 gtk.main_iteration()
158
159 def getHistoryLen(self):
160 return len(self.history)
161
162 def waitForRx(self, pat, start):
163
164 rx = re.compile(pat)
165 curr = start
166 while True:
167 assert( curr>=start )
168 for no in range(curr, self.getHistoryLen()):
169 line = self.history[no]
170 if rx.search(line):
171 return no, line
172
173 #Do not forget the last line
174 curr = max(start,self.getHistoryLen()-1)
175 lr, lc = self.lastr, self.lastc
176
177 while (self.lastr, self.lastc) == (lr,lc):
178 gtk.main_iteration()
179
180
181 def getCommand(self):
182 return self.getArgv()[0];
183
184 def getArgv(self):
185 raise NotImplementedError()
186
187 def setPty(self, pty):
188 raise NotImplementedError()
189
190 def setRun(self):
191 raise NotImplementedError()
192
193 def setContinue(self):
194 raise NotImplementedError()
195
196 def setStepover(self):
197 raise NotImplementedError()
198
199 def setStepin(self):
200 raise NotImplementedError()
201
202 def setQuit(self):
203 raise NotImplementedError()
204
205 def setBreakpoint(self, file, lineno, condition=False):
206 raise NotImplementedError()
207
208 def delBreakpoint(self, breakpoint):
209 raise NotImplementedError()
210
211 def getExpression(self, expr):
212 raise NotImplementedError()
213
214 def listCodeSnippet(self):
215 raise NotImplementedError()
216
217 def waitForPrompt(self, his):
218 raise NotImplementedError()
219
220 def testForActivity(self, his):
221 raise NotImplementedError()
222
223 def testForInactivity(self, his):
224 raise NotImplementedError()
225
226 def setActive(self, isactive):
227 self.isactive = isactive
228
229 def isActive(self):
230 return self.isactive
231
232
233
234 def quitHandler(*w):
235 try:
236 gtk.main_quit()
237 except:
238 pass
239
240
241 def updateVim():
242 os.system('gvim --servername pygdb --remote-send ":GDBLoadConfig<CR>"')
243
244
245 def relToAbsPath(absfile, relfile):
246 """When an absfile is given and a relfile is given by
247 relative paths relative to absfile, determine the abs
248 path of relfile"""
249
250 #Get directories except for "." parts
251 relsplit = filter(lambda x: x!=".", string.split(relfile, os.sep))
252 #Get the directories of absfile withouth the trailing filename
253 abssplit = string.split(absfile, os.sep)[:-1]
254
255 #Determine number of ".." and remove them
256 up=0
257 while relsplit[0] == "..":
258 up += 1
259 del relsplit[0]
260 del abssplit[-1]
261
262 return string.join(abssplit + relsplit, os.sep)
263
264
265 class DbgWindow (gtk.Window):
266
267 clientIOWnd = None
268
269
270 def __init__(self, terminal):
271
272 #Set up some members
273 self.terminal = terminal
274
275 #Set up GTK stuff
276 gtk.Window.__init__(self)
277 self.connect("destroy", quitHandler)
278
279 #Set title and add terminal
280 self.set_title("Debugger I/O")
281 self.terminal.history = []
282 self.terminal.history_length = 5
283 self.add(self.terminal)
284
285 #Show the window
286 self.show_all()
287
288 def toggleClientIOWindow(self):
289 if not self.clientIOWnd:
290 self.clientIOWnd = ClientIOTerminal.ClientIOWindow(self, \
291 self.terminal.client_ptymaster)
292 else:
293 self.clientIOWnd.destroy()
294 self.clientIOWnd = None
295
296 def isClientIOWindowExisting(self):
297 return self.clientIOWnd != None
298
299
300