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