File: __init__.py

package info (click to toggle)
gedit-latex-plugin 3.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 4,772 kB
  • ctags: 1,793
  • sloc: sh: 11,232; python: 6,892; xml: 1,885; makefile: 410; perl: 260
file content (277 lines) | stat: -rw-r--r-- 8,847 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# -*- coding: utf-8 -*-

# This file is part of the Gedit LaTeX Plugin
#
# Copyright (C) 2010 Michael Zeising
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public Licence as published by the Free Software
# Foundation; either version 2 of the Licence, 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 Licence for more
# details.
#
# You should have received a copy of the GNU General Public Licence along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA  02110-1301, USA

"""
tools

A tool is what we called a 'build profile' before. 'Tool' is more generic.
It can be used for cleaning up, converting files, for building PDFs etc.
"""

import logging

from gi.repository import Gtk, Gedit

from ..resources import Resources
from ..action import Action

LOG = logging.getLogger(__name__)

class Tool(object):
    """
    The model of a tool. This is to be stored in preferences.
    """
    def __init__(self, label, jobs, description, accelerator, extensions=[]):
        """
        @param label: a label used when displaying the Tool in the UI
        @param jobs: a list of Job objects
        @param description: a descriptive string used as tooltip
        @param accelerator: a key combination for activating this tool
        @param extensions: a list of file extensions for which this Tool can be used
        """
        self.label = label
        self.jobs = jobs
        self.description = description
        self.extensions = extensions
        self.accelerator = accelerator

    def __str__(self):
        return "Tool{%s}" % self.label


class Job(object):
    """
    A Job is one command to be executed in a Tool

    Command templates may contain the following placeholders:

     * $filename : the full filename of the processed file
     * $directory : the parent directory of the processed file
     * $shortname : the filename of the processed file without extension ('/dir/doc' for '/dir/doc.tex')
    """
    def __init__(self, command_template, must_succeed, post_processor):
        """
        Construct a Job

        @param command_template: a template string for the command to be executed
        @param must_succeed: if True this Job may cause the whole Tool to fail
        @param post_processor: a class implementing IPostProcessor
        """
        self._command_template = command_template
        self._must_succeed = must_succeed
        self._post_processor = post_processor

    @property
    def command_template(self):
        return self._command_template

    @property
    def must_succeed(self):
        return self._must_succeed

    @property
    def post_processor(self):
        return self._post_processor


class ToolAction(Action):
    """
    This hooks Tools in the UI. A ToolAction is instantiated for each registered Tool.
    """

    def __init__(self, tool):
        self._tool = tool
        self._runner = ToolRunner()

    @property
    def label(self):
        return self._tool.label

    @property
    def stock_id(self):
        return Gtk.STOCK_EXECUTE

    @property
    def accelerator(self):
        return None

    @property
    def tooltip(self):
        return self._tool.description

    def activate(self, context):
        LOG.debug("tool activate: %s" % self._tool)

        if context.active_editor:
            decorator = context._window_decorator
            doc = decorator.window.get_active_document()
            self.saving_id = doc.connect("saved",self.run_tool,context,doc)
            decorator.save_file()
        else:
            LOG.error("tool activate: no active editor")

    def run_tool(self, document, context, doc):
        tool_view = context.find_view(context.active_editor, "ToolView")

        self._runner.run(context.active_editor.file, self._tool, tool_view)
        LOG.debug("run tool on: %s" % context.active_editor.file)

        # destroy the save listener, or else we get a compile on any save
        doc.disconnect(self.saving_id)



from os import chdir
from .util import Process
from string import Template


class ToolRunner(Process):
    """
    This runs a Tool in a subprocess
    """

    def run(self, file, tool, issue_handler):
        """
        @param file: a File object
        @param tool: a Tool object
        @param issue_handler: an object implementing IStructuredIssueHandler
        """
        self._file = file
        self._stdout_text = ""
        self._stderr_text = ""
        self._job_iter = iter(tool.jobs)

        # add alert to the statusbar
        self._statusbar = Gedit.App.get_default().get_active_window().get_statusbar()
        self._msg_id = self._statusbar.push(1,'Compiling document ...')

        # init the IStructuredIssueHandler
        self._issue_handler = issue_handler
        self._issue_handler.clear()
        self._root_issue_partition = self._issue_handler.add_partition("<b>%s</b>" % tool.label, "running", None)
        self._issue_partitions = {}
        for job in tool.jobs:
            self._issue_partitions[job] = self._issue_handler.add_partition(job.command_template, "running", self._root_issue_partition)

        # change working directory to prevent issues with relative paths
        chdir(file.dirname)

        # enable abort
        self._issue_handler.set_abort_enabled(True, self.abort)

        # run
        self.__proceed()

    def __proceed(self):
        try:
            self._job = next(self._job_iter)

            command_template = Template(self._job.command_template)
            command = command_template.safe_substitute({"filename" : self._file.path,
                                                        "shortname" : self._file.shortname,
                                                        "directory" : self._file.dirname,
                                                        "plugin_path" : Resources().get_system_dir()})

            self._issue_handler.set_partition_state(self._issue_partitions[self._job], "running")

            self.execute(command)
        except StopIteration:
            # Tool finished successfully
            self._issue_handler.set_partition_state(self._root_issue_partition, "succeeded")
            # disable abort

            # FIXME: CRASHES
            # self._issue_handler.set_abort_enabled(False, None)

            self._on_tool_succeeded()

    def _on_stdout(self, text):
        """
        """
        LOG.debug("tool stdout: " + text)
        self._stdout_text += text

    def _on_stderr(self, text):
        """
        """
        LOG.debug("tool stderr: " + text)
        self._stderr_text += text

    def _on_abort(self):
        """
        """
        # disable abort
        self._issue_handler.set_abort_enabled(False, None)
        # mark Tool and all Jobs as aborted
        self._issue_handler.set_partition_state(self._root_issue_partition, "aborted")
        self._issue_handler.set_partition_state(self._issue_partitions[self._job], "aborted")
        for job in self._job_iter:
            self._issue_handler.set_partition_state(self._issue_partitions[job], "aborted")

    def _on_exit(self, condition):
        """
        """
        LOG.debug("tool exit")

        assert self._job

        # create post-processor instance
        post_processor = self._job.post_processor()

        # run post-processor
        post_processor.process(self._file, self._stdout_text, self._stderr_text, condition)

        # show issues
        self._issue_handler.append_issues(self._issue_partitions[self._job], post_processor.issues)

        # remove alert
        self._statusbar.remove(1,self._msg_id)

        if post_processor.successful:
            self._issue_handler.set_partition_state(self._issue_partitions[self._job], "succeeded")
            self.__proceed()
        else:
            self._issue_handler.set_partition_state(self._issue_partitions[self._job], "failed")
            if self._job.must_succeed:
                # whole Tool failed
                self._issue_handler.set_partition_state(self._root_issue_partition, "failed")
                # disable abort
                self._issue_handler.set_abort_enabled(False, None)

                self._on_tool_failed()
            else:
                self.__proceed()

    def _on_tool_succeeded(self):
        """
        The Tool has finished successfully

        To be overridden by subclass
        """

    def _on_tool_failed(self):
        """
        The Tool has failed

        To be overridden by subclass
        """

# ex:ts=4:et: