diff --git a/betterpythonconsole.plugin b/betterpythonconsole.plugin index 085c74d..34abcc2 100644 --- a/betterpythonconsole.plugin +++ b/betterpythonconsole.plugin @@ -1,10 +1,10 @@ [Plugin] -Loader=python +Loader=python3 Module=betterpythonconsole IAge=3 Name=Better Python Console Description=A python console in the style of IDLE. Icon=gnome-mime-text-x-python -Authors=Zeth Green, Jono Finger +Authors=Zeth Green, Jono Finger , Jacek Pliszka Copyright=Copyright © 2006-7 Zeth Green, © 2012 Jono Finger -Website=http://www.pywm.eu +Website=https://wiki.gnome.org/Apps/Gedit/Plugins/BetterPythonConsole diff --git a/betterpythonconsole/__init__.py b/betterpythonconsole/__init__.py index c2626c3..aeadb11 100644 --- a/betterpythonconsole/__init__.py +++ b/betterpythonconsole/__init__.py @@ -18,11 +18,28 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """IDLE like Console for Gedit, hit F5 and it executes the module""" -from gi.repository import Gtk, GObject, Gedit -import consolefunctions -import sys +from gi.repository import GObject, Gedit, Gio +from betterpythonconsole import consolefunctions -class BetterConsolePlugin(GObject.Object, Gedit.WindowActivatable): + +class BetterConsoleAppActivatable(GObject.Object, Gedit.AppActivatable): + + app = GObject.property(type=Gedit.App) + + def do_activate(self): + # action self.on_clear_document_activate)]) + self.app.add_accelerator("F5", "win.betterconsole", None) + self.menu_ext = self.extend_menu("tools-section") + item = Gio.MenuItem.new(_("Better Console"), "win.betterconsole") + self.menu_ext.append_menu_item(item) + + def do_deactivate(self): + """Pull our item from the menu.""" + self.app.remove_accelerator("win.betterconsole", None) + self.menu_ext = None + + +class BetterConsoleWindowActivatable(GObject.Object, Gedit.WindowActivatable): """This Class creates the Gedit plugin. """ window = GObject.property(type=Gedit.Window) @@ -35,7 +52,16 @@ def do_activate(self): """This adds the plugin to the running Gedit. This method is used when the plugin is turned on and then when Gedit starts""" home_path = __path__[0] - self._instances[self.window] = consolefunctions.BetterConsoleHelper(self, self.window, home_path) + self._instances[self.window] = consolefunctions.BetterConsoleHelper( + self, self.window, home_path + ) + + action = Gio.SimpleAction(name="betterconsole") + action.connect('activate', self.on_clear_document_activate) + self.window.add_action(action) + + for view in self.window.get_views(): + self.add_helper(view, self.window) def do_deactivate(self): """This removes the plugin from the running Gedit.""" @@ -45,3 +71,7 @@ def do_deactivate(self): def update_ui(self): """We do not use this yet.""" self._instances[self.window].update_ui() + + def on_clear_document_activate(self, action, data=None): + self._instances[self.window].on_clear_document_activate(action) + diff --git a/betterpythonconsole/consolefunctions.py b/betterpythonconsole/consolefunctions.py index a0f8a19..a44f161 100644 --- a/betterpythonconsole/consolefunctions.py +++ b/betterpythonconsole/consolefunctions.py @@ -18,75 +18,28 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """Core Functions for Gedit to interact with the Python Console. """ -import sys -from gi.repository import Gtk from gi.repository import GObject import subprocess -# Insert a new item in the Tools menu -UI_STR = """ - - - - - - - - -""" + class BetterConsoleHelper: """Provides interaction with Gedit.""" def __init__(self, plugin, window, consolepath): self._window = window self._plugin = plugin self._consolepath = consolepath - # Insert menu items - self._insert_menu() def deactivate(self): """Remove any installed menu items from the Gedit Menu.""" - self._remove_menu() - self._window = None self._plugin = None self._action_group = None - def _insert_menu(self): - """Insert our item into the Gedit menu.""" - # Get the GtkUIManager - manager = self._window.get_ui_manager() - - # Create a new action group - self._action_group = Gtk.ActionGroup("BetterConsolePluginActions") - self._action_group.add_actions([("BetterConsole", None, _("Run Module"), - 'F5', _("Run file in Python Console"), - self.on_clear_document_activate)]) - - # Insert the action group - manager.insert_action_group(self._action_group, -1) - - # Merge the UI - self._ui_id = manager.add_ui_from_string(UI_STR) - - def _remove_menu(self): - """Pull our item from the menu.""" - # Get the GtkUIManager - manager = self._window.get_ui_manager() - - # Remove the ui - manager.remove_ui(self._ui_id) - - # Remove the action group - manager.remove_action_group(self._action_group) - - # Make sure the manager updates - manager.ensure_update() - def update_ui(self): """Unused in our case at the moment, but required for the plugins system to be happy.""" self._action_group.set_sensitive( - self._window.get_active_document() != None) + self._window.get_active_document() is not None) def on_clear_document_activate(self, action): """Menu activate handler, @@ -98,43 +51,44 @@ def on_clear_document_activate(self, action): return our_filename = doc.get_short_name_for_display() - # Check for unsaved changes - unsaved = self._window.get_unsaved_documents() + # Check for unsaved changes + unsaved = self._window.get_unsaved_documents() unsaved_filenames = [] for i in range(len(unsaved)): - unsaved_filenames.append(unsaved[i].get_uri_for_display()) + unsaved_filenames.append(unsaved[i].get_uri_for_display()) if unsaved_filenames.count(our_filename) == 1: mes_id = "unsaved_changes" - message = "There are unsaved changes." + message = "There are unsaved changes." self.send_staus_message(message, mes_id) - - # Check for an untitled document - elif doc.is_untitled() == True: + + # Check for an untitled document + elif doc.is_untitled(): mes_id = "untitled_document" message = "You must save the document first." self.send_staus_message(message, mes_id) - - # Check for an non-local file + + # Check for an non-local file # elif doc.get_uri_for_display()[:7]!="file://": # mes_id = "unsupported_location" # message = """This file location is currently unsupported. # Please save the file locally.""" # self.send_staus_message(message, mes_id) - + # Everything is fine else: self.launch_python_console(doc.get_uri_for_display()) mes_id = "upforit" - message = "The module " + doc.get_short_name_for_display() + \ - " has been executed." + message = "The module {} has been executed.".format( + doc.get_short_name_for_display() + ) self.send_staus_message(message, mes_id) - + def launch_python_console(self, filename): """Launch a console.""" interpreter_name = "python2" fullpath = self._consolepath + "/consoleinterface.py" run_command = [interpreter_name, fullpath, filename] - p1 = subprocess.Popen(run_command, stdout=subprocess.PIPE) + subprocess.Popen(run_command, stdout=subprocess.PIPE) def send_staus_message(self, message, mes_id): """Put a message on the Status bar.""" @@ -142,9 +96,10 @@ def send_staus_message(self, message, mes_id): our_newid = our_statusbar.get_context_id(mes_id) our_statusbar.push(our_newid, message) GObject.timeout_add( - 2000,self.clear_statusbar_from_crap,our_newid,our_statusbar) + 2000, self.clear_statusbar_from_crap, our_newid, our_statusbar) def clear_statusbar_from_crap(self, crap_id, status_bar): """Take a message off the Status bar.""" status_bar.pop(crap_id) - return False + return False + diff --git a/betterpythonconsole/consoleinterface.py b/betterpythonconsole/consoleinterface.py index 6b7aff6..f2f234f 100644 --- a/betterpythonconsole/consoleinterface.py +++ b/betterpythonconsole/consoleinterface.py @@ -16,42 +16,44 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ # -# Executing this file in Gedit through the Better Python Console Plugin -# is not recommended as it will cause a hairy loop and make your X server +# Executing this file in Gedit through the Better Python Console Plugin +# is not recommended as it will cause a hairy loop and make your X server # unresponsive. You have been warned! # -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ # This module is based on pycons.py by Nicolas Rougier, -# which in turn is based on the Gimp's GTK Interactive Console. -# To find out more please visit http://www.loria.fr/~rougier/ +# which in turn is based on the Gimp's GTK Interactive Console. +# To find out more please visit http://www.loria.fr/~rougier/ # # Original Copyright (c) 1998 James Henstridge, 2006 Nicolas Rougier -# +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. -# -#------------------------------------------------------------------------------ +# +# ------------------------------------------------------------------------------ """ Interactive GTK console This console is heavily based on the GTK Interactive Console bundled with -The Gimp and implements an interactive python session in a GTK window. +The Gimp and implements an interactive python session in a GTK window. """ __version__ = '1.0' -__author__ = 'Nicolas Rougier' -__email__ = 'Nicolas.Rougier@loria.fr' +__author__ = 'Nicolas Rougier' +__email__ = 'Nicolas.Rougier@loria.fr' -import os.path, sys, traceback +import os.path +import sys +import traceback from gi.repository import Gtk, GConf, Pango, GObject, Gdk @@ -68,27 +70,47 @@ class gtkoutfile: A fake output file object. It sends output to a GTK TextView widget, and if asked for a file number, returns one set on instance creation """ - + def __init__(self, console, fn, font): self.fn = fn self.console = console - #self.__b = w.get_buffer() - #self.__ins = self.__b.get_mark('insert') + # self.__b = w.get_buffer() + # self.__ins = self.__b.get_mark('insert') self.font = font - def close(self): pass + + def close(self): + pass + flush = close - def fileno(self): return self.fn - def isatty(self): return False - def read(self, a): return '' - def readline(self): return '' - def readlines(self): return [] + + def fileno(self): + return self.fn + + def isatty(self): + return False + + def read(self, a): + return '' + + def readline(self): + return '' + + def readlines(self): + return [] + def write(self, s): - self.console.write (s, self.font) + self.console.write(s, self.font) + def writelines(self, l): for s in l: - self.console.write (s, self.font) - def seek(self, a): raise IOError(29, 'Illegal seek') - def tell(self): raise IOError(29, 'Illegal seek') + self.console.write(s, self.font) + + def seek(self, a): + raise IOError(29, 'Illegal seek') + + def tell(self): + raise IOError(29, 'Illegal seek') + truncate = tell @@ -98,15 +120,25 @@ class gtkinfile: A fake input file object. It receives input from a GTK TextView widget, and if asked for a file number, returns one set on instance creation """ - + def __init__(self, console, fn): self.fn = fn self.console = console - def close(self): pass + + def close(self): + pass + flush = close - def fileno(self): return self.fn - def isatty(self): return False - def read(self, a): return self.readline() + + def fileno(self): + return self.fn + + def isatty(self): + return False + + def read(self, a): + return self.readline() + def readline(self): self.console.input_mode = True while self.console.input_mode: @@ -114,12 +146,23 @@ def readline(self): Gtk.main_iteration() s = self.console.input self.console.input = '' - return s+'\n' - def readlines(self): return [] - def write(self, s): return None - def writelines(self, l): return None - def seek(self, a): raise IOError(29, 'Illegal seek') - def tell(self): raise IOError(29, 'Illegal seek') + return s + '\n' + + def readlines(self): + return [] + + def write(self, s): + return None + + def writelines(self, l): + return None + + def seek(self, a): + raise IOError(29, 'Illegal seek') + + def tell(self): + raise IOError(29, 'Illegal seek') + truncate = tell @@ -127,51 +170,54 @@ def tell(self): raise IOError(29, 'Illegal seek') class History: """ Basic command history class """ - - def __init__ (self): + + def __init__(self): """ Initializes history """ - + self.history = [''] - self.position = len (self.history)-1 - - def prev (self, current): + self.position = len(self.history) - 1 + + def prev(self, current): """ Get previous command in history """ - + if self.position > 0: l = current - if len(l) > 0 and l[0] == '\n': l = l[1:] - if len(l) > 0 and l[-1] == '\n': l = l[:-1] + if len(l) > 0 and l[0] == '\n': + l = l[1:] + if len(l) > 0 and l[-1] == '\n': + l = l[:-1] if self.position > 0: if self.position == (len(self.history)-1): self.history[len(self.history)-1] = l self.position = self.position - 1 return self.history[self.position] return current - - def next (self, current): + + def next(self, current): """ Get next command in history """ - + if self.position < len(self.history) - 1: self.position = self.position + 1 return self.history[self.position] return current - - def append (self, line): + + def append(self, line): """ Append a new command to history """ - + self.position = len(self.history) - 1 if not len(line): return - if ((self.position == 0) or (self.position > 0 and - line != self.history[self.position-1])): + if (self.position == 0) or ( + self.position > 0 and line != self.history[self.position-1] + ): self.history[self.position] = line self.position = self.position + 1 self.history.append('') - - def open (self, filename): + + def open(self, filename): """ Open an history file """ - - file = open (filename) + + file = open(filename) self.history = [] for l in file: self.history.append(l[:-1]) @@ -179,78 +225,74 @@ def open (self, filename): self.position = len(self.history)-1 file.close() - def save (self, filename): + def save(self, filename): """ Save history to a file """ - - file = open (filename, 'w') + + file = open(filename, 'w') for l in self.history: if len(l) > 0: file.write(l+'\n') file.close() - + def __repr__(self): """ History representation """ - - return self.history.__repr__() + return self.history.__repr__() # ============================================================================= -class Console (Gtk.ScrolledWindow): +class Console(Gtk.ScrolledWindow): """ Interactive GTK console class """ - def __init__(self, namespace={}, quit_handler = None): + def __init__(self, namespace={}, quit_handler=None): """ Initialize console """ # Get font from gedit's entries in gconf client = GConf.Client.get_default() default_question = client.get_bool( '/apps/gedit-2/preferences/editor/font/use_default_font') - if default_question == True: + if default_question: userfont = client.get_string( '/desktop/gnome/interface/font_name') - else: + else: userfont = client.get_string( '/apps/gedit-2/preferences/editor/font/editor_font') - + # Setup scrolled window GObject.GObject.__init__(self) self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) - self.set_shadow_type (Gtk.ShadowType.ETCHED_IN) + self.set_shadow_type(Gtk.ShadowType.ETCHED_IN) self.set_border_width(0) # Setup text view - self.text = Gtk.TextView () - self.text.set_property ('can-focus', True) - self.text.modify_font (Pango.FontDescription(userfont)) - self.text.set_editable (True) + self.text = Gtk.TextView() + self.text.set_property('can-focus', True) + self.text.modify_font(Pango.FontDescription(userfont)) + self.text.set_editable(True) self.text.set_wrap_mode(True) self.text.set_left_margin(1) self.text.set_right_margin(1) self.text.set_size_request(0, 0) - + # Setup text buffer - self.buffer = self.text.get_buffer () - self.buffer.create_tag ('prompt', - weight=Pango.Weight.BOLD) - self.buffer.create_tag ('script', - foreground='darkgrey', style=Pango.Style.OBLIQUE) - self.buffer.create_tag ('normal', - foreground='blue') - self.buffer.create_tag ('error', - foreground='red', style=Pango.Style.OBLIQUE) - self.buffer.create_tag ('extern', - foreground='orange') - self.buffer.create_tag ('center', - justification=Gtk.Justification.CENTER) - + self.buffer = self.text.get_buffer() + self.buffer.create_tag('prompt', weight=Pango.Weight.BOLD) + self.buffer.create_tag( + 'script', foreground='darkgrey', style=Pango.Style.OBLIQUE) + self.buffer.create_tag('normal', foreground='blue') + self.buffer.create_tag( + 'error', foreground='red', style=Pango.Style.OBLIQUE) + self.buffer.create_tag('extern', foreground='orange') + self.buffer.create_tag( + 'center', justification=Gtk.Justification.CENTER) + # Setup event handlers self.text.add_events(Gdk.EventMask.KEY_PRESS_MASK) - self.text.connect ('button-press-event', self.on_button_press) - self.text.connect ('key-press-event', self.on_key_pressed) - self.text.connect ('drag-data-received', self.on_drag_data_received) + self.text.connect('button-press-event', self.on_button_press) + self.text.connect('key-press-event', self.on_key_pressed) + self.text.connect('drag-data-received', self.on_drag_data_received) self.add(self.text) - + # Internal setup self.namespace = namespace self.cmd = '' @@ -262,109 +304,101 @@ def __init__(self, namespace={}, quit_handler = None): self.quit_handler = quit_handler # Setup hooks for standard output. - self.stdout = gtkoutfile (self, sys.stdout.fileno(), 'normal') - self.stderr = gtkoutfile (self, sys.stderr.fileno(), 'error') - self.stdin = gtkinfile (self, sys.stdin.fileno()) + self.stdout = gtkoutfile(self, sys.stdout.fileno(), 'normal') + self.stderr = gtkoutfile(self, sys.stderr.fileno(), 'error') + self.stdin = gtkinfile(self, sys.stdin.fileno()) # Setup command history self.history = History() self.namespace['__history__'] = self.history self.show_all() - def banner(self): """ Display python banner """ - + # iter = self.buffer.get_iter_at_mark(self.buffer.get_insert()) # self.buffer.insert (iter, 'Python %s\n' % sys.version) # iter = self.buffer.get_iter_at_mark(self.buffer.get_insert()) # self.buffer.insert (iter, '''Type "help", "copyright", "credits" or''' # ''' "license" for more information.\n''') - self.text.scroll_to_mark (self.buffer.get_insert(), 0, False, 0, 0) + self.text.scroll_to_mark(self.buffer.get_insert(), 0, False, 0, 0) self.prompt1() - - def prompt1 (self): + def prompt1(self): """ Display normal prompt """ - - self.prompt = sys.ps1 - self.write (self.prompt, 'prompt') + self.prompt = sys.ps1 + self.write(self.prompt, 'prompt') - def prompt2 (self): + def prompt2(self): """ Display continuation prompt """ - - self.prompt = sys.ps2 - self.write (self.prompt, 'prompt') + self.prompt = sys.ps2 + self.write(self.prompt, 'prompt') - def clear (self): + def clear(self): """ Clear text buffer & view """ - + line = self.current_line() - self.buffer.delete ( + self.buffer.delete( self.buffer.get_start_iter(), self.buffer.get_end_iter()) - self.write (self.prompt, 'prompt') - self.write (line) - + self.write(self.prompt, 'prompt') + self.write(line) - def write (self, line, style=None): + def write(self, line, style=None): """ Write a line using given style (if any) """ - + start, end = self.text.get_buffer().get_bounds() - if style == None: - self.text.get_buffer().insert (end, line) + if style is None: + self.text.get_buffer().insert(end, line) else: - self.text.get_buffer().insert_with_tags_by_name (end, line, style) - self.text.scroll_mark_onscreen (self.buffer.get_insert()) + self.text.get_buffer().insert_with_tags_by_name(end, line, style) + self.text.scroll_mark_onscreen(self.buffer.get_insert()) self.linestart = self.buffer.get_end_iter().get_offset() - def replace (self, line): + def replace(self, line): """ Replace current active line with line """ - + start, end = self.current_line_bounds() - self.text.get_buffer().delete (start, end) + self.text.get_buffer().delete(start, end) l = self.linestart - self.write (line) + self.write(line) self.linestart = l - - def current_line (self): + def current_line(self): """ Get current active line """ - - start, end = self.current_line_bounds() - return self.buffer.get_text (start, end, True) + start, end = self.current_line_bounds() + return self.buffer.get_text(start, end, True) - def current_line_bounds (self): + def current_line_bounds(self): """ Get current active line bounds """ - + l = self.buffer.get_line_count() - 1 start = self.buffer.get_iter_at_line(l) - #mark = self.buffer.get_mark('linestart') - #start = self.buffer.get_iter_at_mark (mark) + # mark = self.buffer.get_mark('linestart') + # start = self.buffer.get_iter_at_mark (mark) if start.get_chars_in_line() >= 4: start.forward_chars(4) end = self.buffer.get_end_iter() return start, end - - def is_balanced (self, line): + def is_balanced(self, line): """ Checks line balance for brace, bracket, parenthese and string quote This helper function checks for the balance of brace, bracket, parenthese and string quote. Any unbalanced line means to wait until some other lines are fed to the console. """ - + s = line s = filter(lambda x: x in '()[]{}"\'', s) - s = s.replace ("'''", "'") - s = s.replace ('"""', '"') + s = s.replace("'''", "'") + s = s.replace('"""', '"') instring = False - brackets = {'(':')', '[':']', '{':'}', '"':'"', '\'':'\''} + brackets = {'(': ')', '[': ']', '{': '}', '"': '"', '\'': '\''} stack = [] - + while len(s): if not instring: if s[0] in ')]}': @@ -388,25 +422,24 @@ def is_balanced (self, line): s = s[1:] return len(stack) == 0 - - def eval (self): + def eval(self): """ Evaluate if current line is ready for execution """ - + l = self.current_line() - self.write ('\n') - self.history.append (l) + self.write('\n') + self.history.append(l) end = self.buffer.get_end_iter() self.buffer.place_cursor(end) if l == '': cmd = self.cmd self.cmd = '' - self.execute (cmd) + self.execute(cmd) self.prompt1() return self.cmd = self.cmd + l + '\n' - if not self.is_balanced (self.cmd): + if not self.is_balanced(self.cmd): self.prompt2() return l = l.rstrip() @@ -417,41 +450,39 @@ def eval (self): cmd = self.cmd self.cmd = '' - self.execute (cmd) + self.execute(cmd) self.prompt1() return - - def idle (self, frame, event, arg): + def idle(self, frame, event, arg): """ Idle function to be used when running a command. - + This idle function is set as a trace function when executing some commands, it allows to process gtk events even when executing code. """ - + while Gtk.events_pending(): Gtk.main_iteration() return self.idle - - def execute (self, cmd): + def execute(self, cmd): """ Execute a given command """ sys.stdout, self.stdout = self.stdout, sys.stdout sys.stderr, self.stderr = self.stderr, sys.stderr - sys.stdin, self.stdin = self.stdin, sys.stdin - sys.settrace (self.idle) + sys.stdin, self.stdin = self.stdin, sys.stdin + sys.settrace(self.idle) try: try: - r = eval (cmd, self.namespace, self.namespace) - + r = eval(cmd, self.namespace, self.namespace) + if r is not None: print(r) except SyntaxError: - exec cmd in self.namespace + exec(cmd, self.namespace) except: - if hasattr (sys, 'last_type') and sys.last_type == SystemExit: + if hasattr(sys, 'last_type') and sys.last_type == SystemExit: self.quit_handler() else: try: @@ -459,118 +490,112 @@ def execute (self, cmd): tb = info[2] if tb: tb = tb.tb_next - traceback.print_exception (info[0], info[1], tb) + traceback.print_exception(info[0], info[1], tb) except: sys.stderr, self.stderr = self.stderr, sys.stderr traceback.print_exc() - sys.settrace (None) + sys.settrace(None) sys.stdout, self.stdout = self.stdout, sys.stdout sys.stderr, self.stderr = self.stderr, sys.stderr - sys.stdin, self.stdin = self.stdin, sys.stdin - + sys.stdin, self.stdin = self.stdin, sys.stdin - def open (self, filename): + def open(self, filename): """ Open and execute a given filename """ - + if not filename: return - if not os.path.exists (filename): + if not os.path.exists(filename): dialog = Gtk.MessageDialog( - None, Gtk.DialogFlags.DESTROY_WITH_PARENT, - Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, - "Unable to open '%s', the file does not exist." % filename) + None, Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, + "Unable to open '%s', the file does not exist." % filename) dialog.run() dialog.destroy() return # By here we need to have the Path sorted out - # or we will be north of the river. + # or we will be north of the river. # Does not matter if it has been called without a file. - sys.path.append(os.path.dirname(filename)) - + sys.path.append(os.path.dirname(filename)) + f = open(filename) try: - self.write ("Executing '%s'\n\n" % filename, 'extern') + self.write("Executing '%s'\n\n" % filename, 'extern') # for line in f: # self.write ('\t'+line, 'script') - self.write ('\n') - self.execute ("exec(open('%s').read())" % filename) + self.write('\n') + self.execute("exec(open('%s').read())" % filename) self.prompt1() finally: f.close() - def quit (self, *args): + def quit(self, *args): """ Default handler on quit """ - Gtk.main_quit(); + Gtk.main_quit() return True - def on_drag_data_received (self, - widget, context, x, y, selection, info, etime): + def on_drag_data_received( + self, widget, context, x, y, selection, info, etime + ): """ Handler for drag data """ - - self.write (selection.data) - widget.emit_stop_by_name ("drag-data-received") - self.text.grab_focus() + self.write(selection.data) + widget.emit_stop_by_name("drag-data-received") + self.text.grab_focus() - def on_button_press (self, *args): + def on_button_press(self, *args): """ Grab focus when window is clicked """ - + self.text.grab_focus() return True - - def on_key_pressed (self, widget, event): + def on_key_pressed(self, widget, event): """ Key pressed handler """ - + # Enter if event.keyval == Gdk.KEY_Return: if self.input_mode: self.input_mode = False end = self.buffer.get_end_iter() - start = self.buffer.get_iter_at_offset (self.linestart) - self.input = self.buffer.get_text (start, end, True) + start = self.buffer.get_iter_at_offset(self.linestart) + self.input = self.buffer.get_text(start, end, True) self.write('\n') else: self.eval() return True - + # Previous command elif event.keyval in (Gdk.KEY_KP_Up, Gdk.KEY_Up): if not self.input_mode: - self.replace (self.history.prev (self.current_line())) + self.replace(self.history.prev(self.current_line())) return True - + # Next command elif event.keyval in (Gdk.KEY_KP_Down, Gdk.KEY_Down): if not self.input_mode: - self.replace (self.history.next (self.current_line())) + self.replace(self.history.next(self.current_line())) return True - + # Left arrow (control cursor position relative to prompt) elif event.keyval in (Gdk.KEY_KP_Left, Gdk.KEY_Left): iter = self.buffer.get_iter_at_mark(self.buffer.get_insert()) - if iter.get_offset() == self.linestart: - return True - return False - + return iter.get_offset() == self.linestart + # Backspace elif event.keyval == Gdk.KEY_BackSpace: iter = self.buffer.get_iter_at_mark(self.buffer.get_insert()) - if iter.get_offset() == self.linestart: - return True - return False + return iter.get_offset() == self.linestart # Home elif event.keyval == Gdk.KEY_Home: - start = self.buffer.get_iter_at_offset (self.linestart) + start = self.buffer.get_iter_at_offset(self.linestart) self.text.get_buffer().place_cursor(start) return True elif event.get_state() & Gdk.ModifierType.CONTROL_MASK: # Ctrl-A if event.keyval in (Gdk.KEY_A, Gdk.KEY_a): - start = self.buffer.get_iter_at_offset (self.linestart) + start = self.buffer.get_iter_at_offset(self.linestart) self.text.get_buffer().place_cursor(start) return True @@ -579,18 +604,18 @@ def on_key_pressed (self, widget, event): if self.input_mode: return True end = self.buffer.get_end_iter() - self.buffer.place_cursor (end) + self.buffer.place_cursor(end) return True # Ctrl-D elif event.keyval in (Gdk.KEY_D, Gdk.KEY_d): if self.input_mode: - return True + return True iter = self.buffer.get_iter_at_mark(self.buffer.get_insert()) if iter.get_line_offset() == 4: self.quit_handler() return True - + # Ctrl-L elif event.keyval in (Gdk.KEY_L, Gdk.KEY_l): if not self.input_mode: @@ -599,35 +624,39 @@ def on_key_pressed (self, widget, event): return False - # ============================================================================= class ConsoleWindow: """ Interactive GTK console window """ - def __init__ (self, ns, title='Python', command=None): + def __init__(self, ns, title='Python', command=None): """ Initialize s console window """ - + self.win = Gtk.Window() - self.win.set_default_size (640, 400) - self.win.set_border_width (3) - self.win.connect ("destroy", lambda w: Gtk.main_quit()) - self.win.connect ("delete_event", lambda w, e: Gtk.main_quit()) - self.win.set_title (title) - self.console = Console (namespace=ns) - self.win.add (self.console) - self.console.banner () + self.win.set_default_size(640, 400) + self.win.set_border_width(3) + self.win.connect("destroy", lambda w: Gtk.main_quit()) + self.win.connect("delete_event", lambda w, e: Gtk.main_quit()) + self.win.set_title(title) + self.console = Console(namespace=ns) + self.win.add(self.console) + self.console.banner() if command: - self.console.execute (command) + self.console.execute(command) self.win.show_all() - + return if __name__ == '__main__': - conswin = ConsoleWindow ({'__builtins__': __builtins__, - '__name__': '__main__', - '__doc__': None}, - title = 'Python Console') + conswin = ConsoleWindow( + { + '__builtins__': __builtins__, + '__name__': '__main__', + '__doc__': None + }, + title='Python Console' + ) if len(sys.argv) > 1: - conswin.console.open (sys.argv[1]) + conswin.console.open(sys.argv[1]) Gtk.main() +