##// END OF EJS Templates
- Close #131.
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,267 +1,281 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Class and program to colorize python source code for ANSI terminals.
4 4
5 5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7 7
8 8 Modifications by Fernando Perez (fperez@colorado.edu).
9 9
10 10 Information on the original HTML highlighter follows:
11 11
12 12 MoinMoin - Python Source Parser
13 13
14 14 Title:olorize Python source using the built-in tokenizer
15 15
16 16 Submitter: Jurgen Hermann
17 17 Last Updated:2001/04/06
18 18
19 19 Version no:1.2
20 20
21 21 Description:
22 22
23 23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 24 Python source code to HTML markup, rendering comments, keywords,
25 25 operators, numeric and string literals in different colors.
26 26
27 27 It shows how to use the built-in keyword, token and tokenize modules to
28 28 scan Python source code and re-emit it with no changes to its original
29 29 formatting (which is the hard part).
30 30
31 $Id: PyColorize.py 2155 2007-03-19 00:45:51Z fperez $"""
31 $Id: PyColorize.py 2205 2007-04-04 06:04:01Z fperez $"""
32 32
33 33 __all__ = ['ANSICodeColors','Parser']
34 34
35 35 _scheme_default = 'Linux'
36 36
37 37 # Imports
38 38 import cStringIO
39 39 import keyword
40 40 import os
41 41 import string
42 42 import sys
43 43 import token
44 44 import tokenize
45 45
46 46 from IPython.ColorANSI import *
47 47
48 48 #############################################################################
49 49 ### Python Source Parser (does Hilighting)
50 50 #############################################################################
51 51
52 52 _KEYWORD = token.NT_OFFSET + 1
53 53 _TEXT = token.NT_OFFSET + 2
54 54
55 55 #****************************************************************************
56 56 # Builtin color schemes
57 57
58 58 Colors = TermColors # just a shorthand
59 59
60 60 # Build a few color schemes
61 61 NoColor = ColorScheme(
62 62 'NoColor',{
63 63 token.NUMBER : Colors.NoColor,
64 64 token.OP : Colors.NoColor,
65 65 token.STRING : Colors.NoColor,
66 66 tokenize.COMMENT : Colors.NoColor,
67 67 token.NAME : Colors.NoColor,
68 68 token.ERRORTOKEN : Colors.NoColor,
69 69
70 70 _KEYWORD : Colors.NoColor,
71 71 _TEXT : Colors.NoColor,
72 72
73 73 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
74 74 } )
75 75
76 76 LinuxColors = ColorScheme(
77 77 'Linux',{
78 78 token.NUMBER : Colors.LightCyan,
79 79 token.OP : Colors.Yellow,
80 80 token.STRING : Colors.LightBlue,
81 81 tokenize.COMMENT : Colors.LightRed,
82 82 token.NAME : Colors.White,
83 83 token.ERRORTOKEN : Colors.Red,
84 84
85 85 _KEYWORD : Colors.LightGreen,
86 86 _TEXT : Colors.Yellow,
87 87
88 88 'normal' : Colors.Normal # color off (usu. Colors.Normal)
89 89 } )
90 90
91 91 LightBGColors = ColorScheme(
92 92 'LightBG',{
93 93 token.NUMBER : Colors.Cyan,
94 94 token.OP : Colors.Blue,
95 95 token.STRING : Colors.Blue,
96 96 tokenize.COMMENT : Colors.Red,
97 97 token.NAME : Colors.Black,
98 98 token.ERRORTOKEN : Colors.Red,
99 99
100 100 _KEYWORD : Colors.Green,
101 101 _TEXT : Colors.Blue,
102 102
103 103 'normal' : Colors.Normal # color off (usu. Colors.Normal)
104 104 } )
105 105
106 106 # Build table of color schemes (needed by the parser)
107 107 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
108 108 _scheme_default)
109 109
110 110 class Parser:
111 111 """ Format colored Python source.
112 112 """
113 113
114 114 def __init__(self, color_table=None,out = sys.stdout):
115 115 """ Create a parser with a specified color table and output channel.
116 116
117 117 Call format() to process code.
118 118 """
119 119 self.color_table = color_table and color_table or ANSICodeColors
120 120 self.out = out
121 121
122 122 def format(self, raw, out = None, scheme = ''):
123 123 return self.format2(raw, out, scheme)[0]
124 124
125 125 def format2(self, raw, out = None, scheme = ''):
126 126 """ Parse and send the colored source.
127 127
128 128 If out and scheme are not specified, the defaults (given to
129 129 constructor) are used.
130 130
131 131 out should be a file-type object. Optionally, out can be given as the
132 132 string 'str' and the parser will automatically return the output in a
133 133 string."""
134 134
135 self.raw = string.strip(string.expandtabs(raw))
136 135 string_output = 0
137 136 if out == 'str' or self.out == 'str':
138 137 out_old = self.out
139 138 self.out = cStringIO.StringIO()
140 139 string_output = 1
141 140 elif out is not None:
142 141 self.out = out
143 # local shorthand
142
143 # Fast return of the unmodified input for NoColor scheme
144 if scheme == 'NoColor':
145 error = False
146 self.out.write(raw)
147 if string_output:
148 return raw,error
149 else:
150 return None,error
151
152 # local shorthands
144 153 colors = self.color_table[scheme].colors
145 154 self.colors = colors # put in object so __call__ sees it
155
156 # Remove trailing whitespace and normalize tabs
157 self.raw = raw.expandtabs().rstrip()
146 158 # store line offsets in self.lines
147 159 self.lines = [0, 0]
148 160 pos = 0
161 raw_find = raw.find
162 lines_append = self.lines.append
149 163 while 1:
150 pos = string.find(self.raw, '\n', pos) + 1
164 pos = raw_find('\n', pos) + 1
151 165 if not pos: break
152 self.lines.append(pos)
153 self.lines.append(len(self.raw))
166 lines_append(pos)
167 lines_append(len(self.raw))
154 168
155 169 # parse the source and write it
156 170 self.pos = 0
157 171 text = cStringIO.StringIO(self.raw)
158 #self.out.write('<pre><font face="Courier New">')
159 172
160 173 error = False
161 174 try:
162 175 tokenize.tokenize(text.readline, self)
163 176 except tokenize.TokenError, ex:
164 177 msg = ex[0]
165 178 line = ex[1][0]
166 179 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
167 180 (colors[token.ERRORTOKEN],
168 181 msg, self.raw[self.lines[line]:],
169 182 colors.normal)
170 183 )
171 184 error = True
172 185 self.out.write(colors.normal+'\n')
173 186 if string_output:
174 187 output = self.out.getvalue()
175 188 self.out = out_old
176 189 return (output, error)
177 190 return (None, error)
178 191
179 192 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
180 193 """ Token handler, with syntax highlighting."""
181 194
182 # local shorthand
195 # local shorthands
183 196 colors = self.colors
197 owrite = self.out.write
184 198
185 199 # line separator, so this works across platforms
186 200 linesep = os.linesep
187 201
188 202 # calculate new positions
189 203 oldpos = self.pos
190 204 newpos = self.lines[srow] + scol
191 205 self.pos = newpos + len(toktext)
192 206
193 207 # handle newlines
194 208 if toktype in [token.NEWLINE, tokenize.NL]:
195 self.out.write(linesep)
209 owrite(linesep)
196 210 return
197 211
198 212 # send the original whitespace, if needed
199 213 if newpos > oldpos:
200 self.out.write(self.raw[oldpos:newpos])
214 owrite(self.raw[oldpos:newpos])
201 215
202 216 # skip indenting tokens
203 217 if toktype in [token.INDENT, token.DEDENT]:
204 218 self.pos = newpos
205 219 return
206 220
207 221 # map token type to a color group
208 222 if token.LPAR <= toktype and toktype <= token.OP:
209 223 toktype = token.OP
210 224 elif toktype == token.NAME and keyword.iskeyword(toktext):
211 225 toktype = _KEYWORD
212 226 color = colors.get(toktype, colors[_TEXT])
213 227
214 228 #print '<%s>' % toktext, # dbg
215 229
216 230 # Triple quoted strings must be handled carefully so that backtracking
217 231 # in pagers works correctly. We need color terminators on _each_ line.
218 232 if linesep in toktext:
219 233 toktext = toktext.replace(linesep, '%s%s%s' %
220 234 (colors.normal,linesep,color))
221 235
222 236 # send text
223 self.out.write('%s%s%s' % (color,toktext,colors.normal))
237 owrite('%s%s%s' % (color,toktext,colors.normal))
224 238
225 239 def main():
226 240 """Colorize a python file using ANSI color escapes and print to stdout.
227 241
228 242 Usage:
229 243 %s [-s scheme] filename
230 244
231 245 Options:
232 246
233 247 -s scheme: give the color scheme to use. Currently only 'Linux'
234 248 (default) and 'LightBG' and 'NoColor' are implemented (give without
235 249 quotes). """
236 250
237 251 def usage():
238 252 print >> sys.stderr, main.__doc__ % sys.argv[0]
239 253 sys.exit(1)
240 254
241 255 # FIXME: rewrite this to at least use getopt
242 256 try:
243 257 if sys.argv[1] == '-s':
244 258 scheme_name = sys.argv[2]
245 259 del sys.argv[1:3]
246 260 else:
247 261 scheme_name = _scheme_default
248 262
249 263 except:
250 264 usage()
251 265
252 266 try:
253 267 fname = sys.argv[1]
254 268 except:
255 269 usage()
256 270
257 271 # write colorized version to stdout
258 272 parser = Parser()
259 273 try:
260 274 parser.format(file(fname).read(),scheme = scheme_name)
261 275 except IOError,msg:
262 276 # if user reads through a pager and quits, don't print traceback
263 277 if msg.args != (32,'Broken pipe'):
264 278 raise
265 279
266 280 if __name__ == "__main__":
267 281 main()
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now