| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
""" |
|---|
| 6 |
HTML rendering of Python source. |
|---|
| 7 |
""" |
|---|
| 8 |
|
|---|
| 9 |
import tokenize, cgi, keyword |
|---|
| 10 |
import reflect |
|---|
| 11 |
|
|---|
| 12 |
class TokenPrinter: |
|---|
| 13 |
|
|---|
| 14 |
currentCol, currentLine = 0, 1 |
|---|
| 15 |
lastIdentifier = parameters = 0 |
|---|
| 16 |
|
|---|
| 17 |
def __init__(self, writer): |
|---|
| 18 |
self.writer = writer |
|---|
| 19 |
|
|---|
| 20 |
def printtoken(self, type, token, (srow, scol), (erow, ecol), line): |
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
if self.currentLine < srow: |
|---|
| 25 |
self.writer('\n'*(srow-self.currentLine)) |
|---|
| 26 |
self.currentLine, self.currentCol = srow, 0 |
|---|
| 27 |
self.writer(' '*(scol-self.currentCol)) |
|---|
| 28 |
if self.lastIdentifier: |
|---|
| 29 |
type = "identifier" |
|---|
| 30 |
self.parameters = 1 |
|---|
| 31 |
elif type == tokenize.NAME: |
|---|
| 32 |
if keyword.iskeyword(token): |
|---|
| 33 |
type = 'keyword' |
|---|
| 34 |
else: |
|---|
| 35 |
if self.parameters: |
|---|
| 36 |
type = 'parameter' |
|---|
| 37 |
else: |
|---|
| 38 |
type = 'variable' |
|---|
| 39 |
else: |
|---|
| 40 |
type = tokenize.tok_name.get(type).lower() |
|---|
| 41 |
self.writer(token, type) |
|---|
| 42 |
self.currentCol = ecol |
|---|
| 43 |
self.currentLine += token.count('\n') |
|---|
| 44 |
if self.currentLine != erow: |
|---|
| 45 |
self.currentCol = 0 |
|---|
| 46 |
self.lastIdentifier = token in ('def', 'class') |
|---|
| 47 |
if token == ':': |
|---|
| 48 |
self.parameters = 0 |
|---|
| 49 |
|
|---|
| 50 |
|
|---|
| 51 |
class HTMLWriter: |
|---|
| 52 |
|
|---|
| 53 |
noSpan = [] |
|---|
| 54 |
|
|---|
| 55 |
def __init__(self, writer): |
|---|
| 56 |
self.writer = writer |
|---|
| 57 |
noSpan = [] |
|---|
| 58 |
reflect.accumulateClassList(self.__class__, "noSpan", noSpan) |
|---|
| 59 |
self.noSpan = noSpan |
|---|
| 60 |
|
|---|
| 61 |
def write(self, token, type=None): |
|---|
| 62 |
token = cgi.escape(token) |
|---|
| 63 |
if (type is None) or (type in self.noSpan): |
|---|
| 64 |
self.writer(token) |
|---|
| 65 |
else: |
|---|
| 66 |
self.writer('<span class="py-src-%s">%s</span>' % |
|---|
| 67 |
(type, token)) |
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
class SmallerHTMLWriter(HTMLWriter): |
|---|
| 71 |
"""HTMLWriter that doesn't generate spans for some junk. |
|---|
| 72 |
|
|---|
| 73 |
Results in much smaller HTML output. |
|---|
| 74 |
""" |
|---|
| 75 |
noSpan = ["endmarker", "indent", "dedent", "op", "newline", "nl"] |
|---|
| 76 |
|
|---|
| 77 |
def filter(inp, out, writer=HTMLWriter): |
|---|
| 78 |
out.write('<pre>') |
|---|
| 79 |
printer = TokenPrinter(writer(out.write).write).printtoken |
|---|
| 80 |
try: |
|---|
| 81 |
tokenize.tokenize(inp.readline, printer) |
|---|
| 82 |
except tokenize.TokenError: |
|---|
| 83 |
pass |
|---|
| 84 |
out.write('</pre>\n') |
|---|
| 85 |
|
|---|
| 86 |
def main(): |
|---|
| 87 |
import sys |
|---|
| 88 |
filter(open(sys.argv[1]), sys.stdout) |
|---|
| 89 |
|
|---|
| 90 |
if __name__ == '__main__': |
|---|
| 91 |
main() |
|---|