Add LICENSE
[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 import traceback
104 traceback.print_exc()
105 print e
106
107 return True
108
109
110
111 def contents_changed(self, term):
112 assert( self.getHistoryLen()>0 )
113
114 c,r = term.get_cursor_position()
115 text = self.get_text_range(self.lastr,0,r,c,lambda *w:True)
116 self.lastc, self.lastr = c,r
117
118 #Remove annoying \n at the end
119 assert(text[-1] == "\n")
120 text = text[:-1]
121
122 #Get the lines and remove empty lines
123 lines = string.split(text, "\n")
124
125 #Remove the incomplete line
126 len = max(0,self.getHistoryLen())
127 self.history[-1] = lines[0]
128 self.history += lines[1:]
129
130
131 #Check if activity status has been changed
132 for i in range(len, self.getHistoryLen()):
133 line = self.history[i]
134
135 res = self.testForInactivity(i)
136 if res != None:
137 while self.activityChanged != None:
138 print "wait for pending activity"
139 gtk.main_iteration()
140
141 self.setActive(False)
142 self.activityChanged = res
143
144 res = self.testForActivity(i)
145 if res != None:
146 while self.activityChanged != None:
147 print "wait for pending activity"
148 gtk.main_iteration()
149
150 self.setActive(True)
151 self.activityChanged = res
152
153
154
155
156 def waitForNewline(self):
157 l = self.getHistoryLen()
158 while not self.getHistoryLen() > l:
159 gtk.main_iteration()
160
161 def getHistoryLen(self):
162 return len(self.history)
163
164 def waitForRx(self, pat, start):
165
166 rx = re.compile(pat)
167 curr = start
168 while True:
169 assert( curr>=start )
170 for no in range(curr, self.getHistoryLen()):
171 line = self.history[no]
172 if rx.search(line):
173 return no, line
174
175 #Do not forget the last line
176 curr = max(start,self.getHistoryLen()-1)
177 lr, lc = self.lastr, self.lastc
178
179 while (self.lastr, self.lastc) == (lr,lc):
180 gtk.main_iteration()
181
182
183 def getCommand(self):
184 return self.getArgv()[0];
185
186 def getArgv(self):
187 raise NotImplementedError()
188
189 def setPty(self, pty):
190 raise NotImplementedError()
191
192 def setRun(self):
193 raise NotImplementedError()
194
195 def setContinue(self):
196 raise NotImplementedError()
197
198 def setStepover(self):
199 raise NotImplementedError()
200
201 def setStepin(self):
202 raise NotImplementedError()
203
204 def setStepout(self):
205 raise NotImplementedError()
206
207 def setQuit(self):
208 raise NotImplementedError()
209
210 def setBreakpoint(self, file, lineno, condition=False):
211 raise NotImplementedError()
212
213 def delBreakpoint(self, breakpoint):
214 raise NotImplementedError()
215
216 def getExpression(self, expr):
217 raise NotImplementedError()
218
219 def listCodeSnippet(self):
220 raise NotImplementedError()
221
222 def getBacktrace(self):
223 raise NotImplementedError()
224
225 def waitForPrompt(self, his):
226 raise NotImplementedError()
227
228 def testForActivity(self, his):
229 raise NotImplementedError()
230
231 def testForInactivity(self, his):
232 raise NotImplementedError()
233
234 def setActive(self, isactive):
235 self.isactive = isactive
236
237 def isActive(self):
238 return self.isactive
239
240
241
242 def quitHandler(*w):
243 try:
244 gtk.main_quit()
245 except:
246 pass
247
248
249 def relToAbsPath(absfile, relfile):
250 """When an absfile is given and a relfile is given by
251 relative paths relative to absfile, determine the abs
252 path of relfile"""
253
254 #Get directories except for "." parts
255 relsplit = filter(lambda x: x!=".", string.split(relfile, os.sep))
256 #Get the directories of absfile withouth the trailing filename
257 abssplit = string.split(absfile, os.sep)[:-1]
258
259 #Determine number of ".." and remove them
260 up=0
261 while relsplit[0] == "..":
262 up += 1
263 del relsplit[0]
264 del abssplit[-1]
265
266 return string.join(abssplit + relsplit, os.sep)
267
268
269 class DbgWindow (gtk.Window):
270
271 clientIOWnd = None
272
273
274 def __init__(self, terminal):
275
276 #Set up some members
277 self.terminal = terminal
278
279 #Set up GTK stuff
280 gtk.Window.__init__(self)
281 self.connect("destroy", quitHandler)
282
283 #Set title and add terminal
284 self.set_title("Debugger I/O")
285 self.terminal.history = []
286 self.terminal.history_length = 5
287 self.add(self.terminal)
288
289 #Show the window
290 self.show_all()
291
292 def toggleClientIOWindow(self):
293 if not self.clientIOWnd:
294 self.clientIOWnd = ClientIOTerminal.ClientIOWindow(self, \
295 self.terminal.client_ptymaster)
296 else:
297 self.clientIOWnd.destroy()
298 self.clientIOWnd = None
299
300 def isClientIOWindowExisting(self):
301 return self.clientIOWnd != None
302
303
304