Files
i2p.www/i2p2www/extensions.py
2023-11-22 14:48:24 -05:00

125 lines
3.9 KiB
Python

# -*- coding: utf8 -*-
from __future__ import absolute_import
from __future__ import print_function
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
import six
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(six.text_type(sys.executable, encoding))
return os.path.dirname(six.text_type(__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() + '/spec/spectags'
if 'tagurlformat' not in parameters:
lang = 'en'
if hasattr(g, 'lang') and g.lang:
lang = g.lang
parameters['tagurlformat'] = '/spec/%(path)s%(fname)s'
if formatter == 'textspec':
formatter = TextSpecFormatter(**parameters)
else:
formatter = I2PHtmlFormatter(**parameters)
code = highlight(Markup(body).unescape(), lexer, formatter)
return code