/*
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
(parent: &P, refs: &mut HashMap<&ID, Target>) where P: HasChildren, C: ResolvableRefs {
for c in parent.children() {
c.populate_targets(&mut refs);
}
}
fn sub_res(parent: P, refs: &HashMap<&ID, Target>) -> P where P: e::Element + HasChildren, 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(),
}
}
}