import re from docutils import nodes, utils from docutils.parsers.rst import Directive, directives, roles from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexers import TextLexer, get_lexer_by_name import pelican.settings as pys class Pygments(Directive): """ Source code syntax highlighting. """ required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True option_spec = { 'anchorlinenos': directives.flag, 'classprefix': directives.unchanged, 'hl_lines': directives.unchanged, 'lineanchors': directives.unchanged, 'linenos': directives.unchanged, 'linenospecial': directives.nonnegative_int, 'linenostart': directives.nonnegative_int, 'linenostep': directives.nonnegative_int, 'lineseparator': directives.unchanged, 'linespans': directives.unchanged, 'nobackground': directives.flag, 'nowrap': directives.flag, 'tagsfile': directives.unchanged, 'tagurlformat': directives.unchanged, } has_content = True def run(self): self.assert_has_content() try: lexer = get_lexer_by_name(self.arguments[0]) except ValueError: # no lexer found - use the text one instead of an exception lexer = TextLexer() # Fetch the defaults if pys.PYGMENTS_RST_OPTIONS is not None: for k, v in pys.PYGMENTS_RST_OPTIONS.items(): # Locally set options overrides the defaults if k not in self.options: self.options[k] = v if ('linenos' in self.options and self.options['linenos'] not in ('table', 'inline')): if self.options['linenos'] == 'none': self.options.pop('linenos') else: self.options['linenos'] = 'table' for flag in ('nowrap', 'nobackground', 'anchorlinenos'): if flag in self.options: self.options[flag] = True # noclasses should already default to False, but just in case... formatter = HtmlFormatter(noclasses=False, **self.options) parsed = highlight('\n'.join(self.content), lexer, formatter) return [nodes.raw('', parsed, format='html')] directives.register_directive('code-block', Pygments) directives.register_directive('sourcecode', Pygments) _abbr_re = re.compile(r'\((.*)\)$', re.DOTALL) class abbreviation(nodes.Inline, nodes.TextElement): pass def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) m = _abbr_re.search(text) if m is None: return [abbreviation(text, text)], [] abbr = text[:m.start()].strip() expl = m.group(1) return [abbreviation(abbr, abbr, explanation=expl)], [] roles.register_local_role('abbr', abbr_role)