diff hgext/highlight.py @ 5532:40a06e39f010

extension for synax highlighting in the hgweb file revision view Depends on the pygments syntax highlighting library: http://pygments.org/
author Adam Hupp <adam@hupp.org>
date Sat, 10 Nov 2007 17:54:57 -0500
parents
children 6cf7d7fe7d3d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/highlight.py	Sat Nov 10 17:54:57 2007 -0500
@@ -0,0 +1,153 @@
+"""
+This is Mercurial extension for syntax highlighting in the file
+revision view of hgweb.
+
+It depends on the pygments syntax highlighting library:
+http://pygments.org/
+
+To enable the extension add this to hgrc:
+
+[extensions]
+hgext.highlight =
+
+There is a single configuration option:
+
+[web]
+pygments_style = <style>
+
+The default is 'colorful'.  If this is changed the corresponding CSS
+file should be re-generated by running
+
+# pygmentize -f html -S <newstyle>
+
+
+-- Adam Hupp <adam@hupp.org>
+
+
+"""
+
+from mercurial import demandimport
+demandimport.ignore.extend(['pkgutil',
+                            'pkg_resources',
+                            '__main__',])
+
+import mimetypes
+
+from mercurial.hgweb import hgweb_mod
+from mercurial.hgweb.hgweb_mod import hgweb
+from mercurial import util
+from mercurial.hgweb.common import paritygen
+from mercurial.node import hex
+
+from pygments import highlight
+from pygments.util import ClassNotFound
+from pygments.lexers import guess_lexer_for_filename, TextLexer
+from pygments.formatters import HtmlFormatter
+
+SYNTAX_CSS = '\n<link rel="stylesheet" href="#staticurl#highlight.css" type="text/css" />'
+
+class StripedHtmlFormatter(HtmlFormatter):
+
+    def __init__(self, stripecount, *args, **kwargs):
+        super(StripedHtmlFormatter, self).__init__(*args, **kwargs)
+        self.stripecount = stripecount
+        
+    def wrap(self, source, outfile):
+        yield 0, "<div class='highlight'>"
+        yield 0, "<pre>"
+        parity = paritygen(self.stripecount)
+
+        for n, i in source:
+            if n == 1:
+                i = "<div class='parity%s'>%s</div>" % \
+                (parity.next(), i)
+            yield n, i
+
+        yield 0, "</pre>"
+        yield 0, "</div>"
+
+
+def pygments_format(filename, rawtext,
+                    forcetext=False,
+                    stripecount=1,
+                    style='colorful'):
+
+    if not forcetext:
+        try:
+            lexer = guess_lexer_for_filename(filename, rawtext)
+        except ClassNotFound:
+            lexer = TextLexer()
+    else:
+        lexer = TextLexer()
+        
+    formatter = StripedHtmlFormatter(stripecount,
+                                     style=style,
+                                     linenos='inline')
+
+    return highlight(rawtext, lexer, formatter)
+
+
+"""
+This reimplements hgweb.filerevision to use syntax highlighting
+"""
+def filerevision_pygments(self, fctx):
+    filename = fctx.path()
+
+    rawtext = fctx.data()
+    text = rawtext
+
+    mt = mimetypes.guess_type(filename)[0]
+
+    if util.binary(text):
+        mt = mt or 'application/octet-stream'
+        text = "(binary:%s)" % mt
+
+        # don't parse (binary:...) as anything
+        forcetext = True
+    else:
+        mt = mt or 'text/plain'
+        forcetext = False
+
+
+    def lines(text):
+        for line in text.splitlines(True):
+            yield {"line": line}
+
+    style = self.config("web", "pygments_style", "colorful")
+
+    text_formatted = lines(pygments_format(filename, text,
+                                           forcetext=forcetext,
+                                           stripecount=self.stripecount,
+                                           style=style))
+
+    # override per-line template   
+    self.t.cache['fileline'] = '#line#'
+
+    # append a <link ...> to the syntax highlighting css
+    old_header = ''.join(self.t('header'))
+    if SYNTAX_CSS not in old_header:
+        new_header =  old_header + SYNTAX_CSS
+        self.t.cache['header'] = new_header
+
+    
+    yield self.t("filerevision",
+                 file=filename,
+                 path=hgweb_mod._up(filename), # fixme: make public
+                 text=text_formatted,
+                 raw=rawtext,
+                 mimetype=mt,
+                 rev=fctx.rev(),
+                 node=hex(fctx.node()),
+                 author=fctx.user(),
+                 date=fctx.date(),
+                 desc=fctx.description(),
+                 parent=self.siblings(fctx.parents()),
+                 child=self.siblings(fctx.children()),
+                 rename=self.renamelink(fctx.filelog(),
+                                        fctx.filenode()),
+                 permissions=fctx.manifest().flags(filename))
+
+# monkeypatch in the new version
+# should be safer than overriding the method in a derived class
+# and then patching the class
+hgweb.filerevision = filerevision_pygments