diff options
Diffstat (limited to '')
-rw-r--r-- | plugins/externaltools/tools/functions.py | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/plugins/externaltools/tools/functions.py b/plugins/externaltools/tools/functions.py new file mode 100644 index 0000000..bc755be --- /dev/null +++ b/plugins/externaltools/tools/functions.py @@ -0,0 +1,365 @@ +# -*- coding: utf-8 -*- +# Gedit External Tools plugin +# Copyright (C) 2005-2006 Steve Frécinaux <steve@istique.net> +# +# 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. +# +# 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 General Public License for more details. +# +# 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 + +import os +from gi.repository import Gio, Gtk, Gdk, GtkSource, Gedit +from .capture import * + +try: + import gettext + gettext.bindtextdomain('gedit') + gettext.textdomain('gedit') + _ = gettext.gettext +except: + _ = lambda s: s + +def default(val, d): + if val is not None: + return val + else: + return d + + +def current_word(document): + piter = document.get_iter_at_mark(document.get_insert()) + start = piter.copy() + + if not piter.starts_word() and (piter.inside_word() or piter.ends_word()): + start.backward_word_start() + + if not piter.ends_word() and piter.inside_word(): + piter.forward_word_end() + + return (start, piter) + + +def file_browser_root(window): + bus = window.get_message_bus() + + if bus.is_registered('/plugins/filebrowser', 'get_root'): + msg = bus.send_sync('/plugins/filebrowser', 'get_root') + + if msg: + browser_root = msg.props.location + + if browser_root and browser_root.is_native(): + return browser_root.get_path() + + return None + + +# ==== Capture related functions ==== +def run_external_tool(window, panel, node): + # Configure capture environment + try: + cwd = os.getcwd() + except OSError: + cwd = os.getenv('HOME') + + capture = Capture(node.command, cwd) + capture.env = os.environ.copy() + capture.set_env(GEDIT_CWD=cwd) + + view = window.get_active_view() + document = None + + if view is not None: + # Environment vars relative to current document + document = view.get_buffer() + location = document.get_file().get_location() + + # Current line number + piter = document.get_iter_at_mark(document.get_insert()) + capture.set_env(GEDIT_CURRENT_LINE_NUMBER=str(piter.get_line() + 1)) + + # Current line text + piter.set_line_offset(0) + end = piter.copy() + + if not end.ends_line(): + end.forward_to_line_end() + + capture.set_env(GEDIT_CURRENT_LINE=piter.get_text(end)) + + if document.get_language() is not None: + capture.set_env(GEDIT_CURRENT_DOCUMENT_LANGUAGE=document.get_language().get_id()) + + # Selected text (only if input is not selection) + if node.input != 'selection' and node.input != 'selection-document': + bounds = document.get_selection_bounds() + + if bounds: + capture.set_env(GEDIT_SELECTED_TEXT=bounds[0].get_text(bounds[1])) + + bounds = current_word(document) + capture.set_env(GEDIT_CURRENT_WORD=bounds[0].get_text(bounds[1])) + + capture.set_env(GEDIT_CURRENT_DOCUMENT_TYPE=document.get_mime_type()) + + if location is not None: + scheme = location.get_uri_scheme() + name = location.get_basename() + capture.set_env(GEDIT_CURRENT_DOCUMENT_URI=location.get_uri(), + GEDIT_CURRENT_DOCUMENT_NAME=name, + GEDIT_CURRENT_DOCUMENT_SCHEME=scheme) + if location.has_uri_scheme('file'): + path = location.get_path() + cwd = os.path.dirname(path) + capture.set_cwd(cwd) + capture.set_env(GEDIT_CURRENT_DOCUMENT_PATH=path, + GEDIT_CURRENT_DOCUMENT_DIR=cwd) + + documents_location = [doc.get_file().get_location() + for doc in window.get_documents() + if doc.get_file().get_location() is not None] + documents_uri = [location.get_uri() + for location in documents_location + if location.get_uri() is not None] + documents_path = [location.get_path() + for location in documents_location + if location.has_uri_scheme('file')] + capture.set_env(GEDIT_DOCUMENTS_URI=' '.join(documents_uri), + GEDIT_DOCUMENTS_PATH=' '.join(documents_path)) + + # set file browser root env var if possible + browser_root = file_browser_root(window) + if browser_root: + capture.set_env(GEDIT_FILE_BROWSER_ROOT=browser_root) + + flags = capture.CAPTURE_BOTH + + if not node.has_hash_bang(): + flags |= capture.CAPTURE_NEEDS_SHELL + + capture.set_flags(flags) + + # Get input text + input_type = node.input + output_type = node.output + + # Clear the panel + panel.clear() + + if output_type == 'output-panel': + panel.show() + + # Assign the error output to the output panel + panel.set_process(capture) + + if input_type != 'nothing' and view is not None: + if input_type == 'document': + start, end = document.get_bounds() + elif input_type == 'selection' or input_type == 'selection-document': + try: + start, end = document.get_selection_bounds() + except ValueError: + if input_type == 'selection-document': + start, end = document.get_bounds() + + if output_type == 'replace-selection': + document.select_range(start, end) + else: + start = document.get_iter_at_mark(document.get_insert()) + end = start.copy() + + elif input_type == 'line': + start = document.get_iter_at_mark(document.get_insert()) + end = start.copy() + if not start.starts_line(): + start.set_line_offset(0) + if not end.ends_line(): + end.forward_to_line_end() + elif input_type == 'word': + start = document.get_iter_at_mark(document.get_insert()) + end = start.copy() + if not start.inside_word(): + panel.write(_('You must be inside a word to run this command'), + panel.error_tag) + return + if not start.starts_word(): + start.backward_word_start() + if not end.ends_word(): + end.forward_word_end() + + input_text = document.get_text(start, end, False) + capture.set_input(input_text) + + # Assign the standard output to the chosen "file" + if output_type == 'new-document': + tab = window.create_tab(True) + view = tab.get_view() + document = tab.get_document() + pos = document.get_start_iter() + capture.connect('stdout-line', capture_stdout_line_document, document, pos) + document.begin_user_action() + view.set_editable(False) + view.set_cursor_visible(False) + elif output_type != 'output-panel' and output_type != 'nothing' and view is not None: + document.begin_user_action() + view.set_editable(False) + view.set_cursor_visible(False) + + if output_type.startswith('replace-'): + if output_type == 'replace-selection': + try: + start_iter, end_iter = document.get_selection_bounds() + except ValueError: + start_iter = document.get_iter_at_mark(document.get_insert()) + end_iter = start_iter.copy() + elif output_type == 'replace-document': + start_iter, end_iter = document.get_bounds() + capture.connect('stdout-line', capture_delayed_replace, + document, start_iter, end_iter) + else: + if output_type == 'insert': + pos = document.get_iter_at_mark(document.get_insert()) + else: + pos = document.get_end_iter() + capture.connect('stdout-line', capture_stdout_line_document, document, pos) + elif output_type != 'nothing': + capture.connect('stdout-line', capture_stdout_line_panel, panel) + + if not document is None: + document.begin_user_action() + + capture.connect('stderr-line', capture_stderr_line_panel, panel) + capture.connect('begin-execute', capture_begin_execute_panel, panel, view, node.name) + capture.connect('end-execute', capture_end_execute_panel, panel, view, output_type) + + # Run the command + capture.execute() + + if output_type != 'nothing': + if not document is None: + document.end_user_action() + +class MultipleDocumentsSaver: + def __init__(self, window, panel, all_docs, node): + self._window = window + self._panel = panel + self._node = node + + if all_docs: + docs = window.get_documents() + else: + docs = [window.get_active_document()] + + self._docs_to_save = [doc for doc in docs if doc.get_modified()] + self.save_next_document() + + def save_next_document(self): + if len(self._docs_to_save) == 0: + # The documents are saved, we can run the tool. + run_external_tool(self._window, self._panel, self._node) + else: + next_doc = self._docs_to_save[0] + self._docs_to_save.remove(next_doc) + + Gedit.commands_save_document_async(next_doc, + self._window, + None, + self.on_document_saved, + None) + + def on_document_saved(self, doc, result, user_data): + saved = Gedit.commands_save_document_finish(doc, result) + if saved: + self.save_next_document() + + +def capture_menu_action(action, parameter, window, panel, node): + if node.save_files == 'document' and window.get_active_document(): + MultipleDocumentsSaver(window, panel, False, node) + return + elif node.save_files == 'all': + MultipleDocumentsSaver(window, panel, True, node) + return + + run_external_tool(window, panel, node) + + +def capture_stderr_line_panel(capture, line, panel): + if not panel.visible(): + panel.show() + + panel.write(line, panel.error_tag) + + +def capture_begin_execute_panel(capture, panel, view, label): + if view: + view.get_window(Gtk.TextWindowType.TEXT).set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) + + panel['stop'].set_sensitive(True) + panel.clear() + panel.write(_("Running tool:"), panel.italic_tag) + panel.write(" %s\n\n" % label, panel.bold_tag) + + +def capture_end_execute_panel(capture, exit_code, panel, view, output_type): + panel['stop'].set_sensitive(False) + + if view: + if output_type in ('new-document', 'replace-document'): + doc = view.get_buffer() + start = doc.get_start_iter() + end = start.copy() + end.forward_chars(300) + uri = '' + + mtype, uncertain = Gio.content_type_guess(None, doc.get_text(start, end, False).encode('utf-8')) + lmanager = GtkSource.LanguageManager.get_default() + + location = doc.get_file().get_location() + if location: + uri = location.get_uri() + language = lmanager.guess_language(uri, mtype) + + if language is not None: + doc.set_language(language) + + view.get_window(Gtk.TextWindowType.TEXT).set_cursor(Gdk.Cursor.new(Gdk.CursorType.XTERM)) + view.set_cursor_visible(True) + view.set_editable(True) + + if exit_code == 0: + panel.write("\n" + _("Done.") + "\n", panel.italic_tag) + else: + panel.write("\n" + _("Exited") + ":", panel.italic_tag) + panel.write(" %d\n" % exit_code, panel.bold_tag) + + +def capture_stdout_line_panel(capture, line, panel): + panel.write(line) + + +def capture_stdout_line_document(capture, line, document, pos): + document.insert(pos, line) + + +def capture_delayed_replace(capture, line, document, start_iter, end_iter): + document.delete(start_iter, end_iter) + + # Must be done after deleting the text + pos = document.get_iter_at_mark(document.get_insert()) + + capture_stdout_line_document(capture, line, document, pos) + + capture.disconnect_by_func(capture_delayed_replace) + capture.connect('stdout-line', capture_stdout_line_document, document, pos) + +# ex:ts=4:et: |