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
14# this file is a modified version of source code from the Accerciser project
15# https://wiki.gnome.org/Apps/Accerciser
16
17import gi
18
19gi.require_version("Gtk", "3.0")
20import os
21import re
22import sys
23from functools import reduce
24from io import StringIO
25
26from gi.repository import Gdk, GLib, Gtk, Pango
27from pkg_resources import parse_version
28
29## Try to import IPython
30try:
31 import IPython
32except ImportError:
33 ##@ var IPython
34 #
35 IPython = None
36
37
38## IterableIPShell class
40 ## @var IP
41 # IP
42 ## @var iter_more
43 # iterate more
44 ## @var history_level
45 # history level
46 ## @var complete_sep
47 # separators
48 ## @var no_input_splitter
49 # no input splitter
50 ## @var lines
51 # lines
52 ## @var indent_spaces
53 # indent spaces
54 ## @var prompt
55 # prompt
56 ## @var header
57 # header
58 ## @var config
59 # config
60 ## @var colors
61 # colors
62 ## @var raw_input
63 # raw input
64
66 self,
67 argv=[],
68 user_ns=None,
69 user_global_ns=None,
70 cin=None,
71 cout=None,
72 cerr=None,
73 input_func=None,
74 ):
75 """!
76 Constructor for the IterableIPShell class
77 @param self: this object
78 @param argv: Command line options for IPython
79 @param user_ns: User namespace.
80 @param user_global_ns: User global namespace.
81 @param cin: Console standard input.
82 @param cout: Console standard output.
83 @param cerr: Console standard error.
84 @param input_func: Replacement for builtin raw_input()
85 """
86 io = IPython.utils.io
87 if input_func:
88 IPython.terminal.interactiveshell.raw_input_original = input_func
89 if IPython.version_info < (8,):
90 if cin:
91 io.stdin = io.IOStream(cin)
92 if cout:
93 io.stdout = io.IOStream(cout)
94 if cerr:
95 io.stderr = io.IOStream(cerr)
96 else:
97 if cin:
98 sys.stdin = cin
99 if cout:
100 sys.stdout = cout
101 if cerr:
102 sys.stderr = cerr
103
104 # This is to get rid of the blockage that occurs during
105 # IPython.Shell.InteractiveShell.user_setup()
106 io.raw_input = lambda x: None
107
108 os.environ["TERM"] = "dumb"
109 excepthook = sys.excepthook
110
111 from traitlets.config.loader import Config
112
113 cfg = Config()
114 cfg.InteractiveShell.colors = "Linux"
115 cfg.Completer.use_jedi = False
116
117 if IPython.version_info < (8,):
118 # InteractiveShell's __init__ overwrites io.stdout,io.stderr with
119 # sys.stdout, sys.stderr, this makes sure they are right
120 old_stdout, old_stderr = sys.stdout, sys.stderr
121 sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
122
123 # InteractiveShell inherits from SingletonConfigurable, so use instance()
124 #
125 self.IP = IPython.terminal.embed.InteractiveShellEmbed.instance(config=cfg, user_ns=user_ns)
126
127 if IPython.version_info < (8,):
128 sys.stdout, sys.stderr = old_stdout, old_stderr
129
130 self.IP.system = lambda cmd: self.shell(
131 self.IP.var_expand(cmd), header="IPython system call: "
132 )
133 # local_ns=user_ns)
134 # global_ns=user_global_ns)
135 # verbose=self.IP.rc.system_verbose)
136
137 self.IP.raw_input = input_func
138 sys.excepthook = excepthook
139 self.iter_more = 0
141 self.complete_sep = re.compile("[\s\{\}\[\]\‍(\‍)]")
142 self.updateNamespace({"exit": lambda: None})
143 self.updateNamespace({"quit": lambda: None})
144 # Workaround for updating namespace with sys.modules
145 #
146 self.__update_namespace()
147
148 # Avoid using input splitter when not really needed.
149 # Perhaps it could work even before 5.8.0
150 # But it definitely does not work any more with >= 7.0.0
151 self.no_input_splitter = parse_version(IPython.release.version) >= parse_version("5.8.0")
152 self.lines = []
154
156 """!
157 Update self.IP namespace for autocompletion with sys.modules
158 @return none
159 """
160 for k, v in list(sys.modules.items()):
161 if not "." in k:
162 self.IP.user_ns.update({k: v})
163
164 def execute(self):
165 """!
166 Executes the current line provided by the shell object.
167 @return none
168 """
169 self.history_level = 0
170
171 if IPython.version_info < (8,):
172 # this is needed because some functions in IPython use 'print' to print
173 # output (like 'who')
174
175 orig_stdout = sys.stdout
176 sys.stdout = IPython.utils.io.stdout
177
178 orig_stdin = sys.stdin
179 sys.stdin = IPython.utils.io.stdin
180
182
183 self.IP.hooks.pre_prompt_hook()
184 if self.iter_more:
185 try:
186 self.prompt = self.generatePrompt(True)
187 except:
188 self.IP.showtraceback()
189 if self.IP.autoindent:
190 self.IP.rl_do_indent = True
191
192 try:
193 line = self.IP.raw_input(self.prompt)
194 except KeyboardInterrupt:
195 self.IP.write("\nKeyboardInterrupt\n")
196 if self.no_input_splitter:
197 self.lines = []
198 else:
199 self.IP.input_splitter.reset()
200 except:
201 self.IP.showtraceback()
202 else:
203 if self.no_input_splitter:
204 self.lines.append(line)
205 (status, self.indent_spaces) = self.IP.check_complete("\n".join(self.lines))
206 self.iter_more = status == "incomplete"
207 else:
208 self.IP.input_splitter.push(line)
209 self.iter_more = self.IP.input_splitter.push_accepts_more()
210 if not self.iter_more:
211 if self.no_input_splitter:
212 source_raw = "\n".join(self.lines)
213 self.lines = []
214 else:
215 source_raw = self.IP.input_splitter.raw_reset()
216 self.IP.run_cell(source_raw, store_history=True)
217 self.IP.rl_do_indent = False
218 else:
219 # TODO: Auto-indent
220 #
221 self.IP.rl_do_indent = True
222 pass
223 self.prompt = self.generatePrompt(self.iter_more)
224
225 if IPython.version_info < (8,):
226 sys.stdout = orig_stdout
227 sys.stdin = orig_stdin
228
229 def generatePrompt(self, is_continuation):
230 """!
231 Generate prompt depending on is_continuation value
232
233 @param is_continuation
234 @return: The prompt string representation
235
236 """
237
238 if is_continuation:
239 prompt = "... "
240 else:
241 prompt = ">>> "
242 return prompt
243
244 def historyBack(self):
245 """!
246 Provides one history command back.
247
248 @param self this object
249 @return: The command string.
250 """
251 self.history_level -= 1
252 if not self._getHistory():
253 self.history_level += 1
254 return self._getHistory()
255
256 def historyForward(self):
257 """!
258 Provides one history command forward.
259
260 @param self this object
261 @return: The command string.
262 """
263 if self.history_level < 0:
264 self.history_level += 1
265 return self._getHistory()
266
267 def _getHistory(self):
268 """!
269 Gets the command string of the current history level.
270
271 @param self this object
272 @return: Historic command string.
273 """
274 try:
275 rv = self.IP.user_ns["In"][self.history_level].strip("\n")
276 except IndexError:
277 rv = ""
278 return rv
279
280 def updateNamespace(self, ns_dict):
281 """!
282 Add the current dictionary to the shell namespace.
283
284 @param ns_dict: A dictionary of symbol-values.
285 @return none
286 """
287 self.IP.user_ns.update(ns_dict)
288
289 def complete(self, line):
290 """!
291 Returns an auto completed line and/or possibilities for completion.
292
293 @param line: Given line so far.
294 @return: Line completed as for as possible, and possible further completions.
295 """
296 split_line = self.complete_sep.split(line)
297 if split_line[-1]:
298 possibilities = self.IP.complete(split_line[-1])
299 else:
300 completed = line
301 possibilities = ["", []]
302 if possibilities:
303
304 def _commonPrefix(str1, str2):
305 """!
306 Reduction function. returns common prefix of two given strings.
307
308 @param str1: First string.
309 @param str2: Second string
310 @return: Common prefix to both strings.
311 """
312 for i in range(len(str1)):
313 if not str2.startswith(str1[: i + 1]):
314 return str1[:i]
315 return str1
316
317 if possibilities[1]:
318 common_prefix = reduce(_commonPrefix, possibilities[1]) or split_line[-1]
319 completed = line[: -len(split_line[-1])] + common_prefix
320 else:
321 completed = line
322 else:
323 completed = line
324 return completed, possibilities[1]
325
326 def shell(self, cmd, verbose=0, debug=0, header=""):
327 """!
328 Replacement method to allow shell commands without them blocking.
329
330 @param cmd: Shell command to execute.
331 @param verbose: Verbosity
332 @param debug: Debug level
333 @param header: Header to be printed before output
334 @return none
335 """
336 stat = 0
337 if verbose or debug:
338 print(header + cmd)
339 # flush stdout so we don't mangle python's buffering
340 if not debug:
341 input, output = os.popen4(cmd)
342 print(output.read())
343 output.close()
344 input.close()
345
346
347## ConsoleView class
348class ConsoleView(Gtk.TextView):
349 ## @var ANSI_COLORS
350 # color list
351 ## @var text_buffer
352 # text buffer
353 ## @var mark
354 # scroll mark
355 ## @var color_pat
356 # color pattern
357 ## @var line_start
358 # line start
359 ## @var onKeyPress
360 # onKeyPress function
361 ## @var _write
362 # _write function
363 ## @var _showPrompt
364 # _showPrompt function
365 ## @var _changeLine
366 # _changeLine function
367 ## @var _showReturned
368 # _showReturned function
369 ## @var prompt
370 # prompt function
371
372 """
373 Specialized text view for console-like workflow.
374
375 @cvar ANSI_COLORS: Mapping of terminal control sequence values to
376 tuples containing foreground and background color names.
377 @type ANSI_COLORS: dictionary
378
379 @ivar text_buffer: Widget's text buffer.
380 @type text_buffer: Gtk.TextBuffer
381 @ivar color_pat: Regex of terminal color pattern
382 @type color_pat: _sre.SRE_Pattern
383 @ivar mark: Scroll mark for automatic scrolling on input.
384 @type mark: Gtk.TextMark
385 @ivar line_start: Start of command line mark.
386 @type line_start: Gtk.TextMark
387 """
388 ANSI_COLORS = {
389 "0;30": ("Black", None),
390 "0;31": ("Red", None),
391 "0;32": ("Green", None),
392 "0;33": ("Brown", None),
393 "0;34": ("Blue", None),
394 "0;35": ("Purple", None),
395 "0;36": ("Cyan", None),
396 "0;37": ("LightGray", None),
397 "1;30": ("DarkGray", None),
398 "1;31": ("DarkRed", None),
399 "1;32": ("SeaGreen", None),
400 "1;33": ("Yellow", None),
401 "1;34": ("LightBlue", None),
402 "1;35": ("MediumPurple", None),
403 "1;36": ("LightCyan", None),
404 "1;37": ("White", None),
405 "38;5;124;43": ("DarkRed", "Yellow"),
406 "38;5;241": ("Gray", None),
407 "38;5;241;43": ("Gray", "Yellow"),
408 "39": ("Black", None),
409 "39;49": ("Red", "White"),
410 "43": (None, "Yellow"),
411 "49": (None, "White"),
412 }
413
414 def __init__(self):
415 """
416 Initialize console view.
417 """
418 Gtk.TextView.__init__(self)
419 self.modify_font(Pango.FontDescription("Mono"))
420 self.set_cursor_visible(True)
421 self.text_buffer = self.get_buffer()
422 self.mark = self.text_buffer.create_mark(
423 "scroll_mark", self.text_buffer.get_end_iter(), False
424 )
425 for code in self.ANSI_COLORS:
426 self.text_buffer.create_tag(
427 code,
428 foreground=self.ANSI_COLORS[code][0],
429 background=self.ANSI_COLORS[code][1],
430 weight=700,
431 )
432 self.text_buffer.create_tag("0")
433 self.text_buffer.create_tag("notouch", editable=False)
434 self.color_pat = re.compile("\x01?\x1b\[(.*?)m\x02?")
435 self.line_start = self.text_buffer.create_mark(
436 "line_start", self.text_buffer.get_end_iter(), True
437 )
438 self.connect("key-press-event", self.onKeyPress)
439
440 def write(self, text, editable=False):
441 """!
442 Write given text to buffer.
443
444 @param text: Text to append.
445 @param editable: If true, added text is editable.
446 @return none
447 """
448 GLib.idle_add(self._write, text, editable)
449
450 def _write(self, text, editable=False):
451 """!
452 Write given text to buffer.
453
454 @param text: Text to append.
455 @param editable: If true, added text is editable.
456 @return none
457 """
458 segments = self.color_pat.split(text)
459 segment = segments.pop(0)
460 start_mark = self.text_buffer.create_mark(None, self.text_buffer.get_end_iter(), True)
461 self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
462
463 if segments:
464 ansi_tags = self.color_pat.findall(text)
465 for tag in ansi_tags:
466 i = segments.index(tag)
467 self.text_buffer.insert_with_tags_by_name(
468 self.text_buffer.get_end_iter(), segments[i + 1], str(tag)
469 )
470 segments.pop(i)
471 if not editable:
472 self.text_buffer.apply_tag_by_name(
473 "notouch",
474 self.text_buffer.get_iter_at_mark(start_mark),
475 self.text_buffer.get_end_iter(),
476 )
477 self.text_buffer.delete_mark(start_mark)
478 self.scroll_mark_onscreen(self.mark)
479
480 def showPrompt(self, prompt):
481 """!
482 Prints prompt at start of line.
483
484 @param prompt: Prompt to print.
485 @return none
486 """
487 GLib.idle_add(self._showPrompt, prompt)
488
489 def _showPrompt(self, prompt):
490 """!
491 Prints prompt at start of line.
492
493 @param prompt: Prompt to print.
494 @return none
495 """
496 self._write(prompt)
497 self.text_buffer.move_mark(self.line_start, self.text_buffer.get_end_iter())
498
499 def changeLine(self, text):
500 """!
501 Replace currently entered command line with given text.
502
503 @param text: Text to use as replacement.
504 @return none
505 """
506 GLib.idle_add(self._changeLine, text)
507
508 def _changeLine(self, text):
509 """!
510 Replace currently entered command line with given text.
511
512 @param text: Text to use as replacement.
513 @return none
514 """
515 iter = self.text_buffer.get_iter_at_mark(self.line_start)
516 iter.forward_to_line_end()
517 self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.line_start), iter)
518 self._write(text, True)
519
520 def getCurrentLine(self):
521 """!
522 Get text in current command line.
523
524 @return Text of current command line.
525 """
526 rv = self.text_buffer.get_slice(
527 self.text_buffer.get_iter_at_mark(self.line_start),
528 self.text_buffer.get_end_iter(),
529 False,
530 )
531 return rv
532
533 def showReturned(self, text):
534 """!
535 Show returned text from last command and print new prompt.
536
537 @param text: Text to show.
538 @return none
539 """
540 GLib.idle_add(self._showReturned, text)
541
542 def _showReturned(self, text):
543 """!
544 Show returned text from last command and print new prompt.
545
546 @param text: Text to show.
547 @return none
548 """
549 iter = self.text_buffer.get_iter_at_mark(self.line_start)
550 iter.forward_to_line_end()
551 self.text_buffer.apply_tag_by_name(
552 "notouch", self.text_buffer.get_iter_at_mark(self.line_start), iter
553 )
554 self._write("\n" + text)
555 if text:
556 self._write("\n")
557 self._showPrompt(self.prompt)
558 self.text_buffer.move_mark(self.line_start, self.text_buffer.get_end_iter())
559 self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
560
561 if self.IP.rl_do_indent:
562 if self.no_input_splitter:
563 indentation = self.indent_spaces
564 else:
565 indentation = self.IP.input_splitter.indent_spaces * " "
566 self.text_buffer.insert_at_cursor(indentation)
567
568 def onKeyPress(self, widget, event):
569 """!
570 Key press callback used for correcting behavior for console-like
571 interfaces. For example 'home' should go to prompt, not to beginning of
572 line.
573
574 @param widget: Widget that key press accored in.
575 @param event: Event object
576 @return Return True if event should not trickle.
577 """
578 insert_mark = self.text_buffer.get_insert()
579 insert_iter = self.text_buffer.get_iter_at_mark(insert_mark)
580 selection_mark = self.text_buffer.get_selection_bound()
581 selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
582 start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
583 if event.keyval == Gdk.KEY_Home:
584 if (
585 event.state & Gdk.ModifierType.CONTROL_MASK
586 or event.state & Gdk.ModifierType.MOD1_MASK
587 ):
588 pass
589 elif event.state & Gdk.ModifierType.SHIFT_MASK:
590 self.text_buffer.move_mark(insert_mark, start_iter)
591 return True
592 else:
593 self.text_buffer.place_cursor(start_iter)
594 return True
595 elif event.keyval == Gdk.KEY_Left:
596 insert_iter.backward_cursor_position()
597 if not insert_iter.editable(True):
598 return True
599 elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval in [ord("L"), ord("l")]:
600 # clear previous output on Ctrl+L, but remember current input line + cursor position
601 cursor_offset = self.text_buffer.get_property("cursor-position")
602 cursor_pos_in_line = cursor_offset - start_iter.get_offset() + len(self.prompt)
603 current_input = self.text_buffer.get_text(
604 start_iter, self.text_buffer.get_end_iter(), False
605 )
606 self.text_buffer.set_text(self.prompt + current_input)
607 self.text_buffer.move_mark(
608 self.line_start, self.text_buffer.get_iter_at_offset(len(self.prompt))
609 )
610 self.text_buffer.place_cursor(self.text_buffer.get_iter_at_offset(cursor_pos_in_line))
611 return True
612 elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval in [Gdk.KEY_k, Gdk.KEY_K]:
613 # clear text after input cursor on Ctrl+K
614 if insert_iter.editable(True):
615 self.text_buffer.delete(insert_iter, self.text_buffer.get_end_iter())
616 return True
617 elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval == Gdk.KEY_C:
618 # copy selection on Ctrl+C (upper-case 'C' only)
619 self.text_buffer.copy_clipboard(Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD))
620 return True
621 elif not event.string:
622 pass
623 elif start_iter.compare(insert_iter) <= 0 and start_iter.compare(selection_iter) <= 0:
624 pass
625 elif start_iter.compare(insert_iter) > 0 and start_iter.compare(selection_iter) > 0:
626 self.text_buffer.place_cursor(start_iter)
627 elif insert_iter.compare(selection_iter) < 0:
628 self.text_buffer.move_mark(insert_mark, start_iter)
629 elif insert_iter.compare(selection_iter) > 0:
630 self.text_buffer.move_mark(selection_mark, start_iter)
631
632 return self.onKeyPressExtend(event)
633
634 def onKeyPressExtend(self, event):
635 """!
636 For some reason we can't extend onKeyPress directly (bug #500900).
637 @param event key press
638 @return none
639 """
640 pass
641
642
643## IPythonView class
645 ## @var cout
646 # cout
647 ## @var interrupt
648 # interrupt
649 ## @var execute
650 # execute
651 ## @var prompt
652 # prompt
653 ## @var showPrompt
654 # show prompt
655 ## @var history_pos
656 # history list
657 ## @var window
658 # GTK Window
659 """
660 Sub-class of both modified IPython shell and L{ConsoleView} this makes
661 a GTK+ IPython console.
662 """
663
664 def __init__(self):
665 """
666 Initialize. Redirect I/O to console.
667 """
668 ConsoleView.__init__(self)
669 self.cout = StringIO()
670 IterableIPShell.__init__(self, cout=self.cout, cerr=self.cout, input_func=self.raw_input)
671 self.interrupt = False
672 self.execute()
673 self.promptprompt = self.generatePrompt(False)
674 self.cout.truncate(0)
675 self.showPrompt(self.promptprompt)
676
677 def raw_input(self, prompt=""):
678 """!
679 Custom raw_input() replacement. Gets current line from console buffer.
680
681 @param prompt: Prompt to print. Here for compatibility as replacement.
682 @return The current command line text.
683 """
684 if self.interrupt:
685 self.interrupt = False
686 raise KeyboardInterrupt
687 return self.getCurrentLine()
688
689 def onKeyPressExtend(self, event):
690 """!
691 Key press callback with plenty of shell goodness, like history,
692 autocompletions, etc.
693
694 @param event: Event object.
695 @return True if event should not trickle.
696 """
697
698 if event.get_state() & Gdk.ModifierType.CONTROL_MASK and event.keyval == 99:
699 self.interrupt = True
700 self._processLine()
701 return True
702 elif event.keyval == Gdk.KEY_Return:
703 self._processLine()
704 return True
705 elif event.keyval == Gdk.KEY_Up:
706 self.changeLine(self.historyBack())
707 return True
708 elif event.keyval == Gdk.KEY_Down:
709 self.changeLine(self.historyForward())
710 return True
711 elif event.keyval == Gdk.KEY_Tab:
712 if not self.getCurrentLine().strip():
713 return False
714 completed, possibilities = self.complete(self.getCurrentLine())
715 if len(possibilities) > 1:
716 slice = self.getCurrentLine()
717 self.write("\n")
718 for symbol in possibilities:
719 self.write(symbol + "\n")
720 self.showPrompt(self.promptprompt)
721 self.changeLine(completed or slice)
722 return True
723
724 def _processLine(self):
725 """!
726 Process current command line.
727 @return none
728 """
729 self.history_pos = 0
730 self.execute()
731 rv = self.cout.getvalue()
732 if rv:
733 rv = rv.strip("\n")
734 self.showReturned(rv)
735 self.cout.truncate(0)
736 self.cout.seek(0)
737
738
739if __name__ == "__main__":
740 window = Gtk.Window()
741 window.set_default_size(640, 320)
742 window.connect("delete-event", lambda x, y: Gtk.main_quit())
743 window.add(IPythonView())
744 window.show_all()
745 Gtk.main()
def write(self, text, editable=False)
Write given text to buffer.
def changeLine(self, text)
Replace currently entered command line with given text.
def _showReturned(self, text)
Show returned text from last command and print new prompt.
def getCurrentLine(self)
Get text in current command line.
def _showPrompt(self, prompt)
Prints prompt at start of line.
def onKeyPressExtend(self, event)
For some reason we can't extend onKeyPress directly (bug #500900).
def onKeyPress(self, widget, event)
Key press callback used for correcting behavior for console-like interfaces.
def showPrompt(self, prompt)
Prints prompt at start of line.
def _write(self, text, editable=False)
Write given text to buffer.
def _changeLine(self, text)
Replace currently entered command line with given text.
def showReturned(self, text)
Show returned text from last command and print new prompt.
def onKeyPressExtend(self, event)
Key press callback with plenty of shell goodness, like history, autocompletions, etc.
def _processLine(self)
Process current command line.
def raw_input(self, prompt="")
Custom raw_input() replacement.
def updateNamespace(self, ns_dict)
Add the current dictionary to the shell namespace.
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 __init__(self, argv=[], user_ns=None, user_global_ns=None, cin=None, cout=None, cerr=None, input_func=None)
Constructor for the IterableIPShell class.
Definition: ipython_view.py:74
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