show backtrace in source view
[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 getBacktrace(self):
218 raise NotImplementedError()
219
220 def waitForPrompt(self, his):
221 raise NotImplementedError()
222
223 def testForActivity(self, his):
224 raise NotImplementedError()
225
226 def testForInactivity(self, his):
227 raise NotImplementedError()
228
229 def setActive(self, isactive):
230 self.isactive = isactive
231
232 def isActive(self):
233 return self.isactive
234
235
236
237 def quitHandler(*w):
238 try:
239 gtk.main_quit()
240 except:
241 pass
242
243
244 def updateVim():
245 os.system('gvim --servername pygdb --remote-send "<ESC> :GDBLoadConfig<CR>"')
246
247
248 def relToAbsPath(absfile, relfile):
249 """When an absfile is given and a relfile is given by
250 relative paths relative to absfile, determine the abs
251 path of relfile"""
252
253 #Get directories except for "." parts
254 relsplit = filter(lambda x: x!=".", string.split(relfile, os.sep))
255 #Get the directories of absfile withouth the trailing filename
256 abssplit = string.split(absfile, os.sep)[:-1]
257
258 #Determine number of ".." and remove them
259 up=0
260 while relsplit[0] == "..":
261 up += 1
262 del relsplit[0]
263 del abssplit[-1]
264
265 return string.join(abssplit + relsplit, os.sep)
266
267
268 class DbgWindow (gtk.Window):
269
270 clientIOWnd = None
271
272
273 def __init__(self, terminal):
274
275 #Set up some members
276 self.terminal = terminal
277
278 #Set up GTK stuff
279 gtk.Window.__init__(self)
280 self.connect("destroy", quitHandler)
281
282 #Set title and add terminal
283 self.set_title("Debugger I/O")
284 self.terminal.history = []
285 self.terminal.history_length = 5
286 self.add(self.terminal)
287
288 #Show the window
289 self.show_all()
290
291 def toggleClientIOWindow(self):
292 if not self.clientIOWnd:
293 self.clientIOWnd = ClientIOTerminal.ClientIOWindow(self, \
294 self.terminal.client_ptymaster)
295 else:
296 self.clientIOWnd.destroy()
297 self.clientIOWnd = None
298
299 def isClientIOWindowExisting(self):
300 return self.clientIOWnd != None
301
302
303