comparison lib/ipython_view.py @ 709:7a41504ed8fc

3rdparty ipython widget Ignore-this: 16d2871d631081b92677f2f3760a70d5
author Drew Perttula <drewp@bigasterisk.com>
date Sun, 10 Jun 2012 17:56:56 +0000
parents
children 547d65ea9902
comparison
equal deleted inserted replaced
708:10ee0756a119 709:7a41504ed8fc
1 # this version is adapted from http://wiki.ipython.org/Old_Embedding/GTK
2
3 """
4 Backend to the console plugin.
5
6 @author: Eitan Isaacson
7 @organization: IBM Corporation
8 @copyright: Copyright (c) 2007 IBM Corporation
9 @license: BSD
10
11 All rights reserved. This program and the accompanying materials are made
12 available under the terms of the BSD which accompanies this distribution, and
13 is available at U{http://www.opensource.org/licenses/bsd-license.php}
14 """
15 # this file is a modified version of source code from the Accerciser project
16 # http://live.gnome.org/accerciser
17
18 import gtk
19 import re
20 import sys
21 import os
22 import pango
23 from StringIO import StringIO
24
25 try:
26 import IPython
27 except Exception,e:
28 raise "Error importing IPython (%s)" % str(e)
29
30 ansi_colors = {'0;30': 'Black',
31 '0;31': 'Red',
32 '0;32': 'Green',
33 '0;33': 'Brown',
34 '0;34': 'Blue',
35 '0;35': 'Purple',
36 '0;36': 'Cyan',
37 '0;37': 'LightGray',
38 '1;30': 'DarkGray',
39 '1;31': 'DarkRed',
40 '1;32': 'SeaGreen',
41 '1;33': 'Yellow',
42 '1;34': 'LightBlue',
43 '1;35': 'MediumPurple',
44 '1;36': 'LightCyan',
45 '1;37': 'White'}
46
47 class IterableIPShell:
48 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
49 cin=None, cout=None,cerr=None, input_func=None):
50 if input_func:
51 IPython.iplib.raw_input_original = input_func
52 if cin:
53 IPython.Shell.Term.cin = cin
54 if cout:
55 IPython.Shell.Term.cout = cout
56 if cerr:
57 IPython.Shell.Term.cerr = cerr
58
59 if argv is None:
60 argv=[]
61
62 # This is to get rid of the blockage that occurs during
63 # IPython.Shell.InteractiveShell.user_setup()
64 IPython.iplib.raw_input = lambda x: None
65
66 self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
67 os.environ['TERM'] = 'dumb'
68 excepthook = sys.excepthook
69 self.IP = IPython.Shell.make_IPython(argv,user_ns=user_ns,
70 user_global_ns=user_global_ns,
71 embedded=True,
72 shell_class=IPython.Shell.InteractiveShell)
73 self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
74 header='IPython system call: ',
75 verbose=self.IP.rc.system_verbose)
76 sys.excepthook = excepthook
77 self.iter_more = 0
78 self.history_level = 0
79 self.complete_sep = re.compile('[\s\{\}\[\]\(\)]')
80
81 def execute(self):
82 self.history_level = 0
83 orig_stdout = sys.stdout
84 sys.stdout = IPython.Shell.Term.cout
85 try:
86 line = self.IP.raw_input(None, self.iter_more)
87 if self.IP.autoindent:
88 self.IP.readline_startup_hook(None)
89 except KeyboardInterrupt:
90 self.IP.write('\nKeyboardInterrupt\n')
91 self.IP.resetbuffer()
92 # keep cache in sync with the prompt counter:
93 self.IP.outputcache.prompt_count -= 1
94
95 if self.IP.autoindent:
96 self.IP.indent_current_nsp = 0
97 self.iter_more = 0
98 except:
99 self.IP.showtraceback()
100 else:
101 self.iter_more = self.IP.push(line)
102 if (self.IP.SyntaxTB.last_syntax_error and
103 self.IP.rc.autoedit_syntax):
104 self.IP.edit_syntax_error()
105 if self.iter_more:
106 self.prompt = str(self.IP.outputcache.prompt2).strip()
107 if self.IP.autoindent:
108 self.IP.readline_startup_hook(self.IP.pre_readline)
109 else:
110 self.prompt = str(self.IP.outputcache.prompt1).strip()
111 sys.stdout = orig_stdout
112
113 def historyBack(self):
114 self.history_level -= 1
115 return self._getHistory()
116
117 def historyForward(self):
118 self.history_level += 1
119 return self._getHistory()
120
121 def _getHistory(self):
122 try:
123 rv = self.IP.user_ns['In'][self.history_level].strip('\n')
124 except IndexError:
125 self.history_level = 0
126 rv = ''
127 return rv
128
129 def updateNamespace(self, ns_dict):
130 self.IP.user_ns.update(ns_dict)
131
132 def complete(self, line):
133 split_line = self.complete_sep.split(line)
134 possibilities = self.IP.complete(split_line[-1])
135 if possibilities:
136 common_prefix = reduce(self._commonPrefix, possibilities)
137 completed = line[:-len(split_line[-1])]+common_prefix
138 else:
139 completed = line
140 return completed, possibilities
141
142 def _commonPrefix(self, str1, str2):
143 for i in range(len(str1)):
144 if not str2.startswith(str1[:i+1]):
145 return str1[:i]
146 return str1
147
148 def shell(self, cmd,verbose=0,debug=0,header=''):
149 stat = 0
150 if verbose or debug: print header+cmd
151 # flush stdout so we don't mangle python's buffering
152 if not debug:
153 input, output = os.popen4(cmd)
154 print output.read()
155 output.close()
156 input.close()
157
158 class ConsoleView(gtk.TextView):
159 def __init__(self):
160 gtk.TextView.__init__(self)
161 self.modify_font(pango.FontDescription('Mono'))
162 self.set_cursor_visible(True)
163 self.text_buffer = self.get_buffer()
164 self.mark = self.text_buffer.create_mark('scroll_mark',
165 self.text_buffer.get_end_iter(),
166 False)
167 for code in ansi_colors:
168 self.text_buffer.create_tag(code,
169 foreground=ansi_colors[code],
170 weight=700)
171 self.text_buffer.create_tag('0')
172 self.text_buffer.create_tag('notouch', editable=False)
173 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
174 self.line_start = \
175 self.text_buffer.create_mark('line_start',
176 self.text_buffer.get_end_iter(), True
177 )
178 self.connect('key-press-event', self._onKeypress)
179 self.last_cursor_pos = 0
180
181 def write(self, text, editable=False):
182 segments = self.color_pat.split(text)
183 segment = segments.pop(0)
184 start_mark = self.text_buffer.create_mark(None,
185 self.text_buffer.get_end_iter(),
186 True)
187 self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
188
189 if segments:
190 ansi_tags = self.color_pat.findall(text)
191 for tag in ansi_tags:
192 i = segments.index(tag)
193 self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(),
194 segments[i+1], tag)
195 segments.pop(i)
196 if not editable:
197 self.text_buffer.apply_tag_by_name('notouch',
198 self.text_buffer.get_iter_at_mark(start_mark),
199 self.text_buffer.get_end_iter())
200 self.text_buffer.delete_mark(start_mark)
201 self.scroll_mark_onscreen(self.mark)
202
203 def showPrompt(self, prompt):
204 self.write(prompt)
205 self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
206
207 def changeLine(self, text):
208 iter = self.text_buffer.get_iter_at_mark(self.line_start)
209 iter.forward_to_line_end()
210 self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.line_start), iter)
211 self.write(text, True)
212
213 def getCurrentLine(self):
214 rv = self.text_buffer.get_slice(self.text_buffer.get_iter_at_mark(self.line_start),
215 self.text_buffer.get_end_iter(), False)
216 return rv
217
218 def showReturned(self, text):
219 iter = self.text_buffer.get_iter_at_mark(self.line_start)
220 iter.forward_to_line_end()
221 self.text_buffer.apply_tag_by_name('notouch',
222 self.text_buffer.get_iter_at_mark(self.line_start),
223 iter)
224 self.write('\n'+text)
225 if text:
226 self.write('\n')
227 self.showPrompt(self.prompt)
228 self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
229 self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
230
231 def _onKeypress(self, obj, event):
232 if not event.string:
233 return
234 insert_mark = self.text_buffer.get_insert()
235 insert_iter = self.text_buffer.get_iter_at_mark(insert_mark)
236 selection_mark = self.text_buffer.get_selection_bound()
237 selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
238 start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
239 if start_iter.compare(insert_iter) <= 0 and \
240 start_iter.compare(selection_iter) <= 0:
241 return
242 elif start_iter.compare(insert_iter) > 0 and \
243 start_iter.compare(selection_iter) > 0:
244 self.text_buffer.place_cursor(start_iter)
245 elif insert_iter.compare(selection_iter) < 0:
246 self.text_buffer.move_mark(insert_mark, start_iter)
247 elif insert_iter.compare(selection_iter) > 0:
248 self.text_buffer.move_mark(selection_mark, start_iter)
249
250
251 class IPythonView(ConsoleView, IterableIPShell):
252 def __init__(self, **kw):
253 ConsoleView.__init__(self)
254 self.cout = StringIO()
255 IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
256 input_func=self.raw_input, **kw)
257 self.connect('key_press_event', self.keyPress)
258 self.execute()
259 self.cout.truncate(0)
260 self.showPrompt(self.prompt)
261 self.interrupt = False
262
263 def raw_input(self, prompt=''):
264 if self.interrupt:
265 self.interrupt = False
266 raise KeyboardInterrupt
267 return self.getCurrentLine()
268
269 def keyPress(self, widget, event):
270 if event.state & gtk.gdk.CONTROL_MASK and event.keyval == 99:
271 self.interrupt = True
272 self._processLine()
273 return True
274 elif event.keyval == gtk.keysyms.Return:
275 self._processLine()
276 return True
277 elif event.keyval == gtk.keysyms.Up:
278 self.changeLine(self.historyBack())
279 return True
280 elif event.keyval == gtk.keysyms.Down:
281 self.changeLine(self.historyForward())
282 return True
283 # todo: Home needs to advance past the ipython prompt
284 elif event.keyval == gtk.keysyms.Tab:
285 if not self.getCurrentLine().strip():
286 return False
287 completed, possibilities = self.complete(self.getCurrentLine())
288 if len(possibilities) > 1:
289 slice = self.getCurrentLine()
290 self.write('\n')
291 for symbol in possibilities:
292 self.write(symbol+'\n')
293 self.showPrompt(self.prompt)
294 self.changeLine(completed or slice)
295 return True
296
297 def _processLine(self):
298 self.history_pos = 0
299 self.execute()
300 rv = self.cout.getvalue()
301 if rv: rv = rv.strip('\n')
302 self.showReturned(rv)
303 self.cout.truncate(0)