diff options
author | Marc Abramowitz <marc@marc-abramowitz.com> | 2015-04-30 16:42:17 -0700 |
---|---|---|
committer | Marc Abramowitz <marc@marc-abramowitz.com> | 2015-04-30 16:42:17 -0700 |
commit | 12a3f1f4cfa7f88478dc1b0e949fcc095b9fc804 (patch) | |
tree | ddb8079523d846f0b074437fc33fa5e28b508183 /paste/util/PySourceColor.py | |
download | paste-git-eliminate_cgi_parse_qsl_2.tar.gz |
Replace cgi.parse_qsl w/ six.moves.urllib.parse.parse_sqleliminate_cgi_parse_qsl_2eliminate_cgi_parse_qsl
because `cgi.parse_qsl` is deprecated, according to
https://docs.python.org/2/library/cgi.html#cgi.parse_qsl
Diffstat (limited to 'paste/util/PySourceColor.py')
-rw-r--r-- | paste/util/PySourceColor.py | 2102 |
1 files changed, 2102 insertions, 0 deletions
diff --git a/paste/util/PySourceColor.py b/paste/util/PySourceColor.py new file mode 100644 index 0000000..c576ead --- /dev/null +++ b/paste/util/PySourceColor.py @@ -0,0 +1,2102 @@ +# -*- coding: Latin-1 -*- +""" +PySourceColor: color Python source code +""" + +""" + PySourceColor.py + +---------------------------------------------------------------------------- + + A python source to colorized html/css/xhtml converter. + Hacked by M.E.Farmer Jr. 2004, 2005 + Python license + +---------------------------------------------------------------------------- + + - HTML markup does not create w3c valid html, but it works on every + browser i've tried so far.(I.E.,Mozilla/Firefox,Opera,Konqueror,wxHTML). + - CSS markup is w3c validated html 4.01 strict, + but will not render correctly on all browsers. + - XHTML markup is w3c validated xhtml 1.0 strict, + like html 4.01, will not render correctly on all browsers. + +---------------------------------------------------------------------------- + +Features: + + -Three types of markup: + html (default) + css/html 4.01 strict + xhtml 1.0 strict + + -Can tokenize and colorize: + 12 types of strings + 2 comment types + numbers + operators + brackets + math operators + class / name + def / name + decorator / name + keywords + arguments class/def/decorator + linenumbers + names + text + + -Eight colorschemes built-in: + null + mono + lite (default) + dark + dark2 + idle + viewcvs + pythonwin + + -Header and footer + set to '' for builtin header / footer. + give path to a file containing the html + you want added as header or footer. + + -Arbitrary text and html + html markup converts all to raw (TEXT token) + #@# for raw -> send raw text. + #$# for span -> inline html and text. + #%# for div -> block level html and text. + + -Linenumbers + Supports all styles. New token is called LINENUMBER. + Defaults to NAME if not defined. + + Style options + + -ALL markups support these text styles: + b = bold + i = italic + u = underline + -CSS and XHTML has limited support for borders: + HTML markup functions will ignore these. + Optional: Border color in RGB hex + Defaults to the text forecolor. + #rrggbb = border color + Border size: + l = thick + m = medium + t = thin + Border type: + - = dashed + . = dotted + s = solid + d = double + g = groove + r = ridge + n = inset + o = outset + You can specify multiple sides, + they will all use the same style. + Optional: Default is full border. + v = bottom + < = left + > = right + ^ = top + NOTE: Specify the styles you want. + The markups will ignore unsupported styles + Also note not all browsers can show these options + + -All tokens default to NAME if not defined + so the only absolutely critical ones to define are: + NAME, ERRORTOKEN, PAGEBACKGROUND + +---------------------------------------------------------------------------- + +Example usage:: + + # import + import PySourceColor as psc + psc.convert('c:/Python22/PySourceColor.py', colors=psc.idle, show=1) + + # from module import * + from PySourceColor import * + convert('c:/Python22/Lib', colors=lite, markup="css", + header='#$#<b>This is a simpe heading</b><hr/>') + + # How to use a custom colorscheme, and most of the 'features' + from PySourceColor import * + new = { + ERRORTOKEN: ('bui','#FF8080',''), + DECORATOR_NAME: ('s','#AACBBC',''), + DECORATOR: ('n','#333333',''), + NAME: ('t.<v','#1133AA','#DDFF22'), + NUMBER: ('','#236676','#FF5555'), + OPERATOR: ('b','#454567','#BBBB11'), + MATH_OPERATOR: ('','#935623','#423afb'), + BRACKETS: ('b','#ac34bf','#6457a5'), + COMMENT: ('t-#0022FF','#545366','#AABBFF'), + DOUBLECOMMENT: ('<l#553455','#553455','#FF00FF'), + CLASS_NAME: ('m^v-','#000000','#FFFFFF'), + DEF_NAME: ('l=<v','#897845','#000022'), + KEYWORD: ('.b','#345345','#FFFF22'), + SINGLEQUOTE: ('mn','#223344','#AADDCC'), + SINGLEQUOTE_R: ('','#344522',''), + SINGLEQUOTE_U: ('','#234234',''), + DOUBLEQUOTE: ('m#0022FF','#334421',''), + DOUBLEQUOTE_R: ('','#345345',''), + DOUBLEQUOTE_U: ('','#678673',''), + TRIPLESINGLEQUOTE: ('tv','#FFFFFF','#000000'), + TRIPLESINGLEQUOTE_R: ('tbu','#443256','#DDFFDA'), + TRIPLESINGLEQUOTE_U: ('','#423454','#DDFFDA'), + TRIPLEDOUBLEQUOTE: ('li#236fd3b<>','#000000','#FFFFFF'), + TRIPLEDOUBLEQUOTE_R: ('tub','#000000','#FFFFFF'), + TRIPLEDOUBLEQUOTE_U: ('-', '#CCAABB','#FFFAFF'), + LINENUMBER: ('ib-','#ff66aa','#7733FF'),] + TEXT: ('','#546634',''), + PAGEBACKGROUND: '#FFFAAA', + } + if __name__ == '__main__': + import sys + convert(sys.argv[1], './xhtml.html', colors=new, markup='xhtml', show=1, + linenumbers=1) + convert(sys.argv[1], './html.html', colors=new, markup='html', show=1, + linenumbers=1) + +""" + +__all__ = ['ERRORTOKEN','DECORATOR_NAME', 'DECORATOR', 'ARGS', 'EXTRASPACE', + 'NAME', 'NUMBER', 'OPERATOR', 'COMMENT', 'MATH_OPERATOR', + 'DOUBLECOMMENT', 'CLASS_NAME', 'DEF_NAME', 'KEYWORD', 'BRACKETS', + 'SINGLEQUOTE','SINGLEQUOTE_R','SINGLEQUOTE_U','DOUBLEQUOTE', + 'DOUBLEQUOTE_R', 'DOUBLEQUOTE_U', 'TRIPLESINGLEQUOTE', 'TEXT', + 'TRIPLESINGLEQUOTE_R', 'TRIPLESINGLEQUOTE_U', 'TRIPLEDOUBLEQUOTE', + 'TRIPLEDOUBLEQUOTE_R', 'TRIPLEDOUBLEQUOTE_U', 'PAGEBACKGROUND', + 'LINENUMBER', 'CODESTART', 'CODEEND', 'PY', 'TOKEN_NAMES', 'CSSHOOK', + 'null', 'mono', 'lite', 'dark','dark2', 'pythonwin','idle', + 'viewcvs', 'Usage', 'cli', 'str2stdout', 'path2stdout', 'Parser', + 'str2file', 'str2html', 'str2css', 'str2markup', 'path2file', + 'path2html', 'convert', 'walkdir', 'defaultColors', 'showpage', + 'pageconvert','tagreplace', 'MARKUPDICT'] +__title__ = 'PySourceColor' +__version__ = "2.1a" +__date__ = '25 April 2005' +__author__ = "M.E.Farmer Jr." +__credits__ = '''This was originally based on a python recipe +submitted by Jürgen Hermann to ASPN. Now based on the voices in my head. +M.E.Farmer 2004, 2005 +Python license +''' +import os +import sys +import time +import glob +import getopt +import keyword +import token +import tokenize +import traceback +from six.moves import cStringIO as StringIO +# Do not edit +NAME = token.NAME +NUMBER = token.NUMBER +COMMENT = tokenize.COMMENT +OPERATOR = token.OP +ERRORTOKEN = token.ERRORTOKEN +ARGS = token.NT_OFFSET + 1 +DOUBLECOMMENT = token.NT_OFFSET + 2 +CLASS_NAME = token.NT_OFFSET + 3 +DEF_NAME = token.NT_OFFSET + 4 +KEYWORD = token.NT_OFFSET + 5 +SINGLEQUOTE = token.NT_OFFSET + 6 +SINGLEQUOTE_R = token.NT_OFFSET + 7 +SINGLEQUOTE_U = token.NT_OFFSET + 8 +DOUBLEQUOTE = token.NT_OFFSET + 9 +DOUBLEQUOTE_R = token.NT_OFFSET + 10 +DOUBLEQUOTE_U = token.NT_OFFSET + 11 +TRIPLESINGLEQUOTE = token.NT_OFFSET + 12 +TRIPLESINGLEQUOTE_R = token.NT_OFFSET + 13 +TRIPLESINGLEQUOTE_U = token.NT_OFFSET + 14 +TRIPLEDOUBLEQUOTE = token.NT_OFFSET + 15 +TRIPLEDOUBLEQUOTE_R = token.NT_OFFSET + 16 +TRIPLEDOUBLEQUOTE_U = token.NT_OFFSET + 17 +PAGEBACKGROUND = token.NT_OFFSET + 18 +DECORATOR = token.NT_OFFSET + 19 +DECORATOR_NAME = token.NT_OFFSET + 20 +BRACKETS = token.NT_OFFSET + 21 +MATH_OPERATOR = token.NT_OFFSET + 22 +LINENUMBER = token.NT_OFFSET + 23 +TEXT = token.NT_OFFSET + 24 +PY = token.NT_OFFSET + 25 +CODESTART = token.NT_OFFSET + 26 +CODEEND = token.NT_OFFSET + 27 +CSSHOOK = token.NT_OFFSET + 28 +EXTRASPACE = token.NT_OFFSET + 29 + +# markup classname lookup +MARKUPDICT = { + ERRORTOKEN: 'py_err', + DECORATOR_NAME: 'py_decn', + DECORATOR: 'py_dec', + ARGS: 'py_args', + NAME: 'py_name', + NUMBER: 'py_num', + OPERATOR: 'py_op', + COMMENT: 'py_com', + DOUBLECOMMENT: 'py_dcom', + CLASS_NAME: 'py_clsn', + DEF_NAME: 'py_defn', + KEYWORD: 'py_key', + SINGLEQUOTE: 'py_sq', + SINGLEQUOTE_R: 'py_sqr', + SINGLEQUOTE_U: 'py_squ', + DOUBLEQUOTE: 'py_dq', + DOUBLEQUOTE_R: 'py_dqr', + DOUBLEQUOTE_U: 'py_dqu', + TRIPLESINGLEQUOTE: 'py_tsq', + TRIPLESINGLEQUOTE_R: 'py_tsqr', + TRIPLESINGLEQUOTE_U: 'py_tsqu', + TRIPLEDOUBLEQUOTE: 'py_tdq', + TRIPLEDOUBLEQUOTE_R: 'py_tdqr', + TRIPLEDOUBLEQUOTE_U: 'py_tdqu', + BRACKETS: 'py_bra', + MATH_OPERATOR: 'py_mop', + LINENUMBER: 'py_lnum', + TEXT: 'py_text', + } +# might help users that want to create custom schemes +TOKEN_NAMES= { + ERRORTOKEN:'ERRORTOKEN', + DECORATOR_NAME:'DECORATOR_NAME', + DECORATOR:'DECORATOR', + ARGS:'ARGS', + NAME:'NAME', + NUMBER:'NUMBER', + OPERATOR:'OPERATOR', + COMMENT:'COMMENT', + DOUBLECOMMENT:'DOUBLECOMMENT', + CLASS_NAME:'CLASS_NAME', + DEF_NAME:'DEF_NAME', + KEYWORD:'KEYWORD', + SINGLEQUOTE:'SINGLEQUOTE', + SINGLEQUOTE_R:'SINGLEQUOTE_R', + SINGLEQUOTE_U:'SINGLEQUOTE_U', + DOUBLEQUOTE:'DOUBLEQUOTE', + DOUBLEQUOTE_R:'DOUBLEQUOTE_R', + DOUBLEQUOTE_U:'DOUBLEQUOTE_U', + TRIPLESINGLEQUOTE:'TRIPLESINGLEQUOTE', + TRIPLESINGLEQUOTE_R:'TRIPLESINGLEQUOTE_R', + TRIPLESINGLEQUOTE_U:'TRIPLESINGLEQUOTE_U', + TRIPLEDOUBLEQUOTE:'TRIPLEDOUBLEQUOTE', + TRIPLEDOUBLEQUOTE_R:'TRIPLEDOUBLEQUOTE_R', + TRIPLEDOUBLEQUOTE_U:'TRIPLEDOUBLEQUOTE_U', + BRACKETS:'BRACKETS', + MATH_OPERATOR:'MATH_OPERATOR', + LINENUMBER:'LINENUMBER', + TEXT:'TEXT', + PAGEBACKGROUND:'PAGEBACKGROUND', + } + +###################################################################### +# Edit colors and styles to taste +# Create your own scheme, just copy one below , rename and edit. +# Custom styles must at least define NAME, ERRORTOKEN, PAGEBACKGROUND, +# all missing elements will default to NAME. +# See module docstring for details on style attributes. +###################################################################### +# Copy null and use it as a starter colorscheme. +null = {# tokentype: ('tags border_color', 'textforecolor', 'textbackcolor') + ERRORTOKEN: ('','#000000',''),# Error token + DECORATOR_NAME: ('','#000000',''),# Decorator name + DECORATOR: ('','#000000',''),# @ symbol + ARGS: ('','#000000',''),# class,def,deco arguments + NAME: ('','#000000',''),# All other python text + NUMBER: ('','#000000',''),# 0->10 + OPERATOR: ('','#000000',''),# ':','<=',';',',','.','==', etc + MATH_OPERATOR: ('','#000000',''),# '+','-','=','','**',etc + BRACKETS: ('','#000000',''),# '[',']','(',')','{','}' + COMMENT: ('','#000000',''),# Single comment + DOUBLECOMMENT: ('','#000000',''),## Double comment + CLASS_NAME: ('','#000000',''),# Class name + DEF_NAME: ('','#000000',''),# Def name + KEYWORD: ('','#000000',''),# Python keywords + SINGLEQUOTE: ('','#000000',''),# 'SINGLEQUOTE' + SINGLEQUOTE_R: ('','#000000',''),# r'SINGLEQUOTE' + SINGLEQUOTE_U: ('','#000000',''),# u'SINGLEQUOTE' + DOUBLEQUOTE: ('','#000000',''),# "DOUBLEQUOTE" + DOUBLEQUOTE_R: ('','#000000',''),# r"DOUBLEQUOTE" + DOUBLEQUOTE_U: ('','#000000',''),# u"DOUBLEQUOTE" + TRIPLESINGLEQUOTE: ('','#000000',''),# '''TRIPLESINGLEQUOTE''' + TRIPLESINGLEQUOTE_R: ('','#000000',''),# r'''TRIPLESINGLEQUOTE''' + TRIPLESINGLEQUOTE_U: ('','#000000',''),# u'''TRIPLESINGLEQUOTE''' + TRIPLEDOUBLEQUOTE: ('','#000000',''),# """TRIPLEDOUBLEQUOTE""" + TRIPLEDOUBLEQUOTE_R: ('','#000000',''),# r"""TRIPLEDOUBLEQUOTE""" + TRIPLEDOUBLEQUOTE_U: ('','#000000',''),# u"""TRIPLEDOUBLEQUOTE""" + TEXT: ('','#000000',''),# non python text + LINENUMBER: ('>ti#555555','#000000',''),# Linenumbers + PAGEBACKGROUND: '#FFFFFF'# set the page background + } + +mono = { + ERRORTOKEN: ('s#FF0000','#FF8080',''), + DECORATOR_NAME: ('bu','#000000',''), + DECORATOR: ('b','#000000',''), + ARGS: ('b','#555555',''), + NAME: ('','#000000',''), + NUMBER: ('b','#000000',''), + OPERATOR: ('b','#000000',''), + MATH_OPERATOR: ('b','#000000',''), + BRACKETS: ('b','#000000',''), + COMMENT: ('i','#999999',''), + DOUBLECOMMENT: ('b','#999999',''), + CLASS_NAME: ('bu','#000000',''), + DEF_NAME: ('b','#000000',''), + KEYWORD: ('b','#000000',''), + SINGLEQUOTE: ('','#000000',''), + SINGLEQUOTE_R: ('','#000000',''), + SINGLEQUOTE_U: ('','#000000',''), + DOUBLEQUOTE: ('','#000000',''), + DOUBLEQUOTE_R: ('','#000000',''), + DOUBLEQUOTE_U: ('','#000000',''), + TRIPLESINGLEQUOTE: ('','#000000',''), + TRIPLESINGLEQUOTE_R: ('','#000000',''), + TRIPLESINGLEQUOTE_U: ('','#000000',''), + TRIPLEDOUBLEQUOTE: ('i','#000000',''), + TRIPLEDOUBLEQUOTE_R: ('i','#000000',''), + TRIPLEDOUBLEQUOTE_U: ('i','#000000',''), + TEXT: ('','#000000',''), + LINENUMBER: ('>ti#555555','#000000',''), + PAGEBACKGROUND: '#FFFFFF' + } + +dark = { + ERRORTOKEN: ('s#FF0000','#FF8080',''), + DECORATOR_NAME: ('b','#FFBBAA',''), + DECORATOR: ('b','#CC5511',''), + ARGS: ('b','#DDDDFF',''), + NAME: ('','#DDDDDD',''), + NUMBER: ('','#FF0000',''), + OPERATOR: ('b','#FAF785',''), + MATH_OPERATOR: ('b','#FAF785',''), + BRACKETS: ('b','#FAF785',''), + COMMENT: ('','#45FCA0',''), + DOUBLECOMMENT: ('i','#A7C7A9',''), + CLASS_NAME: ('b','#B666FD',''), + DEF_NAME: ('b','#EBAE5C',''), + KEYWORD: ('b','#8680FF',''), + SINGLEQUOTE: ('','#F8BAFE',''), + SINGLEQUOTE_R: ('','#F8BAFE',''), + SINGLEQUOTE_U: ('','#F8BAFE',''), + DOUBLEQUOTE: ('','#FF80C0',''), + DOUBLEQUOTE_R: ('','#FF80C0',''), + DOUBLEQUOTE_U: ('','#FF80C0',''), + TRIPLESINGLEQUOTE: ('','#FF9595',''), + TRIPLESINGLEQUOTE_R: ('','#FF9595',''), + TRIPLESINGLEQUOTE_U: ('','#FF9595',''), + TRIPLEDOUBLEQUOTE: ('','#B3FFFF',''), + TRIPLEDOUBLEQUOTE_R: ('','#B3FFFF',''), + TRIPLEDOUBLEQUOTE_U: ('','#B3FFFF',''), + TEXT: ('','#FFFFFF',''), + LINENUMBER: ('>mi#555555','#bbccbb','#333333'), + PAGEBACKGROUND: '#000000' + } + +dark2 = { + ERRORTOKEN: ('','#FF0000',''), + DECORATOR_NAME: ('b','#FFBBAA',''), + DECORATOR: ('b','#CC5511',''), + ARGS: ('b','#DDDDDD',''), + NAME: ('','#C0C0C0',''), + NUMBER: ('b','#00FF00',''), + OPERATOR: ('b','#FF090F',''), + MATH_OPERATOR: ('b','#EE7020',''), + BRACKETS: ('b','#FFB90F',''), + COMMENT: ('i','#D0D000','#522000'),#'#88AA88','#11111F'), + DOUBLECOMMENT: ('i','#D0D000','#522000'),#'#77BB77','#11111F'), + CLASS_NAME: ('b','#DD4080',''), + DEF_NAME: ('b','#FF8040',''), + KEYWORD: ('b','#4726d1',''), + SINGLEQUOTE: ('','#8080C0',''), + SINGLEQUOTE_R: ('','#8080C0',''), + SINGLEQUOTE_U: ('','#8080C0',''), + DOUBLEQUOTE: ('','#ADB9F1',''), + DOUBLEQUOTE_R: ('','#ADB9F1',''), + DOUBLEQUOTE_U: ('','#ADB9F1',''), + TRIPLESINGLEQUOTE: ('','#00C1C1',''),#A050C0 + TRIPLESINGLEQUOTE_R: ('','#00C1C1',''),#A050C0 + TRIPLESINGLEQUOTE_U: ('','#00C1C1',''),#A050C0 + TRIPLEDOUBLEQUOTE: ('','#33E3E3',''),#B090E0 + TRIPLEDOUBLEQUOTE_R: ('','#33E3E3',''),#B090E0 + TRIPLEDOUBLEQUOTE_U: ('','#33E3E3',''),#B090E0 + TEXT: ('','#C0C0C0',''), + LINENUMBER: ('>mi#555555','#bbccbb','#333333'), + PAGEBACKGROUND: '#000000' + } + +lite = { + ERRORTOKEN: ('s#FF0000','#FF8080',''), + DECORATOR_NAME: ('b','#BB4422',''), + DECORATOR: ('b','#3333AF',''), + ARGS: ('b','#000000',''), + NAME: ('','#333333',''), + NUMBER: ('b','#DD2200',''), + OPERATOR: ('b','#000000',''), + MATH_OPERATOR: ('b','#000000',''), + BRACKETS: ('b','#000000',''), + COMMENT: ('','#007F00',''), + DOUBLECOMMENT: ('','#608060',''), + CLASS_NAME: ('b','#0000DF',''), + DEF_NAME: ('b','#9C7A00',''),#f09030 + KEYWORD: ('b','#0000AF',''), + SINGLEQUOTE: ('','#600080',''), + SINGLEQUOTE_R: ('','#600080',''), + SINGLEQUOTE_U: ('','#600080',''), + DOUBLEQUOTE: ('','#A0008A',''), + DOUBLEQUOTE_R: ('','#A0008A',''), + DOUBLEQUOTE_U: ('','#A0008A',''), + TRIPLESINGLEQUOTE: ('','#337799',''), + TRIPLESINGLEQUOTE_R: ('','#337799',''), + TRIPLESINGLEQUOTE_U: ('','#337799',''), + TRIPLEDOUBLEQUOTE: ('','#1166AA',''), + TRIPLEDOUBLEQUOTE_R: ('','#1166AA',''), + TRIPLEDOUBLEQUOTE_U: ('','#1166AA',''), + TEXT: ('','#000000',''), + LINENUMBER: ('>ti#555555','#000000',''), + PAGEBACKGROUND: '#FFFFFF' + } + +idle = { + ERRORTOKEN: ('s#FF0000','#FF8080',''), + DECORATOR_NAME: ('','#900090',''), + DECORATOR: ('','#FF7700',''), + NAME: ('','#000000',''), + NUMBER: ('','#000000',''), + OPERATOR: ('','#000000',''), + MATH_OPERATOR: ('','#000000',''), + BRACKETS: ('','#000000',''), + COMMENT: ('','#DD0000',''), + DOUBLECOMMENT: ('','#DD0000',''), + CLASS_NAME: ('','#0000FF',''), + DEF_NAME: ('','#0000FF',''), + KEYWORD: ('','#FF7700',''), + SINGLEQUOTE: ('','#00AA00',''), + SINGLEQUOTE_R: ('','#00AA00',''), + SINGLEQUOTE_U: ('','#00AA00',''), + DOUBLEQUOTE: ('','#00AA00',''), + DOUBLEQUOTE_R: ('','#00AA00',''), + DOUBLEQUOTE_U: ('','#00AA00',''), + TRIPLESINGLEQUOTE: ('','#00AA00',''), + TRIPLESINGLEQUOTE_R: ('','#00AA00',''), + TRIPLESINGLEQUOTE_U: ('','#00AA00',''), + TRIPLEDOUBLEQUOTE: ('','#00AA00',''), + TRIPLEDOUBLEQUOTE_R: ('','#00AA00',''), + TRIPLEDOUBLEQUOTE_U: ('','#00AA00',''), + TEXT: ('','#000000',''), + LINENUMBER: ('>ti#555555','#000000',''), + PAGEBACKGROUND: '#FFFFFF' + } + +pythonwin = { + ERRORTOKEN: ('s#FF0000','#FF8080',''), + DECORATOR_NAME: ('b','#DD0080',''), + DECORATOR: ('b','#000080',''), + ARGS: ('','#000000',''), + NAME: ('','#303030',''), + NUMBER: ('','#008080',''), + OPERATOR: ('','#000000',''), + MATH_OPERATOR: ('','#000000',''), + BRACKETS: ('','#000000',''), + COMMENT: ('','#007F00',''), + DOUBLECOMMENT: ('','#7F7F7F',''), + CLASS_NAME: ('b','#0000FF',''), + DEF_NAME: ('b','#007F7F',''), + KEYWORD: ('b','#000080',''), + SINGLEQUOTE: ('','#808000',''), + SINGLEQUOTE_R: ('','#808000',''), + SINGLEQUOTE_U: ('','#808000',''), + DOUBLEQUOTE: ('','#808000',''), + DOUBLEQUOTE_R: ('','#808000',''), + DOUBLEQUOTE_U: ('','#808000',''), + TRIPLESINGLEQUOTE: ('','#808000',''), + TRIPLESINGLEQUOTE_R: ('','#808000',''), + TRIPLESINGLEQUOTE_U: ('','#808000',''), + TRIPLEDOUBLEQUOTE: ('','#808000',''), + TRIPLEDOUBLEQUOTE_R: ('','#808000',''), + TRIPLEDOUBLEQUOTE_U: ('','#808000',''), + TEXT: ('','#303030',''), + LINENUMBER: ('>ti#555555','#000000',''), + PAGEBACKGROUND: '#FFFFFF' + } + +viewcvs = { + ERRORTOKEN: ('s#FF0000','#FF8080',''), + DECORATOR_NAME: ('','#000000',''), + DECORATOR: ('','#000000',''), + ARGS: ('','#000000',''), + NAME: ('','#000000',''), + NUMBER: ('','#000000',''), + OPERATOR: ('','#000000',''), + MATH_OPERATOR: ('','#000000',''), + BRACKETS: ('','#000000',''), + COMMENT: ('i','#b22222',''), + DOUBLECOMMENT: ('i','#b22222',''), + CLASS_NAME: ('','#000000',''), + DEF_NAME: ('b','#0000ff',''), + KEYWORD: ('b','#a020f0',''), + SINGLEQUOTE: ('b','#bc8f8f',''), + SINGLEQUOTE_R: ('b','#bc8f8f',''), + SINGLEQUOTE_U: ('b','#bc8f8f',''), + DOUBLEQUOTE: ('b','#bc8f8f',''), + DOUBLEQUOTE_R: ('b','#bc8f8f',''), + DOUBLEQUOTE_U: ('b','#bc8f8f',''), + TRIPLESINGLEQUOTE: ('b','#bc8f8f',''), + TRIPLESINGLEQUOTE_R: ('b','#bc8f8f',''), + TRIPLESINGLEQUOTE_U: ('b','#bc8f8f',''), + TRIPLEDOUBLEQUOTE: ('b','#bc8f8f',''), + TRIPLEDOUBLEQUOTE_R: ('b','#bc8f8f',''), + TRIPLEDOUBLEQUOTE_U: ('b','#bc8f8f',''), + TEXT: ('','#000000',''), + LINENUMBER: ('>ti#555555','#000000',''), + PAGEBACKGROUND: '#FFFFFF' + } + +defaultColors = lite + +def Usage(): + doc = """ + ----------------------------------------------------------------------------- + PySourceColor.py ver: %s + ----------------------------------------------------------------------------- + Module summary: + This module is designed to colorize python source code. + Input--->python source + Output-->colorized (html, html4.01/css, xhtml1.0) + Standalone: + This module will work from the command line with options. + This module will work with redirected stdio. + Imported: + This module can be imported and used directly in your code. + ----------------------------------------------------------------------------- + Command line options: + -h, --help + Optional-> Display this help message. + -t, --test + Optional-> Will ignore all others flags but --profile + test all schemes and markup combinations + -p, --profile + Optional-> Works only with --test or -t + runs profile.py and makes the test work in quiet mode. + -i, --in, --input + Optional-> If you give input on stdin. + Use any of these for the current dir (.,cwd) + Input can be file or dir. + Input from stdin use one of the following (-,stdin) + If stdin is used as input stdout is output unless specified. + -o, --out, --output + Optional-> output dir for the colorized source. + default: output dir is the input dir. + To output html to stdout use one of the following (-,stdout) + Stdout can be used without stdin if you give a file as input. + -c, --color + Optional-> null, mono, dark, dark2, lite, idle, pythonwin, viewcvs + default: dark + -s, --show + Optional-> Show page after creation. + default: no show + -m, --markup + Optional-> html, css, xhtml + css, xhtml also support external stylesheets (-e,--external) + default: HTML + -e, --external + Optional-> use with css, xhtml + Writes an style sheet instead of embedding it in the page + saves it as pystyle.css in the same directory. + html markup will silently ignore this flag. + -H, --header + Opional-> add a page header to the top of the output + -H + Builtin header (name,date,hrule) + --header + You must specify a filename. + The header file must be valid html + and must handle its own font colors. + ex. --header c:/tmp/header.txt + -F, --footer + Opional-> add a page footer to the bottom of the output + -F + Builtin footer (hrule,name,date) + --footer + You must specify a filename. + The footer file must be valid html + and must handle its own font colors. + ex. --footer c:/tmp/footer.txt + -l, --linenumbers + Optional-> default is no linenumbers + Adds line numbers to the start of each line in the code. + --convertpage + Given a webpage that has code embedded in tags it will + convert embedded code to colorized html. + (see pageconvert for details) + ----------------------------------------------------------------------------- + Option usage: + # Test and show pages + python PySourceColor.py -t -s + # Test and only show profile results + python PySourceColor.py -t -p + # Colorize all .py,.pyw files in cwdir you can also use: (.,cwd) + python PySourceColor.py -i . + # Using long options w/ = + python PySourceColor.py --in=c:/myDir/my.py --color=lite --show + # Using short options w/out = + python PySourceColor.py -i c:/myDir/ -c idle -m css -e + # Using any mix + python PySourceColor.py --in . -o=c:/myDir --show + # Place a custom header on your files + python PySourceColor.py -i . -o c:/tmp -m xhtml --header c:/header.txt + ----------------------------------------------------------------------------- + Stdio usage: + # Stdio using no options + python PySourceColor.py < c:/MyFile.py > c:/tmp/MyFile.html + # Using stdin alone automatically uses stdout for output: (stdin,-) + python PySourceColor.py -i- < c:/MyFile.py > c:/tmp/myfile.html + # Stdout can also be written to directly from a file instead of stdin + python PySourceColor.py -i c:/MyFile.py -m css -o- > c:/tmp/myfile.html + # Stdin can be used as input , but output can still be specified + python PySourceColor.py -i- -o c:/pydoc.py.html -s < c:/Python22/my.py + _____________________________________________________________________________ + """ + print(doc % (__version__)) + sys.exit(1) + +###################################################### Command line interface + +def cli(): + """Handle command line args and redirections""" + try: + # try to get command line args + opts, args = getopt.getopt(sys.argv[1:], + "hseqtplHFi:o:c:m:h:f:",["help", "show", "quiet", + "test", "external", "linenumbers", "convertpage", "profile", + "input=", "output=", "color=", "markup=","header=", "footer="]) + except getopt.GetoptError: + # on error print help information and exit: + Usage() + # init some names + input = None + output = None + colorscheme = None + markup = 'html' + header = None + footer = None + linenumbers = 0 + show = 0 + quiet = 0 + test = 0 + profile = 0 + convertpage = 0 + form = None + # if we have args then process them + for o, a in opts: + if o in ["-h", "--help"]: + Usage() + sys.exit() + if o in ["-o", "--output", "--out"]: + output = a + if o in ["-i", "--input", "--in"]: + input = a + if input in [".", "cwd"]: + input = os.getcwd() + if o in ["-s", "--show"]: + show = 1 + if o in ["-q", "--quiet"]: + quiet = 1 + if o in ["-t", "--test"]: + test = 1 + if o in ["--convertpage"]: + convertpage = 1 + if o in ["-p", "--profile"]: + profile = 1 + if o in ["-e", "--external"]: + form = 'external' + if o in ["-m", "--markup"]: + markup = str(a) + if o in ["-l", "--linenumbers"]: + linenumbers = 1 + if o in ["--header"]: + header = str(a) + elif o == "-H": + header = '' + if o in ["--footer"]: + footer = str(a) + elif o == "-F": + footer = '' + if o in ["-c", "--color"]: + try: + colorscheme = globals().get(a.lower()) + except: + traceback.print_exc() + Usage() + if test: + if profile: + import profile + profile.run('_test(show=%s, quiet=%s)'%(show,quiet)) + else: + # Parse this script in every possible colorscheme and markup + _test(show,quiet) + elif input in [None, "-", "stdin"] or output in ["-", "stdout"]: + # determine if we are going to use stdio + if input not in [None, "-", "stdin"]: + if os.path.isfile(input) : + path2stdout(input, colors=colorscheme, markup=markup, + linenumbers=linenumbers, header=header, + footer=footer, form=form) + else: + raise PathError('File does not exists!') + else: + try: + if sys.stdin.isatty(): + raise InputError('Please check input!') + else: + if output in [None,"-","stdout"]: + str2stdout(sys.stdin.read(), colors=colorscheme, + markup=markup, header=header, + footer=footer, linenumbers=linenumbers, + form=form) + else: + str2file(sys.stdin.read(), outfile=output, show=show, + markup=markup, header=header, footer=footer, + linenumbers=linenumbers, form=form) + except: + traceback.print_exc() + Usage() + else: + if os.path.exists(input): + if convertpage: + # if there was at least an input given we can proceed + pageconvert(input, out=output, colors=colorscheme, + show=show, markup=markup,linenumbers=linenumbers) + else: + # if there was at least an input given we can proceed + convert(source=input, outdir=output, colors=colorscheme, + show=show, markup=markup, quiet=quiet, header=header, + footer=footer, linenumbers=linenumbers, form=form) + else: + raise PathError('File does not exists!') + Usage() + +######################################################### Simple markup tests + +def _test(show=0, quiet=0): + """Test the parser and most of the functions. + + There are 19 test total(eight colorschemes in three diffrent markups, + and a str2file test. Most functions are tested by this. + """ + fi = sys.argv[0] + if not fi.endswith('.exe'):# Do not test if frozen as an archive + # this is a collection of test, most things are covered. + path2file(fi, '/tmp/null.html', null, show=show, quiet=quiet) + path2file(fi, '/tmp/null_css.html', null, show=show, + markup='css', quiet=quiet) + path2file(fi, '/tmp/mono.html', mono, show=show, quiet=quiet) + path2file(fi, '/tmp/mono_css.html', mono, show=show, + markup='css', quiet=quiet) + path2file(fi, '/tmp/lite.html', lite, show=show, quiet=quiet) + path2file(fi, '/tmp/lite_css.html', lite, show=show, + markup='css', quiet=quiet, header='', footer='', + linenumbers=1) + path2file(fi, '/tmp/lite_xhtml.html', lite, show=show, + markup='xhtml', quiet=quiet) + path2file(fi, '/tmp/dark.html', dark, show=show, quiet=quiet) + path2file(fi, '/tmp/dark_css.html', dark, show=show, + markup='css', quiet=quiet, linenumbers=1) + path2file(fi, '/tmp/dark2.html', dark2, show=show, quiet=quiet) + path2file(fi, '/tmp/dark2_css.html', dark2, show=show, + markup='css', quiet=quiet) + path2file(fi, '/tmp/dark2_xhtml.html', dark2, show=show, + markup='xhtml', quiet=quiet, header='', footer='', + linenumbers=1, form='external') + path2file(fi, '/tmp/idle.html', idle, show=show, quiet=quiet) + path2file(fi, '/tmp/idle_css.html', idle, show=show, + markup='css', quiet=quiet) + path2file(fi, '/tmp/viewcvs.html', viewcvs, show=show, + quiet=quiet, linenumbers=1) + path2file(fi, '/tmp/viewcvs_css.html', viewcvs, show=show, + markup='css', linenumbers=1, quiet=quiet) + path2file(fi, '/tmp/pythonwin.html', pythonwin, show=show, + quiet=quiet) + path2file(fi, '/tmp/pythonwin_css.html', pythonwin, show=show, + markup='css', quiet=quiet) + teststr=r'''"""This is a test of decorators and other things""" +# This should be line 421... +@whatever(arg,arg2) +@A @B(arghh) @C +def LlamaSaysNi(arg='Ni!',arg2="RALPH"): + """This docstring is deeply disturbed by all the llama references""" + print('%s The Wonder Llama says %s'% (arg2,arg)) +# So I was like duh!, and he was like ya know?!, +# and so we were both like huh...wtf!? RTFM!! LOL!!;) +@staticmethod## Double comments are KewL. +def LlamasRLumpy(): + """This docstring is too sexy to be here. + """ + u""" +============================= +A Møøse once bit my sister... +============================= + """ + ## Relax, this won't hurt a bit, just a simple, painless procedure, + ## hold still while I get the anesthetizing hammer. + m = {'three':'1','won':'2','too':'3'} + o = r'fishy\fishy\fishy/fish\oh/where/is\my/little\..' + python = uR""" + No realli! She was Karving her initials øn the møøse with the sharpened end + of an interspace tøøthbrush given her by Svenge - her brother-in-law -an Oslo + dentist and star of many Norwegian møvies: "The Høt Hands of an Oslo + Dentist", "Fillings of Passion", "The Huge Mølars of Horst Nordfink"...""" + RU"""142 MEXICAN WHOOPING LLAMAS"""#<-Can you fit 142 llamas in a red box? + n = u' HERMSGERVØRDENBRØTBØRDA ' + """ YUTTE """ + t = """SAMALLNIATNUOMNAIRODAUCE"""+"DENIARTYLLAICEPS04" + ## We apologise for the fault in the + ## comments. Those responsible have been + ## sacked. + y = '14 NORTH CHILEAN GUANACOS \ +(CLOSELY RELATED TO THE LLAMA)' + rules = [0,1,2,3,4,5] + print y''' + htmlPath = os.path.abspath('/tmp/strtest_lines.html') + str2file(teststr, htmlPath, colors=dark, markup='xhtml', + linenumbers=420, show=show) + _printinfo(" wrote %s" % htmlPath, quiet) + htmlPath = os.path.abspath('/tmp/strtest_nolines.html') + str2file(teststr, htmlPath, colors=dark, markup='xhtml', + show=show) + _printinfo(" wrote %s" % htmlPath, quiet) + else: + Usage() + return + +# emacs wants this: ' + +####################################################### User funtctions + +def str2stdout(sourcestring, colors=None, title='', markup='html', + header=None, footer=None, + linenumbers=0, form=None): + """Converts a code(string) to colorized HTML. Writes to stdout. + + form='code',or'snip' (for "<pre>yourcode</pre>" only) + colors=null,mono,lite,dark,dark2,idle,or pythonwin + """ + Parser(sourcestring, colors=colors, title=title, markup=markup, + header=header, footer=footer, + linenumbers=linenumbers).format(form) + +def path2stdout(sourcepath, title='', colors=None, markup='html', + header=None, footer=None, + linenumbers=0, form=None): + """Converts code(file) to colorized HTML. Writes to stdout. + + form='code',or'snip' (for "<pre>yourcode</pre>" only) + colors=null,mono,lite,dark,dark2,idle,or pythonwin + """ + sourcestring = open(sourcepath).read() + Parser(sourcestring, colors=colors, title=sourcepath, + markup=markup, header=header, footer=footer, + linenumbers=linenumbers).format(form) + +def str2html(sourcestring, colors=None, title='', + markup='html', header=None, footer=None, + linenumbers=0, form=None): + """Converts a code(string) to colorized HTML. Returns an HTML string. + + form='code',or'snip' (for "<pre>yourcode</pre>" only) + colors=null,mono,lite,dark,dark2,idle,or pythonwin + """ + stringIO = StringIO.StringIO() + Parser(sourcestring, colors=colors, title=title, out=stringIO, + markup=markup, header=header, footer=footer, + linenumbers=linenumbers).format(form) + stringIO.seek(0) + return stringIO.read() + +def str2css(sourcestring, colors=None, title='', + markup='css', header=None, footer=None, + linenumbers=0, form=None): + """Converts a code string to colorized CSS/HTML. Returns CSS/HTML string + + If form != None then this will return (stylesheet_str, code_str) + colors=null,mono,lite,dark,dark2,idle,or pythonwin + """ + if markup.lower() not in ['css' ,'xhtml']: + markup = 'css' + stringIO = StringIO.StringIO() + parse = Parser(sourcestring, colors=colors, title=title, + out=stringIO, markup=markup, + header=header, footer=footer, + linenumbers=linenumbers) + parse.format(form) + stringIO.seek(0) + if form != None: + return parse._sendCSSStyle(external=1), stringIO.read() + else: + return None, stringIO.read() + +def str2markup(sourcestring, colors=None, title = '', + markup='xhtml', header=None, footer=None, + linenumbers=0, form=None): + """ Convert code strings into ([stylesheet or None], colorized string) """ + if markup.lower() == 'html': + return None, str2html(sourcestring, colors=colors, title=title, + header=header, footer=footer, markup=markup, + linenumbers=linenumbers, form=form) + else: + return str2css(sourcestring, colors=colors, title=title, + header=header, footer=footer, markup=markup, + linenumbers=linenumbers, form=form) + +def str2file(sourcestring, outfile, colors=None, title='', + markup='html', header=None, footer=None, + linenumbers=0, show=0, dosheet=1, form=None): + """Converts a code string to a file. + + makes no attempt at correcting bad pathnames + """ + css , html = str2markup(sourcestring, colors=colors, title='', + markup=markup, header=header, footer=footer, + linenumbers=linenumbers, form=form) + # write html + f = open(outfile,'wt') + f.writelines(html) + f.close() + #write css + if css != None and dosheet: + dir = os.path.dirname(outfile) + outcss = os.path.join(dir,'pystyle.css') + f = open(outcss,'wt') + f.writelines(css) + f.close() + if show: + showpage(outfile) + +def path2html(sourcepath, colors=None, markup='html', + header=None, footer=None, + linenumbers=0, form=None): + """Converts code(file) to colorized HTML. Returns an HTML string. + + form='code',or'snip' (for "<pre>yourcode</pre>" only) + colors=null,mono,lite,dark,dark2,idle,or pythonwin + """ + stringIO = StringIO.StringIO() + sourcestring = open(sourcepath).read() + Parser(sourcestring, colors, title=sourcepath, out=stringIO, + markup=markup, header=header, footer=footer, + linenumbers=linenumbers).format(form) + stringIO.seek(0) + return stringIO.read() + +def convert(source, outdir=None, colors=None, + show=0, markup='html', quiet=0, + header=None, footer=None, linenumbers=0, form=None): + """Takes a file or dir as input and places the html in the outdir. + + If outdir is none it defaults to the input dir + """ + count=0 + # If it is a filename then path2file + if not os.path.isdir(source): + if os.path.isfile(source): + count+=1 + path2file(source, outdir, colors, show, markup, + quiet, form, header, footer, linenumbers, count) + else: + raise PathError('File does not exist!') + # If we pass in a dir we need to walkdir for files. + # Then we need to colorize them with path2file + else: + fileList = walkdir(source) + if fileList != None: + # make sure outdir is a dir + if outdir != None: + if os.path.splitext(outdir)[1] != '': + outdir = os.path.split(outdir)[0] + for item in fileList: + count+=1 + path2file(item, outdir, colors, show, markup, + quiet, form, header, footer, linenumbers, count) + _printinfo('Completed colorizing %s files.'%str(count), quiet) + else: + _printinfo("No files to convert in dir.", quiet) + +def path2file(sourcePath, out=None, colors=None, show=0, + markup='html', quiet=0, form=None, + header=None, footer=None, linenumbers=0, count=1): + """ Converts python source to html file""" + # If no outdir is given we use the sourcePath + if out == None:#this is a guess + htmlPath = sourcePath + '.html' + else: + # If we do give an out_dir, and it does + # not exist , it will be created. + if os.path.splitext(out)[1] == '': + if not os.path.isdir(out): + os.makedirs(out) + sourceName = os.path.basename(sourcePath) + htmlPath = os.path.join(out,sourceName)+'.html' + # If we do give an out_name, and its dir does + # not exist , it will be created. + else: + outdir = os.path.split(out)[0] + if not os.path.isdir(outdir): + os.makedirs(outdir) + htmlPath = out + htmlPath = os.path.abspath(htmlPath) + # Open the text and do the parsing. + source = open(sourcePath).read() + parse = Parser(source, colors, sourcePath, open(htmlPath, 'wt'), + markup, header, footer, linenumbers) + parse.format(form) + _printinfo(" wrote %s" % htmlPath, quiet) + # html markup will ignore the external flag, but + # we need to stop the blank file from being written. + if form == 'external' and count == 1 and markup != 'html': + cssSheet = parse._sendCSSStyle(external=1) + cssPath = os.path.join(os.path.dirname(htmlPath),'pystyle.css') + css = open(cssPath, 'wt') + css.write(cssSheet) + css.close() + _printinfo(" wrote %s" % cssPath, quiet) + if show: + # load HTML page into the default web browser. + showpage(htmlPath) + return htmlPath + +def tagreplace(sourcestr, colors=lite, markup='xhtml', + linenumbers=0, dosheet=1, tagstart='<PY>'.lower(), + tagend='</PY>'.lower(), stylesheet='pystyle.css'): + """This is a helper function for pageconvert. Returns css, page. + """ + if markup.lower() != 'html': + link = '<link rel="stylesheet" href="%s" type="text/css"/></head>' + css = link%stylesheet + if sourcestr.find(css) == -1: + sourcestr = sourcestr.replace('</head>', css, 1) + starttags = sourcestr.count(tagstart) + endtags = sourcestr.count(tagend) + if starttags: + if starttags == endtags: + for _ in range(starttags): + datastart = sourcestr.find(tagstart) + dataend = sourcestr.find(tagend) + data = sourcestr[datastart+len(tagstart):dataend] + data = unescape(data) + css , data = str2markup(data, colors=colors, + linenumbers=linenumbers, markup=markup, form='embed') + start = sourcestr[:datastart] + end = sourcestr[dataend+len(tagend):] + sourcestr = ''.join([start,data,end]) + else: + raise InputError('Tag mismatch!\nCheck %s,%s tags'%tagstart,tagend) + if not dosheet: + css = None + return css, sourcestr + +def pageconvert(path, out=None, colors=lite, markup='xhtml', linenumbers=0, + dosheet=1, tagstart='<PY>'.lower(), tagend='</PY>'.lower(), + stylesheet='pystyle', show=1, returnstr=0): + """This function can colorize Python source + + that is written in a webpage enclosed in tags. + """ + if out == None: + out = os.path.dirname(path) + infile = open(path, 'r').read() + css,page = tagreplace(sourcestr=infile,colors=colors, + markup=markup, linenumbers=linenumbers, dosheet=dosheet, + tagstart=tagstart, tagend=tagend, stylesheet=stylesheet) + if not returnstr: + newpath = os.path.abspath(os.path.join( + out,'tmp', os.path.basename(path))) + if not os.path.exists(newpath): + try: + os.makedirs(os.path.dirname(newpath)) + except: + pass#traceback.print_exc() + #Usage() + y = open(newpath, 'w') + y.write(page) + y.close() + if css: + csspath = os.path.abspath(os.path.join( + out,'tmp','%s.css'%stylesheet)) + x = open(csspath,'w') + x.write(css) + x.close() + if show: + try: + os.startfile(newpath) + except: + traceback.print_exc() + return newpath + else: + return css, page + +##################################################################### helpers + +def walkdir(dir): + """Return a list of .py and .pyw files from a given directory. + + This function can be written as a generator Python 2.3, or a genexp + in Python 2.4. But 2.2 and 2.1 would be left out.... + """ + # Get a list of files that match *.py* + GLOB_PATTERN = os.path.join(dir, "*.[p][y]*") + pathlist = glob.glob(GLOB_PATTERN) + # Now filter out all but py and pyw + filterlist = [x for x in pathlist + if x.endswith('.py') + or x.endswith('.pyw')] + if filterlist != []: + # if we have a list send it + return filterlist + else: + return None + +def showpage(path): + """Helper function to open webpages""" + try: + import webbrowser + webbrowser.open_new(os.path.abspath(path)) + except: + traceback.print_exc() + +def _printinfo(message, quiet): + """Helper to print messages""" + if not quiet: + print(message) + +def escape(text): + """escape text for html. similar to cgi.escape""" + text = text.replace("&", "&") + text = text.replace("<", "<") + text = text.replace(">", ">") + return text + +def unescape(text): + """unsecape escaped text""" + text = text.replace(""", '"') + text = text.replace(">", ">") + text = text.replace("<", "<") + text = text.replace("&", "&") + return text + +########################################################### Custom Exceptions + +class PySourceColorError(Exception): + # Base for custom errors + def __init__(self, msg=''): + self._msg = msg + Exception.__init__(self, msg) + def __repr__(self): + return self._msg + __str__ = __repr__ + +class PathError(PySourceColorError): + def __init__(self, msg): + PySourceColorError.__init__(self, + 'Path error! : %s'% msg) + +class InputError(PySourceColorError): + def __init__(self, msg): + PySourceColorError.__init__(self, + 'Input error! : %s'% msg) + +########################################################## Python code parser + +class Parser(object): + + """MoinMoin python parser heavily chopped :)""" + + def __init__(self, raw, colors=None, title='', out=sys.stdout, + markup='html', header=None, footer=None, linenumbers=0): + """Store the source text & set some flags""" + if colors == None: + colors = defaultColors + self.raw = raw.expandtabs().rstrip() + self.title = os.path.basename(title) + self.out = out + self.line = '' + self.lasttext = '' + self.argFlag = 0 + self.classFlag = 0 + self.defFlag = 0 + self.decoratorFlag = 0 + self.external = 0 + self.markup = markup.upper() + self.colors = colors + self.header = header + self.footer = footer + self.doArgs = 1 # overrides the new tokens + self.doNames = 1 # overrides the new tokens + self.doMathOps = 1 # overrides the new tokens + self.doBrackets = 1 # overrides the new tokens + self.doURL = 1 # override url conversion + self.LINENUMHOLDER = "___line___".upper() + self.LINESTART = "___start___".upper() + self.skip = 0 + # add space left side of code for padding.Override in color dict. + self.extraspace = self.colors.get(EXTRASPACE, '') + # Linenumbers less then zero also have numberlinks + self.dolinenums = self.linenum = abs(linenumbers) + if linenumbers < 0: + self.numberlinks = 1 + else: + self.numberlinks = 0 + + def format(self, form=None): + """Parse and send the colorized source""" + if form in ('snip','code'): + self.addEnds = 0 + elif form == 'embed': + self.addEnds = 0 + self.external = 1 + else: + if form == 'external': + self.external = 1 + self.addEnds = 1 + + # Store line offsets in self.lines + self.lines = [0, 0] + pos = 0 + + # Add linenumbers + if self.dolinenums: + start=self.LINENUMHOLDER+' '+self.extraspace + else: + start=''+self.extraspace + newlines = [] + lines = self.raw.splitlines(0) + for l in lines: + # span and div escape for customizing and embedding raw text + if (l.startswith('#$#') + or l.startswith('#%#') + or l.startswith('#@#')): + newlines.append(l) + else: + # kludge for line spans in css,xhtml + if self.markup in ['XHTML','CSS']: + newlines.append(self.LINESTART+' '+start+l) + else: + newlines.append(start+l) + self.raw = "\n".join(newlines)+'\n'# plus an extra newline at the end + + # Gather lines + while 1: + pos = self.raw.find('\n', pos) + 1 + if not pos: break + self.lines.append(pos) + self.lines.append(len(self.raw)) + + # Wrap text in a filelike object + self.pos = 0 + text = StringIO.StringIO(self.raw) + + # Markup start + if self.addEnds: + self._doPageStart() + else: + self._doSnippetStart() + + ## Tokenize calls the __call__ + ## function for each token till done. + # Parse the source and write out the results. + try: + tokenize.tokenize(text.readline, self) + except tokenize.TokenError as ex: + msg = ex[0] + line = ex[1][0] + self.out.write("<h3>ERROR: %s</h3>%s\n"% + (msg, self.raw[self.lines[line]:])) + #traceback.print_exc() + + # Markup end + if self.addEnds: + self._doPageEnd() + else: + self._doSnippetEnd() + + def __call__(self, toktype, toktext, srow_col, erow_col, line): + """Token handler. Order is important do not rearrange.""" + self.line = line + srow, scol = srow_col + erow, ecol = erow_col + # Calculate new positions + oldpos = self.pos + newpos = self.lines[srow] + scol + self.pos = newpos + len(toktext) + # Handle newlines + if toktype in (token.NEWLINE, tokenize.NL): + self.decoratorFlag = self.argFlag = 0 + # kludge for line spans in css,xhtml + if self.markup in ['XHTML','CSS']: + self.out.write('</span>') + self.out.write('\n') + return + + # Send the original whitespace, and tokenize backslashes if present. + # Tokenizer.py just sends continued line backslashes with whitespace. + # This is a hack to tokenize continued line slashes as operators. + # Should continued line backslashes be treated as operators + # or some other token? + + if newpos > oldpos: + if self.raw[oldpos:newpos].isspace(): + # consume a single space after linestarts and linenumbers + # had to have them so tokenizer could seperate them. + # multiline strings are handled by do_Text functions + if self.lasttext != self.LINESTART \ + and self.lasttext != self.LINENUMHOLDER: + self.out.write(self.raw[oldpos:newpos]) + else: + self.out.write(self.raw[oldpos+1:newpos]) + else: + slash = self.raw[oldpos:newpos].find('\\')+oldpos + self.out.write(self.raw[oldpos:slash]) + getattr(self, '_send%sText'%(self.markup))(OPERATOR, '\\') + self.linenum+=1 + # kludge for line spans in css,xhtml + if self.markup in ['XHTML','CSS']: + self.out.write('</span>') + self.out.write(self.raw[slash+1:newpos]) + + # Skip indenting tokens + if toktype in (token.INDENT, token.DEDENT): + self.pos = newpos + return + + # Look for operators + if token.LPAR <= toktype and toktype <= token.OP: + # Trap decorators py2.4 > + if toktext == '@': + toktype = DECORATOR + # Set a flag if this was the decorator start so + # the decorator name and arguments can be identified + self.decoratorFlag = self.argFlag = 1 + else: + if self.doArgs: + # Find the start for arguments + if toktext == '(' and self.argFlag: + self.argFlag = 2 + # Find the end for arguments + elif toktext == ':': + self.argFlag = 0 + ## Seperate the diffrent operator types + # Brackets + if self.doBrackets and toktext in ['[',']','(',')','{','}']: + toktype = BRACKETS + # Math operators + elif self.doMathOps and toktext in ['*=','**=','-=','+=','|=', + '%=','>>=','<<=','=','^=', + '/=', '+','-','**','*','/','%']: + toktype = MATH_OPERATOR + # Operator + else: + toktype = OPERATOR + # example how flags should work. + # def fun(arg=argvalue,arg2=argvalue2): + # 0 1 2 A 1 N 2 A 1 N 0 + if toktext == "=" and self.argFlag == 2: + self.argFlag = 1 + elif toktext == "," and self.argFlag == 1: + self.argFlag = 2 + # Look for keywords + elif toktype == NAME and keyword.iskeyword(toktext): + toktype = KEYWORD + # Set a flag if this was the class / def start so + # the class / def name and arguments can be identified + if toktext in ['class', 'def']: + if toktext =='class' and \ + not line[:line.find('class')].endswith('.'): + self.classFlag = self.argFlag = 1 + elif toktext == 'def' and \ + not line[:line.find('def')].endswith('.'): + self.defFlag = self.argFlag = 1 + else: + # must have used a keyword as a name i.e. self.class + toktype = ERRORTOKEN + + # Look for class, def, decorator name + elif (self.classFlag or self.defFlag or self.decoratorFlag) \ + and self.doNames: + if self.classFlag: + self.classFlag = 0 + toktype = CLASS_NAME + elif self.defFlag: + self.defFlag = 0 + toktype = DEF_NAME + elif self.decoratorFlag: + self.decoratorFlag = 0 + toktype = DECORATOR_NAME + + # Look for strings + # Order of evaluation is important do not change. + elif toktype == token.STRING: + text = toktext.lower() + # TRIPLE DOUBLE QUOTE's + if (text[:3] == '"""'): + toktype = TRIPLEDOUBLEQUOTE + elif (text[:4] == 'r"""'): + toktype = TRIPLEDOUBLEQUOTE_R + elif (text[:4] == 'u"""' or + text[:5] == 'ur"""'): + toktype = TRIPLEDOUBLEQUOTE_U + # DOUBLE QUOTE's + elif (text[:1] == '"'): + toktype = DOUBLEQUOTE + elif (text[:2] == 'r"'): + toktype = DOUBLEQUOTE_R + elif (text[:2] == 'u"' or + text[:3] == 'ur"'): + toktype = DOUBLEQUOTE_U + # TRIPLE SINGLE QUOTE's + elif (text[:3] == "'''"): + toktype = TRIPLESINGLEQUOTE + elif (text[:4] == "r'''"): + toktype = TRIPLESINGLEQUOTE_R + elif (text[:4] == "u'''" or + text[:5] == "ur'''"): + toktype = TRIPLESINGLEQUOTE_U + # SINGLE QUOTE's + elif (text[:1] == "'"): + toktype = SINGLEQUOTE + elif (text[:2] == "r'"): + toktype = SINGLEQUOTE_R + elif (text[:2] == "u'" or + text[:3] == "ur'"): + toktype = SINGLEQUOTE_U + + # test for invalid string declaration + if self.lasttext.lower() == 'ru': + toktype = ERRORTOKEN + + # Look for comments + elif toktype == COMMENT: + if toktext[:2] == "##": + toktype = DOUBLECOMMENT + elif toktext[:3] == '#$#': + toktype = TEXT + self.textFlag = 'SPAN' + toktext = toktext[3:] + elif toktext[:3] == '#%#': + toktype = TEXT + self.textFlag = 'DIV' + toktext = toktext[3:] + elif toktext[:3] == '#@#': + toktype = TEXT + self.textFlag = 'RAW' + toktext = toktext[3:] + if self.doURL: + # this is a 'fake helper function' + # url(URI,Alias_name) or url(URI) + url_pos = toktext.find('url(') + if url_pos != -1: + before = toktext[:url_pos] + url = toktext[url_pos+4:] + splitpoint = url.find(',') + endpoint = url.find(')') + after = url[endpoint+1:] + url = url[:endpoint] + if splitpoint != -1: + urlparts = url.split(',',1) + toktext = '%s<a href="%s">%s</a>%s'%( + before,urlparts[0],urlparts[1].lstrip(),after) + else: + toktext = '%s<a href="%s">%s</a>%s'%(before,url,url,after) + + # Seperate errors from decorators + elif toktype == ERRORTOKEN: + # Bug fix for < py2.4 + # space between decorators + if self.argFlag and toktext.isspace(): + #toktype = NAME + self.out.write(toktext) + return + # Bug fix for py2.2 linenumbers with decorators + elif toktext.isspace(): + # What if we have a decorator after a >>> or ... + #p = line.find('@') + #if p >= 0 and not line[:p].isspace(): + #self.out.write(toktext) + #return + if self.skip: + self.skip=0 + return + else: + self.out.write(toktext) + return + # trap decorators < py2.4 + elif toktext == '@': + toktype = DECORATOR + # Set a flag if this was the decorator start so + # the decorator name and arguments can be identified + self.decoratorFlag = self.argFlag = 1 + + # Seperate args from names + elif (self.argFlag == 2 and + toktype == NAME and + toktext != 'None' and + self.doArgs): + toktype = ARGS + + # Look for line numbers + # The conversion code for them is in the send_text functions. + if toktext in [self.LINENUMHOLDER,self.LINESTART]: + toktype = LINENUMBER + # if we don't have linenumbers set flag + # to skip the trailing space from linestart + if toktext == self.LINESTART and not self.dolinenums \ + or toktext == self.LINENUMHOLDER: + self.skip=1 + + + # Skip blank token that made it thru + ## bugfix for the last empty tag. + if toktext == '': + return + + # Last token text history + self.lasttext = toktext + + # escape all but the urls in the comments + if toktype in (DOUBLECOMMENT, COMMENT): + if toktext.find('<a href=') == -1: + toktext = escape(toktext) + else: + pass + elif toktype == TEXT: + pass + else: + toktext = escape(toktext) + + # Send text for any markup + getattr(self, '_send%sText'%(self.markup))(toktype, toktext) + return + + ################################################################# Helpers + + def _doSnippetStart(self): + if self.markup == 'HTML': + # Start of html snippet + self.out.write('<pre>\n') + else: + # Start of css/xhtml snippet + self.out.write(self.colors.get(CODESTART,'<pre class="py">\n')) + + def _doSnippetEnd(self): + # End of html snippet + self.out.write(self.colors.get(CODEEND,'</pre>\n')) + + ######################################################## markup selectors + + def _getFile(self, filepath): + try: + _file = open(filepath,'r') + content = _file.read() + _file.close() + except: + traceback.print_exc() + content = '' + return content + + def _doPageStart(self): + getattr(self, '_do%sStart'%(self.markup))() + + def _doPageHeader(self): + if self.header != None: + if self.header.find('#$#') != -1 or \ + self.header.find('#$#') != -1 or \ + self.header.find('#%#') != -1: + self.out.write(self.header[3:]) + else: + if self.header != '': + self.header = self._getFile(self.header) + getattr(self, '_do%sHeader'%(self.markup))() + + def _doPageFooter(self): + if self.footer != None: + if self.footer.find('#$#') != -1 or \ + self.footer.find('#@#') != -1 or \ + self.footer.find('#%#') != -1: + self.out.write(self.footer[3:]) + else: + if self.footer != '': + self.footer = self._getFile(self.footer) + getattr(self, '_do%sFooter'%(self.markup))() + + def _doPageEnd(self): + getattr(self, '_do%sEnd'%(self.markup))() + + ################################################### color/style retrieval + ## Some of these are not used anymore but are kept for documentation + + def _getLineNumber(self): + num = self.linenum + self.linenum+=1 + return str(num).rjust(5)+" " + + def _getTags(self, key): + # style tags + return self.colors.get(key, self.colors[NAME])[0] + + def _getForeColor(self, key): + # get text foreground color, if not set to black + color = self.colors.get(key, self.colors[NAME])[1] + if color[:1] != '#': + color = '#000000' + return color + + def _getBackColor(self, key): + # get text background color + return self.colors.get(key, self.colors[NAME])[2] + + def _getPageColor(self): + # get page background color + return self.colors.get(PAGEBACKGROUND, '#FFFFFF') + + def _getStyle(self, key): + # get the token style from the color dictionary + return self.colors.get(key, self.colors[NAME]) + + def _getMarkupClass(self, key): + # get the markup class name from the markup dictionary + return MARKUPDICT.get(key, MARKUPDICT[NAME]) + + def _getDocumentCreatedBy(self): + return '<!--This document created by %s ver.%s on: %s-->\n'%( + __title__,__version__,time.ctime()) + + ################################################### HTML markup functions + + def _doHTMLStart(self): + # Start of html page + self.out.write('<!DOCTYPE html PUBLIC \ +"-//W3C//DTD HTML 4.01//EN">\n') + self.out.write('<html><head><title>%s</title>\n'%(self.title)) + self.out.write(self._getDocumentCreatedBy()) + self.out.write('<meta http-equiv="Content-Type" \ +content="text/html;charset=iso-8859-1">\n') + # Get background + self.out.write('</head><body bgcolor="%s">\n'%self._getPageColor()) + self._doPageHeader() + self.out.write('<pre>') + + def _getHTMLStyles(self, toktype, toktext): + # Get styles + tags, color = self.colors.get(toktype, self.colors[NAME])[:2]# + tagstart=[] + tagend=[] + # check for styles and set them if needed. + if 'b' in tags:#Bold + tagstart.append('<b>') + tagend.append('</b>') + if 'i' in tags:#Italics + tagstart.append('<i>') + tagend.append('</i>') + if 'u' in tags:#Underline + tagstart.append('<u>') + tagend.append('</u>') + # HTML tags should be paired like so : <b><i><u>Doh!</u></i></b> + tagend.reverse() + starttags="".join(tagstart) + endtags="".join(tagend) + return starttags,endtags,color + + def _sendHTMLText(self, toktype, toktext): + numberlinks = self.numberlinks + + # If it is an error, set a red box around the bad tokens + # older browsers should ignore it + if toktype == ERRORTOKEN: + style = ' style="border: solid 1.5pt #FF0000;"' + else: + style = '' + # Get styles + starttag, endtag, color = self._getHTMLStyles(toktype, toktext) + # This is a hack to 'fix' multi-line strings. + # Multi-line strings are treated as only one token + # even though they can be several physical lines. + # That makes it hard to spot the start of a line, + # because at this level all we know about are tokens. + + if toktext.count(self.LINENUMHOLDER): + # rip apart the string and separate it by line. + # count lines and change all linenum token to line numbers. + # embedded all the new font tags inside the current one. + # Do this by ending the tag first then writing our new tags, + # then starting another font tag exactly like the first one. + if toktype == LINENUMBER: + splittext = toktext.split(self.LINENUMHOLDER) + else: + splittext = toktext.split(self.LINENUMHOLDER+' ') + store = [] + store.append(splittext.pop(0)) + lstarttag, lendtag, lcolor = self._getHTMLStyles(LINENUMBER, toktext) + count = len(splittext) + for item in splittext: + num = self._getLineNumber() + if numberlinks: + numstrip = num.strip() + content = '<a name="%s" href="#%s">%s</a>' \ + %(numstrip,numstrip,num) + else: + content = num + if count <= 1: + endtag,starttag = '','' + linenumber = ''.join([endtag,'<font color=', lcolor, '>', + lstarttag, content, lendtag, '</font>' ,starttag]) + store.append(linenumber+item) + toktext = ''.join(store) + # send text + ## Output optimization + # skip font tag if black text, but styles will still be sent. (b,u,i) + if color !='#000000': + startfont = '<font color="%s"%s>'%(color, style) + endfont = '</font>' + else: + startfont, endfont = ('','') + if toktype != LINENUMBER: + self.out.write(''.join([startfont,starttag, + toktext,endtag,endfont])) + else: + self.out.write(toktext) + return + + def _doHTMLHeader(self): + # Optional + if self.header != '': + self.out.write('%s\n'%self.header) + else: + color = self._getForeColor(NAME) + self.out.write('<b><font color="%s"># %s \ + <br># %s</font></b><hr>\n'% + (color, self.title, time.ctime())) + + def _doHTMLFooter(self): + # Optional + if self.footer != '': + self.out.write('%s\n'%self.footer) + else: + color = self._getForeColor(NAME) + self.out.write('<b><font color="%s"> \ + <hr># %s<br># %s</font></b>\n'% + (color, self.title, time.ctime())) + + def _doHTMLEnd(self): + # End of html page + self.out.write('</pre>\n') + # Write a little info at the bottom + self._doPageFooter() + self.out.write('</body></html>\n') + + #################################################### CSS markup functions + + def _getCSSStyle(self, key): + # Get the tags and colors from the dictionary + tags, forecolor, backcolor = self._getStyle(key) + style=[] + border = None + bordercolor = None + tags = tags.lower() + if tags: + # get the border color if specified + # the border color will be appended to + # the list after we define a border + if '#' in tags:# border color + start = tags.find('#') + end = start + 7 + bordercolor = tags[start:end] + tags.replace(bordercolor,'',1) + # text styles + if 'b' in tags:# Bold + style.append('font-weight:bold;') + else: + style.append('font-weight:normal;') + if 'i' in tags:# Italic + style.append('font-style:italic;') + if 'u' in tags:# Underline + style.append('text-decoration:underline;') + # border size + if 'l' in tags:# thick border + size='thick' + elif 'm' in tags:# medium border + size='medium' + elif 't' in tags:# thin border + size='thin' + else:# default + size='medium' + # border styles + if 'n' in tags:# inset border + border='inset' + elif 'o' in tags:# outset border + border='outset' + elif 'r' in tags:# ridge border + border='ridge' + elif 'g' in tags:# groove border + border='groove' + elif '=' in tags:# double border + border='double' + elif '.' in tags:# dotted border + border='dotted' + elif '-' in tags:# dashed border + border='dashed' + elif 's' in tags:# solid border + border='solid' + # border type check + seperate_sides=0 + for side in ['<','>','^','v']: + if side in tags: + seperate_sides+=1 + # border box or seperate sides + if seperate_sides==0 and border: + style.append('border: %s %s;'%(border,size)) + else: + if border == None: + border = 'solid' + if 'v' in tags:# bottom border + style.append('border-bottom:%s %s;'%(border,size)) + if '<' in tags:# left border + style.append('border-left:%s %s;'%(border,size)) + if '>' in tags:# right border + style.append('border-right:%s %s;'%(border,size)) + if '^' in tags:# top border + style.append('border-top:%s %s;'%(border,size)) + else: + style.append('font-weight:normal;')# css inherited style fix + # we have to define our borders before we set colors + if bordercolor: + style.append('border-color:%s;'%bordercolor) + # text forecolor + style.append('color:%s;'% forecolor) + # text backcolor + if backcolor: + style.append('background-color:%s;'%backcolor) + return (self._getMarkupClass(key),' '.join(style)) + + def _sendCSSStyle(self, external=0): + """ create external and internal style sheets""" + styles = [] + external += self.external + if not external: + styles.append('<style type="text/css">\n<!--\n') + # Get page background color and write styles ignore any we don't know + styles.append('body { background:%s; }\n'%self._getPageColor()) + # write out the various css styles + for key in MARKUPDICT: + styles.append('.%s { %s }\n'%self._getCSSStyle(key)) + # If you want to style the pre tag you must modify the color dict. + # Example: + # lite[PY] = .py {border: solid thin #000000;background:#555555}\n''' + styles.append(self.colors.get(PY, '.py { }\n')) + # Extra css can be added here + # add CSSHOOK to the color dict if you need it. + # Example: + #lite[CSSHOOK] = """.mytag { border: solid thin #000000; } \n + # .myothertag { font-weight:bold; )\n""" + styles.append(self.colors.get(CSSHOOK,'')) + if not self.external: + styles.append('--></style>\n') + return ''.join(styles) + + def _doCSSStart(self): + # Start of css/html 4.01 page + self.out.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">\n') + self.out.write('<html><head><title>%s</title>\n'%(self.title)) + self.out.write(self._getDocumentCreatedBy()) + self.out.write('<meta http-equiv="Content-Type" \ +content="text/html;charset=iso-8859-1">\n') + self._doCSSStyleSheet() + self.out.write('</head>\n<body>\n') + # Write a little info at the top. + self._doPageHeader() + self.out.write(self.colors.get(CODESTART,'<pre class="py">\n')) + return + + def _doCSSStyleSheet(self): + if not self.external: + # write an embedded style sheet + self.out.write(self._sendCSSStyle()) + else: + # write a link to an external style sheet + self.out.write('<link rel="stylesheet" \ +href="pystyle.css" type="text/css">') + return + + def _sendCSSText(self, toktype, toktext): + # This is a hack to 'fix' multi-line strings. + # Multi-line strings are treated as only one token + # even though they can be several physical lines. + # That makes it hard to spot the start of a line, + # because at this level all we know about are tokens. + markupclass = MARKUPDICT.get(toktype, MARKUPDICT[NAME]) + # if it is a LINENUMBER type then we can skip the rest + if toktext == self.LINESTART and toktype == LINENUMBER: + self.out.write('<span class="py_line">') + return + if toktext.count(self.LINENUMHOLDER): + # rip apart the string and separate it by line + # count lines and change all linenum token to line numbers + # also convert linestart and lineend tokens + # <linestart> <lnumstart> lnum <lnumend> text <lineend> + ################################################# + newmarkup = MARKUPDICT.get(LINENUMBER, MARKUPDICT[NAME]) + lstartspan = '<span class="%s">'%(newmarkup) + if toktype == LINENUMBER: + splittext = toktext.split(self.LINENUMHOLDER) + else: + splittext = toktext.split(self.LINENUMHOLDER+' ') + store = [] + # we have already seen the first linenumber token + # so we can skip the first one + store.append(splittext.pop(0)) + for item in splittext: + num = self._getLineNumber() + if self.numberlinks: + numstrip = num.strip() + content= '<a name="%s" href="#%s">%s</a>' \ + %(numstrip,numstrip,num) + else: + content = num + linenumber= ''.join([lstartspan,content,'</span>']) + store.append(linenumber+item) + toktext = ''.join(store) + if toktext.count(self.LINESTART): + # wraps the textline in a line span + # this adds a lot of kludges, is it really worth it? + store = [] + parts = toktext.split(self.LINESTART+' ') + # handle the first part differently + # the whole token gets wraqpped in a span later on + first = parts.pop(0) + # place spans before the newline + pos = first.rfind('\n') + if pos != -1: + first=first[:pos]+'</span></span>'+first[pos:] + store.append(first) + #process the rest of the string + for item in parts: + #handle line numbers if present + if self.dolinenums: + item = item.replace('</span>', + '</span><span class="%s">'%(markupclass)) + else: + item = '<span class="%s">%s'%(markupclass,item) + # add endings for line and string tokens + pos = item.rfind('\n') + if pos != -1: + item=item[:pos]+'</span></span>\n' + store.append(item) + # add start tags for lines + toktext = '<span class="py_line">'.join(store) + # Send text + if toktype != LINENUMBER: + if toktype == TEXT and self.textFlag == 'DIV': + startspan = '<div class="%s">'%(markupclass) + endspan = '</div>' + elif toktype == TEXT and self.textFlag == 'RAW': + startspan,endspan = ('','') + else: + startspan = '<span class="%s">'%(markupclass) + endspan = '</span>' + self.out.write(''.join([startspan, toktext, endspan])) + else: + self.out.write(toktext) + return + + def _doCSSHeader(self): + if self.header != '': + self.out.write('%s\n'%self.header) + else: + name = MARKUPDICT.get(NAME) + self.out.write('<div class="%s"># %s <br> \ +# %s</div><hr>\n'%(name, self.title, time.ctime())) + + def _doCSSFooter(self): + # Optional + if self.footer != '': + self.out.write('%s\n'%self.footer) + else: + self.out.write('<hr><div class="%s"># %s <br> \ +# %s</div>\n'%(MARKUPDICT.get(NAME),self.title, time.ctime())) + + def _doCSSEnd(self): + # End of css/html page + self.out.write(self.colors.get(CODEEND,'</pre>\n')) + # Write a little info at the bottom + self._doPageFooter() + self.out.write('</body></html>\n') + return + + ################################################## XHTML markup functions + + def _doXHTMLStart(self): + # XHTML is really just XML + HTML 4.01. + # We only need to change the page headers, + # and a few tags to get valid XHTML. + # Start of xhtml page + self.out.write('<?xml version="1.0"?>\n \ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\n \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n \ +<html xmlns="http://www.w3.org/1999/xhtml">\n') + self.out.write('<head><title>%s</title>\n'%(self.title)) + self.out.write(self._getDocumentCreatedBy()) + self.out.write('<meta http-equiv="Content-Type" \ +content="text/html;charset=iso-8859-1"/>\n') + self._doXHTMLStyleSheet() + self.out.write('</head>\n<body>\n') + # Write a little info at the top. + self._doPageHeader() + self.out.write(self.colors.get(CODESTART,'<pre class="py">\n')) + return + + def _doXHTMLStyleSheet(self): + if not self.external: + # write an embedded style sheet + self.out.write(self._sendCSSStyle()) + else: + # write a link to an external style sheet + self.out.write('<link rel="stylesheet" \ +href="pystyle.css" type="text/css"/>\n') + return + + def _sendXHTMLText(self, toktype, toktext): + self._sendCSSText(toktype, toktext) + + def _doXHTMLHeader(self): + # Optional + if self.header: + self.out.write('%s\n'%self.header) + else: + name = MARKUPDICT.get(NAME) + self.out.write('<div class="%s"># %s <br/> \ +# %s</div><hr/>\n '%( + name, self.title, time.ctime())) + + def _doXHTMLFooter(self): + # Optional + if self.footer: + self.out.write('%s\n'%self.footer) + else: + self.out.write('<hr/><div class="%s"># %s <br/> \ +# %s</div>\n'%(MARKUPDICT.get(NAME), self.title, time.ctime())) + + def _doXHTMLEnd(self): + self._doCSSEnd() + +############################################################################# + +if __name__ == '__main__': + cli() + +############################################################################# +# PySourceColor.py +# 2004, 2005 M.E.Farmer Jr. +# Python license |