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} 
   21 from StringIO 
import StringIO
 
   24 from pkg_resources 
import parse_version
 
   32   def __init__(self,argv=None,user_ns=None,user_global_ns=None,
 
   33                cin=
None, cout=
None,cerr=
None, input_func=
None):
 
   37     @param argv: Command line options for IPython 
   39     @param user_ns: User namespace. 
   40     @type user_ns: dictionary 
   41     @param user_global_ns: User global namespace. 
   42     @type user_global_ns: dictionary. 
   43     @param cin: Console standard input. 
   45     @param cout: Console standard output. 
   47     @param cerr: Console standard error. 
   49     @param input_func: Replacement for builtin raw_input() 
   50     @type input_func: function 
   54       if parse_version(IPython.release.version) >= parse_version(
"1.2.1"):
 
   55         IPython.terminal.interactiveshell.raw_input_original = input_func
 
   57         IPython.frontend.terminal.interactiveshell.raw_input_original = input_func
 
   59       io.stdin = io.IOStream(cin)
 
   61       io.stdout = io.IOStream(cout)
 
   63       io.stderr = io.IOStream(cerr)
 
   68     io.raw_input = 
lambda x: 
None 
   70     os.environ[
'TERM'] = 
'dumb' 
   71     excepthook = sys.excepthook 
 
   73     from IPython.config.loader 
import Config
 
   75     cfg.InteractiveShell.colors = 
"Linux" 
   80     old_stdout, old_stderr = sys.stdout, sys.stderr
 
   81     sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
 
   85     if parse_version(IPython.release.version) >= parse_version(
"1.2.1"):
 
   86       self.
IP = IPython.terminal.embed.InteractiveShellEmbed.instance(\
 
   87               config=cfg, user_ns=user_ns)
 
   89       self.
IP = IPython.frontend.terminal.embed.InteractiveShellEmbed.instance(\
 
   90               config=cfg, user_ns=user_ns)
 
   92     sys.stdout, sys.stderr = old_stdout, old_stderr
 
   94     self.IP.system = 
lambda cmd: self.
shell(self.IP.var_expand(cmd),
 
   95                                             header=
'IPython system call: ')
 
  100     self.IP.raw_input = input_func
 
  101     sys.excepthook = excepthook
 
  107     self.IP.readline_startup_hook(self.IP.pre_readline)
 
  114     Update self.IP namespace for autocompletion with sys.modules 
  116     for k, v 
in list(sys.modules.items()):
 
  118           self.IP.user_ns.update({k:v})
 
  122     Executes the current line provided by the shell object. 
  125     orig_stdout = sys.stdout
 
  126     sys.stdout = IPython.utils.io.stdout
 
  128     orig_stdin = sys.stdin
 
  129     sys.stdin = IPython.utils.io.stdin;
 
  132     self.IP.hooks.pre_prompt_hook()
 
  137             self.IP.showtraceback()
 
  138         if self.IP.autoindent:
 
  139             self.IP.rl_do_indent = 
True 
  142       line = self.IP.raw_input(self.
prompt)
 
  143     except KeyboardInterrupt:
 
  144       self.IP.write(
'\nKeyboardInterrupt\n')
 
  145       self.IP.input_splitter.reset()
 
  147       self.IP.showtraceback()
 
  149       self.IP.input_splitter.push(line)
 
  150       self.
iter_more = self.IP.input_splitter.push_accepts_more()
 
  152       if (self.IP.SyntaxTB.last_syntax_error 
and 
  153           self.IP.autoedit_syntax):
 
  154           self.IP.edit_syntax_error()
 
  156           if parse_version(IPython.release.version) >= parse_version(
"2.0.0-dev"):
 
  157             source_raw = self.IP.input_splitter.raw_reset()
 
  159             source_raw = self.IP.input_splitter.source_raw_reset()[1]
 
  160           self.IP.run_cell(source_raw, store_history=
True)
 
  161           self.IP.rl_do_indent = 
False 
  165           self.IP.rl_do_indent = 
True 
  168     sys.stdout = orig_stdout
 
  169     sys.stdin = orig_stdin
 
  173     Generate prompt depending on is_continuation value 
  175     @param is_continuation 
  176     @type is_continuation: boolean  
  178     @return: The prompt string representation 
  185     ver = IPython.__version__
 
  187         prompt = self.IP.hooks.generate_prompt(is_continuation)
 
  190             prompt = self.IP.prompt_manager.render(
'in2')
 
  192             prompt = self.IP.prompt_manager.render(
'in')
 
  199     Provides one history command back. 
  201     @return: The command string. 
  211     Provides one history command forward. 
  213     @return: The command string. 
  222     Get's the command string of the current history level. 
  224     @return: Historic command string. 
  235     Add the current dictionary to the shell namespace. 
  237     @param ns_dict: A dictionary of symbol-values. 
  238     @type ns_dict: dictionary 
  240     self.IP.user_ns.update(ns_dict)
 
  244     Returns an auto completed line and/or posibilities for completion. 
  246     @param line: Given line so far. 
  249     @return: Line completed as for as possible,  
  250     and possible further completions. 
  253     split_line = self.complete_sep.split(line)
 
  255       possibilities = self.IP.complete(split_line[-1])
 
  258       possibilities = [
'', []]
 
  260       def _commonPrefix(str1, str2):
 
  262         Reduction function. returns common prefix of two given strings. 
  264         @param str1: First string. 
  266         @param str2: Second string 
  269         @return: Common prefix to both strings. 
  272         for i 
in range(len(str1)):
 
  273           if not str2.startswith(str1[:i+1]):
 
  277         common_prefix = reduce(_commonPrefix, possibilities[1]) 
or line[-1]
 
  278         completed = line[:-len(split_line[-1])]+common_prefix
 
  283     return completed, possibilities[1]
 
  286   def shell(self, cmd,verbose=0,debug=0,header=''):
 
  288     Replacement method to allow shell commands without them blocking. 
  290     @param cmd: Shell command to execute. 
  292     @param verbose: Verbosity 
  293     @type verbose: integer 
  294     @param debug: Debug level 
  296     @param header: Header to be printed before output 
  300     if verbose 
or debug: 
print header+cmd
 
  303       input, output = os.popen4(cmd)
 
  310   Specialized text view for console-like workflow. 
  312   @cvar ANSI_COLORS: Mapping of terminal colors to X11 names. 
  313   @type ANSI_COLORS: dictionary 
  315   @ivar text_buffer: Widget's text buffer. 
  316   @type text_buffer: gtk.TextBuffer 
  317   @ivar color_pat: Regex of terminal color pattern 
  318   @type color_pat: _sre.SRE_Pattern 
  319   @ivar mark: Scroll mark for automatic scrolling on input. 
  320   @type mark: gtk.TextMark 
  321   @ivar line_start: Start of command line mark. 
  322   @type line_start: gtk.TextMark 
  324   ANSI_COLORS =  {
'0;30': 
'Black',     
'0;31': 
'Red',
 
  325                   '0;32': 
'Green',     
'0;33': 
'Brown',
 
  326                   '0;34': 
'Blue',      
'0;35': 
'Purple',
 
  327                   '0;36': 
'Cyan',      
'0;37': 
'LightGray',
 
  328                   '1;30': 
'DarkGray',  
'1;31': 
'DarkRed',
 
  329                   '1;32': 
'SeaGreen',  
'1;33': 
'Yellow',
 
  330                   '1;34': 
'LightBlue', 
'1;35': 
'MediumPurple',
 
  331                   '1;36': 
'LightCyan', 
'1;37': 
'White'}
 
  335     Initialize console view. 
  337     gtk.TextView.__init__(self)
 
  338     self.modify_font(pango.FontDescription(
'Mono'))
 
  339     self.set_cursor_visible(
True)
 
  341     self.
mark = self.text_buffer.create_mark(
'scroll_mark',
 
  342                                              self.text_buffer.get_end_iter(),
 
  345       self.text_buffer.create_tag(code, 
 
  348     self.text_buffer.create_tag(
'0')
 
  349     self.text_buffer.create_tag(
'notouch', editable=
False)
 
  352         self.text_buffer.create_mark(
'line_start', 
 
  353                                      self.text_buffer.get_end_iter(), 
True)
 
  354     self.connect(
'key-press-event', self.
onKeyPress)
 
  356   def write(self, text, editable=False):
 
  357     gobject.idle_add(self.
_write, text, editable)
 
  361     Write given text to buffer. 
  363     @param text: Text to append. 
  365     @param editable: If true, added text is editable. 
  366     @type editable: boolean 
  368     segments = self.color_pat.split(text)
 
  369     segment = segments.pop(0)
 
  370     start_mark = self.text_buffer.create_mark(
None,
 
  371                                               self.text_buffer.get_end_iter(),
 
  373     self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
 
  376       ansi_tags = self.color_pat.findall(text)
 
  377       for tag 
in ansi_tags:
 
  378         i = segments.index(tag)
 
  379         self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(),
 
  380                                                   segments[i+1], str(tag))
 
  383       self.text_buffer.apply_tag_by_name(
'notouch',
 
  384                                          self.text_buffer.get_iter_at_mark(start_mark),
 
  385                                          self.text_buffer.get_end_iter())
 
  386     self.text_buffer.delete_mark(start_mark)
 
  387     self.scroll_mark_onscreen(self.
mark)
 
  394     Prints prompt at start of line. 
  396     @param prompt: Prompt to print. 
  401                                self.text_buffer.get_end_iter())
 
  408     Replace currently entered command line with given text. 
  410     @param text: Text to use as replacement. 
  413     iter = self.text_buffer.get_iter_at_mark(self.
line_start)
 
  414     iter.forward_to_line_end()
 
  415     self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.
line_start), iter)
 
  420     Get text in current command line. 
  422     @return: Text of current command line. 
  425     rv = self.text_buffer.get_slice(
 
  426       self.text_buffer.get_iter_at_mark(self.
line_start),
 
  427       self.text_buffer.get_end_iter(), 
False)
 
  435     Show returned text from last command and print new prompt. 
  437     @param text: Text to show. 
  440     iter = self.text_buffer.get_iter_at_mark(self.
line_start)
 
  441     iter.forward_to_line_end()
 
  442     self.text_buffer.apply_tag_by_name(
 
  444       self.text_buffer.get_iter_at_mark(self.
line_start),
 
  450     self.text_buffer.move_mark(self.
line_start,self.text_buffer.get_end_iter())
 
  451     self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
 
  453     if self.IP.rl_do_indent:
 
  454       indentation = self.IP.input_splitter.indent_spaces * 
' ' 
  455       self.text_buffer.insert_at_cursor(indentation)
 
  459     Key press callback used for correcting behavior for console-like  
  460     interfaces. For example 'home' should go to prompt, not to begining of 
  463     @param widget: Widget that key press accored in. 
  464     @type widget: gtk.Widget 
  465     @param event: Event object 
  466     @type event: gtk.gdk.Event 
  468     @return: Return True if event should not trickle. 
  471     insert_mark = self.text_buffer.get_insert()
 
  472     insert_iter = self.text_buffer.get_iter_at_mark(insert_mark)
 
  473     selection_mark = self.text_buffer.get_selection_bound()
 
  474     selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
 
  475     start_iter = self.text_buffer.get_iter_at_mark(self.
line_start)
 
  476     if event.keyval == gtk.keysyms.Home:
 
  477       if event.state & gtk.gdk.CONTROL_MASK 
or event.state & gtk.gdk.MOD1_MASK:
 
  479       elif event.state & gtk.gdk.SHIFT_MASK:
 
  480         self.text_buffer.move_mark(insert_mark, start_iter)
 
  483         self.text_buffer.place_cursor(start_iter)
 
  485     elif event.keyval == gtk.keysyms.Left:
 
  486       insert_iter.backward_cursor_position()
 
  487       if not insert_iter.editable(
True):
 
  489     elif not event.string:
 
  491     elif start_iter.compare(insert_iter) <= 0 
and \
 
  492           start_iter.compare(selection_iter) <= 0:
 
  494     elif start_iter.compare(insert_iter) > 0 
and \
 
  495           start_iter.compare(selection_iter) > 0:
 
  496       self.text_buffer.place_cursor(start_iter)
 
  497     elif insert_iter.compare(selection_iter) < 0:
 
  498       self.text_buffer.move_mark(insert_mark, start_iter)
 
  499     elif insert_iter.compare(selection_iter) > 0:
 
  500       self.text_buffer.move_mark(selection_mark, start_iter)             
 
  506     For some reason we can't extend onKeyPress directly (bug #500900). 
  510 class IPythonView(ConsoleView, IterableIPShell):
 
  512   Sub-class of both modified IPython shell and L{ConsoleView} this makes 
  513   a GTK+ IPython console. 
  517     Initialize. Redirect I/O to console. 
  519     ConsoleView.__init__(self)
 
  521     IterableIPShell.__init__(self, cout=self.
cout,cerr=self.
cout,
 
  526     self.cout.truncate(0)
 
  531     Custom raw_input() replacement. Get's current line from console buffer. 
  533     @param prompt: Prompt to print. Here for compatability as replacement. 
  536     @return: The current command line text. 
  541       raise KeyboardInterrupt
 
  546     Key press callback with plenty of shell goodness, like history,  
  547     autocompletions, etc. 
  549     @param widget: Widget that key press occured in. 
  550     @type widget: gtk.Widget 
  551     @param event: Event object. 
  552     @type event: gtk.gdk.Event 
  554     @return: True if event should not trickle. 
  558     if event.state & gtk.gdk.CONTROL_MASK 
and event.keyval == 99:
 
  562     elif event.keyval == gtk.keysyms.Return:
 
  565     elif event.keyval == gtk.keysyms.Up:
 
  568     elif event.keyval == gtk.keysyms.Down:
 
  571     elif event.keyval == gtk.keysyms.Tab:
 
  575       if len(possibilities) > 1:
 
  578         for symbol 
in possibilities:
 
  579           self.
write(symbol+
'\n')
 
  586     Process current command line. 
  590     rv = self.cout.getvalue()
 
  591     if rv: rv = rv.strip(
'\n')
 
  593     self.cout.truncate(0)
 
  596 if __name__ == 
"__main__":
 
  597   window = gtk.Window()
 
  598   window.set_default_size(640, 320)
 
  599   window.connect(
'delete-event', 
lambda x, y: gtk.main_quit())
 
def onKeyPressExtend(self, event)
 
def onKeyPressExtend(self, event)
 
def changeLine(self, text)
 
def _showReturned(self, text)
 
def onKeyPress(self, widget, event)
 
def __update_namespace(self)
 
def generatePrompt(self, is_continuation)
 
def _changeLine(self, text)
 
def updateNamespace(self, ns_dict)
 
def _showPrompt(self, prompt)
 
def showPrompt(self, prompt)
 
def showReturned(self, text)