[pitivi] plugins: Add Pitivi Developer Console plugin
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] plugins: Add Pitivi Developer Console plugin
- Date: Sat, 4 Aug 2018 13:32:49 +0000 (UTC)
commit f6cdd1ad3228f26f116782d287c920eb1e245dd7
Author: Fabian Orccon <cfoch fabian gmail com>
Date: Fri Jul 13 11:13:32 2018 -0500
plugins: Add Pitivi Developer Console plugin
Closes #2055
plugins/console/console.plugin | 9 ++++
plugins/console/console.py | 89 ++++++++++++++++++++++++++++++++++++++++
plugins/console/consolebuffer.py | 83 +++++++++++++++++++++++++++++++++++++
plugins/console/utils.py | 52 +++++++++++++++++++++++
plugins/console/widgets.py | 79 +++++++++++++++++++++++++++++++++++
5 files changed, 312 insertions(+)
---
diff --git a/plugins/console/console.plugin b/plugins/console/console.plugin
new file mode 100644
index 00000000..317b7a12
--- /dev/null
+++ b/plugins/console/console.plugin
@@ -0,0 +1,9 @@
+[Plugin]
+Module=console
+Name=Pitivi Developer Console
+Loader=Python3
+Description=Add a developer console to Pitivi.
+Authors=Fabian Orccon <cfoch fabian gmail com>
+Copyright=Copyright © 2017 Fabian Orccon
+Website=http://pitivi.org
+Help=http://developer.pitivi.org
diff --git a/plugins/console/console.py b/plugins/console/console.py
new file mode 100644
index 00000000..cceb028a
--- /dev/null
+++ b/plugins/console/console.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Pitivi Developer Console
+# Copyright (c) 2017-2018, Fabian Orccon <cfoch fabian gmail com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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.
+"""Python console for inspecting and interacting with Pitivi and the project."""
+import sys
+from gettext import gettext as _
+
+from gi.repository import GObject
+from gi.repository import Gtk
+from gi.repository import Peas
+from widgets import ConsoleWidget
+
+
+class Console(GObject.GObject, Peas.Activatable):
+ """Plugin which adds a Python console for development purposes."""
+
+ __gtype_name__ = "ConsolePlugin"
+ object = GObject.Property(type=GObject.Object)
+
+ def __init__(self):
+ GObject.GObject.__init__(self)
+ self.window = None
+ self.terminal = None
+ self.menu_item = None
+ self.app = None
+
+ # Set prompt.
+ sys.ps1 = ">>> "
+ sys.ps2 = "... "
+
+ def do_activate(self):
+ api = self.object
+ self.app = api.app
+ self._setup_dialog()
+ self.add_menu_item()
+ self.menu_item.show()
+
+ def do_deactivate(self):
+ self.window.destroy()
+ self.remove_menu_item()
+ self.window = None
+ self.terminal = None
+ self.menu_item = None
+ self.app = None
+
+ def add_menu_item(self):
+ """Inserts a menu item into the Pitivi menu."""
+ menu = self.app.gui.editor.builder.get_object("menu")
+ self.menu_item = Gtk.MenuItem.new_with_label(_("Developer Console"))
+ self.menu_item.connect("activate", self.__menu_item_activate_cb)
+ menu.add(self.menu_item)
+
+ def remove_menu_item(self):
+ """Removes a menu item from the Pitivi menu."""
+ menu = self.app.gui.editor.builder.get_object("menu")
+ menu.remove(self.menu_item)
+ self.menu_item = None
+
+ def _setup_dialog(self):
+ namespace = {"app": self.app}
+ self.window = Gtk.Window()
+ self.terminal = ConsoleWidget(namespace)
+
+ self.window.set_default_size(600, 400)
+ self.window.set_title(_("Pitivi Console"))
+ self.window.connect("delete-event", self.__delete_event_cb)
+ self.window.add(self.terminal)
+
+ def __menu_item_activate_cb(self, unused_data):
+ self.window.show_all()
+ self.window.set_keep_above(True)
+
+ def __delete_event_cb(self, unused_widget, unused_data):
+ return self.window.hide_on_delete()
diff --git a/plugins/console/consolebuffer.py b/plugins/console/consolebuffer.py
new file mode 100644
index 00000000..d65f9c36
--- /dev/null
+++ b/plugins/console/consolebuffer.py
@@ -0,0 +1,83 @@
+# pylint: disable=missing-docstring
+# -*- coding: utf-8 -*-
+# Pitivi Developer Console
+# Copyright (c) 2017-2018, Fabian Orccon <cfoch fabian gmail com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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.
+import code
+import sys
+
+from gi.repository import Gtk
+from utils import FakeOut
+from utils import swap_std
+
+
+class ConsoleBuffer(Gtk.TextBuffer):
+
+ def __init__(self, namespace):
+ Gtk.TextBuffer.__init__(self)
+
+ self.insert_at_cursor(sys.ps1)
+ self.prompt_mark = self.create_mark("after-prompt", self.get_end_iter(), left_gravity=True)
+
+ self._stdout = FakeOut(self)
+ self._stderr = FakeOut(self)
+ self._console = code.InteractiveConsole(namespace)
+
+ def process_command_line(self):
+ """Process the current input command line executing it if complete."""
+ cmd = self.get_command_line()
+
+ with swap_std(self._stdout, self._stderr):
+ self.write("\n")
+ is_command_incomplete = self._console.push(cmd)
+
+ if is_command_incomplete:
+ prompt = sys.ps2
+ else:
+ prompt = sys.ps1
+ self.write(prompt)
+
+ self.move_mark(self.prompt_mark, self.get_end_iter())
+ self.place_cursor(self.get_end_iter())
+
+ def is_cursor(self, before=False, at=False, after=False):
+ """Compares the position of the cursor compared to the prompt."""
+ prompt_iter = self.get_iter_at_mark(self.prompt_mark)
+ cursor_iter = self.get_iter_at_mark(self.get_insert())
+ res = cursor_iter.compare(prompt_iter)
+ return (before and res == -1) or (at and res == 0) or (after and res == 1)
+
+ def write(self, text):
+ """Writes a text to the buffer."""
+ self.insert(self.get_end_iter(), text)
+
+ def get_command_line(self):
+ """Gets the last command line after the prompt.
+
+ A command line can be a single line or multiple lines for example when
+ a function or a class is defined.
+ """
+ after_prompt_iter = self.get_iter_at_mark(self.prompt_mark)
+ end_iter = self.get_end_iter()
+ return self.get_text(after_prompt_iter, end_iter, include_hidden_chars=False)
+
+ def set_command_line(self, cmd):
+ """Inserts a command line after the prompt."""
+ after_prompt_iter = self.get_iter_at_mark(self.prompt_mark)
+ end_iter = self.get_end_iter()
+ self.delete(after_prompt_iter, end_iter)
+ self.write(cmd)
diff --git a/plugins/console/utils.py b/plugins/console/utils.py
new file mode 100644
index 00000000..33f2850c
--- /dev/null
+++ b/plugins/console/utils.py
@@ -0,0 +1,52 @@
+# pylint: disable=missing-docstring
+# -*- coding: utf-8 -*-
+# Pitivi Developer Console
+# Copyright (c) 2017-2018, Fabian Orccon <cfoch fabian gmail com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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.
+import sys
+from contextlib import contextmanager
+from io import TextIOBase
+
+
+@contextmanager
+def swap_std(stdout=None, stderr=None):
+ """Swaps temporarily stdout and stderr with the respective arguments."""
+ try:
+ if stdout:
+ sys.stdout, stdout = stdout, sys.stdout
+ if stderr:
+ sys.stderr, stderr = stderr, sys.stderr
+ yield
+ finally:
+ if stdout:
+ sys.stdout = stdout
+ if stderr:
+ sys.stderr = stderr
+
+
+class FakeOut(TextIOBase):
+ """Replacement for sys.stdout/err which redirects writes."""
+
+ def __init__(self, buf):
+ TextIOBase.__init__(self)
+ self.buf = buf
+
+ def write(self, string):
+ self.buf.write(string)
+
+ def writelines(self, lines):
+ self.buf.write(lines)
diff --git a/plugins/console/widgets.py b/plugins/console/widgets.py
new file mode 100644
index 00000000..c35c4976
--- /dev/null
+++ b/plugins/console/widgets.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+# Pitivi Developer Console
+# Copyright (c) 2017-2018, Fabian Orccon <cfoch fabian gmail com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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.
+"""The developer console widget:"""
+from gi.repository import Gdk
+from gi.repository import GLib
+from gi.repository import Gtk
+
+from consolebuffer import ConsoleBuffer
+
+
+class ConsoleWidget(Gtk.ScrolledWindow):
+ """An emulated Python console.
+
+ The console can be used to access an app, window, or anything through the
+ provided namespace. It works redirecting stdout and stderr to a
+ GtkTextBuffer. This class is (and should be) independent of the application
+ it is integrated with.
+ """
+
+ def __init__(self, namespace):
+ Gtk.ScrolledWindow.__init__(self)
+ self._view = Gtk.TextView()
+ buf = ConsoleBuffer(namespace)
+ self._view.set_buffer(buf)
+ self._view.set_editable(True)
+ self.add(self._view)
+
+ self._view.connect("key-press-event", self.__key_press_event_cb)
+ buf.connect("mark-set", self.__mark_set_cb)
+ buf.connect("insert-text", self.__insert_text_cb)
+
+ def scroll_to_end(self):
+ """Scrolls the view to the end."""
+ end_iter = self._view.get_buffer().get_end_iter()
+ self._view.scroll_to_iter(end_iter, within_margin=0.0, use_align=False,
+ xalign=0, yalign=0)
+ return False
+
+ @classmethod
+ def __key_press_event_cb(cls, view, event):
+ buf = view.get_buffer()
+ if event.keyval == Gdk.KEY_Return:
+ buf.process_command_line()
+ return True
+ if event.keyval in (Gdk.KEY_KP_Down, Gdk.KEY_Down):
+ return True
+ if event.keyval in (Gdk.KEY_KP_Up, Gdk.KEY_Up):
+ return True
+ if event.keyval in (Gdk.KEY_KP_Left, Gdk.KEY_Left, Gdk.KEY_BackSpace):
+ return buf.is_cursor(at=True)
+ if event.keyval in (Gdk.KEY_KP_Home, Gdk.KEY_Home):
+ buf.place_cursor(buf.get_iter_at_mark(buf.prompt_mark))
+ return True
+ return False
+
+ def __mark_set_cb(self, buf, unused_iter, mark):
+ if not mark.props.name == "insert":
+ return
+
+ self._view.set_editable(buf.is_cursor(at=True, after=True))
+
+ def __insert_text_cb(self, buf, unused_iter, unused_text, unused_len):
+ GLib.idle_add(self.scroll_to_end)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]