diff options
Diffstat (limited to 'support/autolatex/plugins/gedit2/autolatex/utils')
8 files changed, 1099 insertions, 0 deletions
diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/__init__.py b/support/autolatex/plugins/gedit2/autolatex/utils/__init__.py new file mode 100644 index 0000000000..714513ca5a --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/__init__.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/__init__.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +__all__ = [ ] diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/debug.py b/support/autolatex/plugins/gedit2/autolatex/utils/debug.py new file mode 100644 index 0000000000..ffba72fdfe --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/debug.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/utils.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import pprint + +def dbg(*variables): + pp = pprint.PrettyPrinter(indent=2) + pp.pprint(variables) + exit(255) + +def dbg_struct(var): + print dir(var) + exit(255) diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/gedit_runner.py b/support/autolatex/plugins/gedit2/autolatex/utils/gedit_runner.py new file mode 100644 index 0000000000..b956f3c289 --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/gedit_runner.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/gtk_utils.py +# Copyright (C) 2013-14 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +from gi.repository import GObject, Gtk, Gedit +import runner + +# List of all the runners +_all_runners = [] + +def kill_all_runners(): + runner.kill_all_runners() + +class Runner(runner.Listener): + + def __init__(self, caller, label, show_progress, directory, directive, params): + runner.Listener.__init__(self) + self._caller = caller + self._info_bar_label = label + self._show_progress = bool(show_progress) + self._gedit_tab = None + self._info_bar = None + self._sig_info_bar_response = 0 + self._sig_info_bar_remove = 0 + self._automatic_bar_creation = False + self._last_fraction = 0 + self._last_comment = None + self._thread = runner.Runner(self, directory, directive, params) + + def start(self): + if self._thread: + self._thread.start() + + def cancel(self): + if self._thread: + self._thread.cancel() + self._thread = None + if self._info_bar: + self._info_bar.set_response_sensitive( + Gtk.ResponseType.CANCEL, + False) + + def get_runner_progress(self): + return self._show_progress and self._info_bar_label is not None + + def on_runner_add_ui(self): + self._gedit_tab = self._caller.window.get_active_tab() + GObject.idle_add(self._add_info_bar) + + def on_runner_remove_ui(self): + GObject.idle_add(self._hide_info_bar) + + def on_runner_progress(self, amount, comment): + GObject.idle_add(self._update_info_bar, amount, comment) + + def on_runner_finalize_execution(self, retcode, output, latex_warnings): + self._automatic_bar_creation = False + GObject.idle_add(self._caller._update_action_validity, + True, output, latex_warnings) + + def _add_info_bar(self): + if self._gedit_tab: + self._info_bar = Gedit.ProgressInfoBar() + self._info_bar.set_stock_image(Gtk.STOCK_EXECUTE) + self._info_bar.set_text(self._info_bar_label) + self._sig_info_bar_response = self._info_bar.connect( + "response", + self._on_cancel_action) + self._sig_info_bar_remove = self._info_bar.connect( + "parent-set", + self._on_parent_remove_action) + self._gedit_tab.set_info_bar(self._info_bar) + self._info_bar.show() + self._gedit_tab.grab_focus(); + + def _hide_info_bar(self): + if self._info_bar: + self._info_bar.hide() + self._info_bar.disconnect(self._sig_info_bar_response); + self._info_bar.disconnect(self._sig_info_bar_remove); + self._info_bar.destroy() + self._info_bar = None + self._gedit_tab.grab_focus(); + + def _on_cancel_action(self, widget, response, data=None): + if response == Gtk.ResponseType.CANCEL: + self.cancel() + + def _on_parent_remove_action(self, widget, oldParent=None, data=None): + # The progress bar was removed by an other info bar + bar = self._info_bar + if bar and bar.get_parent() == None: + self._hide_info_bar() + self._automatic_bar_creation = True + GObject.idle_add(self._update_info_bar, + self._last_fraction, self._last_comment) + + def __has_info_child(self): + if self._gedit_tab: + for child in self._gedit_tab.get_children(): + if isinstance(child, Gtk.InfoBar): + return True # Search says: has info bar + return False # Search says: no info bar + return True # Assume that the panel is inside + + def _update_info_bar(self, progress_value, comment): + #print "MOVE TO "+str(progress_value)+"/"+str(comment) + self._last_fraction = progress_value + self._last_comment = comment + if self._automatic_bar_creation and not self._info_bar and not self.__has_info_child(): + self._automatic_bar_creation = False + GObject.idle_add(self._add_info_bar) + GObject.idle_add(self.__set_info_bar_data, progress_value, comment) + + def __set_info_bar_data(self, progress_value, comment): + #print "MOVE TO "+str(progress_value)+"/"+str(comment) + if self._info_bar: + self._info_bar.set_fraction(progress_value) + if comment: + self._info_bar.set_text(comment) + self._info_bar.show() + diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/gsettings.py b/support/autolatex/plugins/gedit2/autolatex/utils/gsettings.py new file mode 100644 index 0000000000..4247ead07a --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/gsettings.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/gsettings.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +#--------------------------------- +# IMPORTS +#--------------------------------- + +# Standard libraries +import os +# Include the Gio, Gtk and Gedit libraries +from gi.repository import Gio, Gtk +# AutoLaTeX internal libs +from . import utils + +#--------------------------------- +# Constants +#--------------------------------- + +_GSETTINGS_BASE_KEY = "apps.autolatex" + +#--------------------------------- +# Class that is managing the settings +#--------------------------------- + +class Manager: + + def _is_schema_installed(): + for schema in Gio.Settings.list_schemas(): + if schema == _GSETTINGS_BASE_KEY: + return True + return False + _is_schema_installed = staticmethod(_is_schema_installed) + + def __init__(self): + if Manager._is_schema_installed(): + self._sig_binded_signals = {} + self.settings = Gio.Settings.new(_GSETTINGS_BASE_KEY) + # Force application of gsettings + self._update_autolatex_cmd(self.settings.get_string('autolatex-cmd')) + self._update_autolatex_backend_cmd(self.settings.get_string('autolatex-backend-cmd')) + # Listen on changes + self._sig_autolatex_cmd_changed = self.settings.connect("changed::autolatex-cmd", self.on_autolatex_cmd_changed) + self._sig_autolatex_backend_cmd_changed = self.settings.connect("changed::autolatex-backend-cmd", self.on_autolatex_backend_cmd_changed) + else: + self.settings = None + self._data = { + 'force-synctex': True, + 'show-progress-info': True, + 'save-before-run-autolatex': True, + } + + def unbind(self): + if self.settings: + self.settings.disconnect(self._sig_autolatex_cmd_changed) + self.settings.disconnect(self._sig_autolatex_backend_cmd_changed) + for datakey in self._sig_binded_signals: + self.settings.disconnect(self._sig_binded_signals[datakey]) + self._sig_binded_signals = {} + self.settings.apply() + + def connect(self, datakey, callback): + if self.settings: + self._sig_binded_signals[datakey] = self.settings.connect("changed::"+str(datakey), callback) + + def disconnect(self, datakey): + if self.settings: + self.settings.disconnect(self._sig_binded_signals[datakey]) + del self._sig_binded_signals[datakey] + + def _update_autolatex_cmd(self, cmd): + if cmd and os.path.isfile(cmd) and os.access(cmd, os.X_OK): + utils.AUTOLATEX_BINARY = cmd + else: + utils.AUTOLATEX_BINARY = utils.DEFAULT_AUTOLATEX_BINARY + + def _update_autolatex_backend_cmd(self, cmd): + if cmd and os.path.isfile(cmd) and os.access(cmd, os.X_OK): + utils.AUTOLATEX_BACKEND_BINARY = cmd + else: + utils.AUTOLATEX_BACKEND_BINARY = utils.DEFAULT_AUTOLATEX_BACKEND_BINARY + + def on_autolatex_cmd_changed(self, settings, key, data=None): + if self.settings: + self._update_autolatex_cmd(self.settings.get_string('autolatex-cmd')) + + def on_autolatex_backend_cmd_changed(self, settings, key, data=None): + if self.settings: + self._update_autolatex_backend_cmd(self.settings.get_string('autolatex-backend-cmd')) + + def get_autolatex_cmd(self): + if self.settings: + path = self.settings.get_string('autolatex-cmd') + return path if path else None + else: + return None + + def set_autolatex_cmd(self,path): + if self.settings: + path = str(path) if path else '' + self.settings.set_string('autolatex-cmd', path) + self.settings.apply() + else: + self._update_autolatex_cmd(path) + + def get_autolatex_backend_cmd(self): + if self.settings: + path = self.settings.get_string('autolatex-backend-cmd') + return path if path else None + else: + return None + + def set_autolatex_backend_cmd(self, path): + if self.settings: + path = str(path) if path else '' + self.settings.set_string('autolatex-backend-cmd', path) + self.settings.apply() + else: + self._update_autolatex_backend_cmd(path) + + def get_force_synctex(self): + if self.settings: + return self.settings.get_boolean('force-synctex') + else: + return self._data['force-synctex'] + + def set_force_synctex(self, is_force): + if self.settings: + self.settings.set_boolean('force-synctex', bool(is_force)) + self.settings.apply() + else: + self._data['force-synctex'] = bool(is_force) + + def get_progress_info_visibility(self): + if self.settings: + return self.settings.get_boolean('show-progress-info') + else: + return self._data['show-progress-info'] + + def set_progress_info_visibility(self, is_shown): + if self.settings: + self.settings.set_boolean('show-progress-info', bool(is_shown)) + self.settings.apply() + else: + self._data['show-progress-info'] = bool(is_shown) + + def get_save_before_run_autolatex(self): + if self.settings: + return self.settings.get_boolean('save-before-run-autolatex') + else: + return self._data['save-before-run-autolatex'] + + def set_save_before_run_autolatex(self, is_saving): + if self.settings: + self.settings.set_boolean('save-before-run-autolatex', bool(is_saving)) + self.settings.apply() + else: + self._data['save-before-run-autolatex'] = bool(is_saving) + diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/gtk_utils.py b/support/autolatex/plugins/gedit2/autolatex/utils/gtk_utils.py new file mode 100644 index 0000000000..d8f941166f --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/gtk_utils.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/gtk_utils.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +#--------------------------------- +# IMPORTS +#--------------------------------- + +# Import standard python libs +from gi.repository import Gtk + +def get_insert_index_dichotomic(list_store, column, data): + f = 0 + l = list_store.iter_n_children(None) - 1 + while l >= f: + c = (f+l) / 2 + path = Gtk.TreePath(c) + d = list_store[path][column] + cmpt = (data > d) - (data < d) + if cmpt == 0: + return -1 + elif cmpt < 0: + l = c-1 + else: + f = c+1 + return f + diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/latex_log_parser.py b/support/autolatex/plugins/gedit2/autolatex/utils/latex_log_parser.py new file mode 100644 index 0000000000..d68b43c14e --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/latex_log_parser.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/latex_log_parser.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +#--------------------------------- +# IMPORTS +#--------------------------------- + +# Import standard python libs +import os +import re +# Import AutoLaTeX libraries +import utils + +#--------------------------------- +# INTERNATIONALIZATION +#--------------------------------- + +import gettext +_T = gettext.gettext + + + +class TeXWarning: + def __init__(self, filename, extension, line, message): + self._data = {} + if extension: + self._filename = filename.strip()+extension + else: + self._filename = filename.strip() + self._linenumber = line + expr = re.compile("[\n\r\f\t ]+") + self._message = re.sub(expr, ' ', message) + + def append(self, message): + self._message = self._message + message + + def set_data(self, key, value): + self._data[key] = value + + def get_data(self, key): + return self._data[key] + + def get_all_data(self): + return self._data + + def get_filename(self): + return self._filename + + def get_line_number(self): + return self._linenumber + + def get_message(self): + return self._message + + def set_message(self, message): + self._message = message + + def __str__(self): + s = str(self._filename)+":"+str(self._linenumber)+":"+str(self._message)+"\n" + if self._data: + s = s + self._data + return s + +class Parser: + + def __init__(self, log_file): + self._directory = os.path.dirname(log_file) + # + self._warnings = [] + # Parsing the log file + regex_start = re.compile("^\\!\\!\\!\\!\\[BeginWarning\\](.*)$") + regex_end = re.compile("^\\!\\!\\!\\!\\[EndWarning\\]") + regex_warn = re.compile("^(.*?):([^:]*):([0-9]+):\\s*(.*?)\\s*$") + f = open(log_file, 'r') + current_log_block = '' + warning = False + line = f.readline() + while line: + if warning: + mo = re.match(regex_end, line) + if mo: + mo = re.match(regex_warn, current_log_block) + if mo: + w = TeXWarning( + mo.group(1), + mo.group(2), + mo.group(3), + mo.group(4)) + self._warnings.append(w) + warning = False + current_log_block = '' + else: + l = line + if not l.endswith(".\n"): + l = l.rstrip() + current_log_block = current_log_block + l + else: + mo = re.match(regex_start, line) + if mo: + l = mo.group(1) + if not l.endswith(".\n"): + l = l.rstrip() + current_log_block = l + warning = True + line = f.readline() + + if warning and current_log_block: + mo = re.match(regex_warn, current_log_block) + if mo: + w = TeXWarning( + mo.group(1), + mo.group(2), + mo.group(3), + mo.group(4)) + self._warnings.append(w) + + def __str__(self): + text = "" + for w in self._warnings: + text = text + str(w) + "\n" + return text + + def get_undefined_citation_warnings(self): + regex = re.compile( + "^.*citation\\s*\\`([^']+)\\'.+undefined.*$", + re.I|re.S) + warnings = [] + for warning in self._warnings: + message = warning.get_message() + mo = re.match(regex, message) + if mo: + warning.set_message( + warning.get_filename()+":"+ + str(warning.get_line_number())+": "+ + (_T("Citation '%s' undefined") % mo.group(1))) + warnings.append(warning) + return warnings + + def get_undefined_reference_warnings(self): + regex = re.compile( + "^.*reference\\s*\\`([^']+)\\'.+undefined.*$", + re.I|re.S) + warnings = [] + for warning in self._warnings: + message = warning.get_message() + mo = re.match(regex, message) + if mo: + warning.set_message( + warning.get_filename()+":"+ + str(warning.get_line_number())+": "+ + (_T("Reference '%s' undefined") % mo.group(1))) + warnings.append(warning) + return warnings + + def get_multidefined_label_warnings(self): + regex = re.compile( + "^.*label\\s*\\`([^']+)\\'.+multiply\\s+defined.*$", + re.I|re.S) + warnings = [] + for warning in self._warnings: + message = warning.get_message() + mo = re.match(regex, message) + if mo: + warning.set_message( + warning.get_filename()+":"+ + str(warning.get_line_number())+": "+ + (_T("Label '%s' multiply defined") % mo.group(1))) + warnings.append(warning) + return warnings + diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/runner.py b/support/autolatex/plugins/gedit2/autolatex/utils/runner.py new file mode 100644 index 0000000000..d5725e00cb --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/runner.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/runner.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os +import re +import subprocess + +# Try to use the threading library if it is available +try: + import threading as _threading +except ImportError: + import dummy_threading as _threading + +import utils + +# List of all the runners +_all_runners = [] + +def kill_all_runners(): + global _all_runners + tab = _all_runners + _all_runners = [] + for r in tab: + r.cancel() + +# Launch AutoLaTeX inside a thread, and wait for the result +class Listener(object): + def get_runner_progress(self): + return False + def on_runner_add_ui(self): + pass + def on_runner_remove_ui(self): + pass + def on_runner_progress(self, amount, comment): + pass + def on_runner_finalize_execution(self, retcode, output, latex_warnings): + pass + +# Launch AutoLaTeX inside a thread, and wait for the result +class Runner(_threading.Thread): + + # listener is the listener on the events + # directory is the path to set as the current path + # directive is the AutoLaTeX command + # params are the CLI options for AutoLaTeX + def __init__(self, listener, directory, directive, params): + _threading.Thread.__init__(self) + assert listener + self.daemon = True + self._listener = listener + self._directory = directory + self._cmd = [ utils.AUTOLATEX_BINARY, '--file-line-warning' ] + params + if directive: + self._cmd.append(directive) + self._has_progress = False + self._subprocess = None + + # Cancel the execution + def cancel(self): + if self._subprocess: + self._subprocess.terminate() + self._subprocess = None + if self._has_progress: + # Remove the info bar from the inside of the UI thread + self._listener.on_runner_remove_ui() + # Update the rest of the UI from the inside of the UI thread + self._listener.on_runner_finalize_execution(0, '', []) + + # Run the thread + def run(self): + global _all_runners + _all_runners.append(self) + progress_line_pattern = None + + self._has_progress = self._listener.get_runner_progress() + + if self._has_progress: + # Add the progress UI + self._listener.on_runner_add_ui() + # Update the command line to obtain the progress data + self._cmd.append('--progress=n') + # Compile a regular expression to extract the progress amount + progress_line_pattern = re.compile("^\\[\\s*([0-9]+)\\%\\]\\s+[#.]+(.*)$") + + # Launch the subprocess + os.chdir(self._directory) + self._subprocess = subprocess.Popen(self._cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output = '' + if self._subprocess: + if self._has_progress: + # Use the info bar to draw the progress of the task + if self._subprocess: + self._subprocess.poll() + # Loop until the subprocess is dead + while self._subprocess and self._subprocess.returncode is None: + if self._subprocess and not self._subprocess.stdout.closed: + # Read a line from STDOUT and extract the progress amount + if self._subprocess: + self._subprocess.stdout.flush() + if self._subprocess: + line = self._subprocess.stdout.readline() + if line: + mo = re.match(progress_line_pattern, line) + if mo: + amount = (float(mo.group(1)) / 100.) + comment = mo.group(2).strip() + self._listener.on_runner_progress(amount, comment) + + if self._subprocess: + self._subprocess.poll() + # Kill the subprocess if + proc = self._subprocess + if proc: + retcode = proc.returncode + # Read the error output of AutoLaTeX + proc.stderr.flush() + for line in proc.stderr: + output = output + line + proc.stdout.close() + proc.stderr.close() + + else: + # Silent execution of the task + out, err = self._subprocess.communicate() if self._subprocess else ('','') + retcode = self._subprocess.returncode if self._subprocess else 0 + output = err + + # Stop because the subprocess was cancelled + if not self._subprocess: + if self in _all_runners: + _all_runners.remove(self) + return 0 + self._subprocess = None + + # If AutoLaTeX had failed, the output is assumed to + # be the error message. + # If AutoLaTeX had not failed, the output may contains + # "warning" notifications. + latex_warnings = [] + if retcode == 0: + regex_expr = re.compile("^\\!\\!(.+?):(W[0-9]+):[^:]+:\\s*(.+?)\\s*$") + for output_line in re.split("[\n\r]+", output): + mo = re.match(regex_expr, output_line) + if mo: + latex_warnings.append([mo.group(3),mo.group(1), mo.group(2)]) + output = '' # Output is no more interesting + + if self._has_progress: + # Remove the info bar from the inside of the UI thread + self._listener.on_runner_remove_ui() + + # Update the rest of the UI from the inside of the UI thread + self._listener.on_runner_finalize_execution(retcode, output, latex_warnings) + if self in _all_runners: + _all_runners.remove(self) + diff --git a/support/autolatex/plugins/gedit2/autolatex/utils/utils.py b/support/autolatex/plugins/gedit2/autolatex/utils/utils.py new file mode 100644 index 0000000000..38e81bb96b --- /dev/null +++ b/support/autolatex/plugins/gedit2/autolatex/utils/utils.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# autolatex/utils/utils.py +# Copyright (C) 2013 Stephane Galland <galland@arakhne.org> +# +# 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; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +#--------------------------------- +# IMPORTS +#--------------------------------- + +# Import standard python libs +import os +import sys +import subprocess +import ConfigParser +import StringIO +import gettext + +#--------------------------------- +# UTILITY FUNCTION +#--------------------------------- + +# Search an executable in the PATH +def which(cmd): + # can't search the path if a directory is specified + assert not os.path.dirname(cmd) + extensions = os.environ.get("PATHEXT", "").split(os.pathsep) + for directory in os.environ.get("PATH", "").split(os.pathsep): + base = os.path.join(directory, cmd) + options = [base] + [(base + ext) for ext in extensions] + for filename in options: + if os.path.exists(filename): + return filename + return None + +# Search a module in the sys.path or in search_part +def resolve_module_path(path, search_path=[]): + if not os.path.isabs(path): + for p in search_path: + full_name = os.path.join(p, path) + if os.path.exists(full_name): + return full_name + for p in sys.path: + full_name = os.path.join(p, path) + if os.path.exists(full_name): + return full_name + return path + +#--------------------------------- +# CONSTANTS +#--------------------------------- + +# Level of verbosity of AutoLaTeX +DEFAULT_LOG_LEVEL = '--quiet' + +# String that is representing an empty string for the AutoLaTeX backend. +CONFIG_EMPTY_VALUE = '<<<<empty>>>>' + +# Paths +AUTOLATEX_PLUGIN_PATH = None +AUTOLATEX_DEV_PATH = None +AUTOLATEX_INSTALL_PATH = None +AUTOLATEX_PO_PATH = None # Default locale path +AUTOLATEX_PM_PATH = None +TOOLBAR_ICON_PATH = None +NOTEBOOK_ICON_PATH = None +TABLE_ICON_PATH = None + +# Binary files +AUTOLATEX_BINARY = None +DEFAULT_AUTOLATEX_BINARY = None +AUTOLATEX_BACKEND_BINARY = None +DEFAULT_AUTOLATEX_BACKEND_BINARY = None + +def init_plugin_configuration(plugin_file, po_name, search_path=[]): + global AUTOLATEX_PLUGIN_PATH + global AUTOLATEX_DEV_PATH + global AUTOLATEX_INSTALL_PATH + global AUTOLATEX_PO_PATH + global AUTOLATEX_PM_PATH + global AUTOLATEX_BINARY + global AUTOLATEX_BACKEND_BINARY + global DEFAULT_AUTOLATEX_BINARY + global DEFAULT_AUTOLATEX_BACKEND_BINARY + global TOOLBAR_ICON_PATH + global NOTEBOOK_ICON_PATH + global TABLE_ICON_PATH + + bin_autolatex = which('autolatex') + + # Build the plugin's filename + plugin_file = resolve_module_path(plugin_file, search_path) + + # Path of the plugin + AUTOLATEX_PLUGIN_PATH = os.path.dirname(plugin_file) + + # Path to the development directory + pdev_path = os.path.realpath(os.path.join(AUTOLATEX_PLUGIN_PATH, + os.path.basename(os.path.splitext(plugin_file)[0])+'.py')) + dev_path = os.path.dirname(pdev_path) + while dev_path and pdev_path and pdev_path!=dev_path and not os.path.exists( + os.path.join(dev_path, 'autolatex.pl')): + pdev_path = dev_path + dev_path = os.path.dirname(dev_path) + if dev_path and os.path.isfile(os.path.join(dev_path, 'autolatex.pl')): + AUTOLATEX_DEV_PATH = dev_path + else: + dev_path = os.path.realpath(bin_autolatex) + if dev_path: + AUTOLATEX_DEV_PATH = os.path.dirname(dev_path) + else: + AUTOLATEX_DEV_PATH = None + + + # Path to the install directory + if AUTOLATEX_DEV_PATH: + AUTOLATEX_INSTALL_PATH = AUTOLATEX_DEV_PATH + else: + path = os.path.realpath(bin_autolatex) + AUTOLATEX_INSTALL_PATH = os.path.dirname(path) + + # Path to PO files + AUTOLATEX_PO_PATH = None + if AUTOLATEX_DEV_PATH: + path = os.path.join(AUTOLATEX_DEV_PATH, 'po') + if os.path.exists(os.path.join(path, 'fr', 'LC_MESSAGES', po_name+'.mo')): + AUTOLATEX_PO_PATH = path + + # Path to PM files + AUTOLATEX_PM_PATH = os.path.join(AUTOLATEX_INSTALL_PATH, 'pm') + + # Binary file + AUTOLATEX_BINARY = bin_autolatex + if AUTOLATEX_DEV_PATH: + path = os.path.join(dev_path, 'autolatex.pl') + if os.path.exists(path): + AUTOLATEX_BINARY = path + DEFAULT_AUTOLATEX_BINARY = AUTOLATEX_BINARY + + AUTOLATEX_BACKEND_BINARY = which('autolatex-backend') + if AUTOLATEX_DEV_PATH: + path = os.path.join(dev_path, 'autolatex-backend.pl') + if os.path.exists(path): + AUTOLATEX_BACKEND_BINARY = path + DEFAULT_AUTOLATEX_BACKEND_BINARY = AUTOLATEX_BACKEND_BINARY + + # Icons paths + TOOLBAR_ICON_PATH = os.path.join(AUTOLATEX_PLUGIN_PATH, 'icons', '24') + NOTEBOOK_ICON_PATH = os.path.join(AUTOLATEX_PLUGIN_PATH, 'icons', '16') + TABLE_ICON_PATH = os.path.join(AUTOLATEX_PLUGIN_PATH, 'icons', '16') + + # Init internationalization tools + gettext.bindtextdomain(po_name, AUTOLATEX_PO_PATH) + gettext.textdomain(po_name) + +def make_toolbar_icon_path(name): + assert TOOLBAR_ICON_PATH + return os.path.join(TOOLBAR_ICON_PATH, name) + +def make_notebook_icon_path(name): + assert NOTEBOOK_ICON_PATH + return os.path.join(NOTEBOOK_ICON_PATH, name) + +def make_table_icon_path(name): + assert TABLE_ICON_PATH + return os.path.join(TABLE_ICON_PATH, name) + + + +def backend_get_translators(directory): + os.chdir(directory) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'get', 'translators'], stdout=subprocess.PIPE ) + data = process.communicate()[0] + string_in = StringIO.StringIO(data) + config = ConfigParser.ConfigParser() + config.readfp(string_in) + string_in.close() + return config + +def backend_get_loads(directory): + os.chdir(directory) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'get', 'loads', ], stdout=subprocess.PIPE ) + data = process.communicate()[0] + string_in = StringIO.StringIO(data) + config = ConfigParser.ConfigParser() + config.readfp(string_in) + string_in.close() + return config + +def backend_get_configuration(directory, level, section): + os.chdir(directory) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'get', 'config', level, section], stdout=subprocess.PIPE ) + data = process.communicate()[0] + string_in = StringIO.StringIO(data) + config = ConfigParser.ConfigParser() + config.readfp(string_in) + string_in.close() + return config + +def backend_get_images(directory): + os.chdir(directory) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'get', 'images'], stdout=subprocess.PIPE ) + data = process.communicate()[0] + string_in = StringIO.StringIO(data) + config = ConfigParser.ConfigParser() + config.readfp(string_in) + string_in.close() + return config + +def backend_set_loads(directory, load_config): + os.chdir(directory) + string_out = StringIO.StringIO() + load_config.write(string_out) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'set', 'loads', ], stdin=subprocess.PIPE) + process.communicate(input=string_out.getvalue()) + string_out.close() + return process.returncode == 0 + +def backend_set_configuration(directory, level, settings): + os.chdir(directory) + string_out = StringIO.StringIO() + settings.write(string_out) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'set', 'config', level, 'false' ], stdin=subprocess.PIPE) + process.communicate(input=string_out.getvalue()) + string_out.close() + return process.returncode == 0 + +def backend_set_images(directory, settings): + os.chdir(directory) + string_out = StringIO.StringIO() + settings.write(string_out) + process = subprocess.Popen( [AUTOLATEX_BACKEND_BINARY, 'set', 'images', 'false' ], stdin=subprocess.PIPE) + process.communicate(input=string_out.getvalue()) + string_out.close() + return process.returncode == 0 + + +def first_of(*values): + for value in values: + if value is not None: + return value + return None + +def get_autolatex_user_config_directory(): + if os.name == 'posix': + return os.path.join(os.path.expanduser("~"), ".autolatex") + elif os.name == 'nt': + return os.path.join(os.path.expanduser("~"),"Local Settings","Application Data","autolatex") + else: + return os.path.join(os.path.expanduser("~"), "autolatex") + +def get_autolatex_user_config_file(): + directory = get_autolatex_user_config_directory() + if os.path.isdir(directory): + return os.path.join(directory, 'autolatex.conf') + if os.name == 'posix': + return os.path.join(os.path.expanduser("~"), ".autolatex") + elif os.name == 'nt': + return os.path.join(os.path.expanduser("~"),"Local Settings","Application Data","autolatex.conf") + else: + return os.path.join(os.path.expanduser("~"), "autolatex.conf") + +def get_autolatex_document_config_file(directory): + if os.name == 'posix': + return os.path.join(directory, ".autolatex_project.cfg") + else: + return os.path.join(directory, "autolatex_project.cfg") + +# Test if a given string is a standard extension for TeX document +def is_TeX_extension(ext): + ext = ext.lower() + if ext == '.tex' or ext =='.latex': + return True + else: + return False + +# Replies if the active document is a TeX document +def is_TeX_document(filename): + if filename: + ext = os.path.splitext(filename)[-1] + return is_TeX_extension(ext) + return False + +# Try to find the directory where an AutoLaTeX configuration file is +# located. The search is traversing the parent directory from the current +# document. +def find_AutoLaTeX_directory(current_document): + adir = None + if os.path.isdir(current_document): + directory = current_document + else: + directory = os.path.dirname(current_document) + directory = os.path.abspath(directory) + document_dir = directory + cfgFile = get_autolatex_document_config_file(directory) + previousFile = '' + while previousFile != cfgFile and not os.path.exists(cfgFile): + directory = os.path.dirname(directory) + previousFile = cfgFile + cfgFile = get_autolatex_document_config_file(directory) + + if previousFile != cfgFile: + adir = os.path.dirname(cfgFile) + else: + ext = os.path.splitext(current_document)[-1] + if is_TeX_extension(ext): + adir = document_dir + + return adir + |