afeca3de2d2cf1cccbddbbc3c0477d661782c056
[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 checkActivityChanged(self):
66
67 try:
68
69 #There was activity
70 if self.activityChanged != None:
71
72 res = self.activityChanged
73 self.activityChanged = None
74
75 status, param = res
76 if self.isActive():
77 print "got active: ", res
78 for cb in self.gotActiveCallback:
79 cb(status, param)
80 else:
81 print "got inactive: ", res
82 for cb in self.gotInactiveCallback:
83 cb(status, param)
84 except Exception, e:
85 print e
86
87 return True
88
89
90
91 def contents_changed(self, term):
92 assert( self.getHistoryLen()>0 )
93
94 c,r = term.get_cursor_position()
95 text = self.get_text_range(self.lastr,0,r,c,lambda *w:True)
96 self.lastc, self.lastr = c,r
97
98 #Remove annoying \n at the end
99 assert(text[-1] == "\n")
100 text = text[:-1]
101
102 #Get the lines and remove empty lines
103 lines = string.split(text, "\n")
104
105 #Remove the incomplete line
106 len = max(0,self.getHistoryLen())
107 self.history[-1] = lines[0]
108 self.history += lines[1:]
109
110
111 #Check if activity status has been changed
112 for i in range(len, self.getHistoryLen()):
113 line = self.history[i]
114
115 res = self.testForInactivity(i)
116 if res != None:
117 while self.activityChanged != None:
118 print "wait for pending activity"
119 gtk.main_iteration()
120
121 self.setActive(False)
122 self.activityChanged = res
123
124 res = self.testForActivity(i)
125 if res != None:
126 while self.activityChanged != None:
127 print "wait for pending activity"
128 gtk.main_iteration()
129
130 self.setActive(True)
131 self.activityChanged = res
132
133
134
135
136 def waitForNewline(self):
137 l = self.getHistoryLen()
138 while not self.getHistoryLen() > l:
139 gtk.main_iteration()
140
141 def getHistoryLen(self):
142 return len(self.history)
143
144 def waitForRx(self, pat, start):
145
146 rx = re.compile(pat)
147 curr = start
148 while True:
149 assert( curr>=start )
150 for no in range(curr, self.getHistoryLen()):
151 line = self.history[no]
152 if rx.search(line):
153 return no, line
154
155 #Do not forget the last line
156 curr = max(start,self.getHistoryLen()-1)
157 lr, lc = self.lastr, self.lastc
158
159 while (self.lastr, self.lastc) == (lr,lc):
160 gtk.main_iteration()
161
162
163 def getCommand(self):
164 return self.getArgv()[0];
165
166 def getArgv(self):
167 raise NotImplementedError()
168
169 def setPty(self, pty):
170 raise NotImplementedError()
171
172 def setRun(self):
173 raise NotImplementedError()
174
175 def setContinue(self):
176 raise NotImplementedError()
177
178 def setStepover(self):
179 raise NotImplementedError()
180
181 def setStepin(self):
182 raise NotImplementedError()
183
184 def setQuit(self):
185 raise NotImplementedError()
186
187 def setBreakpoint(self, file, lineno, condition=False):
188 raise NotImplementedError()
189
190 def delBreakpoint(self, breakpoint):
191 raise NotImplementedError()
192
193 def getExpression(self, expr):
194 raise NotImplementedError()
195
196 def listCodeSnippet(self):
197 raise NotImplementedError()
198
199 def waitForPrompt(self, his):
200 raise NotImplementedError()
201
202 def testForActivity(self, his):
203 raise NotImplementedError()
204
205 def testForInactivity(self, his):
206 raise NotImplementedError()
207
208 def setActive(self, isactive):
209 self.isactive = isactive
210
211 def isActive(self):
212 return self.isactive
213
214
215
216 def quitHandler(*w):
217 try:
218 gtk.main_quit()
219 except:
220 pass
221
222
223
224 class DbgWindow (gtk.Window):
225
226 clientIOWnd = None
227
228
229 def __init__(self, terminal):
230
231 #Set up some members
232 self.terminal = terminal
233
234 #Set up GTK stuff
235 gtk.Window.__init__(self)
236 self.connect("destroy", quitHandler)
237
238 #Set title and add terminal
239 self.set_title("Debugger I/O")
240 self.terminal.history = []
241 self.terminal.history_length = 5
242 self.add(self.terminal)
243
244 #Show the window
245 self.show_all()
246
247 def toggleClientIOWindow(self):
248 if not self.clientIOWnd:
249 self.clientIOWnd = ClientIOTerminal.ClientIOWindow(self, \
250 self.terminal.client_ptymaster)
251 else:
252 self.clientIOWnd.destroy()
253 self.clientIOWnd = None
254
255 def isClientIOWindowExisting(self):
256 return self.clientIOWnd != None
257
258
259