Blob Blame History Raw
# This file is part of Rubber and thus covered by the GPL
# (c) Emmanuel Beffara, 2002--2006
"""
This module defines the messages diplay class, and creates the application-wide
msg object.
"""
import os, os.path
import sys
import logging

def _(txt): return txt

class Message (object):
    """
    All messages in the program are output using the `msg' object in the
    main package. This class defines the interface for this object.
    """
    def __init__ (self, level=1, write=None):
        """
        Initialize the object with the specified verbosity level and an
        optional writing function. If no such function is specified, no
        message will be output until the 'write' field is changed.
        """
        self.level = level
        self.write = self.write_stdout
        if write:
            self.write = write
        self.short = 0
        self.path = ""
        self.cwd = "./"
        self.pos = []
        self._log = logging.getLogger("dblatex")
        level = self._log.getEffectiveLevel()
        if level >= logging.WARNING:
            self.stdout = open(os.devnull, "w")
        else:
            self.stdout = None

    def write_stdout(self, text, level=0):
        print text
    def write_stderr(self, text, level=0):
        print >>sys.stderr, text

    def push_pos (self, pos):
        self.pos.append(pos)
    def pop_pos (self):
        del self.pos[-1]

    def __call__ (self, level, text):
        """
        This is the low level printing function, it receives a line of text
        with an associated verbosity level, so that output can be filtered
        depending on command-line options.
        """
        if self.write and level <= self.level:
            self.write(text, level=level)

    def display (self, kind, text, **info):
        """
        Print an error or warning message. The argument 'kind' indicates the
        kind of message, among "error", "warning", "abort", the argument
        'text' is the main text of the message, the other arguments provide
        additional information, including the location of the error.
        """
        if kind == "error":
            if text[0:13] == "LaTeX Error: ":
                text = text[13:]
            self._log.error(self.format_pos(info, text))
            if info.has_key("code") and info["code"] and not self.short:
                self._log.error(self.format_pos(info,
                    _("leading text: ") + info["code"]))

        elif kind == "abort":
            if self.short:
                msg = _("compilation aborted ") + info["why"]
            else:
                msg = _("compilation aborted: %s %s") % (text, info["why"])
            self._log.error(self.format_pos(info, msg))

#        elif kind == "warning":
#            self._log.warning(self.format_pos(info, text))

    def error (self, text, **info):
        self.display(kind="error", text=text, **info)
    def warn (self, what, **where):
        self._log.warning(self.format_pos(where, what))
    def progress (self, what, **where):
        self._log.info(self.format_pos(where, what + "..."))
    def info (self, what, **where):
        self._log.info(self.format_pos(where, what))
    def log (self, what, **where):
        self._log.debug(self.format_pos(where, what))
    def debug (self, what, **where):
        self._log.debug(self.format_pos(where, what))

    def format_pos (self, where, text):
        """
        Format the given text into a proper error message, with file and line
        information in the standard format. Position information is taken from
        the dictionary given as first argument.
        """
        if len(self.pos) > 0:
            if where is None or not where.has_key("file"):
                where = self.pos[-1]
        elif where is None or where == {}:
            return text

        if where.has_key("file") and where["file"] is not None:
            pos = self.simplify(where["file"])
            if where.has_key("line") and where["line"]:
                pos = "%s:%d" % (pos, int(where["line"]))
                if where.has_key("last"):
                    if where["last"] != where["line"]:
                        pos = "%s-%d" % (pos, int(where["last"]))
            pos = pos + ": "
        else:
            pos = ""
        if where.has_key("page"):
            text = "%s (page %d)" % (text, int(where["page"]))
        if where.has_key("pkg"):
            text = "[%s] %s" % (where["pkg"], text)
        return pos + text

    def simplify (self, name):
        """
        Simplify an path name by removing the current directory if the
        specified path is in a subdirectory.
        """
        path = os.path.normpath(os.path.join(self.path, name))
        if path[:len(self.cwd)] == self.cwd:
            return path[len(self.cwd):]
        return path

    def display_all (self, generator, writer=None):
        if writer:
            write = self.write
            self.write = writer
        something = 0
        for msg in generator:
            self.display(**msg)
            something = 1
        if writer:
            self.write = write
        return something

msg = Message()