2 Backend to the console plugin.
4 @author: Eitan Isaacson
5 @organization: IBM Corporation
6 @copyright: Copyright (c) 2007 IBM Corporation
9 All rights reserved. This program and the accompanying materials are made
10 available under the terms of the BSD which accompanies this distribution, and
11 is available at U{http://www.opensource.org/licenses/bsd-license.php}
19 gi.require_version(
"Gtk",
"3.0")
23 from functools
import reduce
24 from io
import StringIO
26 from gi.repository
import Gdk, GLib, Gtk, Pango
27 from pkg_resources
import parse_version
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()
88 IPython.terminal.interactiveshell.raw_input_original = input_func
89 if IPython.version_info < (8,):
91 io.stdin = io.IOStream(cin)
93 io.stdout = io.IOStream(cout)
95 io.stderr = io.IOStream(cerr)
106 io.raw_input =
lambda x:
None
108 os.environ[
"TERM"] =
"dumb"
109 excepthook = sys.excepthook
111 from traitlets.config.loader
import Config
114 cfg.InteractiveShell.colors =
"Linux"
115 cfg.Completer.use_jedi =
False
117 if IPython.version_info < (8,):
120 old_stdout, old_stderr = sys.stdout, sys.stderr
121 sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
125 self.
IPIP = IPython.terminal.embed.InteractiveShellEmbed.instance(config=cfg, user_ns=user_ns)
127 if IPython.version_info < (8,):
128 sys.stdout, sys.stderr = old_stdout, old_stderr
130 self.
IPIP.system =
lambda cmd: self.
shellshell(
131 self.
IPIP.var_expand(cmd), header=
"IPython system call: "
137 self.
IPIP.raw_input = input_func
138 sys.excepthook = excepthook
151 self.
no_input_splitterno_input_splitter = parse_version(IPython.release.version) >= parse_version(
"5.8.0")
157 Update self.IP namespace for autocompletion with sys.modules
160 for k, v
in list(sys.modules.items()):
162 self.
IPIP.user_ns.update({k: v})
166 Executes the current line provided by the shell object.
171 if IPython.version_info < (8,):
175 orig_stdout = sys.stdout
176 sys.stdout = IPython.utils.io.stdout
178 orig_stdin = sys.stdin
179 sys.stdin = IPython.utils.io.stdin
183 self.
IPIP.hooks.pre_prompt_hook()
188 self.
IPIP.showtraceback()
189 if self.
IPIP.autoindent:
190 self.
IPIP.rl_do_indent =
True
193 line = self.
IPIP.raw_input(self.
promptprompt)
194 except KeyboardInterrupt:
195 self.
IPIP.write(
"\nKeyboardInterrupt\n")
199 self.
IPIP.input_splitter.reset()
201 self.
IPIP.showtraceback()
204 self.
lineslines.append(line)
205 (status, self.
indent_spacesindent_spaces) = self.
IPIP.check_complete(
"\n".join(self.
lineslines))
206 self.
iter_moreiter_more = status ==
"incomplete"
208 self.
IPIP.input_splitter.push(line)
209 self.
iter_moreiter_more = self.
IPIP.input_splitter.push_accepts_more()
212 source_raw =
"\n".join(self.
lineslines)
215 source_raw = self.
IPIP.input_splitter.raw_reset()
216 self.
IPIP.run_cell(source_raw, store_history=
True)
217 self.
IPIP.rl_do_indent =
False
221 self.
IPIP.rl_do_indent =
True
225 if IPython.version_info < (8,):
226 sys.stdout = orig_stdout
227 sys.stdin = orig_stdin
231 Generate prompt depending on is_continuation value
233 @param is_continuation
234 @return: The prompt string representation
246 Provides one history command back.
248 @param self this object
249 @return: The command string.
258 Provides one history command forward.
260 @param self this object
261 @return: The command string.
269 Gets the command string of the current history level.
271 @param self this object
272 @return: Historic command string.
275 rv = self.
IPIP.user_ns[
"In"][self.
history_levelhistory_level].strip(
"\n")
282 Add the current dictionary to the shell namespace.
284 @param ns_dict: A dictionary of symbol-values.
287 self.
IPIP.user_ns.update(ns_dict)
291 Returns an auto completed line and/or possibilities for completion.
293 @param line: Given line so far.
294 @return: Line completed as for as possible, and possible further completions.
298 possibilities = self.
IPIP.
complete(split_line[-1])
301 possibilities = [
"", []]
304 def _commonPrefix(str1, str2):
306 Reduction function. returns common prefix of two given strings.
308 @param str1: First string.
309 @param str2: Second string
310 @return: Common prefix to both strings.
312 for i
in range(len(str1)):
313 if not str2.startswith(str1[: i + 1]):
318 common_prefix = reduce(_commonPrefix, possibilities[1])
or split_line[-1]
319 completed = line[: -len(split_line[-1])] + common_prefix
324 return completed, possibilities[1]
326 def shell(self, cmd, verbose=0, debug=0, header=""):
328 Replacement method to allow shell commands without them blocking.
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
341 input, output = os.popen4(cmd)
373 Specialized text view for console-like workflow.
375 @cvar ANSI_COLORS: Mapping of terminal control sequence values to
376 tuples containing foreground and background color names.
377 @type ANSI_COLORS: dictionary
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
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"),
416 Initialize console view.
418 Gtk.TextView.__init__(self)
419 self.modify_font(Pango.FontDescription(
"Mono"))
420 self.set_cursor_visible(
True)
423 "scroll_mark", self.
text_buffertext_buffer.get_end_iter(),
False
433 self.
text_buffertext_buffer.create_tag(
"notouch", editable=
False)
434 self.
color_patcolor_pat = re.compile(
"\x01?\x1b\[(.*?)m\x02?")
436 "line_start", self.
text_buffertext_buffer.get_end_iter(),
True
438 self.connect(
"key-press-event", self.
onKeyPressonKeyPress)
440 def write(self, text, editable=False):
442 Write given text to buffer.
444 @param text: Text to append.
445 @param editable: If true, added text is editable.
448 GLib.idle_add(self.
_write_write, text, editable)
452 Write given text to buffer.
454 @param text: Text to append.
455 @param editable: If true, added text is editable.
458 segments = self.
color_patcolor_pat.split(text)
459 segment = segments.pop(0)
460 start_mark = self.
text_buffertext_buffer.create_mark(
None, self.
text_buffertext_buffer.get_end_iter(),
True)
464 ansi_tags = self.
color_patcolor_pat.findall(text)
465 for tag
in ansi_tags:
466 i = segments.index(tag)
467 self.
text_buffertext_buffer.insert_with_tags_by_name(
468 self.
text_buffertext_buffer.get_end_iter(), segments[i + 1], str(tag)
474 self.
text_buffertext_buffer.get_iter_at_mark(start_mark),
477 self.
text_buffertext_buffer.delete_mark(start_mark)
478 self.scroll_mark_onscreen(self.
markmark)
482 Prints prompt at start of line.
484 @param prompt: Prompt to print.
491 Prints prompt at start of line.
493 @param prompt: Prompt to print.
501 Replace currently entered command line with given text.
503 @param text: Text to use as replacement.
510 Replace currently entered command line with given text.
512 @param text: Text to use as replacement.
516 iter.forward_to_line_end()
518 self.
_write_write(text,
True)
522 Get text in current command line.
524 @return Text of current command line.
535 Show returned text from last command and print new prompt.
537 @param text: Text to show.
544 Show returned text from last command and print new prompt.
546 @param text: Text to show.
550 iter.forward_to_line_end()
554 self.
_write_write(
"\n" + text)
561 if self.IP.rl_do_indent:
562 if self.no_input_splitter:
563 indentation = self.indent_spaces
565 indentation = self.IP.input_splitter.indent_spaces *
" "
566 self.
text_buffertext_buffer.insert_at_cursor(indentation)
570 Key press callback used for correcting behavior for console-like
571 interfaces. For example 'home' should go to prompt, not to beginning of
574 @param widget: Widget that key press accored in.
575 @param event: Event object
576 @return Return True if event should not trickle.
578 insert_mark = self.
text_buffertext_buffer.get_insert()
579 insert_iter = self.
text_buffertext_buffer.get_iter_at_mark(insert_mark)
580 selection_mark = self.
text_buffertext_buffer.get_selection_bound()
581 selection_iter = self.
text_buffertext_buffer.get_iter_at_mark(selection_mark)
583 if event.keyval == Gdk.KEY_Home:
585 event.state & Gdk.ModifierType.CONTROL_MASK
586 or event.state & Gdk.ModifierType.MOD1_MASK
589 elif event.state & Gdk.ModifierType.SHIFT_MASK:
590 self.
text_buffertext_buffer.move_mark(insert_mark, start_iter)
593 self.
text_buffertext_buffer.place_cursor(start_iter)
595 elif event.keyval == Gdk.KEY_Left:
596 insert_iter.backward_cursor_position()
597 if not insert_iter.editable(
True):
599 elif event.state & Gdk.ModifierType.CONTROL_MASK
and event.keyval
in [ord(
"L"), ord(
"l")]:
601 cursor_offset = self.
text_buffertext_buffer.get_property(
"cursor-position")
602 cursor_pos_in_line = cursor_offset - start_iter.get_offset() + len(self.prompt)
603 current_input = self.
text_buffertext_buffer.get_text(
604 start_iter, self.
text_buffertext_buffer.get_end_iter(),
False
606 self.
text_buffertext_buffer.set_text(self.prompt + current_input)
610 self.
text_buffertext_buffer.place_cursor(self.
text_buffertext_buffer.get_iter_at_offset(cursor_pos_in_line))
612 elif event.state & Gdk.ModifierType.CONTROL_MASK
and event.keyval
in [Gdk.KEY_k, Gdk.KEY_K]:
614 if insert_iter.editable(
True):
617 elif event.state & Gdk.ModifierType.CONTROL_MASK
and event.keyval == Gdk.KEY_C:
619 self.
text_buffertext_buffer.copy_clipboard(Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD))
621 elif not event.string:
623 elif start_iter.compare(insert_iter) <= 0
and start_iter.compare(selection_iter) <= 0:
625 elif start_iter.compare(insert_iter) > 0
and start_iter.compare(selection_iter) > 0:
626 self.
text_buffertext_buffer.place_cursor(start_iter)
627 elif insert_iter.compare(selection_iter) < 0:
628 self.
text_buffertext_buffer.move_mark(insert_mark, start_iter)
629 elif insert_iter.compare(selection_iter) > 0:
630 self.
text_buffertext_buffer.move_mark(selection_mark, start_iter)
636 For some reason we can't extend onKeyPress directly (bug #500900).
637 @param event key press
644 class IPythonView(ConsoleView, IterableIPShell):
660 Sub-class of both modified IPython shell and L{ConsoleView} this makes
661 a GTK+ IPython console.
666 Initialize. Redirect I/O to console.
668 ConsoleView.__init__(self)
670 IterableIPShell.__init__(self, cout=self.
coutcout, cerr=self.
coutcout, input_func=self.
raw_inputraw_input)
674 self.
coutcout.truncate(0)
679 Custom raw_input() replacement. Gets current line from console buffer.
681 @param prompt: Prompt to print. Here for compatibility as replacement.
682 @return The current command line text.
686 raise KeyboardInterrupt
691 Key press callback with plenty of shell goodness, like history,
692 autocompletions, etc.
694 @param event: Event object.
695 @return True if event should not trickle.
698 if event.get_state() & Gdk.ModifierType.CONTROL_MASK
and event.keyval == 99:
702 elif event.keyval == Gdk.KEY_Return:
705 elif event.keyval == Gdk.KEY_Up:
708 elif event.keyval == Gdk.KEY_Down:
711 elif event.keyval == Gdk.KEY_Tab:
715 if len(possibilities) > 1:
717 self.
writewrite(
"\n")
718 for symbol
in possibilities:
719 self.
writewrite(symbol +
"\n")
726 Process current command line.
731 rv = self.
coutcout.getvalue()
735 self.
coutcout.truncate(0)
736 self.
coutcout.seek(0)
739 if __name__ ==
"__main__":
740 window = Gtk.Window()
741 window.set_default_size(640, 320)
742 window.connect(
"delete-event",
lambda x, y: Gtk.main_quit())
def write(self, text, editable=False)
Write given text to buffer.
def changeLine(self, text)
Replace currently entered command line with given text.
dictionary ANSI_COLORS
color list
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.
no_input_splitter
no input splitter
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.
def historyBack(self)
Provides one history command back.
history_level
history level
def generatePrompt(self, is_continuation)
Generate prompt depending on is_continuation value.
def historyForward(self)
Provides one history command forward.
indent_spaces
indent spaces
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.