122 lines
3.8 KiB
Python
122 lines
3.8 KiB
Python
# -*- coding: utf8 -*-
|
|
|
|
import os
|
|
import sys
|
|
from jinja2 import nodes
|
|
from jinja2.ext import Extension, Markup
|
|
|
|
from pygments import highlight
|
|
from pygments.lexers import get_lexer_by_name, guess_lexer
|
|
from pygments.formatters import HtmlFormatter
|
|
from pygments.util import ClassNotFound
|
|
|
|
try:
|
|
import ctags
|
|
except ImportError:
|
|
ctags = None
|
|
|
|
from flask import g
|
|
|
|
from i2p2www.formatters import I2PHtmlFormatter, TextSpecFormatter
|
|
from i2p2www.lexers import DataSpecLexer
|
|
|
|
|
|
# https://stackoverflow.com/questions/2632199/how-do-i-get-the-path-of-the-current-executed-file-in-python?lq=1
|
|
def we_are_frozen():
|
|
# All of the modules are built-in to the interpreter, e.g., by py2exe
|
|
return hasattr(sys, "frozen")
|
|
|
|
def module_path():
|
|
encoding = sys.getfilesystemencoding()
|
|
if we_are_frozen():
|
|
return os.path.dirname(unicode(sys.executable, encoding))
|
|
return os.path.dirname(unicode(__file__, encoding))
|
|
|
|
|
|
class HighlightExtension(Extension):
|
|
"""Highlight code blocks using Pygments
|
|
|
|
Example::
|
|
|
|
{% highlight 'python' %}
|
|
|
|
from fridge import Beer
|
|
|
|
pint_glass = Beer()
|
|
pint_glass.drink()
|
|
|
|
{% endhighlight %}
|
|
"""
|
|
tags = set(['highlight'])
|
|
|
|
def parse(self, parser):
|
|
lineno = parser.stream.next().lineno
|
|
|
|
# extract the language if available
|
|
# Any additional parameters are passed to HtmlFormatter
|
|
lang = None
|
|
formatter = None
|
|
parameters = []
|
|
while parser.stream.current.type != 'block_end':
|
|
if lang or parameters:
|
|
parser.stream.expect('comma')
|
|
|
|
name = parser.stream.expect('name')
|
|
if name.value in parameters or (name.value == 'lang' and lang) or (name.value == 'formatter' and formatter):
|
|
parser.fail('parameter %r defined twice.' %
|
|
name.value, name.lineno,
|
|
exc=TemplateAssertionError)
|
|
|
|
if parser.stream.current.type == 'assign':
|
|
next(parser.stream)
|
|
if name.value == 'lang':
|
|
lang = parser.parse_expression()
|
|
elif name.value == 'formatter':
|
|
formatter = parser.parse_expression()
|
|
else:
|
|
parameters.append(nodes.Pair(nodes.Const(name.value), parser.parse_expression()))
|
|
|
|
if lang == None:
|
|
lang = nodes.Const(None)
|
|
if formatter == None:
|
|
formatter = nodes.Const('html')
|
|
parameters = nodes.Dict(parameters)
|
|
|
|
# body of the block
|
|
body = parser.parse_statements(['name:endhighlight'], drop_needle=True)
|
|
|
|
return nodes.CallBlock(self.call_method('_highlight', [lang, formatter, parameters]),
|
|
[], [], body).set_lineno(lineno)
|
|
|
|
def _highlight(self, lang, formatter, parameters, caller=None):
|
|
# highlight code using Pygments
|
|
body = caller()
|
|
try:
|
|
if lang is None:
|
|
lexer = guess_lexer(body)
|
|
else:
|
|
lexer = get_lexer_by_name(lang, stripall=False)
|
|
except ClassNotFound as e:
|
|
if lang == 'dataspec':
|
|
lexer = DataSpecLexer(stripall=False)
|
|
else:
|
|
print(e)
|
|
sys.exit(1)
|
|
|
|
if ctags:
|
|
if 'tagsfile' not in parameters:
|
|
parameters['tagsfile'] = module_path() + '/pages/site/spectags'
|
|
|
|
if 'tagurlformat' not in parameters:
|
|
lang = 'en'
|
|
if hasattr(g, 'lang') and g.lang:
|
|
lang = g.lang
|
|
parameters['tagurlformat'] = '/' + lang + '/%(path)s%(fname)s'
|
|
|
|
if formatter == 'textspec':
|
|
formatter = TextSpecFormatter(**parameters)
|
|
else:
|
|
formatter = I2PHtmlFormatter(**parameters)
|
|
code = highlight(Markup(body).unescape(), lexer, formatter)
|
|
return code
|