summaryrefslogtreecommitdiffstats
path: root/plugins/externaltools/tools/functions.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/externaltools/tools/functions.py')
-rw-r--r--plugins/externaltools/tools/functions.py365
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: