Mercurial > kallithea
view rhodecode/lib/annotate.py @ 2399:a8635cdab3c0 beta
Add optional parameters to subprocessio that allow passing params to Popen
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Wed, 06 Jun 2012 17:55:19 +0200 |
parents | 324ac367a4da |
children | c57a37430dc9 |
line wrap: on
line source
# -*- coding: utf-8 -*- """ rhodecode.lib.annotate ~~~~~~~~~~~~~~~~~~~~~~ Anontation library for usage in rhodecode, previously part of vcs :created_on: Dec 4, 2011 :author: marcink :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com> :license: GPLv3, see COPYING for more details. """ from rhodecode.lib.vcs.exceptions import VCSError from rhodecode.lib.vcs.nodes import FileNode from pygments.formatters import HtmlFormatter from pygments import highlight import StringIO def annotate_highlight(filenode, annotate_from_changeset_func=None, order=None, headers=None, **options): """ Returns html portion containing annotated table with 3 columns: line numbers, changeset information and pygmentized line of code. :param filenode: FileNode object :param annotate_from_changeset_func: function taking changeset and returning single annotate cell; needs break line at the end :param order: ordered sequence of ``ls`` (line numbers column), ``annotate`` (annotate column), ``code`` (code column); Default is ``['ls', 'annotate', 'code']`` :param headers: dictionary with headers (keys are whats in ``order`` parameter) """ options['linenos'] = True formatter = AnnotateHtmlFormatter(filenode=filenode, order=order, headers=headers, annotate_from_changeset_func=annotate_from_changeset_func, **options) lexer = filenode.lexer highlighted = highlight(filenode.content, lexer, formatter) return highlighted class AnnotateHtmlFormatter(HtmlFormatter): def __init__(self, filenode, annotate_from_changeset_func=None, order=None, **options): """ If ``annotate_from_changeset_func`` is passed it should be a function which returns string from the given changeset. For example, we may pass following function as ``annotate_from_changeset_func``:: def changeset_to_anchor(changeset): return '<a href="/changesets/%s/">%s</a>\n' %\ (changeset.id, changeset.id) :param annotate_from_changeset_func: see above :param order: (default: ``['ls', 'annotate', 'code']``); order of columns; :param options: standard pygment's HtmlFormatter options, there is extra option tough, ``headers``. For instance we can pass:: formatter = AnnotateHtmlFormatter(filenode, headers={ 'ls': '#', 'annotate': 'Annotate', 'code': 'Code', }) """ super(AnnotateHtmlFormatter, self).__init__(**options) self.annotate_from_changeset_func = annotate_from_changeset_func self.order = order or ('ls', 'annotate', 'code') headers = options.pop('headers', None) if headers and not ('ls' in headers and 'annotate' in headers and 'code' in headers): raise ValueError("If headers option dict is specified it must " "all 'ls', 'annotate' and 'code' keys") self.headers = headers if isinstance(filenode, FileNode): self.filenode = filenode else: raise VCSError("This formatter expect FileNode parameter, not %r" % type(filenode)) def annotate_from_changeset(self, changeset): """ Returns full html line for single changeset per annotated line. """ if self.annotate_from_changeset_func: return self.annotate_from_changeset_func(changeset) else: return ''.join((changeset.id, '\n')) def _wrap_tablelinenos(self, inner): dummyoutfile = StringIO.StringIO() lncount = 0 for t, line in inner: if t: lncount += 1 dummyoutfile.write(line) fl = self.linenostart mw = len(str(lncount + fl - 1)) sp = self.linenospecial st = self.linenostep la = self.lineanchors aln = self.anchorlinenos if sp: lines = [] for i in range(fl, fl + lncount): if i % st == 0: if i % sp == 0: if aln: lines.append('<a href="#%s-%d" class="special">' '%*d</a>' % (la, i, mw, i)) else: lines.append('<span class="special">' '%*d</span>' % (mw, i)) else: if aln: lines.append('<a href="#%s-%d">' '%*d</a>' % (la, i, mw, i)) else: lines.append('%*d' % (mw, i)) else: lines.append('') ls = '\n'.join(lines) else: lines = [] for i in range(fl, fl + lncount): if i % st == 0: if aln: lines.append('<a href="#%s-%d">%*d</a>' \ % (la, i, mw, i)) else: lines.append('%*d' % (mw, i)) else: lines.append('') ls = '\n'.join(lines) annotate_changesets = [tup[1] for tup in self.filenode.annotate] # If pygments cropped last lines break we need do that too ln_cs = len(annotate_changesets) ln_ = len(ls.splitlines()) if ln_cs > ln_: annotate_changesets = annotate_changesets[:ln_ - ln_cs] annotate = ''.join((self.annotate_from_changeset(changeset) for changeset in annotate_changesets)) # in case you wonder about the seemingly redundant <div> here: # since the content in the other cell also is wrapped in a div, # some browsers in some configurations seem to mess up the formatting. ''' yield 0, ('<table class="%stable">' % self.cssclass + '<tr><td class="linenos"><div class="linenodiv"><pre>' + ls + '</pre></div></td>' + '<td class="code">') yield 0, dummyoutfile.getvalue() yield 0, '</td></tr></table>' ''' headers_row = [] if self.headers: headers_row = ['<tr class="annotate-header">'] for key in self.order: td = ''.join(('<td>', self.headers[key], '</td>')) headers_row.append(td) headers_row.append('</tr>') body_row_start = ['<tr>'] for key in self.order: if key == 'ls': body_row_start.append( '<td class="linenos"><div class="linenodiv"><pre>' + ls + '</pre></div></td>') elif key == 'annotate': body_row_start.append( '<td class="annotate"><div class="annotatediv"><pre>' + annotate + '</pre></div></td>') elif key == 'code': body_row_start.append('<td class="code">') yield 0, ('<table class="%stable">' % self.cssclass + ''.join(headers_row) + ''.join(body_row_start) ) yield 0, dummyoutfile.getvalue() yield 0, '</td></tr></table>'