diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-01-18 01:06:26 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-01-18 01:06:26 +0100 |
commit | 4eecf36b02f3dee502d97ac1d4b72d19d61da4ce (patch) | |
tree | a2cd70078019a1e98280040c15d77c26ab9d2a5e /exts | |
parent | 89602bbb777f8fb881b6727af9522f9196e2da16 (diff) | |
download | docs-4eecf36b02f3dee502d97ac1d4b72d19d61da4ce.tar.gz docs-4eecf36b02f3dee502d97ac1d4b72d19d61da4ce.tar.bz2 docs-4eecf36b02f3dee502d97ac1d4b72d19d61da4ce.zip |
restructuring and linking extension
Diffstat (limited to 'exts')
-rw-r--r-- | exts/tsref.py | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/exts/tsref.py b/exts/tsref.py new file mode 100644 index 00000000..abd2c90e --- /dev/null +++ b/exts/tsref.py @@ -0,0 +1,202 @@ +from pygments.util import get_bool_opt +from pygments.token import Name, Comment, Token, _TokenType +from pygments.filter import Filter +from sphinx.highlighting import PygmentsBridge +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.pygments_styles import SphinxStyle +from pygments.formatters import HtmlFormatter +from docutils import nodes +from docutils.nodes import make_id +import re + + +_escape_html_table = { + ord('&'): u'&', + ord('<'): u'<', + ord('>'): u'>', + ord('"'): u'"', + ord("'"): u''', +} + + +class LinkingHtmlFormatter(HtmlFormatter): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._builder = kwargs['_builder'] + + def _fmt(self, value, tok): + cls = self._get_css_class(tok) + href = tok_getprop(tok, "href") + if href: + value = '<a style="color:inherit" href="%s">%s</a>' % (href, value) + print("got target!!!!!!!!!!!") + if cls is None or cls == "": + return value + return '<span class="%s">%s</span>' % (cls, value) + + + + def _format_lines(self, tokensource): + """ + Just format the tokens, without any wrapping tags. + Yield individual lines. + """ + lsep = self.lineseparator + escape_table = _escape_html_table + + line = '' + for ttype, value in tokensource: + link = get_annotation(ttype, "link") + if link: + print("got link", link) + + parts = value.translate(escape_table).split('\n') + + if len(parts) == 0: + # empty token, usually should not happen + pass + elif len(parts) == 1: + # no newline before or after token + line += self._fmt(parts[0], ttype) + else: + line += self._fmt(parts[0], ttype) + yield 1, line + lsep + for part in parts[1:-1]: + yield 1, self._fmt(part, ttype) + lsep + line = self._fmt(parts[-1], ttype) + + if line: + yield 1, line + lsep + + + +class MyPygmentsBridge(PygmentsBridge): + def __init__(self, builder, trim_doctest_flags): + self.dest = "html" + self.trim_doctest_flags = trim_doctest_flags + self.formatter_args = {'style': SphinxStyle, '_builder': builder} + self.formatter = LinkingHtmlFormatter + + +class MyHtmlBuilder(StandaloneHTMLBuilder): + name = "html-linked" + def init_highlighter(self): + if self.config.pygments_style is not None: + style = self.config.pygments_style + elif self.theme: + style = self.theme.get_confstr('theme', 'pygments_style', 'none') + else: + style = 'sphinx' + self.highlighter = MyPygmentsBridge(self, self.config.trim_doctest_flags) + + def write_doc(self, docname, doctree): + print("writing doc", docname) + self._current_docname = docname + super().write_doc(docname, doctree) + + +def get_annotation(tok, key): + if not hasattr(tok, "kv"): + return None + return tok.kv.get(key) + +def copy_token(tok): + new_tok = _TokenType(tok) + # This part is very fragile against API changes ... + new_tok.subtypes = set(tok.subtypes) + new_tok.parent = tok.parent + return new_tok + +def tok_setprop(tok, key, value): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + e = token_props[tokid] = (tok, {}) + _, kv = e + kv[key] = value + +def tok_getprop(tok, key): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + return None + _, kv = e + return kv.get(key) + + +link_reg = re.compile(r"`([^`]+)`_") + +# map from token id to props +token_props = {} + +id_to_doc = {} + + +class LinkFilter(Filter): + def __init__(self, app, **options): + self.app = app + Filter.__init__(self, **options) + + def filter(self, lexer, stream): + for ttype, value in stream: + if ttype in Token.Keyword.Type: + defname = make_id('tsref-type-' + value); + print("looking for", defname) + t = copy_token(ttype) + if defname in id_to_doc: + docname = id_to_doc[defname] + print("found", defname, "in", docname) + href = self.app.builder.get_target_uri(docname) + "#" + defname + tok_setprop(t, "href", href) + + yield t, value + elif ttype in Token.Comment: + last = 0 + for m in re.finditer(link_reg, value): + print("got link comment", value) + pre = value[last:m.start()] + if pre: + yield ttype, pre + t = copy_token(ttype) + id = make_id(m.group(1)) + if id in id_to_doc: + docname = id_to_doc[id] + href = self.app.builder.get_target_uri(docname) + "#" + id + tok_setprop(t, "href", href) + else: + print("target id not found:", id) + print("old", ttype) + print("new", t) + yield t, m.group(1) + last = m.end() + post = value[last:] + if post: + yield ttype, post + else: + yield ttype, value + + + +def remember_targets(app, doctree, docname): + for node in doctree.traverse(): + if not isinstance(node, nodes.Element): + continue + ids = node.get("ids") + if ids: + for id in ids: + id_to_doc[id] = docname + + +def setup(app): + from sphinx.highlighting import lexers + from pygments.lexers import TypeScriptLexer + from pygments.token import Name + from pygments.filters import NameHighlightFilter + lexer = TypeScriptLexer() + lexer.add_filter(LinkFilter(app)) + app.add_lexer('tsref', lexer) + app.add_builder(MyHtmlBuilder) + app.connect("doctree-resolved", remember_targets) + + + |