Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/plug-ins/python/python-console/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 31 kB image not shown  

Quelle  pyconsole.py   Sprache: Python

 

#
#   pyconsole.py
#
#   Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
#   Portions of code by Geoffrey French.
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Lesser General Public version 2.1 as
#   published by the Free Software Foundation.
#
#   See COPYING.lib file that comes with this distribution for full text
#   of the license.
#

# This module 'runs' python interpreter in a TextView widget.
# The main class is Console, usage is:
# Console(locals=None, banner=None, completer=None, use_rlcompleter=True, start_script='') -
# it creates the widget and 'starts' interactive session; see the end
# of this file. If start_script is not empty, it pastes it as it was
# entered from keyboard.
#
# Console has "command" signal which is emitted when code is about to
# be executed. You may connect to it using console.connect or
# console.connect_after to get your callback ran before or after the
# code is executed.
#
# To modify output appearance, set attributes of console.stdout_tag and
# console.stderr_tag.
#
# Console may subclass a type other than gtk.TextView, to allow syntax
# highlighting and stuff,
# e.g.:
#   console_type = pyconsole.ConsoleType(moo.edit.TextView)
#   console = console_type(use_rlcompleter=False, start_script="import moo\nimport gtk\n")
#
# This widget is not a replacement for real terminal with python running
# inside: GtkTextView is not a terminal.
# The use case is: you have a python program, you create this widget,
# and inspect your program interiors.

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
from gi.repository import GObject
from gi.repository import Pango
import code
import sys
import keyword
import re

def pango_pixels(value):
    # The PANGO_PIXELS macro is not accessible through GObject
    # Introspection. Just reimplement it:
    # #define PANGO_PIXELS(d) (((int)(d) + 512) >> 10)
    return (value + 512) >> 10

# commonprefix() from posixpath
def _commonprefix(m):
    "Given a list of pathnames, returns the longest common leading component"
    if not m: return ''
    prefix = m[0]
    for item in m:
        for i in range(len(prefix)):
            if prefix[:i+1] != item[:i+1]:
                prefix = prefix[:i]
                if i == 0:
                    return ''
                break
    return prefix

class _ReadLine(object):

    class Output(object):
        def __init__(self, console, tag_name):
            object.__init__(self)
            self.buffer = console.get_buffer()
            self.tag_name = tag_name
        def write(self, text):
            pos = self.buffer.get_iter_at_mark(self.buffer.get_insert())
            self.buffer.insert_with_tags_by_name(pos, text, self.tag_name)
        def flush(self):
            # The output is just a GtkTextBuffer inside a GtkTexView so I
            # believe it should be always in-sync without needing to be flushed.
            # Nevertheless someone might be just copy-pasting plug-in code to
            # test it, for instance. So let's just add a no-op flush() method to
            # get a similar interface as the real sys.stdout which we overrode.
            # It avoids useless and unexpected code failure.
            pass

    class History(object):
        def __init__(self, initial_history):
            object.__init__(self)
            if initial_history is None or len(initial_history) == 0:
              initial_history = ['']
            elif initial_history[0] != '':
              initial_history = [''] + initial_history
            self.items = initial_history
            self.ptr = 0
            self.edited = {}

        def commit(self, text):
            if text and self.items[-1] != text:
                self.items.append(text)
            self.ptr = 0
            self.edited = {}

        def get(self, dir, text):
            if len(self.items) == 1:
                return None

            if text != self.items[self.ptr]:
                self.edited[self.ptr] = text
            elif self.ptr in self.edited:
                del self.edited[self.ptr]

            # Do not cycle. It's confusing.
            if (self.ptr == 0 and dir > 0) or self.ptr + dir >= len(self.items):
              # Position 0 is a bit weird. It's the last position, not
              # the first!
              self.ptr = 0
            elif self.ptr > 0 and dir < 0 and self.ptr + dir < 1:
              self.ptr = 1
            else:
              self.ptr = self.ptr + dir
              if self.ptr < 0:
                self.ptr = len(self.items) - 1

            try:
                return self.edited[self.ptr]
            except KeyError:
                return self.items[self.ptr]

        def search_backward(self, text):
            if len(self.items) == 1:
              return None, None

            if self.ptr == 1:
              return None, None

            if self.ptr == 0:
              search_iter = len(self.items) - 1
            else:
              search_iter = self.ptr - 1

            while text not in self.items[search_iter]:
              search_iter -= 1
              if search_iter == 1:
                return None, self.items[1]

            return search_iter, self.items[search_iter]

        def search_forward(self, text):
            if len(self.items) == 1:
              return None, None

            if self.ptr == 0:
              return None, None

            if self.ptr == len(self.items) - 1:
              search_iter = 0
            else:
              search_iter = self.ptr + 1

            while text not in self.items[search_iter]:
              if search_iter == 0:
                return None, None
              search_iter += 1
              if search_iter > len(self.items):
                search_iter = 0

            return search_iter, self.items[search_iter]

    def __init__(self, quit_func=None, initial_history=None):
        object.__init__(self)

        self.quit_func = quit_func

        self.set_wrap_mode(Gtk.WrapMode.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

        #Use the theme's color scheme for the text color
        font_color = self.get_style_context().get_property('color', Gtk.StateFlags.NORMAL)
        r = int (font_color.red * 255)
        g = int (font_color.green * 255)
        b = int (font_color.blue * 255)
        hex_font_color = "#" + '{r:02x}{g:02x}{b:02x}'.format (r = r, g = g, b = b)

        #Choose an error text color based on background luminance
        bg_color = self.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL)
        lum = (bg_color.red * 0.22248840) + (bg_color.green * 0.71690369) + (bg_color.blue * 0.06060791)
        background_color = "#B00000"
        if (lum < 0.4):
          background_color = "#FF6161"

        self.stdout_tag = self.buffer.create_tag("stdout", foreground=hex_font_color)
        self.stderr_tag = self.buffer.create_tag("stderr", foreground=background_color)
        self._stdout = _ReadLine.Output(self, "stdout")
        self._stderr = _ReadLine.Output(self, "stderr")

        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.in_raw_input = False
        self.in_modal_raw_input = False
        self.run_on_raw_input = None
        self.tab_pressed = 0
        self.history = _ReadLine.History(initial_history)
        self.nonword_re = re.compile(r"[^\w\._]")

        self._searching_backward = False
        self._searching_forward  = False

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

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

    def raw_input(self, ps=None):
        '''Show prompt 'ps' and enter input mode until the current input
        is committed.'''

        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, False, 0.0, 0.0)

        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 modal_raw_input(self, text):
        '''Starts raw input in modal mode. The event loop is spinned until
        the input is committed. Returns the text entered after the prompt.'''
        orig_ps = self.ps

        self.raw_input(text)
        self.in_modal_raw_input = True

        while self.in_modal_raw_input:
            Gtk.main_iteration()

        self.ps = orig_ps
        self.in_modal_raw_input = False
        self.in_raw_input = False

        return self.modal_raw_input_result

    def modal_input(self, text):
        return eval(self.modal_raw_input(text))

    # Each time the insert mark is modified, move the cursor to it.
    def on_buf_mark_set(self, buffer, iter, mark):
        if mark is not 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, False, 0.0, 0.0)

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

    # Make sure that text insertions while in text input mode are properly
    # committed to the history.
    def on_buf_insert(self, buf, iter, text, len):
        # Bail out if not in input mode.
        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 __delete(self, start, end):
        self.do_delete = True
        self.buffer.delete(start, end)
        self.do_delete = False

    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)

    # We overload the key press event handler to handle "special keys"
    # when in input mode to make history browsing, completions, etc. work.
    def do_key_press_event(self, event):
        if not self.in_raw_input:
            return Gtk.TextView.do_key_press_event(self, event)

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

        state = event.state & (Gdk.ModifierType.CONTROL_MASK |
                               Gdk.ModifierType.MOD1_MASK)
        keyval = event.keyval

        if not state:
            if keyval == Gdk.KEY_Escape:
                self.__history_search_stop()
            elif keyval == Gdk.KEY_Return:
                self.__history_search_stop()
                self._commit()
            elif keyval == Gdk.KEY_Up or keyval == Gdk.KEY_Page_Up:
                self.__history_search_stop()
                self.__history(-1)
            elif keyval == Gdk.KEY_Down or keyval == Gdk.KEY_Page_Down:
                self.__history_search_stop()
                self.__history(1)
            elif keyval == Gdk.KEY_Left:
                self.__history_search_stop()
                self.__move_cursor(-1)
            elif keyval == Gdk.KEY_Right:
                self.__history_search_stop()
                self.__move_cursor(1)
            elif keyval == Gdk.KEY_Home:
                self.__history_search_stop()
                self.__move_cursor(-10000)
            elif keyval == Gdk.KEY_End:
                self.__history_search_stop()
                self.__move_cursor(10000)
            elif keyval == Gdk.KEY_Tab:
                self.__history_search_stop()
                cursor = self.__get_cursor()
                if cursor.starts_line():
                    handled = False
                else:
                    cursor.backward_char()
                    if cursor.get_char().isspace():
                        handled = False
                    else:
                        self.tab_pressed = tab_pressed + 1
                        self.__complete()
            elif self._searching_backward:
                if event.string != '' or keyval == Gdk.KEY_BackSpace:
                  self.__history_search_backward(keyval, event.string)
            elif self._searching_forward:
                if event.string != '' or keyval == Gdk.KEY_BackSpace:
                  self.__history_search_forward(keyval, event.string)
            else:
                handled = False
        elif state == Gdk.ModifierType.CONTROL_MASK:
            if keyval == Gdk.KEY_u:
                self.__history_search_stop()
                start = self.__get_start()
                end = self.__get_cursor()
                self.__delete(start, end)
            elif keyval == Gdk.KEY_d:
                self.__history_search_stop()
                if self.quit_func:
                    self.quit_func()
            elif keyval == Gdk.KEY_r:
                self.__history_search_backward(keyval, '')
            elif keyval == Gdk.KEY_s:
                self.__history_search_forward(keyval, '')
            elif keyval == Gdk.KEY_c and (self._searching_backward or self._searching_forward):
                self.__history_search_cancel()
            else:
                self.__history_search_stop()
                handled = False
        else:
            handled = False

        # Handle ordinary keys
        if not handled:
            return Gtk.TextView.do_key_press_event(self, event)
        else:
            return True

    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, False, 0.0, 0.0)

    def __history_search_stop(self):
        if self._searching_backward or self._searching_forward:
          self._searching_backward = False
          self._searching_forward  = False
          self.ps = self.ps1
          self.__replace_line(self.history.items[self.history.ptr])
          self.__move_cursor(0)
          self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)

    def __history_search_cancel(self):
        if self._searching_backward or self._searching_forward:
          self._searching_backward = False
          self._searching_forward  = False
          self.history.ptr = self._search_initial_ptr
          self.ps = self.ps1
          self.__replace_line(self.history.items[self.history.ptr])
          self.__move_cursor(0)
          self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)

    def __history_search_backward(self, keyval, text):
        search_anyway = False

        if not self._searching_backward:
          self._searching_backward = True
          if not self._searching_forward:
            self._search_initial_ptr = self.history.ptr
            self._search_text = ''
          else:
            search_anyway = True
          self.ps = self.sb
        else:
          if keyval == Gdk.KEY_BackSpace:
            search_anyway = True
            self._search_text = self._search_text[:-1]
          elif text == '':
            search_anyway = True
          else:
            self._search_text += text

        self._searching_forward = False

        if self._search_text != '' and (self._search_text not in self._get_line() or search_anyway):
          ptr, new_text = self.history.search_backward(self._search_text)
          if ptr is not None:
            self.history.ptr = ptr

        self.__replace_line(self.history.items[self.history.ptr])

        self.__move_cursor(0)
        self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)

    def __history_search_forward(self, keyval, text):
        search_anyway = False

        if not self._searching_forward:
          self._searching_forward = True
          if not self._searching_backward:
            self._search_initial_ptr = self.history.ptr
            self._search_text = ''
          else:
            search_anyway = True
          self.ps = self.sf
        else:
          if keyval == Gdk.KEY_BackSpace:
            search_anyway = True
            self._search_text   = self._search_text[:-1]
          elif text == '':
            search_anyway = True
          else:
            self._search_text += text

        self._searching_backward = False

        if self._search_text != '' and (self._search_text not in self._get_line() or search_anyway):
          ptr, new_text = self.history.search_forward(self._search_text)
          if ptr is not None:
            self.history.ptr = ptr

        self.__replace_line(self.history.items[self.history.ptr])

        self.__move_cursor(0)
        self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)

    def __get_cursor(self):
        '''Returns an iterator at the current cursor position.'''
        return self.buffer.get_iter_at_mark(self.cursor)

    def __get_start(self, before_ps=False):
        '''Returns an iterator at the start of the input on the current
        cursor line.'''

        iter = self.__get_cursor()
        iter.set_line(iter.get_line())
        if not before_ps:
          iter.forward_chars(len(self.ps))
        return iter

    def __get_end(self):
        '''Returns an iterator at the end of the cursor line.'''
        iter = self.__get_cursor()
        if not iter.ends_line():
            iter.forward_to_line_end()
        return iter

    def __get_text(self, start, end):
        '''Get text between 'start' and 'end' markers.'''
        return self.buffer.get_text(start, end, False)

    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 __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 __get_width(self):
        '''Estimate the number of characters that will fit in the area
        currently allocated to this widget.'''

        if not self.get_realized():
            return 80

        context = self.get_pango_context()
        metrics = context.get_metrics(context.get_font_description(),
                                      context.get_language())
        pix_width = metrics.get_approximate_char_width()
        allocation = Gtk.Widget.get_allocation(self)
        return allocation.width * Pango.SCALE / pix_width

    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(int(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 = int(col_width - len(completions[int(ind)]))
                    self.__insert(iter, completions[int(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, False, 0.0, 0.0)

    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 = _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(self, text):
        return None

    def _get_line(self):
        '''Return the current input behind the prompt.'''
        start = self.__get_start()
        end = self.__get_end()
        return self.buffer.get_text(start, end, False)

    def __replace_line(self, new_text):
        '''Replace the current input with 'new_text' '''
        start = self.__get_start(True)
        end = self.__get_end()
        self.__delete(start, end)
        self.__insert(end, self.ps)
        if self._searching_backward or self._searching_forward:
          self.__insert(end, '({}) '.format(self._search_text))
        self.__insert(end, new_text)

    def _commit(self):
        '''Commit the input entered on the current line.'''

        # Find iterator and end of cursor line.
        end = self.__get_cursor()
        if not end.ends_line():
            end.forward_to_line_end()

        # Get text at current line.
        text = self._get_line()

        # Move cursor to the end of the line, insert new line.
        self.__move_cursor_to(end)
        self.freeze_undo()
        self.__insert(end, "\n")

        self.history.commit(text)
        if self.in_modal_raw_input:
            self.in_modal_raw_input = False
            self.modal_raw_input_result = text
        else:
            self.in_raw_input = False
            self.do_raw_input(text)

        self.thaw_undo()

    def do_raw_input(self, text):
        pass


class _Console(_ReadLine, code.InteractiveInterpreter):
    def __init__(self, locals=None, banner=None,
                 completer=None, use_rlcompleter=True,
                 start_script=None, quit_func=None,
                 initial_history=None):
        _ReadLine.__init__(self, quit_func, initial_history)

        code.InteractiveInterpreter.__init__(self, locals)
        self.locals["__console__"] = self

        # The builtin raw_input function reads from stdin, we don't want
        # this. Therefore, replace this function with our own modal raw
        # input function.
        exec ("import builtins", self.locals)
        #self.locals['builtins'].__dict__['raw_input'] = lambda text='': self.modal_raw_input(text)
        self.locals['builtins'].__dict__['input'] = lambda text='': self.modal_input(text)

        self.start_script = start_script
        self.completer = completer
        self.banner = banner

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

        self.ps1 = ">>> "
        self.ps2 = "... "
        self.sb  = "^^^ "
        self.sf  = "vvv "
        self.__start()
        self.run_on_raw_input = start_script
        self.raw_input(self.ps1)

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

        self.freeze_undo()
        self.thaw_undo()

        self.do_delete = True
        self.buffer.set_text("")
        self.do_delete = False

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

    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
        self.raw_input(self.ps1)

    def do_raw_input(self, text):
        if self.cmd_buffer:
            cmd = self.cmd_buffer + "\n" + text
        else:
            cmd = text

        saved_stdout, saved_stderr = sys.stdout, sys.stderr
        sys.stdout, sys.stderr = self._stdout, self._stderr

        if self.runsource(cmd):
            self.cmd_buffer = cmd
            ps = self.ps2
        else:
            self.cmd_buffer = ''
            if self._searching_backward:
                ps = self.sb
            elif self._searching_forward:
                ps = self.sb
            else:
                ps = self.ps1

        sys.stdout, sys.stderr = saved_stdout, saved_stderr
        self.raw_input(ps)

    def do_command(self, code):
        try:
            eval(code, self.locals)
        except SystemExit:
            if self.quit_func:
                self.quit_func()
            else:
                raise
        except:
            self.showtraceback()

    def runcode(self, code):
        #if gtk.pygtk_version[1] < 8:
        self.do_command(code)
        #else:
            #self.emit("command", code)

    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 complete(self, text):
        if self.completer:
            completions = []
            i = 0
            try:
                while 1:
                    s = self.completer.complete(text, i)
                    if s:
                        completions.append(s)
                        i += 1
                    else:
                        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__", 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 ReadLineType(t=Gtk.TextView):
    class readline(t, _ReadLine):
        def __init__(self, *args, **kwargs):
            t.__init__(self)
            _ReadLine.__init__(self, *args, **kwargs)
        def do_key_press_event(self, event):
            return _ReadLine.do_key_press_event(self, event)
    GObject.type_register(readline)
    return readline

def ConsoleType(t=Gtk.TextView):
    class console_type(t, _Console):
        __gsignals__ = {
            'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (object,)),
          }

        def __init__(self, *args, **kwargs):
            #if gtk.pygtk_version[1] < 8:
            GObject.GObject.__init__(self)
            #else:
                #t.__init__(self)
            _Console.__init__(self, *args, **kwargs)

        def do_command(self, code):
            return _Console.do_command(self, code)

        def do_key_press_event(self, event):
            return _Console.do_key_press_event(self, event)

        def get_default_size(self):
            context = self.get_pango_context()
            metrics = context.get_metrics(context.get_font_description(),
                                          context.get_language())
            width = metrics.get_approximate_char_width()
            height = metrics.get_ascent() + metrics.get_descent()

            # Default to a 80x40 console
            width = pango_pixels(int(width * 80 * 1.05))
            height = pango_pixels(height * 40)

            return width, height

    #if gtk.pygtk_version[1] < 8:
    GObject.type_register(console_type)

    return console_type

ReadLine = ReadLineType()
Console = ConsoleType()

def _make_window():
    window = Gtk.Window()
    window.set_title("pyconsole.py")
    swin = Gtk.ScrolledWindow()
    swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
    window.add(swin)
    console = Console(banner="Hello there!",
                      use_rlcompleter=False,
                      start_script="gi.require_version('Gimp', '3.0')\nfrom gi.repository import Gimp\n")
    swin.add(console)

    width, height = console.get_default_size()
    sb_width, sb_height = swin.get_vscrollbar().size_request()

    window.set_default_size(width + sb_width, height)
    window.show_all()

    if not Gtk.main_level():
        window.connect("destroy", Gtk.main_quit)
        Gtk.main()

    return console

if __name__ == '__main__':
    if len(sys.argv) < 2 or sys.argv[1] != '-gimp':
        _make_window()

Messung
CHZG
86979090

¤ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.