# -*- coding: utf-8 -*- # Gedit External Tools plugin # Copyright (C) 2005-2006 Steve Frécinaux # # 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: