4 :copyright: Copyright 2019 by Taler Systems SA
11 from pathlib
import Path
13 from docutils
import nodes
14 from typing
import List, Optional, Iterable, Dict, Tuple
15 from typing
import cast
17 from pygments.lexers
import get_lexer_by_name
18 from pygments.filter
import Filter
19 from pygments.token import Literal, Text, Operator, Keyword, Name, Number
22 from pygments.lexer
import RegexLexer, bygroups, include
23 from pygments.formatters
import HtmlFormatter
25 from docutils
import nodes
26 from docutils.nodes
import Element, Node
28 from sphinx.roles
import XRefRole
29 from sphinx.domains
import Domain, ObjType, Index
30 from sphinx.directives
import directives
31 from sphinx.util.docutils
import SphinxDirective
32 from sphinx.util.nodes
import make_refnode
33 from sphinx.util
import logging
34 from sphinx.highlighting
import PygmentsBridge
35 from sphinx.builders.html
import StandaloneHTMLBuilder
36 from sphinx.pygments_styles
import SphinxStyle
38 logger = logging.getLogger(__name__)
43 Directive for a code block with special highlighting or line numbering
48 required_arguments = 1
49 optional_arguments = 0
50 final_argument_whitespace =
False
52 "force": directives.flag,
53 "linenos": directives.flag,
56 "emphasize-lines": directives.unchanged_required,
57 "caption": directives.unchanged_required,
58 "class": directives.class_option,
61 def run(self) -> List[Node]:
62 document = self.state.document
63 code =
"\n".join(self.content)
64 location = self.state_machine.get_source_and_line(self.lineno)
66 linespec = self.options.
get(
"emphasize-lines")
69 nlines =
len(self.content)
70 hl_lines = parselinenos(linespec, nlines)
71 if any(i >= nlines
for i
in hl_lines):
73 __(
"line number spec is out of range(1-%d): %r")
74 % (nlines, self.options[
"emphasize-lines"]),
78 hl_lines = [x + 1
for x
in hl_lines
if x < nlines]
79 except ValueError
as err:
80 return [document.reporter.warning(err, line=self.lineno)]
84 if "dedent" in self.options:
85 location = self.state_machine.get_source_and_line(self.lineno)
86 lines = code.split(
"\n")
87 lines = dedent_lines(lines, self.options[
"dedent"], location=location)
88 code =
"\n".join(lines)
90 literal = nodes.literal_block(code, code)
91 if "linenos" in self.options
or "lineno-start" in self.options:
92 literal[
"linenos"] =
True
93 literal[
"classes"] += self.options.
get(
"class", [])
94 literal[
"force"] =
"force" in self.options
95 literal[
"language"] =
"tsref"
96 extra_args = literal[
"highlight_args"] = {}
97 if hl_lines
is not None:
98 extra_args[
"hl_lines"] = hl_lines
99 if "lineno-start" in self.options:
100 extra_args[
"linenostart"] = self.options[
"lineno-start"]
101 self.set_source_info(literal)
103 caption = self.options.
get(
"caption")
106 literal = container_wrapper(self, literal, caption)
107 except ValueError
as exc:
108 return [document.reporter.warning(exc, line=self.lineno)]
110 tsid =
"tsref-type-" + self.arguments[0]
111 literal[
"ids"].append(tsid)
113 tsname = self.arguments[0]
114 ts = self.env.get_domain(
"ts")
115 ts.add_object(
"type", tsname, self.env.docname, tsid)
121 """TypeScript domain."""
127 "def": TypeScriptDefinition,
132 lowercase=
False, warn_dangling=
True, innernodeclass=nodes.inline
136 dangling_warnings = {
137 "type":
"undefined TypeScript type: %(target)s",
140 def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
142 info = self.
objectsobjects[(str(typ), str(target))]
144 logger.warn(
"type {}/{} not found".format(typ, target))
147 anchor =
"tsref-type-{}".format(str(target))
148 title = typ.upper() +
" " + target
149 return make_refnode(builder, fromdocname, info[0], anchor, contnode, title)
152 """Resolve the pending_xref *node* with the given *target*.
154 The reference comes from an "any" or similar role, which means that Sphinx
157 For now sphinxcontrib-httpdomain doesn't resolve any xref nodes.
160 list of tuples ``('domain:role', newnode)``, where ``'domain:role'``
161 is the name of a role that could have created the same reference,
165 info = self.
objectsobjects[(
"type", str(target))]
169 anchor =
"tsref-type-{}".format(str(target))
170 title =
"TYPE" +
" " + target
171 node = make_refnode(builder, fromdocname, info[0], anchor, contnode, title)
172 ret.append((
"ts:type", node))
176 def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
177 return self.data.setdefault(
181 def add_object(self, objtype: str, name: str, docname: str, labelid: str) ->
None:
182 self.
objectsobjects[objtype, name] = (docname, labelid)
187 For `TypeScript <https://www.typescriptlang.org/>`_ source code.
193 mimetypes = [
"text/x-typescript"]
197 "commentsandwhitespace": [
200 (
r"//.*?\n", Comment.Single),
201 (
r"/\*.*?\*/", Comment.Multiline),
203 "slashstartsregex": [
204 include(
"commentsandwhitespace"),
206 r"/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/" r"([gim]+\b|\B)",
210 (
r"(?=/)", Text, (
"#pop",
"badregex")),
213 "badregex": [(
r"\n", Text,
"#pop")],
215 (
r"[a-zA-Z0-9_?.$]+", Keyword.Type),
218 (
r"\n", Text,
"#pop"),
219 (
r";", Text,
"#pop"),
223 (
r"^(?=\s|/|<!--)", Text,
"slashstartsregex"),
224 include(
"commentsandwhitespace"),
226 r"\+\+|--|~|&&|\?|:|\|\||\\(?=\n)|"
227 r"(<<|>>>?|==?|!=?|[-<>+*%&\|\^/])=?",
231 (
r"[{(\[;,]", Punctuation,
"slashstartsregex"),
232 (
r"[})\].]", Punctuation),
234 r"(for|in|while|do|break|return|continue|switch|case|default|if|else|"
235 r"throw|try|catch|finally|new|delete|typeof|instanceof|void|"
241 r"(var|let|const|with|function)\b",
246 r"(abstract|boolean|byte|char|class|const|debugger|double|enum|export|"
247 r"extends|final|float|goto|implements|import|int|interface|long|native|"
248 r"package|private|protected|public|short|static|super|synchronized|throws|"
249 r"transient|volatile)\b",
252 (
r"(true|false|null|NaN|Infinity|undefined)\b", Keyword.Constant),
254 r"(Array|Boolean|Date|Error|Function|Math|netscape|"
255 r"Number|Object|Packages|RegExp|String|sun|decodeURI|"
256 r"decodeURIComponent|encodeURI|encodeURIComponent|"
257 r"Error|eval|isFinite|isNaN|parseFloat|parseInt|document|this|"
263 r"\b(module)(\s*)(\s*[a-zA-Z0-9_?.$][\w?.$]*)(\s*)",
264 bygroups(Keyword.Reserved, Text, Name.Other, Text),
268 (
r"\b(string|bool|number)\b", Keyword.Type),
270 (
r"\b(constructor|declare|interface|as|AS)\b", Keyword.Reserved),
273 r"(super)(\s*)\(([a-zA-Z0-9,_?.$\s]+\s*)\)",
274 bygroups(Keyword.Reserved, Text),
278 (
r"([a-zA-Z_?.$][\w?.$]*)\(\) \{", Name.Other,
"slashstartsregex"),
281 r"([a-zA-Z0-9_?.$][\w?.$]*)(\s*:\s*)",
282 bygroups(Name.Other, Text),
287 r"\b(type)(\s*)([a-zA-Z0-9_?.$]+)(\s*)(=)(\s*)",
288 bygroups(Keyword.Reserved, Text, Name.Other, Text, Operator, Text),
291 (
r"[$a-zA-Z_][a-zA-Z0-9_]*", Name.Other),
292 (
r"[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?", Number.Float),
293 (
r"0x[0-9a-fA-F]+", Number.Hex),
294 (
r"[0-9]+", Number.Integer),
295 (
r'"(\\\\|\\"|[^"])*"', String.Double),
296 (
r"'(\\\\|\\'|[^'])*'", String.Single),
310 Filter.__init__(self, **options)
314 for m
in re.finditer(literal_reg, value):
315 pre = value[last : m.start()]
327 for ttype, value
in stream:
328 if ttype
in Token.Keyword.Type:
333 elif ttype
in Token.Comment:
335 for m
in re.finditer(link_reg, value):
336 pre = value[last : m.start()]
361 _escape_html_table = {
372 super(LinkingHtmlFormatter, self).
__init__(**kwargs)
381 return '<span style="font-weight: bolder">%s</span>' % (value,)
385 "{}:{}: code block contains xref to '{}' with unsupported trailing underscore".format(
391 if xref.startswith(
'"'):
393 if re.match(
"^[0-9]+$", xref)
is not None:
410 if self.
_bridge_bridge.docname
is None:
414 content = caption
if caption
is not None else value
415 ts = self.
_builder_builder.env.get_domain(
"ts")
416 r1 = ts.objects.get((
"type", xref),
None)
419 self.
_builder_builder.get_relative_uri(self.
_bridge_bridge.docname, r1[0])
424 '<a style="color:inherit;text-decoration:underline" href="%s">%s</a>'
428 std = self.
_builder_builder.env.get_domain(
"std")
429 r2 = std.labels.get(xref.lower(),
None)
432 self.
_builder_builder.get_relative_uri(self.
_bridge_bridge.docname, r2[0])
437 '<a style="color:inherit;text-decoration:underline" href="%s">%s</a>'
440 r3 = std.anonlabels.get(xref.lower(),
None)
443 self.
_builder_builder.get_relative_uri(self.
_bridge_bridge.docname, r3[0])
448 '<a style="color:inherit;text-decoration:underline" href="%s">%s</a>'
453 "{}:{}: code block contains unresolved xref '{}'".format(
461 cls = self._get_css_class(tok)
463 if cls
is None or cls ==
"":
465 return '<span class="%s">%s</span>' % (cls, value)
469 Just format the tokens, without any wrapping tags.
470 Yield individual lines.
472 lsep = self.lineseparator
473 escape_table = _escape_html_table
476 for ttype, value
in tokensource:
479 parts = value.translate(escape_table).split(
"\n")
484 elif len(parts) == 1:
486 line += self.
_fmt_fmt(parts[0], ttype)
488 line += self.
_fmt_fmt(parts[0], ttype)
490 for part
in parts[1:-1]:
491 yield 1, self.
_fmt_fmt(part, ttype) + lsep
492 line = self.
_fmt_fmt(parts[-1], ttype)
503 "style": SphinxStyle,
514 self, source, lang, opts=None, force=False, location=None, **kwargs
516 if isinstance(location, tuple):
517 docname, line = location
519 self.
pathpath = self.
builderbuilder.env.doc2path(docname)
521 elif isinstance(location, Element):
522 self.
lineline = location.line
523 self.
pathpath = location.source
525 return super().
highlight_block(source, lang, opts, force, location, **kwargs)
532 if self.config.pygments_style
is not None:
533 style = self.config.pygments_style
535 style = self.theme.get_confstr(
"theme",
"pygments_style",
"none")
543 if not hasattr(tok,
"kv"):
545 return tok.kv.get(key)
549 new_tok = _TokenType(tok)
551 new_tok.subtypes = set(tok.subtypes)
552 new_tok.parent = tok.parent
558 e = token_props.get(tokid)
560 e = token_props[tokid] = (tok, {})
567 e = token_props.get(tokid)
574 link_reg = re.compile(
r"(?<!`)`([^`<]+)\s*(?:<([^>]+)>)?\s*`_?")
575 literal_reg = re.compile(
r"``([^`]+)``")
581 def __init__(self, **options):
582 super().__init__(**options)
585 app.add_lexer(
"tsref", TsrefLexer)
586 app.add_domain(TypeScriptDomain)
587 app.add_builder(MyHtmlBuilder)
def __init__(self, app, **options)
def _filter_one_literal(self, ttype, value)
def filter(self, lexer, stream)
def __init__(self, **kwargs)
def _fmt(self, value, tok)
def _get_value(self, value, tok)
def _format_lines(self, tokensource)
def init_highlighter(self)
def __init__(self, builder, trim_doctest_flags)
def highlight_block(self, source, lang, opts=None, force=False, location=None, **kwargs)
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode)
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode)
Dict[Tuple[str, str], Tuple[str, str]] objects(self)
None add_object(self, str objtype, str name, str docname, str labelid)
static struct GNUNET_IDENTITY_Handle * id
Handle to identity service.
static int get
Get DID Documement for DID Flag.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
def get_annotation(tok, key)
def tok_getprop(tok, key)
def tok_setprop(tok, key, value)