예제 #1
0
파일: report.py 프로젝트: KDE/pology
def report(text, showcmd=False, subsrc=None, file=sys.stdout, newline=True):
    """
    Generic report.

    Text is output to the file descriptor,
    with one newline appended by default.

    @param text: text to report
    @type text: string
    @param showcmd: whether to show the command name
    @type showcmd: bool
    @param subsrc: more detailed source of the text
    @type subsrc: C{None} or string
    @param file: send output to this file descriptor
    @type file: C{file}
    @param newline: whether to append newline to output
    @type newline: bool
    """

    if not isinstance(text, ColorString):
        text = ColorString("%s") % text
    text = text.resolve(dest=file)

    cmdname = None
    if showcmd:
        cmdname = os.path.basename(sys.argv[0])

    lines = text.split("\n")
    for i in range(len(lines)):
        if i == 0:
            if cmdname and subsrc:
                head = "%s (%s): " % (cmdname, subsrc)
            elif cmdname:
                head = "%s: " % cmdname
            elif subsrc:
                head = "(%s): " % subsrc
            else:
                head = ""
            lhead = len(head)
        else:
            if lhead:
                head = "... "
            else:
                head = ""
        lines[i] = head + lines[i]

    if newline:
        lines.append("")

    text = "\n".join(lines)

    encwrite(file, text)
예제 #2
0
def spell_error(msg, cat, faultyWord, suggestions):
    """Print formated rule error message on screen
    @param msg: pology.message.Message object
    @param cat: pology.catalog.Catalog object
    @param faultyWord: badly spelled word
    @param suggestions : list of correct words to suggest"""
    report("-" * 40)
    report(
        ColorString("<bold>%s:%d(%d)</bold>") %
        (cat.filename, msg.refline, msg.refentry))
    if msg.msgctxt:
        report(
            _("@info",
              "<bold>Context:</bold> %(snippet)s",
              snippet=msg.msgctxt))
    #TODO: color in red part of context that make the mistake
    report(
        _("@info",
          "<bold>Faulty word:</bold> <red>%(word)s</red>",
          word=faultyWord))
    if suggestions:
        report(
            _("@info",
              "<bold>Suggestions:</bold> %(wordlist)s",
              wordlist=format_item_list(suggestions)))
예제 #3
0
def _highlight_spans(text, spans, color, ftext=None):
    """
    Adds colors around highlighted spans in text.

    Spans are given as list of index tuples C{[(start1, end1), ...]} where
    start and end index have standard Python semantics.
    Span tuples can have more than two elements, with indices followed by
    additional elements, which are ignored by this function.
    If start or end index in a span is not an integer, the span is ignored.

    The C{color} parameter is one of the color tags available in
    L{ColorString<colors.ColorString>} markup.

    If C{ftext} is not C{None}, spans are understood as relative to it,
    and the function will try to adapt them to the main text
    (see L{pology.diff.adapt_spans}).

    @param text: text to be highlighted
    @type text: string
    @param spans: spans to highlight
    @type spans: list of tuples
    @param color: color tag
    @type color: string
    @param ftext: text to which spans are actually relative
    @type ftext: string

    @returns: highlighted text
    @rtype: string
    """

    if not spans or color is None:
        return text

    # Adapt spans regardless if filtered text has been given or not,
    # to fix any overlapping and put into expected ordering.
    if ftext is None:
        ftext = text
    spans = adapt_spans(text, ftext, spans, merge=True)
    if not spans:
        return text

    ctext = ""
    cstart = 0
    for span in spans:
        if not isinstance(span[0], int) or not isinstance(span[1], int):
            continue
        ctext += text[cstart:span[0]]
        ctext += (ColorString("<%s>%%s</%s>" % (color, color)) %
                  text[span[0]:span[1]])  # outside, to have auto-escaping
        cstart = span[1]
    ctext += text[span[1]:]

    return ctext
예제 #4
0
파일: __init__.py 프로젝트: KDE/pology
    def to_string(self):
        """
        Translate the text to get ordinary string.

        @returns: translated text
        @rtype: L{ColorString<colors.ColorString>}
        """

        if self._msgid_plural is None:
            trf = _tr.ugettext  # camouflaged against xgettext
            if self._msgctxt is None:
                msgstr = trf(self._msgid)
            else:
                msgstr = trf("%s\x04%s" % (self._msgctxt, self._msgid))
                if "\x04" in msgstr:
                    msgstr = self._msgid
        else:
            n = self._kwargs.get("num")
            if n is None or not isinstance(n, int):
                raise PologyError(
                    _("@info", "No '%(arg)s' keyword argument to "
                      "plural translation request.",
                      arg="num"))
            trf = _tr.ungettext  # camouflaged against xgettext
            if self._msgctxt is None:
                msgstr = trf(self._msgid, self._msgid_plural, n)
            else:
                msgstr = trf("%s\x04%s" % (self._msgctxt, self._msgid),
                             self._msgid_plural, n)
                if "\x04" in msgstr:
                    msgstr = self._msgid

        msgstr = ColorString(msgstr)  # before substituting arguments
        msgstr = msgstr % self._kwargs

        return msgstr
예제 #5
0
파일: message.py 프로젝트: KDE/pology
    def _renew_lines_bymod(self,
                           mod,
                           wrapf=wrap_field,
                           force=False,
                           colorize=0):

        prefix = {}
        if self.obsolete:
            prefix["curr"] = "#~ "
            prefix["prev"] = "#~| "
        else:
            prefix["curr"] = ""
            prefix["prev"] = "#| "

        if force or mod["manual_comment"] or not self._lines_manual_comment:
            self._lines_manual_comment = []
            for manc in self.manual_comment:
                ls = wrap_comment_unwrap("", manc)
                if colorize >= 2:
                    ls = [ColorString("<grey>%s</grey>") % x for x in ls]
                self._lines_manual_comment.extend(ls)

        if force or mod["auto_comment"] or not self._lines_auto_comment:
            self._lines_auto_comment = []
            for autoc in self.auto_comment:
                ls = wrap_comment_unwrap(".", autoc)
                if colorize >= 2:
                    ls = [ColorString("<blue>%s</blue>") % x for x in ls]
                self._lines_auto_comment.extend(ls)

        if force or mod["source"] or not self._lines_source:
            self._lines_source = []
            srcrefs = []
            for src in self.source:
                if src[1] > 0:
                    srcrefs.append(src[0] + ":" + str(src[1]))
                else:
                    srcrefs.append(src[0])
            if srcrefs:
                ls = wrap_comment(":", cjoin(srcrefs, " "))
                if colorize >= 2:
                    ls = [ColorString("<blue>%s</blue>") % x for x in ls]
                self._lines_source = ls

        if force or mod["flag"] or not self._lines_flag:
            self._lines_flag = []
            # Rearange so that fuzzy is first, if present.
            flst = []
            for fl in self.flag:
                if fl == u"fuzzy":
                    if colorize >= 1:
                        fl = ColorString("<underline>%s</underline>") % fl
                    flst.insert(0, fl)
                else:
                    flst.append(fl)
            if flst:
                ls = wrap_comment(",", cjoin(flst, ", "))
                if colorize >= 2:
                    ls = [ColorString("<blue>%s</blue>") % x for x in ls]
                self._lines_flag = ls

        for att in _Message_single_fields:
            att_lins = "_lines_" + att
            if force or mod[att] or not self.__dict__[att_lins]:
                # modcount of this string > 0 or lines not cached or forced
                self.__dict__[att_lins] = []
                msgsth = getattr(self, att)
                if msgsth is not None or att in _Message_mandatory_fields:
                    if msgsth is None:
                        msgsth = u""
                    if att.endswith("_previous"):
                        fname = att[:-len("_previous")]
                        pstat = "prev"
                    else:
                        fname = att
                        pstat = "curr"
                        if colorize >= 1:
                            fname = ColorString("<bold>%s</bold>") % fname
                    self.__dict__[att_lins] = wrapf(fname, _escape(msgsth),
                                                    prefix[pstat])

        # msgstr must be renewed if the plurality of the message changed.
        new_plurality = (getattr(self, "_lines_msgstr", [])
                         and ((self.msgid_plural is None
                               and "msgstr[" in self._lines_msgstr[0]) or
                              (self.msgid_plural is not None
                               and "msgstr[" not in self._lines_msgstr[0])))

        if force or mod["msgstr"] or not self._lines_msgstr or new_plurality:
            self._lines_msgstr = []
            msgstr = self.msgstr or [u""]
            if self.msgid_plural is None:
                fname = "msgstr"
                if colorize >= 1:
                    fname = ColorString("<bold>%s</bold>") % fname
                self._lines_msgstr.extend(
                    wrapf(fname, _escape(msgstr[0]), prefix["curr"]))
            else:
                for i in range(len(msgstr)):
                    fname = "msgstr[%d]" % i
                    if colorize >= 1:
                        fname = ColorString("<bold>%s</bold>") % fname
                    self._lines_msgstr.extend(
                        wrapf(fname, _escape(msgstr[i]), prefix["curr"]))

        # Marshal the lines into proper order.
        self._lines_all = []
        lins = self._lines_all

        lins.extend(self._lines_manual_comment)
        lins.extend(self._lines_auto_comment)
        if not self.obsolete:  # no source for an obsolete message
            lins.extend(self._lines_source)
        lins.extend(self._lines_flag)

        # Actually, it might make sense regardless...
        ## Old originals makes sense only for a message with a fuzzy flag.
        #if self.fuzzy:
        lins.extend(self._lines_msgctxt_previous)
        lins.extend(self._lines_msgid_previous)
        lins.extend(self._lines_msgid_plural_previous)

        lins.extend(self._lines_msgctxt)
        lins.extend(self._lines_msgid)
        lins.extend(self._lines_msgid_plural)
        lins.extend(self._lines_msgstr)

        if self._lines_all[-1] != "\n":
            lins.extend(u"\n")
예제 #6
0
def tabulate(data,
             coln=None,
             rown=None,
             dfmt=None,
             space="  ",
             none="",
             rotated=False,
             colorize=False,
             indent="",
             colnra=False,
             rownra=False,
             colw=0):
    """
    Tabulate data in plain text.

    All data fields can have missing trailing entries. They will be set to
    C{None} according to table extents.

    Examples:

        >>> print T.tabulate(data=((1, 4), (2, ), (3, 6)),
        ...                  coln=("c1", "c2", "c3"), rown=("r1", "r2"),
        ...                  space="  ", none="-")
        -   c1  c2  c3
        r1   1   2   3
        r2   4   -   6

    @param data: column entries (cells) by column
    @type data: [[string*]*]
    @param coln: column names
    @type coln: [string*]
    @param rown: row names
    @type rown: [string*]
    @param dfmt: format strings per column (e.g. C{"%+.2f"} for floats)
    @type dfmt: [string*]
    @param space: fill-in for spacing between cells
    @type space: string
    @param none: fill-in for displaying empty cells (i.e. C{None}-valued)
    @type none: string
    @param rotated: whether the table should be transposed
    @type rotated: bool
    @param colorize: whether the table should have color highlighting
    @type colorize: bool
    @param indent: indent string for the whole table
    @type indent: string
    @param colnra: right align column names
    @type colnra: bool
    @param rownra: right align row names
    @type rownra: bool
    @param colw: minimal column width
    @type colw: integer
    @returns: plain text representation of the table (no trailing newline)
    @rtype: string/L{ColorString<colors.ColorString>}
    """

    # Make local copies, to be able to extend to table extents.
    _data = []
    for col in data:
        _data.append(list(col))
    _coln = None
    if coln: _coln = list(coln)
    _rown = None
    if rown: _rown = list(rown)
    _dfmt = None
    if dfmt: _dfmt = list(dfmt)

    # Calculate maximum row and column number.
    # ...look at data:
    nrows = 0
    ncols = 0
    for col in _data:
        if nrows < len(col):
            nrows = len(col)
        ncols += 1
    # ...look at column and row names:
    if _coln is not None:
        if ncols < len(_coln):
            ncols = len(_coln)
    if _rown is not None:
        if nrows < len(_rown):
            nrows = len(_rown)

    # Index offsets due to column/row names.
    ro = 0
    if _coln is not None:
        ro = 1
    co = 0
    if _rown is not None:
        co = 1

    # Extend all missing table fields.
    # ...add columns:
    for c in range(len(_data), ncols):
        _data.append([])
    # ...add rows:
    for col in _data:
        for r in range(len(col), nrows):
            col.append(None)
    # ...add column names:
    if _coln is not None:
        if _rown is not None:
            _coln.insert(0, none)  # header corner
        for c in range(len(_coln), ncols + co):
            _coln.append(None)
    # ...add row names:
    if _rown is not None:
        if _coln is not None:
            _rown.insert(0, none)  # header corner
        for r in range(len(_rown), nrows + ro):
            _rown.append(None)
    # ...add formats:
    if _dfmt is None:
        _dfmt = []
    if _rown is not None:
        _dfmt.insert(0, u"%s")  # header corner
    for c in range(len(_dfmt), ncols + co):
        _dfmt.append(u"%s")

    # Stringize data.
    # ...nice fat deep assembly of empty stringized table:
    sdata = [[u"" for i in range(nrows + ro)] for j in range(ncols + co)]
    # ...table body:
    for c in range(ncols):
        for r in range(nrows):
            if _data[c][r] is not None:
                sdata[c + co][r + ro] = _dfmt[c + co] % (_data[c][r], )
            else:
                sdata[c + co][r + ro] = none
    # ...column names:
    if _coln is not None:
        for c in range(ncols + co):
            if _coln[c] is not None:
                sdata[c][0] = u"%s" % (_coln[c], )
    # ...row names:
    if _rown is not None:
        for r in range(nrows + ro):
            if _rown[r] is not None:
                sdata[0][r] = u"%s" % (_rown[r], )

    # Rotate needed data for output.
    if rotated:
        _coln, _rown = _rown, _coln
        ncols, nrows = nrows, ncols
        co, ro = ro, co
        sdata_r = [[u"" for i in range(nrows + ro)] for j in range(ncols + co)]
        for c in range(ncols + co):
            for r in range(nrows + ro):
                sdata_r[c][r] = sdata[r][c]
        sdata = sdata_r

    # Calculate maximum lengths per screen column.
    maxlen = [colw] * (ncols + co)
    for c in range(ncols + co):
        for r in range(nrows + ro):
            l = len(sdata[c][r])
            if maxlen[c] < l:
                maxlen[c] = l

    # Reformat strings to maximum length per column.
    for c in range(co, ncols + co):
        lfmt = u"%" + str(maxlen[c]) + "s"
        for r in range(ro, nrows + ro):
            sdata[c][r] = lfmt % (sdata[c][r], )
        # ...but column names aligned as requested:
        if _coln is not None:
            if colnra:
                lfmt = u"%" + str(maxlen[c]) + "s"
            else:
                lfmt = u"%-" + str(maxlen[c]) + "s"
            sdata[c][0] = lfmt % (sdata[c][0], )
            if colorize:
                sdata[c][0] = ColorString("<purple>%s</purple>") % sdata[c][0]
    # ...but row names aligned as requested:
    if _rown is not None:
        if rownra:
            lfmt = u"%" + str(maxlen[0]) + "s"
        else:
            lfmt = u"%-" + str(maxlen[0]) + "s"
        for r in range(nrows + ro):
            sdata[0][r] = lfmt % (sdata[0][r], )
            if colorize:
                sdata[0][r] = ColorString("<blue>%s</blue>") % sdata[0][r]

    # Assemble the table.
    lines = []
    for r in range(nrows + ro):
        cells = []
        for c in range(ncols + co):
            cells.append(sdata[c][r])
        lines.append(indent + cjoin(cells, space))

    return cjoin(lines, "\n")
예제 #7
0
def _msg_pos_fmt(path, line, col):

    return (ColorString("<cyan>%s</cyan>:<purple>%d</purple>"
                        "(<purple>#%d</purple>)") % (path, line, col))
예제 #8
0
def report_msg_content(msg,
                       cat,
                       wrapf=None,
                       force=False,
                       note=None,
                       delim=None,
                       highlight=None,
                       showmsg=True,
                       fmsg=None,
                       showfmsg=False,
                       subsrc=None,
                       file=sys.stdout):
    """
    Report the content of a PO message.

    Provides the message reference, consisting of the catalog name and
    the message position within it, the message contents,
    and any notes on particular segments.

    Parts of the message can be highlighted using colors.
    Parameter C{highlight} provides the highlighting specification, as
    list of tuples where each tuple consists of: name of the message element
    to highlight, element index (used when the element is a list of values),
    list of spans, and optionally the filtered text of the element value.
    For example, to highlight spans C{(5, 10)} and C{(15, 25)} in the C{msgid},
    and C{(30, 40)} in C{msgstr}, the highlighting specification would be::

        [("msgid", 0, [(5, 10), (15, 25)]), ("msgstr", 0, [(30, 40)])]

    Names of the elements that can presently be highlighted are: C{"msgctxt"},
    C{"msgid"}, C{"msgid_plural"}, C{"msgstr"}, C{"manual_comment"},
    C{"auto_comment"}, C{"source"}, C{"flag"}.
    For unique fields the element index is not used, but 0 should be given
    for consistency (may be enforced later).
    Span tuples can have a third element, following the indices, which is
    the note about why the particular span is highlighted;
    there may be more elements after the note, and these are all ignored.
    If start or end index of a span is not an integer,
    then the note is taken as relating to the complete field.

    Sometimes the match to which the spans correspond has been made on a
    filtered value of the message field (e.g. after accelerator markers
    or tags have been removed). In that case, the filtered text can be
    given as the fourth element of the tuple, after the list of spans, and
    the function will try to fit spans from filtered onto original text.
    More globally, if the complete highlight is relative to a modified,
    filtered version of the message, this message can be given as
    C{fmsg} parameter.

    The display of content can be controlled by C{showmsg} parameter;
    if it is C{False}, only the message reference and span notes are shown.
    Similarly for the C{showfmsg} parameter, which controls the display
    of the content of filtered message (if given by C{fmsg}).
    To show the filtered message may be useful for debugging filtering
    in cases when it is not straightforward, or it is user-defined.

    @param msg: the message to report the content for
    @type msg: L{Message_base}
    @param cat: the catalog where the message lives
    @type cat: L{Catalog} or C{None}
    @param wrapf:
        the function used for wrapping message fields in output.
        See L{to_lines()<message.Message_base.to_lines>} method
        of message classes for details.
        If not given, it will be taken from the catalog
        (see L{Catalog.wrapf<catalog.Catalog.wrapf>}).
    @type wrapf: (string)->[string...]
    @param force: whether to force reformatting of cached message content
    @type force: bool
    @param note: note about why the content is being reported
    @type note: string
    @param delim: text to print on the line following the message
    @type delim: C{None} or string
    @param highlight: highlighting specification of message elements
    @type highlight: (see description)
    @param showmsg: show content of the message
    @type showmsg: bool
    @param fmsg: filtered message
    @type fmsg: L{Message_base}
    @param showfmsg: show content of the filtered message, if any
    @type showfmsg: bool
    @param subsrc: more detailed source of the message
    @type subsrc: C{None} or string
    @param file: output stream
    @type file: file
    """

    rsegs = []

    wrapf = wrapf or cat.wrapf()

    notes_data = []
    if highlight:
        msg = Message(msg)  # must work on copy, highlight modifies it
        ffmsg = fmsg or msg  # use original message as filtered if not given

        # Unify spans for same parts, to have single coloring pass per part
        # (otherwise markup can get corrupted).
        highlightd = {}
        for hspec in highlight:
            name, item, spans = hspec[:3]
            pkey = (name, item)
            phspec = highlightd.get(pkey)
            if phspec is None:
                # Make needed copies in order not to modify
                # the original highlight when adding stuff later.
                highlightd[pkey] = list(hspec)
                highlightd[pkey][2] = list(spans)
            else:
                phspec[2].extend(spans)
                # Take filtered text if available and not already taken.
                if len(hspec) > 3 and len(phspec) <= 3:
                    phspec.append(hspec[3])
        highlight = highlightd.values()

        for hspec in highlight:
            name, item, spans = hspec[:3]

            def hl(text, ftext):
                if len(hspec) > 3:
                    # Override filtered text from filtered message
                    # by filtered text from the highlight spec.
                    ftext = hspec[3]
                aspans = adapt_spans(text, ftext, spans, merge=False)
                notes_data.append((text, name, item, aspans))
                text = _highlight_spans(text, spans, "red", ftext=ftext)
                return text

            if name == "msgctxt":
                if msg.msgctxt or ffmsg.msgctxt:
                    msg.msgctxt = hl(msg.msgctxt or u"", ffmsg.msgctxt or u"")
            elif name == "msgid":
                msg.msgid = hl(msg.msgid, ffmsg.msgid)
            elif name == "msgid_plural":
                msg.msgid_plural = hl(msg.msgid_plural or u"",
                                      ffmsg.msgid_plural or u"")
            elif name == "msgstr":
                msg.msgstr[item] = hl(msg.msgstr[item], ffmsg.msgstr[item])
            elif name == "manual_comment":
                msg.manual_comment[item] = hl(msg.manual_comment[item],
                                              ffmsg.manual_comment[item])
            elif name == "auto_comment":
                msg.auto_comment[item] = hl(msg.auto_comment[item],
                                            ffmsg.auto_comment[item])
            elif name == "source":
                msg.source[item] = Monpair(
                    (hl(msg.source[item][0],
                        ffmsg.source[item][0]), msg.source[item][1]))
            elif name == "flag":
                pass  # FIXME: How to do this?
            else:
                warning(
                    _("@info", "Unknown field '%(field)s' "
                      "in highlighting specification.",
                      field=name))

    # Report the message.
    msegs = []
    if cat is not None:
        msegs += [_msg_pos_fmt(cat.filename, msg.refline, msg.refentry) + "\n"]
    if showmsg:
        msgstr = msg.to_string(wrapf=wrapf, force=force, colorize=1)
        msegs += [msgstr.rstrip() + "\n"]
    if msegs:
        rsegs.append(cjoin(msegs).rstrip())

    # Report notes.
    if note is not None:  # global
        notestr = _("@info", "<bold>[note]</bold> %(msg)s", msg=note)
        rsegs.append(notestr)
    if notes_data:  # span notes
        note_ord = 1
        for text, name, item, spans in notes_data:
            if msg.msgid_plural is not None and name == "msgstr":
                name = "%s_%d" % (name, item)
            for span in spans:
                if len(span) < 3:
                    continue
                start, end, snote = span
                if isinstance(start, int) and isinstance(end, int):
                    seglen = end - start
                    if seglen > 0:
                        segtext = text[start:end]
                        if len(segtext) > 30:
                            segtext = _("@item:intext shortened longer text",
                                        "%(snippet)s...",
                                        snippet=segtext[:27])
                        posinfo = "%s:%d:\"%s\"" % (name, start,
                                                    escape(segtext))
                    else:
                        posinfo = "%s:%d" % (name, start)
                else:
                    posinfo = "%s" % name
                posinfo = ColorString("<green>%s</green>") % posinfo
                rsegs.append(
                    _("@info", "[%(pos)s]: %(msg)s", pos=posinfo, msg=snote))
                note_ord += 1

    # Report the filtered message, if given and requested.
    if fmsg and showfmsg:
        fmtnote = (ColorString("<green>%s</green>") %
                   _("@info", ">>> Filtered message was:"))
        rsegs.append(fmtnote)
        fmsgstr = fmsg.to_string(wrapf=wrapf, force=force, colorize=1)
        mstr = fmsgstr.rstrip() + "\n"
        rsegs.append(mstr.rstrip())

    if delim:
        rsegs.append(delim)

    rtext = cjoin(rsegs, "\n").rstrip()
    report(rtext, subsrc=subsrc, file=file)
예제 #9
0
def report_on_msg_hl(highlight,
                     msg,
                     cat,
                     fmsg=None,
                     subsrc=None,
                     file=sys.stdout):
    """
    Report on parts of a PO message.

    For each of the spans found in the L{highlight<report_msg_content>}
    specification which have a note attached, outputs the position reference
    (catalog name, message position, spanned segment) and the span note.
    The highlight can be relative to a somewhat modified, filtered message
    instead of the original one.

    @param highlight: highlight specification
    @type highlight: L{highlight<report_msg_content>}
    @param msg: the message for which the text is reported
    @type msg: L{Message_base}
    @param cat: the catalog where the message lives
    @type cat: L{Catalog}
    @param fmsg: filtered message to which the highlight corresponds
    @type fmsg: L{Message_base}
    @param subsrc: more detailed source of the message
    @type subsrc: C{None} or string
    @param file: send output to this file descriptor
    @type file: C{file}
    """

    refpos = _msg_pos_fmt(cat.filename, msg.refline, msg.refentry)

    if not fmsg:  # use original message as filtered if not given
        fmsg = msg

    for hspec in highlight:
        name, item, spans = hspec[:3]

        if name == "msgctxt":
            text = msg.msgctxt or u""
            ftext = fmsg.msgctxt or u""
        elif name == "msgid":
            text = msg.msgid
            ftext = fmsg.msgid
        elif name == "msgid_plural":
            text = msg.msgid_plural or u""
            ftext = fmsg.msgid_plural or u""
        elif name == "msgstr":
            text = msg.msgstr[item]
            ftext = fmsg.msgstr[item]
        # TODO: Add more fields.
        else:
            warning(
                _("@info", "Unknown field '%(field)s' "
                  "in highlighting specification.",
                  field=name))
            continue

        if len(hspec) > 3:
            # Override filtered text from filtered message
            # by filtered text from the highlight spec.
            ftext = hspec[3]

        spans = adapt_spans(text, ftext, spans, merge=False)

        if msg.msgid_plural is not None and name == "msgstr":
            name = "%s_%d" % (name, item)

        for span in spans:
            if len(span) < 3:
                continue
            start, end, snote = span
            if isinstance(start, int) and isinstance(end, int):
                seglen = end - start
                if seglen > 0:
                    segtext = text[start:end]
                    if len(segtext) > 30:
                        segtext = segtext[:27] + "..."
                    posinfo = "%s:%d:\"%s\"" % (name, start, escape(segtext))
                else:
                    posinfo = "%s:%d" % (name, start)
            else:
                posinfo = "%s" % name
            posinfo = ColorString("<green>%s</green>") % posinfo

            rtext = cinterp("%s[%s]: %s", refpos, posinfo, snote)
            report(rtext, subsrc=subsrc, showcmd=False)
예제 #10
0
파일: stats.py 프로젝트: KDE/pology
    def _bar_stats(self, counts, title, count, summed, dlabel, dcolumn):

        # Count categories to display and chars/colors associated to them.
        # Note: Use only characters from Latin1.
        tspecs = (("trn", u"×", "green"), ("fuz", u"¤", "blue"), ("unt", u"·",
                                                                  "red"))

        # Find out maximum counts overall.
        maxcounts = dict(trn=0, fuz=0, unt=0, tot=0)
        maxcounts_jumbled = maxcounts.copy()
        for otitle, ocount, osummed in counts:
            # If absolute bars, compare counts only for non-summed counts.
            if self.p.absolute and osummed:
                continue

            # Count both messages and words, for the number display padding.
            for tkey in maxcounts_jumbled:
                for dcol in (0, 1):
                    c = ocount[tkey][dcol]
                    if maxcounts_jumbled[tkey] < c:
                        maxcounts_jumbled[tkey] = c

            for tkey in maxcounts:
                c = ocount[tkey][dcolumn]
                if maxcounts[tkey] < c:
                    maxcounts[tkey] = c

        # Character widths of maximum count categories.
        maxcountscw = {}
        for tkey, tval in maxcounts.iteritems():
            maxcountscw[tkey] = len(str(tval))
        maxcountscw_jumbled = {}
        for tkey, tval in maxcounts_jumbled.iteritems():
            maxcountscw_jumbled[tkey] = len(str(tval))

        # Formatted counts by disjunct categories.
        fmt_counts = []
        for tkey, tchar, tcol in tspecs:
            cstr = str(count[tkey][dcolumn])
            if cstr == "0":
                cstr = "-"
            cfmt = ("%%%ds" % maxcountscw_jumbled[tkey]) % cstr
            if tcol is not None:
                fmt_counts.append(
                    (ColorString("<%s>%%s</%s>") % (tcol, tcol)) % cfmt)
            else:
                fmt_counts.append(cfmt)
        fmt_counts = cjoin(fmt_counts, "/")

        # Maximum and nominal bar widths in characters.
        # TODO: Make parameters.
        if self.inline:
            nombarcw = 20
            maxbarcw = 50
        else:
            nombarcw = 40
            maxbarcw = 80

        def roundnear(x):
            return int(round(x, 0))

        def roundup(x):
            ix = int(x)
            if x - ix > 1e-16:
                ix += 1
            return ix

        # Compute number of cells per category.
        n_cells = {}
        if self.p.absolute:
            # Absolute bar.
            n_per_cell = 0
            for npc in (1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000,
                        10000, 20000, 50000, 100000, 200000, 500000):
                if npc * maxbarcw > maxcounts["tot"]:
                    n_per_cell = npc
                    break
            if not n_per_cell:
                warning(
                    _("@info", "Count too large, cannot display bar graph."))
                return
            for tkey, roundf in (("fuz", roundup), ("unt", roundup),
                                 ("tot", roundnear)):
                c = count[tkey][dcolumn]
                n_cells[tkey] = roundf(float(c) / n_per_cell)

            # Correct the situation when there are no cells.
            if n_cells["tot"] < 1:
                n_cells["tot"] = 1

            # Correct the situation when the sum of cells fuzzy+untranslated
            # goes over the total; give priority to untranslated when reducing.
            while n_cells["fuz"] + n_cells["unt"] > n_cells["tot"]:
                if n_cells["fuz"] >= n_cells["unt"]:
                    n_cells["fuz"] -= 1
                else:
                    n_cells["unt"] -= 1

            n_cells["trn"] = n_cells["tot"] - n_cells["fuz"] - n_cells["unt"]

        else:
            # Relative bar.
            if count["tot"][dcolumn] > 0:
                n_per_cell = float(nombarcw) / count["tot"][dcolumn]
            else:
                n_per_cell = 0
            for tkey in ("fuz", "unt"):
                c = count[tkey][dcolumn]
                n_cells[tkey] = roundup(c * n_per_cell)

            # When there are almost none translated, it may have happened that
            # the sum of cells fuzzy+untranslated is over nominal; reduce.
            while n_cells["fuz"] + n_cells["unt"] > nombarcw:
                if n_cells["fuz"] >= n_cells["unt"]:
                    n_cells["fuz"] -= 1
                else:
                    n_cells["unt"] -= 1

            n_cells["trn"] = nombarcw - n_cells["fuz"] - n_cells["unt"]

        # Create the bar.
        fmt_bar = []
        for tkey, tchar, tcol in tspecs:
            bar = tchar * n_cells[tkey]
            if tcol is not None:
                bar = (ColorString("<%s>%%s</%s>") % (tcol, tcol)) % bar
            fmt_bar.append(bar)
        fmt_bar = cjoin(fmt_bar)

        # Assemble final output.
        if not self.p.absolute or not summed:
            if count["tot"][dcolumn] == 0:
                fmt_bar = ""
            report(cinterp("%s %s |%s|", fmt_counts, dlabel, fmt_bar))
        else:
            report(cinterp("%s %s", fmt_counts, dlabel))