|
| 1 | +from sphinx.highlighting import lexers, PygmentsBridge |
| 2 | +from pygments.style import Style |
| 3 | +from pygments.formatters import HtmlFormatter |
| 4 | +from pygments.token import Keyword, Name, Comment, String, Error, \ |
| 5 | + Number, Operator, Generic, Whitespace, Punctuation, Other, Literal |
| 6 | + |
| 7 | +from sphinx.writers.html import HTMLTranslator |
| 8 | +from docutils import nodes |
| 9 | +from sphinx.locale import admonitionlabels, lazy_gettext |
| 10 | + |
| 11 | +customadmonitionlabels = admonitionlabels |
| 12 | +l_ = lazy_gettext |
| 13 | +customadmonitionlabels['best-practice'] = l_('Best Practice') |
| 14 | + |
| 15 | +def _getType(path): |
| 16 | + return path[:path.find('/')] |
| 17 | + |
| 18 | +def _isIndex(path): |
| 19 | + return 'index' in path |
| 20 | + |
| 21 | +class SensioHTMLTranslator(HTMLTranslator): |
| 22 | + def __init__(self, builder, *args, **kwds): |
| 23 | + HTMLTranslator.__init__(self, builder, *args, **kwds) |
| 24 | + builder.templates.environment.filters['get_type'] = _getType |
| 25 | + builder.templates.environment.tests['index'] = _isIndex |
| 26 | + self.highlightlinenothreshold = 0 |
| 27 | + |
| 28 | + def visit_literal(self, node): |
| 29 | + self.body.append(self.starttag(node, 'tt', '', CLASS='docutils literal')) |
| 30 | + self.body.append('<code>') |
| 31 | + |
| 32 | + def depart_literal(self, node): |
| 33 | + self.body.append('</code>') |
| 34 | + self.body.append('</tt>') |
| 35 | + |
| 36 | + def visit_admonition(self, node, name=''): |
| 37 | + self.body.append(self.starttag(node, 'div', CLASS=('admonition-wrapper'))) |
| 38 | + self.body.append('<div class="' + name + '"></div>') |
| 39 | + self.body.append('<div class="admonition admonition-' + name + '">') |
| 40 | + if name and name != 'seealso': |
| 41 | + node.insert(0, nodes.title(name, customadmonitionlabels[name])) |
| 42 | + self.set_first_last(node) |
| 43 | + |
| 44 | + def depart_admonition(self, node=None): |
| 45 | + self.body.append('</div></div>\n') |
| 46 | + |
| 47 | + def visit_sidebar(self, node): |
| 48 | + self.body.append(self.starttag(node, 'div', CLASS=('admonition-wrapper'))) |
| 49 | + self.body.append('<div class="sidebar"></div>') |
| 50 | + self.body.append('<div class="admonition admonition-sidebar">') |
| 51 | + self.set_first_last(node) |
| 52 | + self.in_sidebar = 1 |
| 53 | + |
| 54 | + def depart_sidebar(self, node): |
| 55 | + self.body.append('</div></div>\n') |
| 56 | + self.in_sidebar = None |
| 57 | + |
| 58 | + # overriden to add a new highlight div around each block |
| 59 | + def visit_literal_block(self, node): |
| 60 | + if node.rawsource != node.astext(): |
| 61 | + # most probably a parsed-literal block -- don't highlight |
| 62 | + return BaseTranslator.visit_literal_block(self, node) |
| 63 | + lang = self.highlightlang |
| 64 | + linenos = node.rawsource.count('\n') >= \ |
| 65 | + self.highlightlinenothreshold - 1 |
| 66 | + highlight_args = node.get('highlight_args', {}) |
| 67 | + if node.has_key('language'): |
| 68 | + # code-block directives |
| 69 | + lang = node['language'] |
| 70 | + highlight_args['force'] = True |
| 71 | + if node.has_key('linenos'): |
| 72 | + linenos = node['linenos'] |
| 73 | + def warner(msg): |
| 74 | + self.builder.warn(msg, (self.builder.current_docname, node.line)) |
| 75 | + highlighted = self.highlighter.highlight_block( |
| 76 | + node.rawsource, lang, warn=warner, linenos=linenos, |
| 77 | + **highlight_args) |
| 78 | + starttag = self.starttag(node, 'div', suffix='', |
| 79 | + CLASS='highlight-%s' % lang) |
| 80 | + self.body.append('<div class="literal-block">' + starttag + highlighted + '</div></div>\n') |
| 81 | + raise nodes.SkipNode |
| 82 | + |
| 83 | +class SensioStyle(Style): |
| 84 | + background_color = "#000000" |
| 85 | + default_style = "" |
| 86 | + |
| 87 | + styles = { |
| 88 | + # No corresponding class for the following: |
| 89 | + #Text: "", # class: '' |
| 90 | + Whitespace: "underline #f8f8f8", # class: 'w' |
| 91 | + Error: "#a40000 border:#ef2929", # class: 'err' |
| 92 | + Other: "#ffffff", # class 'x' |
| 93 | + |
| 94 | + Comment: "italic #B729D9", # class: 'c' |
| 95 | + Comment.Single: "italic #B729D9", # class: 'c1' |
| 96 | + Comment.Multiline: "italic #B729D9", # class: 'cm' |
| 97 | + Comment.Preproc: "noitalic #aaa", # class: 'cp' |
| 98 | + |
| 99 | + Keyword: "#FF8400", # class: 'k' |
| 100 | + Keyword.Constant: "#FF8400", # class: 'kc' |
| 101 | + Keyword.Declaration: "#FF8400", # class: 'kd' |
| 102 | + Keyword.Namespace: "#FF8400", # class: 'kn' |
| 103 | + Keyword.Pseudo: "#FF8400", # class: 'kp' |
| 104 | + Keyword.Reserved: "#FF8400", # class: 'kr' |
| 105 | + Keyword.Type: "#FF8400", # class: 'kt' |
| 106 | + |
| 107 | + Operator: "#E0882F", # class: 'o' |
| 108 | + Operator.Word: "#E0882F", # class: 'ow' - like keywords |
| 109 | + |
| 110 | + Punctuation: "#999999", # class: 'p' |
| 111 | + |
| 112 | + # because special names such as Name.Class, Name.Function, etc. |
| 113 | + # are not recognized as such later in the parsing, we choose them |
| 114 | + # to look the same as ordinary variables. |
| 115 | + Name: "#ffffff", # class: 'n' |
| 116 | + Name.Attribute: "#ffffff", # class: 'na' - to be revised |
| 117 | + Name.Builtin: "#ffffff", # class: 'nb' |
| 118 | + Name.Builtin.Pseudo: "#3465a4", # class: 'bp' |
| 119 | + Name.Class: "#ffffff", # class: 'nc' - to be revised |
| 120 | + Name.Constant: "#ffffff", # class: 'no' - to be revised |
| 121 | + Name.Decorator: "#888", # class: 'nd' - to be revised |
| 122 | + Name.Entity: "#ce5c00", # class: 'ni' |
| 123 | + Name.Exception: "#cc0000", # class: 'ne' |
| 124 | + Name.Function: "#ffffff", # class: 'nf' |
| 125 | + Name.Property: "#ffffff", # class: 'py' |
| 126 | + Name.Label: "#f57900", # class: 'nl' |
| 127 | + Name.Namespace: "#ffffff", # class: 'nn' - to be revised |
| 128 | + Name.Other: "#ffffff", # class: 'nx' |
| 129 | + Name.Tag: "#cccccc", # class: 'nt' - like a keyword |
| 130 | + Name.Variable: "#ffffff", # class: 'nv' - to be revised |
| 131 | + Name.Variable.Class: "#ffffff", # class: 'vc' - to be revised |
| 132 | + Name.Variable.Global: "#ffffff", # class: 'vg' - to be revised |
| 133 | + Name.Variable.Instance: "#ffffff", # class: 'vi' - to be revised |
| 134 | + |
| 135 | + Number: "#1299DA", # class: 'm' |
| 136 | + |
| 137 | + Literal: "#ffffff", # class: 'l' |
| 138 | + Literal.Date: "#ffffff", # class: 'ld' |
| 139 | + |
| 140 | + String: "#56DB3A", # class: 's' |
| 141 | + String.Backtick: "#56DB3A", # class: 'sb' |
| 142 | + String.Char: "#56DB3A", # class: 'sc' |
| 143 | + String.Doc: "italic #B729D9", # class: 'sd' - like a comment |
| 144 | + String.Double: "#56DB3A", # class: 's2' |
| 145 | + String.Escape: "#56DB3A", # class: 'se' |
| 146 | + String.Heredoc: "#56DB3A", # class: 'sh' |
| 147 | + String.Interpol: "#56DB3A", # class: 'si' |
| 148 | + String.Other: "#56DB3A", # class: 'sx' |
| 149 | + String.Regex: "#56DB3A", # class: 'sr' |
| 150 | + String.Single: "#56DB3A", # class: 's1' |
| 151 | + String.Symbol: "#56DB3A", # class: 'ss' |
| 152 | + |
| 153 | + Generic: "#ffffff", # class: 'g' |
| 154 | + Generic.Deleted: "#a40000", # class: 'gd' |
| 155 | + Generic.Emph: "italic #ffffff", # class: 'ge' |
| 156 | + Generic.Error: "#ef2929", # class: 'gr' |
| 157 | + Generic.Heading: "#000080", # class: 'gh' |
| 158 | + Generic.Inserted: "#00A000", # class: 'gi' |
| 159 | + Generic.Output: "#888", # class: 'go' |
| 160 | + Generic.Prompt: "#745334", # class: 'gp' |
| 161 | + Generic.Strong: "bold #ffffff", # class: 'gs' |
| 162 | + Generic.Subheading: "bold #800080", # class: 'gu' |
| 163 | + Generic.Traceback: "bold #a40000", # class: 'gt' |
| 164 | + } |
| 165 | + |
| 166 | +def setup(app): |
| 167 | + app.set_translator('html', SensioHTMLTranslator) |
0 commit comments