summaryrefslogtreecommitdiff
path: root/support/autolatex/plugins/gedit2/autolatex/utils
diff options
context:
space:
mode:
Diffstat (limited to 'support/autolatex/plugins/gedit2/autolatex/utils')
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/__init__.py22
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/debug.py31
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/gedit_runner.py139
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/gsettings.py176
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/gtk_utils.py44
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/latex_log_parser.py188
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/runner.py174
-rw-r--r--support/autolatex/plugins/gedit2/autolatex/utils/utils.py325
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
+