-
Notifications
You must be signed in to change notification settings - Fork 20
/
button.py
115 lines (92 loc) · 3.68 KB
/
button.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
from urllib.parse import unquote
from docutils import nodes
from docutils.utils import unescape
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.util.docutils import SphinxDirective
from .utils import string_to_func_inputs
def setup_link_button(app):
app.add_directive("link-button", LinkButton)
# TODO hide badges in non-HTML?
app.add_role("badge", badge_role)
app.add_role("link-badge", link_badge_role)
def create_ref_node(link_type, uri, text, tooltip):
innernode = nodes.inline(text, text)
if link_type == "ref":
ref_node = addnodes.pending_xref(
reftarget=unquote(uri),
reftype="any",
# refdoc=self.env.docname,
refdomain="",
refexplicit=True,
refwarn=True,
)
innernode["classes"] = ["xref", "any"]
# if tooltip:
# ref_node["reftitle"] = tooltip
# ref_node["title"] = tooltip
# TODO this doesn't work
else:
ref_node = nodes.reference()
ref_node["refuri"] = uri
if tooltip:
ref_node["reftitle"] = tooltip
ref_node += innernode
return ref_node
class LinkButton(SphinxDirective):
"""A directive to turn a link into a button."""
has_content = False
required_arguments = 1
final_argument_whitespace = True
option_spec = {
"type": lambda arg: directives.choice(arg, ("url", "ref")),
"text": directives.unchanged,
"tooltip": directives.unchanged,
"classes": directives.unchanged,
}
def run(self):
uri = self.arguments[0]
link_type = self.options.get("type", "url")
text = self.options.get("text", uri)
ref_node = create_ref_node(
link_type, uri, text, self.options.get("tooltip", None)
)
self.set_source_info(ref_node)
ref_node["classes"] = ["sphinx-bs", "btn", "text-wrap"] + self.options.get(
"classes", ""
).split()
# sphinx requires that a reference be inside a block element
container = nodes.paragraph()
container += ref_node
return [container]
def get_badge_inputs(text, cls: str = ""):
return text, cls.split()
def badge_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
try:
args, kwargs = string_to_func_inputs(text)
text, classes = get_badge_inputs(*args, **kwargs)
except Exception as err:
msg = inliner.reporter.error(f"badge input is invalid: {err}", line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
node = nodes.inline(
rawtext, unescape(text), classes=["sphinx-bs", "badge"] + classes
)
# textnodes, messages = inliner.parse(text, lineno, node, memo)
# TODO this would require the memo with reporter, document and language
return [node], []
def get_link_badge_inputs(link, text=None, type="link", cls: str = "", tooltip=None):
return link, text or link, type, cls.split(), tooltip
def link_badge_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
try:
args, kwargs = string_to_func_inputs(text)
uri, text, link_type, classes, tooltip = get_link_badge_inputs(*args, **kwargs)
except Exception as err:
msg = inliner.reporter.error(f"badge input is invalid: {err}", line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
ref_node = create_ref_node(link_type, uri, text, tooltip)
if lineno is not None:
ref_node.source, ref_node.line = inliner.reporter.get_source_and_line(lineno)
ref_node["classes"] = ["sphinx-bs", "badge"] + classes
return [ref_node], []