Skip to content

Commit bf87ea6

Browse files
committed
feat(interlinks): support rst syntax
1 parent e711cca commit bf87ea6

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

interlinks/_extension.yml renamed to _extension.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ version: 1.0.0
44
quarto-required: ">=1.2.0"
55
contributes:
66
filters:
7-
- interlinks.lua
7+
- interlinks/interlinks.py

interlinks/example.qmd

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@ interlinks:
1818

1919
## Testing
2020

21-
Tilde means don't display module:
2221

23-
* :ref:`vetiver.SKLearnHandler`
24-
* :ref:`~vetiver.SKLearnHandler`
25-
* :ref:`siuba.dply.verbs.mutate`
26-
- TODO: should be able to use `domain:...` to use a specific inventory file.
27-
* :refzzz:`some explanation <mutate>`
28-
- TODO: this syntax let's you change the text of the link.
29-
* [some explanation](`vetiver.SKLearnHandler`)
30-
* [](`vetiver.SKLearnHandler`)
22+
| style | syntax | output |
23+
| ----- | ------ | ------ |
24+
| md custom text | `[some explanation](`vetiver.SKLearnHandler`)` | [some explanation](`vetiver.SKLearnHandler`) |
25+
| md blank text | `[](`vetiver.SKLearnHandler`)` | [](`vetiver.SKLearnHandler`) |
26+
| md blank text (~shortened)| `[](`~vetiver.SKLearnHandler`)` | [](`~vetiver.SKLearnHandler`) |
27+
| rst custom text | `` :ref:`some explanation <vetiver.SKLearnHandler>` `` | :ref:`some explanation <vetiver.SKLearnHandler>` |
28+
| rst blank text | `` :ref:`vetiver.SKLearnHandler` `` | :ref:`vetiver.SKLearnHandler` |
29+
| rst blank text (~shortened) | `` :ref:`~vetiver.SKLearnHandler` `` | :ref:`~vetiver.SKLearnHandler` |

interlinks/interlinks.py

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,32 @@
77
inventory = {}
88

99

10-
def ref_to_anchor(ref, text):
10+
def load_mock_inventory(items: "dict[str, str]"):
11+
for k, v in items.items():
12+
inventory[k] = v
13+
14+
15+
def ref_to_anchor(ref: str, text: "str | pf.ListContainer | None"):
16+
"""Return a Link element based on ref in interlink format
17+
18+
Parameters
19+
----------
20+
ref:
21+
The interlink reference (e.g. "my_module.my_function").
22+
text:
23+
The text to be displayed for the link.
24+
25+
Examples
26+
--------
27+
28+
>>> url = "https://example.org/functools.partial.html"
29+
>>> load_mock_inventory({"functools.partial": {"full_uri": url, "name": "functools.partial"}})
30+
>>> ref_to_anchor("functools.partial")
31+
Link(Str(functools.partial); url='https://example.org/functools.partial.html')
32+
33+
>>> ref_to_anchor("~functools.partial")
34+
Link(Str(partial); url='https://example.org/functools.partial.html')
35+
"""
1136
# TODO: for now we just mutate el
1237
is_shortened = ref.startswith("~")
1338

@@ -28,11 +53,41 @@ def ref_to_anchor(ref, text):
2853
else:
2954
# when the element is an Link, content is a ListContainer, but it has to be
3055
# *splatted back into Link?
31-
return pf.Link(*text, url=dst_url)
56+
if isinstance(text, pf.ListContainer):
57+
return pf.Link(*text, url=dst_url)
58+
elif isinstance(text, str):
59+
return pf.Link(pf.Str(text), url=dst_url)
60+
else:
61+
raise TypeError(f"Unsupported type: {type(text)}")
3262

3363
return pf.Link(name, url=dst_url)
3464

3565

66+
def parse_rst_style_ref(full_text):
67+
"""
68+
Returns
69+
-------
70+
tuple
71+
The parsed title (None if no title specified), and corresponding reference.
72+
"""
73+
74+
import re
75+
76+
pf.debug(full_text)
77+
78+
m = re.match(r"(?P<text>.+?)\<(?P<ref>[a-zA-Z\.\-: ]+)\>", full_text)
79+
if m is None:
80+
# TODO: print a warning or something
81+
return full_text, None
82+
83+
text, ref = m.groups()
84+
85+
return ref, text
86+
87+
88+
# Visitor ================================================================================
89+
90+
3691
@dispatch
3792
def visit(el, doc):
3893
return el
@@ -63,12 +118,14 @@ def visit(el: pf.Doc, doc):
63118

64119

65120
@dispatch
66-
def visit(el: pf.Code, doc):
67-
# TODO: also need to remove ref. Should handle in parent?
68-
left_el = el.prev
121+
def visit(el: pf.Plain, doc):
122+
cont = el.content
123+
if len(cont) == 2 and cont[0] == pf.Str(":ref:") and isinstance(cont[1], pf.Code):
124+
_, code = el.content
125+
126+
ref, title = parse_rst_style_ref(code.text)
69127

70-
if left_el == pf.Str(":ref:"):
71-
return ref_to_anchor(el.text, None)
128+
return pf.Plain(ref_to_anchor(ref, title))
72129

73130
return el
74131

0 commit comments

Comments
 (0)