forked from I2P_Developers/i2p.www

* ctags are case-sensitive, and the dataspecs use CamelCase. * HTML anchor tags are case-sensitive. The old specs used CamelCase to match the ctags, and the existing documentation references them extensively. * reStructuredText links are case-insensitive, and the HTML anchor tags that it generates are lower case. Therefore, the links in the .rst files are given in CamelCase, and the dataspec formatters convert this to lower case for links. In direct HTML references (in specs or other areas of documentation), lower case must be used (to be fixed). Command to generate the file: cd i2p2www/spec && ctags -f spectags --langdef=rst --langmap=rst:.rst --regex-rst=/_type-\([a-zA-Z0-9]+\)/\\1/t,type/ --regex-rst=/_struct-\([a-zA-Z0-9]+\)/\\1/s,struct/ --regex-rst=/_msg-\([a-zA-Z]+\)/\\1/m,msg/ -R -n *.rst
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() + '/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
|