Mercurial > hg
comparison 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 |
comparison
equal
deleted
inserted
replaced
5531:a3fe91b4f6eb | 5532:40a06e39f010 |
---|---|
1 """ | |
2 This is Mercurial extension for syntax highlighting in the file | |
3 revision view of hgweb. | |
4 | |
5 It depends on the pygments syntax highlighting library: | |
6 http://pygments.org/ | |
7 | |
8 To enable the extension add this to hgrc: | |
9 | |
10 [extensions] | |
11 hgext.highlight = | |
12 | |
13 There is a single configuration option: | |
14 | |
15 [web] | |
16 pygments_style = <style> | |
17 | |
18 The default is 'colorful'. If this is changed the corresponding CSS | |
19 file should be re-generated by running | |
20 | |
21 # pygmentize -f html -S <newstyle> | |
22 | |
23 | |
24 -- Adam Hupp <adam@hupp.org> | |
25 | |
26 | |
27 """ | |
28 | |
29 from mercurial import demandimport | |
30 demandimport.ignore.extend(['pkgutil', | |
31 'pkg_resources', | |
32 '__main__',]) | |
33 | |
34 import mimetypes | |
35 | |
36 from mercurial.hgweb import hgweb_mod | |
37 from mercurial.hgweb.hgweb_mod import hgweb | |
38 from mercurial import util | |
39 from mercurial.hgweb.common import paritygen | |
40 from mercurial.node import hex | |
41 | |
42 from pygments import highlight | |
43 from pygments.util import ClassNotFound | |
44 from pygments.lexers import guess_lexer_for_filename, TextLexer | |
45 from pygments.formatters import HtmlFormatter | |
46 | |
47 SYNTAX_CSS = '\n<link rel="stylesheet" href="#staticurl#highlight.css" type="text/css" />' | |
48 | |
49 class StripedHtmlFormatter(HtmlFormatter): | |
50 | |
51 def __init__(self, stripecount, *args, **kwargs): | |
52 super(StripedHtmlFormatter, self).__init__(*args, **kwargs) | |
53 self.stripecount = stripecount | |
54 | |
55 def wrap(self, source, outfile): | |
56 yield 0, "<div class='highlight'>" | |
57 yield 0, "<pre>" | |
58 parity = paritygen(self.stripecount) | |
59 | |
60 for n, i in source: | |
61 if n == 1: | |
62 i = "<div class='parity%s'>%s</div>" % \ | |
63 (parity.next(), i) | |
64 yield n, i | |
65 | |
66 yield 0, "</pre>" | |
67 yield 0, "</div>" | |
68 | |
69 | |
70 def pygments_format(filename, rawtext, | |
71 forcetext=False, | |
72 stripecount=1, | |
73 style='colorful'): | |
74 | |
75 if not forcetext: | |
76 try: | |
77 lexer = guess_lexer_for_filename(filename, rawtext) | |
78 except ClassNotFound: | |
79 lexer = TextLexer() | |
80 else: | |
81 lexer = TextLexer() | |
82 | |
83 formatter = StripedHtmlFormatter(stripecount, | |
84 style=style, | |
85 linenos='inline') | |
86 | |
87 return highlight(rawtext, lexer, formatter) | |
88 | |
89 | |
90 """ | |
91 This reimplements hgweb.filerevision to use syntax highlighting | |
92 """ | |
93 def filerevision_pygments(self, fctx): | |
94 filename = fctx.path() | |
95 | |
96 rawtext = fctx.data() | |
97 text = rawtext | |
98 | |
99 mt = mimetypes.guess_type(filename)[0] | |
100 | |
101 if util.binary(text): | |
102 mt = mt or 'application/octet-stream' | |
103 text = "(binary:%s)" % mt | |
104 | |
105 # don't parse (binary:...) as anything | |
106 forcetext = True | |
107 else: | |
108 mt = mt or 'text/plain' | |
109 forcetext = False | |
110 | |
111 | |
112 def lines(text): | |
113 for line in text.splitlines(True): | |
114 yield {"line": line} | |
115 | |
116 style = self.config("web", "pygments_style", "colorful") | |
117 | |
118 text_formatted = lines(pygments_format(filename, text, | |
119 forcetext=forcetext, | |
120 stripecount=self.stripecount, | |
121 style=style)) | |
122 | |
123 # override per-line template | |
124 self.t.cache['fileline'] = '#line#' | |
125 | |
126 # append a <link ...> to the syntax highlighting css | |
127 old_header = ''.join(self.t('header')) | |
128 if SYNTAX_CSS not in old_header: | |
129 new_header = old_header + SYNTAX_CSS | |
130 self.t.cache['header'] = new_header | |
131 | |
132 | |
133 yield self.t("filerevision", | |
134 file=filename, | |
135 path=hgweb_mod._up(filename), # fixme: make public | |
136 text=text_formatted, | |
137 raw=rawtext, | |
138 mimetype=mt, | |
139 rev=fctx.rev(), | |
140 node=hex(fctx.node()), | |
141 author=fctx.user(), | |
142 date=fctx.date(), | |
143 desc=fctx.description(), | |
144 parent=self.siblings(fctx.parents()), | |
145 child=self.siblings(fctx.children()), | |
146 rename=self.renamelink(fctx.filelog(), | |
147 fctx.filenode()), | |
148 permissions=fctx.manifest().flags(filename)) | |
149 | |
150 # monkeypatch in the new version | |
151 # should be safer than overriding the method in a derived class | |
152 # and then patching the class | |
153 hgweb.filerevision = filerevision_pygments |