A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ipython_view.py
Go to the documentation of this file.
1"""
2Backend to the console plugin.
3
4@author: Eitan Isaacson
5@organization: IBM Corporation
6@copyright: Copyright (c) 2007 IBM Corporation
7@license: BSD
8
9All rights reserved. This program and the accompanying materials are made
10available under the terms of the BSD which accompanies this distribution, and
11is available at U{http://www.opensource.org/licenses/bsd-license.php}
12"""
13# this file is a modified version of source code from the Accerciser project
14# https://wiki.gnome.org/Apps/Accerciser
15
16import gtk, gobject
17import re
18import sys
19import os
20from gi.repository import Pango
21from StringIO import StringIO
22import IPython
23
24from pkg_resources import parse_version
25
26
27try:
28 import IPython
29except ImportError:
30
32 IPython = None
33
34
36
55 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
56 cin=None, cout=None,cerr=None, input_func=None):
57 """! Initializer
58
59 @param self: this object
60 @param argv: Command line options for IPython
61 @param user_ns: User namespace.
62 @param user_global_ns: User global namespace.
63 @param cin: Console standard input.
64 @param cout: Console standard output.
65 @param cerr: Console standard error.
66 @param input_func: Replacement for builtin raw_input()
67 """
68 io = IPython.utils.io
69 if input_func:
70 if parse_version(IPython.release.version) >= parse_version("1.2.1"):
71 IPython.terminal.interactiveshell.raw_input_original = input_func
72 else:
73 IPython.frontend.terminal.interactiveshell.raw_input_original = input_func
74 if cin:
75 io.stdin = io.IOStream(cin)
76 if cout:
77 io.stdout = io.IOStream(cout)
78 if cerr:
79 io.stderr = io.IOStream(cerr)
80
81 # This is to get rid of the blockage that occurs during
82 # IPython.Shell.InteractiveShell.user_setup()
83
84 io.raw_input = lambda x: None
85
86 os.environ['TERM'] = 'dumb'
87 excepthook = sys.excepthook
88
89 from IPython.config.loader import Config
90 cfg = Config()
91 cfg.InteractiveShell.colors = "Linux"
92
93 # InteractiveShell's __init__ overwrites io.stdout,io.stderr with
94 # sys.stdout, sys.stderr, this makes sure they are right
95 #
96 old_stdout, old_stderr = sys.stdout, sys.stderr
97 sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
98
99 # InteractiveShell inherits from SingletonConfigurable, so use instance()
100 #
101 if parse_version(IPython.release.version) >= parse_version("1.2.1"):
102 self.IP = IPython.terminal.embed.InteractiveShellEmbed.instance(\
103 config=cfg, user_ns=user_ns)
104 else:
105 self.IP = IPython.frontend.terminal.embed.InteractiveShellEmbed.instance(\
106 config=cfg, user_ns=user_ns)
107
108 sys.stdout, sys.stderr = old_stdout, old_stderr
109
110 self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
111 header='IPython system call: ')
112# local_ns=user_ns)
113 #global_ns=user_global_ns)
114 #verbose=self.IP.rc.system_verbose)
115
116 self.IP.raw_input = input_func
117 sys.excepthook = excepthook
118 self.iter_more = 0
120 self.complete_sep = re.compile('[\s\{\}\[\]\‍(\‍)]')
121 self.updateNamespace({'exit':lambda:None})
122 self.updateNamespace({'quit':lambda:None})
123 self.IP.readline_startup_hook(self.IP.pre_readline)
124 # Workaround for updating namespace with sys.modules
125 #
126 self.__update_namespace()
127
129 """!
130 Update self.IP namespace for autocompletion with sys.modules
131 @return none
132 """
133 for k, v in list(sys.modules.items()):
134 if not '.' in k:
135 self.IP.user_ns.update({k:v})
136
137 def execute(self):
138 """!
139 Executes the current line provided by the shell object.
140 @return none
141 """
142 self.history_level = 0
143 orig_stdout = sys.stdout
144 sys.stdout = IPython.utils.io.stdout
145
146 orig_stdin = sys.stdin
147 sys.stdin = IPython.utils.io.stdin;
149
150 self.IP.hooks.pre_prompt_hook()
151 if self.iter_more:
152 try:
153 self.prompt = self.generatePrompt(True)
154 except:
155 self.IP.showtraceback()
156 if self.IP.autoindent:
157 self.IP.rl_do_indent = True
158
159 try:
160 line = self.IP.raw_input(self.prompt)
161 except KeyboardInterrupt:
162 self.IP.write('\nKeyboardInterrupt\n')
163 self.IP.input_splitter.reset()
164 except:
165 self.IP.showtraceback()
166 else:
167 self.IP.input_splitter.push(line)
168 self.iter_more = self.IP.input_splitter.push_accepts_more()
169 self.prompt = self.generatePrompt(self.iter_more)
170 if (self.IP.SyntaxTB.last_syntax_error and
171 self.IP.autoedit_syntax):
172 self.IP.edit_syntax_error()
173 if not self.iter_more:
174 if parse_version(IPython.release.version) >= parse_version("2.0.0-dev"):
175 source_raw = self.IP.input_splitter.raw_reset()
176 else:
177 source_raw = self.IP.input_splitter.source_raw_reset()[1]
178 self.IP.run_cell(source_raw, store_history=True)
179 self.IP.rl_do_indent = False
180 else:
181 # TODO: Auto-indent
182 #
183 self.IP.rl_do_indent = True
184 pass
185
186 sys.stdout = orig_stdout
187 sys.stdin = orig_stdin
188
189 def generatePrompt(self, is_continuation):
190 """!
191 Generate prompt depending on is_continuation value
192
193 @param is_continuation
194 @return: The prompt string representation
195
196 """
197
198 # Backwards compatibility with ipyton-0.11
199 #
200 ver = IPython.__version__
201 if '0.11' in ver:
202 prompt = self.IP.hooks.generate_prompt(is_continuation)
203 else:
204 if is_continuation:
205 prompt = self.IP.prompt_manager.render('in2')
206 else:
207 prompt = self.IP.prompt_manager.render('in')
208
209 return prompt
210
211
212 def historyBack(self):
213 """!
214 Provides one history command back.
215
216 @param self this object
217 @return: The command string.
218 """
219 self.history_level -= 1
220 if not self._getHistory():
221 self.history_level +=1
222 return self._getHistory()
223
224 def historyForward(self):
225 """!
226 Provides one history command forward.
227
228 @param self this object
229 @return: The command string.
230 """
231 if self.history_level < 0:
232 self.history_level += 1
233 return self._getHistory()
234
235 def _getHistory(self):
236 """!
237 Gets the command string of the current history level.
238
239 @param self this object
240 @return: Historic command string.
241 """
242 try:
243 rv = self.IP.user_ns['In'][self.history_level].strip('\n')
244 except IndexError:
245 rv = ''
246 return rv
247
248 def updateNamespace(self, ns_dict):
249 """!
250 Add the current dictionary to the shell namespace.
251
252 @param ns_dict: A dictionary of symbol-values.
253 @return none
254 """
255 self.IP.user_ns.update(ns_dict)
256
257 def complete(self, line):
258 """!
259 Returns an auto completed line and/or possibilities for completion.
260
261 @param line: Given line so far.
262 @return: Line completed as for as possible, and possible further completions.
263 """
264 split_line = self.complete_sep.split(line)
265 if split_line[-1]:
266 possibilities = self.IP.complete(split_line[-1])
267 else:
268 completed = line
269 possibilities = ['', []]
270 if possibilities:
271 def _commonPrefix(str1, str2):
272 """!
273 Reduction function. returns common prefix of two given strings.
274
275 @param str1: First string.
276 @param str2: Second string
277 @return: Common prefix to both strings.
278 """
279 for i in range(len(str1)):
280 if not str2.startswith(str1[:i+1]):
281 return str1[:i]
282 return str1
283 if possibilities[1]:
284 common_prefix = reduce(_commonPrefix, possibilities[1]) or line[-1]
285 completed = line[:-len(split_line[-1])]+common_prefix
286 else:
287 completed = line
288 else:
289 completed = line
290 return completed, possibilities[1]
291
292
293 def shell(self, cmd,verbose=0,debug=0,header=''):
294 """!
295 Replacement method to allow shell commands without them blocking.
296
297 @param cmd: Shell command to execute.
298 @param verbose: Verbosity
299 @param debug: Debug level
300 @param header: Header to be printed before output
301 @return none
302 """
303 stat = 0
304 if verbose or debug: print(header+cmd)
305 # flush stdout so we don't mangle python's buffering
306 if not debug:
307 input, output = os.popen4(cmd)
308 print(output.read())
309 output.close()
310 input.close()
311
312
313class ConsoleView(Gtk.TextView):
314
324 """
325 Specialized text view for console-like workflow.
326
327 @cvar ANSI_COLORS: Mapping of terminal colors to X11 names.
328 @type ANSI_COLORS: dictionary
329
330 @ivar text_buffer: Widget's text buffer. @type text_buffer: Gtk.TextBuffer
331 @ivar color_pat: Regex of terminal color pattern
332 @type color_pat: _sre.SRE_Pattern
333 @ivar mark: Scroll mark for automatic scrolling on input.
334 @type mark: Gtk.TextMark
335 @ivar line_start: Start of command line mark.
336 @type line_start: Gtk.TextMark
337 """
338 ANSI_COLORS = {'0;30': 'Black', '0;31': 'Red',
339 '0;32': 'Green', '0;33': 'Brown',
340 '0;34': 'Blue', '0;35': 'Purple',
341 '0;36': 'Cyan', '0;37': 'LightGray',
342 '1;30': 'DarkGray', '1;31': 'DarkRed',
343 '1;32': 'SeaGreen', '1;33': 'Yellow',
344 '1;34': 'LightBlue', '1;35': 'MediumPurple',
345 '1;36': 'LightCyan', '1;37': 'White'}
346
347 def __init__(self):
348 """
349 Initialize console view.
350 """
351 GObject.GObject.__init__(self)
352 self.modify_font(Pango.FontDescription('Mono'))
353 self.set_cursor_visible(True)
354 self.text_buffer = self.get_buffer()
355 self.mark = self.text_buffer.create_mark('scroll_mark',
356 self.text_buffer.get_end_iter(),
357 False)
358 for code in self.ANSI_COLORS:
359 self.text_buffer.create_tag(code,
360 foreground=self.ANSI_COLORS[code],
361 weight=700)
362 self.text_buffer.create_tag('0')
363 self.text_buffer.create_tag('notouch', editable=False)
364 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
365 self.line_start = \
366 self.text_buffer.create_mark('line_start',
367 self.text_buffer.get_end_iter(), True)
368 self.connect('key-press-event', self.onKeyPress)
369
370 def write(self, text, editable=False):
371 """!
372 Write given text to buffer.
373
374 @param text: Text to append.
375 @param editable: If true, added text is editable.
376 @return none
377 """
378 GObject.idle_add(self._write, text, editable)
379
380 def _write(self, text, editable=False):
381 """!
382 Write given text to buffer.
383
384 @param text: Text to append.
385 @param editable: If true, added text is editable.
386 @return none
387 """
388 segments = self.color_pat.split(text)
389 segment = segments.pop(0)
390 start_mark = self.text_buffer.create_mark(None,
391 self.text_buffer.get_end_iter(),
392 True)
393 self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
394
395 if segments:
396 ansi_tags = self.color_pat.findall(text)
397 for tag in ansi_tags:
398 i = segments.index(tag)
399 self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(),
400 segments[i+1], str(tag))
401 segments.pop(i)
402 if not editable:
403 self.text_buffer.apply_tag_by_name('notouch',
404 self.text_buffer.get_iter_at_mark(start_mark),
405 self.text_buffer.get_end_iter())
406 self.text_buffer.delete_mark(start_mark)
407 self.scroll_mark_onscreen(self.mark)
408
409 def showPrompt(self, prompt):
410 """!
411 Prints prompt at start of line.
412
413 @param prompt: Prompt to print.
414 @return none
415 """
416 GObject.idle_add(self._showPrompt, prompt)
417
418 def _showPrompt(self, prompt):
419 """!
420 Prints prompt at start of line.
421
422 @param prompt: Prompt to print.
423 @return none
424 """
425 self._write(prompt)
426 self.text_buffer.move_mark(self.line_start,
427 self.text_buffer.get_end_iter())
428
429 def changeLine(self, text):
430 """!
431 Replace currently entered command line with given text.
432
433 @param text: Text to use as replacement.
434 @return none
435 """
436 GObject.idle_add(self._changeLine, text)
437
438 def _changeLine(self, text):
439 """!
440 Replace currently entered command line with given text.
441
442 @param text: Text to use as replacement.
443 @return none
444 """
445 iter = self.text_buffer.get_iter_at_mark(self.line_start)
446 iter.forward_to_line_end()
447 self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.line_start), iter)
448 self._write(text, True)
449
450 def getCurrentLine(self):
451 """!
452 Get text in current command line.
453
454 @return Text of current command line.
455 """
456 rv = self.text_buffer.get_slice(
457 self.text_buffer.get_iter_at_mark(self.line_start),
458 self.text_buffer.get_end_iter(), False)
459 return rv
460
461 def showReturned(self, text):
462 """!
463 Show returned text from last command and print new prompt.
464
465 @param text: Text to show.
466 @return none
467 """
468 GObject.idle_add(self._showReturned, text)
469
470 def _showReturned(self, text):
471 """!
472 Show returned text from last command and print new prompt.
473
474 @param text: Text to show.
475 @return none
476 """
477 iter = self.text_buffer.get_iter_at_mark(self.line_start)
478 iter.forward_to_line_end()
479 self.text_buffer.apply_tag_by_name(
480 'notouch',
481 self.text_buffer.get_iter_at_mark(self.line_start),
482 iter)
483 self._write('\n'+text)
484 if text:
485 self._write('\n')
486 self._showPrompt(self.prompt)
487 self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
488 self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
489
490 if self.IP.rl_do_indent:
491 indentation = self.IP.input_splitter.indent_spaces * ' '
492 self.text_buffer.insert_at_cursor(indentation)
493
494 def onKeyPress(self, widget, event):
495 """!
496 Key press callback used for correcting behavior for console-like
497 interfaces. For example 'home' should go to prompt, not to beginning of
498 line.
499
500 @param widget: Widget that key press accored in.
501 @param event: Event object
502 @return Return True if event should not trickle.
503 """
504 insert_mark = self.text_buffer.get_insert()
505 insert_iter = self.text_buffer.get_iter_at_mark(insert_mark)
506 selection_mark = self.text_buffer.get_selection_bound()
507 selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
508 start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
509 if event.keyval == Gdk.KEY_Home:
510 if event.get_state() & Gdk.ModifierType.CONTROL_MASK or event.get_state() & Gdk.ModifierType.MOD1_MASK:
511 pass
512 elif event.get_state() & Gdk.ModifierType.SHIFT_MASK:
513 self.text_buffer.move_mark(insert_mark, start_iter)
514 return True
515 else:
516 self.text_buffer.place_cursor(start_iter)
517 return True
518 elif event.keyval == Gdk.KEY_Left:
519 insert_iter.backward_cursor_position()
520 if not insert_iter.editable(True):
521 return True
522 elif not event.string:
523 pass
524 elif start_iter.compare(insert_iter) <= 0 and \
525 start_iter.compare(selection_iter) <= 0:
526 pass
527 elif start_iter.compare(insert_iter) > 0 and \
528 start_iter.compare(selection_iter) > 0:
529 self.text_buffer.place_cursor(start_iter)
530 elif insert_iter.compare(selection_iter) < 0:
531 self.text_buffer.move_mark(insert_mark, start_iter)
532 elif insert_iter.compare(selection_iter) > 0:
533 self.text_buffer.move_mark(selection_mark, start_iter)
534
535 return self.onKeyPressExtend(event)
536
537 def onKeyPressExtend(self, event):
538 """!
539 For some reason we can't extend onKeyPress directly (bug #500900).
540 @param event key press
541 @return none
542 """
543 pass
544
545
561 """
562 Sub-class of both modified IPython shell and L{ConsoleView} this makes
563 a GTK+ IPython console.
564 """
565 def __init__(self):
566 """
567 Initialize. Redirect I/O to console.
568 """
569 ConsoleView.__init__(self)
570 self.cout = StringIO()
571 IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
572 input_func=self.raw_input)
573 self.interrupt = False
574 self.execute()
575 self.promptprompt = self.generatePrompt(False)
576 self.cout.truncate(0)
577 self.showPrompt(self.promptprompt)
578
579 def raw_input(self, prompt=''):
580 """!
581 Custom raw_input() replacement. Gets current line from console buffer.
582
583 @param prompt: Prompt to print. Here for compatibility as replacement.
584 @return The current command line text.
585 """
586 if self.interrupt:
587 self.interrupt = False
588 raise KeyboardInterrupt
589 return self.getCurrentLine()
590
591 def onKeyPressExtend(self, event):
592 """!
593 Key press callback with plenty of shell goodness, like history,
594 autocompletions, etc.
595
596 @param event: Event object.
597 @return True if event should not trickle.
598 """
599
600 if event.get_state() & Gdk.ModifierType.CONTROL_MASK and event.keyval == 99:
601 self.interrupt = True
602 self._processLine()
603 return True
604 elif event.keyval == Gdk.KEY_Return:
605 self._processLine()
606 return True
607 elif event.keyval == Gdk.KEY_Up:
608 self.changeLine(self.historyBack())
609 return True
610 elif event.keyval == Gdk.KEY_Down:
611 self.changeLine(self.historyForward())
612 return True
613 elif event.keyval == Gdk.KEY_Tab:
614 if not self.getCurrentLine().strip():
615 return False
616 completed, possibilities = self.complete(self.getCurrentLine())
617 if len(possibilities) > 1:
618 slice = self.getCurrentLine()
619 self.write('\n')
620 for symbol in possibilities:
621 self.write(symbol+'\n')
622 self.showPrompt(self.promptprompt)
623 self.changeLine(completed or slice)
624 return True
625
626 def _processLine(self):
627 """!
628 Process current command line.
629 @return none
630 """
631 self.history_pos = 0
632 self.execute()
633 rv = self.cout.getvalue()
634 if rv: rv = rv.strip('\n')
635 self.showReturned(rv)
636 self.cout.truncate(0)
637 self.cout.seek(0)
638
639if __name__ == "__main__":
640 window = Gtk.Window()
641 window.set_default_size(640, 320)
642 window.connect('delete-event', lambda x, y: Gtk.main_quit())
643 window.add(IPythonView())
644 window.show_all()
645 Gtk.main()
646
647
def write(self, text, editable=False)
Write given text to buffer.
def changeLine(self, text)
Replace currently entered command line with given text.
def _showPrompt(self, prompt)
Prints prompt at start of line.
def _showReturned(self, text)
Show returned text from last command and print new prompt.
def getCurrentLine(self)
Get text in current command line.
def onKeyPressExtend(self, event)
For some reason we can't extend onKeyPress directly (bug #500900).
def _write(self, text, editable=False)
Write given text to buffer.
def _changeLine(self, text)
Replace currently entered command line with given text.
def showPrompt(self, prompt)
Prints prompt at start of line.
def showReturned(self, text)
Show returned text from last command and print new prompt.
def onKeyPress(self, widget, event)
Key press callback used for correcting behavior for console-like interfaces.
def onKeyPressExtend(self, event)
Key press callback with plenty of shell goodness, like history, autocompletions, etc.
def raw_input(self, prompt='')
Custom raw_input() replacement.
def _processLine(self)
Process current command line.
def updateNamespace(self, ns_dict)
Add the current dictionary to the shell namespace.
def __init__(self, argv=None, user_ns=None, user_global_ns=None, cin=None, cout=None, cerr=None, input_func=None)
Initializer.
Definition: ipython_view.py:56
def _getHistory(self)
Gets the command string of the current history level.
def __update_namespace(self)
Update self.IP namespace for autocompletion with sys.modules.
def historyBack(self)
Provides one history command back.
def generatePrompt(self, is_continuation)
Generate prompt depending on is_continuation value.
def historyForward(self)
Provides one history command forward.
def shell(self, cmd, verbose=0, debug=0, header='')
Replacement method to allow shell commands without them blocking.
def execute(self)
Executes the current line provided by the shell object.
def complete(self, line)
Returns an auto completed line and/or possibilities for completion.
#define delete
#define list