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
|
/*
http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#hyperlink-targets
Links can have internal or external targets.
In the source, targets look like:
.. targetname1:
.. targetname2:
some paragraph or list item or so
or:
.. targetname1:
.. targetname2: https://link
There’s also anonymous links and targets without names.
TODO: continue documenting how it’s done via http://svn.code.sf.net/p/docutils/code/trunk/docutils/docutils/transforms/references.py
*/
use std::collections::HashMap;
use crate::target::Target;
use crate::document_tree::{
Document,
HasChildren,
attribute_types::ID,
elements as e,
element_categories as c,
};
enum MaybeDirectTarget {
IndirectTarget(ID),
DirectTarget(Target),
}
trait ResolvableRefs {
fn populate_targets(&self, refs: &mut HashMap<&ID, Target>);
fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self;
}
pub fn resolve_references(mut doc: Document) -> Document {
let mut references = HashMap::new();
for c in doc.children() {
c.populate_targets(&mut references);
}
let new: Vec<_> = doc.children_mut().drain(..).map(|c| c.resolve_refs(&references)).collect();
Document::with_children(new)
}
fn sub_pop<P, C>(parent: &P, refs: &mut HashMap<&ID, Target>) where P: HasChildren<C>, C: ResolvableRefs {
for c in parent.children() {
c.populate_targets(&mut refs);
}
}
fn sub_res<P, C>(parent: P, refs: &HashMap<&ID, Target>) -> P where P: e::Element + HasChildren<C>, C: ResolvableRefs {
let new: Vec<_> = parent.children_mut().drain(..).map(|c| c.resolve_refs(&refs)).collect();
parent.children_mut().extend(new);
parent
}
impl ResolvableRefs for c::StructuralSubElement {
fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
use c::StructuralSubElement::*;
match *self {
Title(e) => sub_pop(&*e, refs),
Subtitle(e) => sub_pop(&*e, refs),
Decoration(e) => sub_pop(&*e, refs),
Docinfo(e) => sub_pop(&*e, refs),
SubStructure(e) => e.populate_targets(refs),
}
}
fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
use c::StructuralSubElement::*;
match self {
Title(e) => sub_res(*e, refs).into(),
Subtitle(e) => sub_res(*e, refs).into(),
Decoration(e) => sub_res(*e, refs).into(),
Docinfo(e) => sub_res(*e, refs).into(),
SubStructure(e) => e.resolve_refs(refs).into(),
}
}
}
impl ResolvableRefs for c::SubStructure {
fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
use c::SubStructure::*;
match *self {
Topic(e) => sub_pop(&*e, refs),
Sidebar(e) => sub_pop(&*e, refs),
Transition(e) => sub_pop(&*e, refs),
Section(e) => sub_pop(&*e, refs),
BodyElement(e) => e.populate_targets(refs),
}
}
fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
use c::SubStructure::*;
match self {
Topic(e) => sub_res(*e, refs).into(),
Sidebar(e) => sub_res(*e, refs).into(),
Transition(e) => sub_res(*e, refs).into(),
Section(e) => sub_res(*e, refs).into(),
BodyElement(e) => e.resolve_refs(refs).into(),
}
}
}
|