Example #1
0
 def reset(self):
     sys.ps1 = ps1
     sys.ps2 = ps2
     self.printer.clear()
     self._reset_needed = False
     self.context.clear()
     self.context = self.original_context.copy()
     self.history = ConsoleHistory()
     self.printer.print_new(banner)
     if not self.done_first_run:
         self.done_first_run = True
         self.browser_sniff()
    def __init__(self, locals=None, banner=None,
                 completer=None, use_rlcompleter=True,
                 start_script=None):

        gtk.TextView.__init__(self)
        if not locals:
            locals = __main__.__dict__
        code.InteractiveInterpreter.__init__(self, locals)
        #self.locals['__console__'] = self

        self.banner = banner

        self.completer = completer
        if not self.completer and use_rlcompleter:
            try:
                import rlcompleter
                self.completer = rlcompleter.Completer()
            except ImportError:
                pass

        self.start_script = start_script

        # for debugging
        #start_script="import gtk\n" + \
                      #"win = gtk.Window()\n" + \
                      #"label = gtk.Label('Hello there!')\n" + \
                      #"win.add(label)\n" + \
                      #"win.show_all()\n"

        self.run_on_raw_input = start_script

        self.connect("key-press-event", self.on_key_press_event)

        self.set_wrap_mode(gtk.WRAP_CHAR)
        self.modify_font(pango.FontDescription("Monospace"))

        self.buffer = self.get_buffer()
        self.buffer.connect("insert-text", self.on_buf_insert)
        self.buffer.connect("delete-range", self.on_buf_delete)
        self.buffer.connect("mark-set", self.on_buf_mark_set)
        self.do_insert = False
        self.do_delete = False

        self.cursor = self.buffer.create_mark("cursor", self.buffer.get_start_iter(), False)
        insert = self.buffer.get_insert()
        self.cursor.set_visible(True)
        insert.set_visible(False)

        self.ps = ''
        self.ps1 = ">>> "
        self.ps2 = "... "
        self.in_raw_input = False
        self.tab_pressed = 0
        self.history = ConsoleHistory()

        self.__start()
        self.raw_input(self.ps1)
Example #3
0
 def reset(self):
     sys.ps1 = ps1
     sys.ps2 = ps2
     self.printer.clear()
     self._reset_needed = False
     self.context.clear()
     self.context = self.original_context.copy()
     self.history = ConsoleHistory()
     self.printer.print_new(banner)
     if not self.done_first_run:
         self.done_first_run = True
         self.browser_sniff()
Example #4
0
class ConsoleTextBox(TextBox):
    def __new__(cls, printer, context, root):
        return TextBox.__new__(cls)
    
    def __init__(self, printer, context, root):
        self._input_data = []
        self.original_context = context
        self.printer = printer
        self.prompt = root.prompt
        self.root = root
        self.done_first_run = False
        self._sync = ManualResetEvent(False)
        self.ff3 = False
        
        self.FontSize = 15
        self.Margin = Thickness(0)
        self.FontFamily = FontFamily("Consolas, Monaco, Lucida Console, Global Monospace")
        self.AcceptsReturn = True
        self.BorderThickness = Thickness(0)
        self.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
        self.MinWidth = 300
        
        def reset():
            "Clear the console, its history and the execution context."
            self._reset_needed = True
            return 'resetting'
        def input(prompt='Input:'):
            'input([prompt]) -> value\n\nEquivalent to eval(raw_input(prompt)).'
            return eval(self.context['raw_input'](prompt), self.context, self.context)
        
        self.original_context['reset'] = reset
        self.original_context['gohome'] = gohome
        self.original_context['exit'] = 'There is no escape...'
        self.original_context['raw_input'] = self.raw_input
        self.original_context['input'] = input

        
        # for debugging only!
        self.original_context['root'] = root
        
        self.context = {}
        self.history = None
        self._reset_needed = False
        self._thread = None
        self._thread_reset = None
        self._raw_input_text = ''
        self._temp_context = None
        self.engine = Python.CreateEngine()
        self.scope = self.engine.CreateScope()
        
        self._original_caret = None
        if hasattr(self, 'CaretBrush'):
            self._original_caret = self.CaretBrush
        self._disabled = SolidColorBrush(Colors.White)
        
        self.KeyDown += self.handle_key
        self.TextChanged += self.text_changed

    
    def reset(self):
        sys.ps1 = ps1
        sys.ps2 = ps2
        self.printer.clear()
        self._reset_needed = False
        self.context.clear()
        self.context = self.original_context.copy()
        self.history = ConsoleHistory()
        self.printer.print_new(banner)
        if not self.done_first_run:
            self.done_first_run = True
            self.browser_sniff()

            
    def browser_sniff(self):
        useragent = HtmlPage.BrowserInformation.UserAgent
        match = re.search(FF3_RE, useragent)
        if match is not None:
            browser = match.groups()[0]
            self.printer.print_new(FF3_MESSAGE % browser)
            self.ff3 = True
        
        
    def OnKeyDown(self, event):
        # needed so that we get KeyDown 
        # for del and backspace events etc
        pass


    def text_changed(self, sender, event):
        # replace any tabs that are pasted in
        if '\t' in self.Text:
            self.Text = self.Text.replace('\t', '    ')
            self.SelectionStart = len(self.Text)

        
    def write(self, data):
        self.printer.write(data)

    
    def is_complete(self, text, pos):
        if len(text.splitlines()) > 1 and pos < len(text.rstrip()):
            return False
        if text.endswith('\\'):
            return False
        
        source = self.engine.CreateScriptSourceFromString(text, '<stdin>', SourceCodeKind.InteractiveCode)
        
        result = source.GetCodeProperties()
        if result == ScriptCodeParseResult.IncompleteToken:
            return False
        elif result == ScriptCodeParseResult.IncompleteStatement:
            if not text.rstrip(' ').endswith('\n'):
                return False
        return True
    
    
    def on_first_line(self, text):
        first_line_end = text.find('\n')
        if first_line_end == -1:
            return True
        return self.SelectionStart <= first_line_end
    
    
    def on_last_line(self, text):
        last_line_end = text.rfind('\n')
        if last_line_end == -1:
            return True
        return self.SelectionStart > last_line_end
        
    
    def handle_key(self, sender, event):
        # Mac Safari uses '\r' for newlines in Silverlight TextBox??
        contents = self.Text.replace('\r\n', '\n').replace('\r', '\n')
        key = event.Key
        start = self.SelectionStart
        end = start + self.SelectionLength
        
        modifiers = Keyboard.Modifiers
        control = (modifiers & ModifierKeys.Control) or (modifiers & ModifierKeys.Apple)
        if key == Key.C and control:
            event.Handled = True
            self.keyboard_interrupt()
            return
        
        if self._thread is not None:
            # ignore key events (we have already checked for Ctrl-C)
            event.Handled = True
            return

        if key != Key.Enter:
            if key == Key.Up:
                if self.on_first_line(contents):
                    event.Handled = True
                    previous = self.history.back(contents)
                    if previous is not None:
                        self.Text = previous
                        self.SelectionStart = len(previous)
                    return
                
            elif key == Key.Down:
                if self.on_last_line(contents):
                    event.Handled = True
                    next = self.history.forward(contents)
                    if next is not None:
                        self.Text = next
                        self.SelectionStart = len(next)
                    return
            
            elif key == Key.Tab:
                event.Handled = True
                self.Text = self.Text[:start] + '    ' + self.Text[end:]
                self.SelectionStart = start + 4
                return
            
            if key == key.Add and self.ff3:
                if not (modifiers & ModifierKeys.Shift):
                    event.Handled = True
                    self.Text = self.Text[:start] + '=' + self.Text[end:]
                    self.SelectionStart = start + 1
                    return 
            
            TextBox.OnKeyDown(self, event)
            return
        
        event.Handled = True
        if empty_or_comment_only(contents):
            # needed or we get a SyntaxError
            self.Text = ''
            self.printer.print_lines(contents)
            self.printer.scroll()
            return
        
        # manual handling unfortunately
        # means things like trailing comments break
        # these functions; so not ideal
        stripped = contents.rstrip()
        if stripped == 'gohome':
            gohome()
        elif stripped == 'reset':
            contents = 'reset()'
        elif stripped == 'import this':
            # import hook so that importing *worked*
            # would be a better solution...
            self.printer.print_lines(stripped)
            self.Text = ''
            self.history.append(contents)
            import this
            self.context['this'] = this
            self.printer.set_prompt()
            self.printer.scroll()
            return
        
        if not self.is_complete(contents, start):
            self.do_indent(start)
        else:
            self.execute(contents)


    def execute(self, contents):
        self.printer.print_lines(contents)
        self.Text = ''
        self.history.append(contents)
        
        self._sync.Reset()
        started = ManualResetEvent(False)
        if self._temp_context is not None:
            self.context.update(self._temp_context)
        def _execute():
            context = self.context
            started.Set()
            try:
                code = compile(contents + '\n', '<stdin>', 'single', 
                               PyCF_DONT_IMPLY_DEDENT)
                exec code in context
            except:
                if reset_event.WaitOne(1):
                    # don't print exception messages if thread has been terminated
                    return
                exc_type, value, tb = sys.exc_info()
                if value is None:
                    # String exceptions
                    # workaround for IronPython bug
                    exc_type = Exception
                    value = Exception('StringException')
                    
                tblist = traceback.extract_tb(tb)
                message = traceback.format_list(tblist)
                del message[:1]
                if message:
                    # we don't print the 'Traceback...' part for SyntaxError
                    message.insert(0, "Traceback (most recent call last):\n")
                message.extend(traceback.format_exception_only(exc_type, value))
                self.printer.print_new(''.join(message))
            
            # access through closure not on self as we may be an orphaned
            # thread - with a new reset_event on self
            result = reset_event.WaitOne(0)
            if not reset_event.WaitOne(0):
                self.completed()
            self._sync.Set()
            
        self._thread_reset = reset_event = ManualResetEvent(False)
        self._thread = Thread(ThreadStart(_execute))
        self._thread.IsBackground = True
        self._thread.Name = "executing"
        self._thread.Start()
        self.prompt.Visibility = Visibility.Collapsed
        if hasattr(self, 'CaretBrush'):
            self.CaretBrush = self._disabled
        started.WaitOne()
        
        
    @invoke
    def completed(self, reset_temp=True):
        if reset_temp:
            self._temp_context = None
        self._thread = None
        self.prompt.Visibility = Visibility.Visible
        self._thread_reset = None
        if hasattr(self, 'CaretBrush'):
            self.CaretBrush = self._original_caret
        if self._reset_needed:
            self.reset()
        else:
            self.printer.set_prompt()
            self.printer.scroll()


    def do_indent(self, start):
        to_the_left = self.Text[:start + 1]
        lines = to_the_left.splitlines()
        initial_indent = '    '
        for line in lines:
            # we do this incase the user is using one or two space
            # indent instead of four
            if line.startswith(' '):
                initial_indent = get_indent(line)
                break
        
        # there *must* be something here because an empty textbox
        # would already have been caught by empty_or_comment_only
        last_line = lines[-1]
        new_indent = current_indent = get_indent(last_line)
        if last_line.rstrip().endswith(':'):
            new_indent = current_indent + initial_indent
        elif is_terminator(last_line):
            new_indent = ' ' * (len(current_indent) - len(initial_indent))
        
        new_start = self.SelectionStart
        new_pos = new_start + len(new_indent)
        self.Text = self.Text[:new_start] + '\n' + new_indent + self.Text[new_start:]
        self.SelectionStart = new_pos + 1

        
    def keyboard_interrupt(self):
        # Aborting threads doesn't work on Silverlight :-(
        #self._thread.Abort()
        reset_temp = True
        if self._thread_reset is not None:
            reset_temp = False
            # signal to background thread not to complete
            self._thread_reset.Set()
            context = self.context
            self._temp_context = context.copy()
            # This will hopefully cause the existing thread to error out
            context.clear()
            context['raw_input'] = context['input'] = blow_up
            
        self._thread_reset = None
        self._thread = None
        
        if self.Text.strip():
            self.history.append(self.Text)
        self.printer.print_new('KeyboardInterrupt')
        self.Text = ''
        self.completed(reset_temp)


    @invoke
    def setup_input_box(self, prompt):
        self.Visibility = Visibility.Collapsed
        self.root.rawInputPrompt.Text = prompt + ' '
        self.root.rawInputField.Text = ''
        self.root.rawInputField.Width = self.Width - 60
        self.root.rawInput.Visibility = Visibility.Visible
        self.root.rawInputField.KeyDown += self.check_for_enter
        self.root.rawInputField.Focus()


    @invoke
    def remove_input_box(self):
        self.Visibility = Visibility.Visible
        self.root.rawInput.Visibility = Visibility.Collapsed
        self.root.rawInputField.KeyDown -= self.check_for_enter
        self.printer.print_new(self.root.rawInputPrompt.Text + self._raw_input_text)
        self.Focus()


    def check_for_enter(self, sender, event):
        if event.Key == Key.Enter:
            event.Handled = True
            self._raw_input_text = self.root.rawInputField.Text
            self.input_event.Set()


    def raw_input(self, prompt='Input:'):
        if not isinstance(prompt, str):
            prompt = str(prompt)
        self.input_event = ManualResetEvent(False)
        self.setup_input_box(prompt)
        self.input_event.WaitOne()
        self.remove_input_box()
        return self._raw_input_text


    def _handle_lines(self, lines):
        try:
            self._input_data = []
            for line in lines:
                self.handle_line(line)
            
            if self._input_data:
                self.handle_line('')
            self.Dispatcher.BeginInvoke(self.Focus)
        except Exception, e:
            _debug('Handle lines', e)
Example #5
0
class ConsoleTextBox(TextBox):
    def __new__(cls, printer, context, root):
        return TextBox.__new__(cls)

    def __init__(self, printer, context, root):
        self._input_data = []
        self.original_context = context
        self.printer = printer
        self.prompt = root.prompt
        self.root = root
        self.done_first_run = False
        self._sync = ManualResetEvent(False)
        self.ff3 = False

        self.FontSize = 15
        self.Margin = Thickness(0)
        self.FontFamily = FontFamily(
            "Consolas, Monaco, Lucida Console, Global Monospace")
        self.AcceptsReturn = True
        self.BorderThickness = Thickness(0)
        self.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
        self.MinWidth = 300

        def reset():
            "Clear the console, its history and the execution context."
            self._reset_needed = True
            return 'resetting'

        def input(prompt='Input:'):
            'input([prompt]) -> value\n\nEquivalent to eval(raw_input(prompt)).'
            return eval(self.context['raw_input'](prompt), self.context,
                        self.context)

        self.original_context['reset'] = reset
        self.original_context['gohome'] = gohome
        self.original_context['exit'] = 'There is no escape...'
        self.original_context['raw_input'] = self.raw_input
        self.original_context['input'] = input

        # for debugging only!
        self.original_context['root'] = root

        self.context = {}
        self.history = None
        self._reset_needed = False
        self._thread = None
        self._thread_reset = None
        self._raw_input_text = ''
        self._temp_context = None
        self.engine = Python.CreateEngine()
        self.scope = self.engine.CreateScope()

        self._original_caret = None
        if hasattr(self, 'CaretBrush'):
            self._original_caret = self.CaretBrush
        self._disabled = SolidColorBrush(Colors.White)

        self.KeyDown += self.handle_key
        self.TextChanged += self.text_changed

    def reset(self):
        sys.ps1 = ps1
        sys.ps2 = ps2
        self.printer.clear()
        self._reset_needed = False
        self.context.clear()
        self.context = self.original_context.copy()
        self.history = ConsoleHistory()
        self.printer.print_new(banner)
        if not self.done_first_run:
            self.done_first_run = True
            self.browser_sniff()

    def browser_sniff(self):
        useragent = HtmlPage.BrowserInformation.UserAgent
        match = re.search(FF3_RE, useragent)
        if match is not None:
            browser = match.groups()[0]
            self.printer.print_new(FF3_MESSAGE % browser)
            self.ff3 = True

    def OnKeyDown(self, event):
        # needed so that we get KeyDown
        # for del and backspace events etc
        pass

    def text_changed(self, sender, event):
        # replace any tabs that are pasted in
        if '\t' in self.Text:
            self.Text = self.Text.replace('\t', '    ')
            self.SelectionStart = len(self.Text)

    def write(self, data):
        self.printer.write(data)

    def is_complete(self, text, pos):
        if len(text.splitlines()) > 1 and pos < len(text.rstrip()):
            return False
        if text.endswith('\\'):
            return False

        source = self.engine.CreateScriptSourceFromString(
            text, 'stdin', SourceCodeKind.InteractiveCode)

        try:
            result = source.GetCodeProperties()
        except TypeError:
            # happens when text is 'lambda' for some reason
            return True

        if result == ScriptCodeParseResult.IncompleteToken:
            return False
        elif result == ScriptCodeParseResult.IncompleteStatement:
            if not text.rstrip(' ').endswith('\n'):
                return False
        return True

    def on_first_line(self, text):
        first_line_end = text.find('\n')
        if first_line_end == -1:
            return True
        return self.SelectionStart <= first_line_end

    def on_last_line(self, text):
        last_line_end = text.rfind('\n')
        if last_line_end == -1:
            return True
        return self.SelectionStart > last_line_end

    def handle_key(self, sender, event):
        # Mac Safari uses '\r' for newlines in Silverlight TextBox??
        contents = self.Text.replace('\r\n', '\n').replace('\r', '\n')
        key = event.Key
        start = self.SelectionStart
        end = start + self.SelectionLength

        modifiers = Keyboard.Modifiers
        control = (modifiers & ModifierKeys.Control) or (modifiers
                                                         & ModifierKeys.Apple)
        if key == Key.C and control:
            event.Handled = True
            self.keyboard_interrupt()
            return

        if self._thread is not None:
            # ignore key events (we have already checked for Ctrl-C)
            event.Handled = True
            return

        if key != Key.Enter:
            if key == Key.Up:
                if self.on_first_line(contents):
                    event.Handled = True
                    previous = self.history.back(contents)
                    if previous is not None:
                        self.Text = previous
                        self.SelectionStart = len(previous)
                    return

            elif key == Key.Down:
                if self.on_last_line(contents):
                    event.Handled = True
                    next = self.history.forward(contents)
                    if next is not None:
                        self.Text = next
                        self.SelectionStart = len(next)
                    return

            elif key == Key.Tab:
                event.Handled = True
                self.Text = self.Text[:start] + '    ' + self.Text[end:]
                self.SelectionStart = start + 4
                return

            if key == key.Add and self.ff3:
                if not (modifiers & ModifierKeys.Shift):
                    event.Handled = True
                    self.Text = self.Text[:start] + '=' + self.Text[end:]
                    self.SelectionStart = start + 1
                    return

            TextBox.OnKeyDown(self, event)
            return

        event.Handled = True
        if empty_or_comment_only(contents):
            # needed or we get a SyntaxError
            self.Text = ''
            self.printer.print_lines(contents)
            self.printer.scroll()
            return

        # manual handling unfortunately
        # means things like trailing comments break
        # these functions; so not ideal
        stripped = contents.rstrip()
        if stripped == 'gohome':
            gohome()
        elif stripped == 'reset':
            contents = 'reset()'
        elif stripped == 'import this':
            # import hook so that importing *worked*
            # would be a better solution...
            self.printer.print_lines(stripped)
            self.Text = ''
            self.history.append(contents)
            import this
            self.context['this'] = this
            self.printer.set_prompt()
            self.printer.scroll()
            return

        if not self.is_complete(contents, start):
            self.do_indent(start)
        else:
            self.execute(contents)

    def execute(self, contents):
        self.printer.print_lines(contents)
        self.Text = ''
        self.history.append(contents)

        self._sync.Reset()
        started = ManualResetEvent(False)
        if self._temp_context is not None:
            self.context.update(self._temp_context)

        def _execute():
            context = self.context
            started.Set()
            try:
                code = compile(contents + '\n', '<stdin>', 'single',
                               PyCF_DONT_IMPLY_DEDENT)
                exec code in context
            except:
                if reset_event.WaitOne(1):
                    # don't print exception messages if thread has been terminated
                    return
                exc_type, value, tb = sys.exc_info()
                if value is None:
                    # String exceptions
                    # workaround for IronPython bug
                    exc_type = Exception
                    value = Exception('StringException')

                tblist = traceback.extract_tb(tb)
                message = traceback.format_list(tblist)
                del message[:1]
                if message:
                    # we don't print the 'Traceback...' part for SyntaxError
                    message.insert(0, "Traceback (most recent call last):\n")
                message.extend(traceback.format_exception_only(
                    exc_type, value))
                self.printer.print_new(''.join(message))

            # access through closure not on self as we may be an orphaned
            # thread - with a new reset_event on self
            result = reset_event.WaitOne(0)
            if not reset_event.WaitOne(0):
                self.completed()
            self._sync.Set()

        self._thread_reset = reset_event = ManualResetEvent(False)
        self._thread = Thread(ThreadStart(_execute))
        self._thread.IsBackground = True
        self._thread.Name = "executing"
        self._thread.Start()
        self.prompt.Visibility = Visibility.Collapsed
        if hasattr(self, 'CaretBrush'):
            self.CaretBrush = self._disabled
        started.WaitOne()

    @invoke
    def completed(self, reset_temp=True):
        if reset_temp:
            self._temp_context = None
        self._thread = None
        self.prompt.Visibility = Visibility.Visible
        self._thread_reset = None
        if hasattr(self, 'CaretBrush'):
            self.CaretBrush = self._original_caret
        if self._reset_needed:
            self.reset()
        else:
            self.printer.set_prompt()
            self.printer.scroll()

    def do_indent(self, start):
        to_the_left = self.Text[:start + 1]
        lines = to_the_left.splitlines()
        initial_indent = '    '
        for line in lines:
            # we do this incase the user is using one or two space
            # indent instead of four
            if line.startswith(' '):
                initial_indent = get_indent(line)
                break

        # there *must* be something here because an empty textbox
        # would already have been caught by empty_or_comment_only
        last_line = lines[-1]
        new_indent = current_indent = get_indent(last_line)
        if last_line.rstrip().endswith(':'):
            new_indent = current_indent + initial_indent
        elif is_terminator(last_line):
            new_indent = ' ' * (len(current_indent) - len(initial_indent))

        new_start = self.SelectionStart
        new_pos = new_start + len(new_indent)
        self.Text = self.Text[:new_start] + '\n' + new_indent + self.Text[
            new_start:]
        self.SelectionStart = new_pos + 1

    def keyboard_interrupt(self):
        # Aborting threads doesn't work on Silverlight :-(
        #self._thread.Abort()
        reset_temp = True
        if self._thread_reset is not None:
            reset_temp = False
            # signal to background thread not to complete
            self._thread_reset.Set()
            context = self.context
            self._temp_context = context.copy()
            # This will hopefully cause the existing thread to error out
            context.clear()
            context['raw_input'] = context['input'] = blow_up

        self._thread_reset = None
        self._thread = None

        if self.Text.strip():
            self.history.append(self.Text)
        self.printer.print_new('KeyboardInterrupt')
        self.Text = ''
        self.completed(reset_temp)

    @invoke
    def setup_input_box(self, prompt):
        self.Visibility = Visibility.Collapsed
        self.root.rawInputPrompt.Text = prompt + ' '
        self.root.rawInputField.Text = ''
        self.root.rawInputField.Width = self.Width - 60
        self.root.rawInput.Visibility = Visibility.Visible
        self.root.rawInputField.KeyDown += self.check_for_enter
        self.root.rawInputField.Focus()

    @invoke
    def remove_input_box(self):
        self.Visibility = Visibility.Visible
        self.root.rawInput.Visibility = Visibility.Collapsed
        self.root.rawInputField.KeyDown -= self.check_for_enter
        self.printer.print_new(self.root.rawInputPrompt.Text +
                               self._raw_input_text)
        self.Focus()

    def check_for_enter(self, sender, event):
        if event.Key == Key.Enter:
            event.Handled = True
            self._raw_input_text = self.root.rawInputField.Text
            self.input_event.Set()

    def raw_input(self, prompt='Input:'):
        if not isinstance(prompt, str):
            prompt = str(prompt)
        self.input_event = ManualResetEvent(False)
        self.setup_input_box(prompt)
        self.input_event.WaitOne()
        self.remove_input_box()
        return self._raw_input_text

    def _handle_lines(self, lines):
        try:
            self._input_data = []
            for line in lines:
                self.handle_line(line)

            if self._input_data:
                self.handle_line('')
            self.Dispatcher.BeginInvoke(lambda: self.Focus())
        except Exception, e:
            _debug('Handle lines', e)
class PythonConsole(gtk.TextView, code.InteractiveConsole):

    nonword_re = re.compile("[^\w\._]")


    def __init__(self, locals=None, banner=None,
                 completer=None, use_rlcompleter=True,
                 start_script=None):

        gtk.TextView.__init__(self)
        if not locals:
            locals = __main__.__dict__
        code.InteractiveInterpreter.__init__(self, locals)
        #self.locals['__console__'] = self

        self.banner = banner

        self.completer = completer
        if not self.completer and use_rlcompleter:
            try:
                import rlcompleter
                self.completer = rlcompleter.Completer()
            except ImportError:
                pass

        self.start_script = start_script

        # for debugging
        #start_script="import gtk\n" + \
                      #"win = gtk.Window()\n" + \
                      #"label = gtk.Label('Hello there!')\n" + \
                      #"win.add(label)\n" + \
                      #"win.show_all()\n"

        self.run_on_raw_input = start_script

        self.connect("key-press-event", self.on_key_press_event)

        self.set_wrap_mode(gtk.WRAP_CHAR)
        self.modify_font(pango.FontDescription("Monospace"))

        self.buffer = self.get_buffer()
        self.buffer.connect("insert-text", self.on_buf_insert)
        self.buffer.connect("delete-range", self.on_buf_delete)
        self.buffer.connect("mark-set", self.on_buf_mark_set)
        self.do_insert = False
        self.do_delete = False

        self.cursor = self.buffer.create_mark("cursor", self.buffer.get_start_iter(), False)
        insert = self.buffer.get_insert()
        self.cursor.set_visible(True)
        insert.set_visible(False)

        self.ps = ''
        self.ps1 = ">>> "
        self.ps2 = "... "
        self.in_raw_input = False
        self.tab_pressed = 0
        self.history = ConsoleHistory()

        self.__start()
        self.raw_input(self.ps1)



    def clear(self, start_script=None):
        if start_script is None:
            start_script = self.start_script
        else:
            self.start_script = start_script

        self.__start()
        self.run_on_raw_input = start_script



    def __commit(self):
        end = self.__get_cursor()
        if not end.ends_line():
            end.forward_to_line_end()
        text = self.__get_line()
        self.__move_cursor_to(end)
        self.freeze_undo()
        self.__insert(end, "\n")
        self.in_raw_input = False
        self.history.commit(text)
        self.do_raw_input(text)
        self.thaw_undo()



    def complete(self, text):
        return None



    def __complete(self):
        text = self.__get_text(self.__get_start(), self.__get_cursor())
        start = ''
        word = text
        nonwords = self.nonword_re.findall(text)
        if nonwords:
            last = text.rfind(nonwords[-1]) + len(nonwords[-1])
            start = text[:last]
            word = text[last:]

        completions = self.complete(word)

        if completions:
            prefix = condensation.core.Util.commonprefix(completions)
            if prefix != word:
                start_iter = self.__get_start()
                start_iter.forward_chars(len(start))
                end_iter = start_iter.copy()
                end_iter.forward_chars(len(word))
                self.__delete(start_iter, end_iter)
                self.__insert(end_iter, prefix)
            elif self.tab_pressed > 1:
                self.freeze_undo()
                self.__print_completions(completions)
                self.thaw_undo()
                self.tab_pressed = 0



    def complete_attr(self, start, end):
        try:
            obj = eval(start, self.locals)
            strings = dir(obj)

            if end:
                completions = {}
                for s in strings:
                    if s.startswith(end):
                        completions[s] = None
                completions = completions.keys()
            else:
                completions = strings

            completions.sort()
            return [start + "." + s for s in completions]
        except:
            return None



    def __delete(self, start, end):
        self.do_delete = True
        self.buffer.delete(start, end)
        self.do_delete = False



    def __delete_at_cursor(self, howmany):
        iter = self.__get_cursor()
        end = self.__get_cursor()
        if not end.ends_line():
            end.forward_to_line_end()
        line_len = end.get_line_offset()
        erase_to = iter.get_line_offset() + howmany
        if erase_to > line_len:
            erase_to = line_len
        elif erase_to < len(self.ps):
            erase_to = len(self.ps)
        end.set_line_offset(erase_to)
        self.__delete(iter, end)



    def do_raw_input(self, text):
        if self.cmd_buffer:
            cmd = self.cmd_buffer + "\n" + text
        else:
            cmd = text
        saved = sys.stdout
        sys.stdout = self
        if code.InteractiveInterpreter.runsource(self, cmd):
            self.cmd_buffer = cmd
            ps = self.ps2
        else:
            self.cmd_buffer = ''
            ps = self.ps1
        self.raw_input(ps)
        sys.stdout = saved



    def execfile(self, filename):
        saved = sys.stdout
        sys.stdout = self
        try:
            execfile(filename, self.locals)
        except SystemExit:
            raise
        except:
            self.showtraceback()
        sys.stdout = saved



    def flush(self):
        """
        Dummy method for stream implementation.
        """
        pass



    def freeze_undo(self):
        try:
            self.begin_not_undoable_action()
        except:
            pass



    def __get_cursor(self):
        return self.buffer.get_iter_at_mark(self.cursor)



    def __get_end(self):
        iter = self.__get_cursor()
        if not iter.ends_line():
            iter.forward_to_line_end()
        return iter



    def __get_line(self):
        start = self.__get_start()
        end = self.__get_end()
        return self.buffer.get_text(start, end, False)



    def __get_start(self):
        iter = self.__get_cursor()
        iter.set_line_offset(len(self.ps))
        return iter



    def __get_text(self, start, end):
        return self.buffer.get_text(start, end, False)



    def __get_width(self):
        if not (self.flags() & gtk.REALIZED):
            return 80
        layout = pango.Layout(self.get_pango_context())
        letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
        layout.set_text(letters)
        pix_width = layout.get_pixel_size()[0]
        return self.allocation.width * len(letters) / pix_width



    def __history(self, dir):
        text = self.__get_line()
        new_text = self.history.get(dir, text)
        if not new_text is None:
            self.__replace_line(new_text)
        self.__move_cursor(0)
        self.scroll_to_mark(self.cursor, 0.2)



    def __insert(self, iter, text):
        self.do_insert = True
        self.buffer.insert(iter, text)
        self.do_insert = False



    def on_key_press_event(self, widget, event):
        if not self.in_raw_input:
            return False

        tab_pressed = self.tab_pressed
        self.tab_pressed = 0
        handled = True

        state = event.state & (gtk.gdk.SHIFT_MASK |
                                gtk.gdk.CONTROL_MASK |
                                gtk.gdk.MOD1_MASK)
        keyval = event.keyval

        if not state:
            if keyval == gtk.keysyms.Return:
                self.__commit()
            elif keyval == gtk.keysyms.Up:
                self.__history(-1)
            elif keyval == gtk.keysyms.Down:
                self.__history(1)
            elif keyval == gtk.keysyms.Left:
                self.__move_cursor(-1)
            elif keyval == gtk.keysyms.Right:
                self.__move_cursor(1)
            elif keyval == gtk.keysyms.Home:
                self.__move_cursor(-10000)
            elif keyval == gtk.keysyms.End:
                self.__move_cursor(10000)
            elif keyval == gtk.keysyms.Tab:
                self.tab_pressed = tab_pressed + 1
                self.__complete()
            else:
                handled = False
        elif state == gtk.gdk.CONTROL_MASK:
            if keyval == gtk.keysyms.u:
                start = self.__get_start()
                end = self.__get_cursor()
                self.__delete(start, end)
            else:
                handled = False
        else:
            handled = False

        return handled




    def thaw_undo(self):
        try:
            self.end_not_undoable_action()
        except:
            pass



    def raw_input(self, ps=None):
        if ps:
            self.ps = ps
        else:
            self.ps = ''

        iter = self.buffer.get_iter_at_mark(self.buffer.get_insert())

        if ps:
            self.freeze_undo()
            self.buffer.insert(iter, self.ps)
            self.thaw_undo()

        self.__move_cursor_to(iter)
        self.scroll_to_mark(self.cursor, 0.2)

        self.in_raw_input = True

        if self.run_on_raw_input:
            run_now = self.run_on_raw_input
            self.run_on_raw_input = None
            self.buffer.insert_at_cursor(run_now + '\n')



    def on_buf_mark_set(self, buffer, iter, mark):
        if not mark is buffer.get_insert():
            return
        start = self.__get_start()
        end = self.__get_end()
        if iter.compare(self.__get_start()) >= 0 and \
           iter.compare(self.__get_end()) <= 0:
                buffer.move_mark_by_name("cursor", iter)
                self.scroll_to_mark(self.cursor, 0.2)



    def on_buf_insert(self, buf, iter, text, len):
        if not self.in_raw_input or self.do_insert or not len:
            return
        buf.stop_emission("insert-text")
        lines = text.splitlines()
        need_eol = False
        for l in lines:
            if need_eol:
                self.__commit()
                iter = self.__get_cursor()
            else:
                cursor = self.__get_cursor()
                if iter.compare(self.__get_start()) < 0:
                    iter = cursor
                elif iter.compare(self.__get_end()) > 0:
                    iter = cursor
                else:
                    self.__move_cursor_to(iter)
            need_eol = True
            self.__insert(iter, l)
        self.__move_cursor(0)



    def on_buf_delete(self, buf, start, end):
        if not self.in_raw_input or self.do_delete:
            return

        buf.stop_emission("delete-range")

        start.order(end)
        line_start = self.__get_start()
        line_end = self.__get_end()

        if start.compare(line_end) > 0:
            return
        if end.compare(line_start) < 0:
            return

        self.__move_cursor(0)

        if start.compare(line_start) < 0:
            start = line_start
        if end.compare(line_end) > 0:
            end = line_end
        self.__delete(start, end)



    def __move_cursor_to(self, iter):
        self.buffer.place_cursor(iter)
        self.buffer.move_mark_by_name("cursor", iter)



    def __move_cursor(self, howmany):
        iter = self.__get_cursor()
        end = self.__get_cursor()
        if not end.ends_line():
            end.forward_to_line_end()
        line_len = end.get_line_offset()
        move_to = iter.get_line_offset() + howmany
        move_to = min(max(move_to, len(self.ps)), line_len)
        iter.set_line_offset(move_to)
        self.__move_cursor_to(iter)



    def __print_completions(self, completions):
        line_start = self.__get_text(self.__get_start(), self.__get_cursor())
        line_end = self.__get_text(self.__get_cursor(), self.__get_end())
        iter = self.buffer.get_end_iter()
        self.__move_cursor_to(iter)
        self.__insert(iter, "\n")

        width = max(self.__get_width(), 4)
        max_width = max([len(s) for s in completions])
        n_columns = max(int(width / (max_width + 1)), 1)
        col_width = int(width / n_columns)
        total = len(completions)
        col_length = total / n_columns
        if total % n_columns:
            col_length = col_length + 1
        col_length = max(col_length, 1)

        if col_length == 1:
            n_columns = total
            col_width = width / total

        for i in range(col_length):
            for j in range(n_columns):
                ind = i + j*col_length
                if ind < total:
                    if j == n_columns - 1:
                        n_spaces = 0
                    else:
                        n_spaces = col_width - len(completions[ind])
                    self.__insert(iter, completions[ind] + " " * n_spaces)
            self.__insert(iter, "\n")

        self.__insert(iter, "%s%s%s" % (self.ps, line_start, line_end))
        iter.set_line_offset(len(self.ps) + len(line_start))
        self.__move_cursor_to(iter)
        self.scroll_to_mark(self.cursor, 0.2)









    def __replace_line(self, new_text):
        start = self.__get_start()
        end = self.__get_end()
        self.__delete(start, end)
        self.__insert(end, new_text)






    def write(self,whatever):
        self.buffer.insert_at_cursor(whatever)


    def __start(self):
        self.cmd_buffer = ""

        self.freeze_undo()
        self.thaw_undo()
        self.buffer.set_text("")

        if self.banner:
            iter = self.buffer.get_start_iter()
            self.buffer.insert(iter, self.banner)
            if not iter.starts_line():
                self.buffer.insert(iter, "\n")



    def runcode(self, code):
        saved = sys.stdout
        sys.stdout = self
        try:
            eval(code, self.locals)
        except SystemExit:
            raise
        except:
            self.showtraceback()
        sys.stdout = saved



    def complete(self, text):
        if self.completer:
            completions = set()
            i = 0
            try:
                while 1:
                    s = self.completer.complete(text, i)
                    if s:
                        completions.add(s)
                        i = i + 1
                    else:
                        completions = list(completions)
                        completions.sort()
                        return completions
            except NameError:
                return None

        dot = text.rfind(".")
        if dot >= 0:
            return self.complete_attr(text[:dot], text[dot+1:])

        completions = {}
        strings = keyword.kwlist

        if self.locals:
            strings.extend(self.locals.keys())

        try:
            strings.extend(eval("globals()", self.locals).keys())
        except:
            pass

        try:
            exec "import __builtin__" in self.locals
            strings.extend(eval("dir(__builtin__)", self.locals))
        except:
            pass

        for s in strings:
            if s.startswith(text):
                completions[s] = None
        completions = completions.keys()
        completions.sort()
        return completions



    def tell(self):
        return 0



    def seek(self, pos):
        pass



    def truncate(self):
        raise IOError, "Illegal seek"