aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreu Botella2019-10-23 09:29:24 +0200
committerPhilipp A2019-10-23 09:29:24 +0200
commit10cc972f2e4b99e6d3082970ee6982bfee5211c0 (patch)
tree038f7199c2a27e89df55d7e15ddea1b1e8781341
parent7d38186a0ae3222b6de9bc91290a87d0e4564e18 (diff)
downloadrust-rst-10cc972f2e4b99e6d3082970ee6982bfee5211c0.tar.bz2
Resolving substitutions. (#9)
-rw-r--r--src/parser/conversion.rs17
-rw-r--r--src/parser/conversion/block.rs7
-rw-r--r--src/parser/conversion/inline.rs23
-rw-r--r--src/parser/simplify.rs197
-rw-r--r--src/rst.pest4
5 files changed, 186 insertions, 62 deletions
diff --git a/src/parser/conversion.rs b/src/parser/conversion.rs
index 5154f40..32461bf 100644
--- a/src/parser/conversion.rs
+++ b/src/parser/conversion.rs
@@ -72,6 +72,23 @@ pub fn convert_document(pairs: Pairs<Rule>) -> Result<e::Document, Error> {
Ok(e::Document::with_children(toplevel))
}
+/// Normalizes a name in terms of whitespace. Equivalent to docutils's
+/// `docutils.nodes.whitespace_normalize_name`.
+pub fn whitespace_normalize_name(name: &str) -> String {
+ // Python's string.split() defines whitespace differently than Rust does.
+ let split_iter = name.split(
+ |ch: char| ch.is_whitespace() || (ch >= '\x1C' && ch <= '\x1F')
+ ).filter(|split| !split.is_empty());
+ let mut ret = String::new();
+ for split in split_iter {
+ if !ret.is_empty() {
+ ret.push(' ');
+ }
+ ret.push_str(split);
+ }
+ ret
+}
+
#[cfg(test)]
mod tests {
diff --git a/src/parser/conversion/block.rs b/src/parser/conversion/block.rs
index 714b410..9552539 100644
--- a/src/parser/conversion/block.rs
+++ b/src/parser/conversion/block.rs
@@ -6,13 +6,14 @@ use crate::document_tree::{
elements as e,
element_categories as c,
extra_attributes as a,
+ attribute_types as at
};
use crate::parser::{
pest_rst::Rule,
pair_ext_parse::PairExt,
};
-use super::inline::convert_inline;
+use super::{whitespace_normalize_name, inline::convert_inline};
#[derive(PartialEq)]
@@ -92,14 +93,14 @@ fn convert_target(pair: Pair<Rule>) -> Result<e::Target, Error> {
fn convert_substitution_def(pair: Pair<Rule>) -> Result<e::SubstitutionDefinition, Error> {
let mut pairs = pair.into_inner();
- let name = pairs.next().unwrap().as_str(); // Rule::substitution_name
+ let name = whitespace_normalize_name(pairs.next().unwrap().as_str()); // Rule::substitution_name
let inner_pair = pairs.next().unwrap();
let inner: c::TextOrInlineElement = match inner_pair.as_rule() {
Rule::image => convert_image::<e::ImageInline>(inner_pair)?.into(),
rule => panic!("Unknown substitution rule {:?}", rule),
};
let mut subst_def = e::SubstitutionDefinition::with_children(vec![inner]);
- subst_def.names_mut().push(name.into());
+ subst_def.names_mut().push(at::NameToken(name));
Ok(subst_def)
}
diff --git a/src/parser/conversion/inline.rs b/src/parser/conversion/inline.rs
index c30b71d..50a6258 100644
--- a/src/parser/conversion/inline.rs
+++ b/src/parser/conversion/inline.rs
@@ -6,6 +6,7 @@ use crate::document_tree::{
elements as e,
element_categories as c,
extra_attributes as a,
+ attribute_types as at
};
use crate::parser::{
@@ -13,11 +14,14 @@ use crate::parser::{
// pair_ext_parse::PairExt,
};
+use super::whitespace_normalize_name;
+
pub fn convert_inline(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> {
Ok(match pair.as_rule() {
- Rule::str => pair.as_str().into(),
- Rule::reference => convert_reference(pair)?.into(),
+ Rule::str => pair.as_str().into(),
+ Rule::reference => convert_reference(pair)?.into(),
+ Rule::substitution_ref => convert_substitution(pair)?.into(),
rule => unimplemented!("unknown rule {:?}", rule),
})
}
@@ -42,3 +46,18 @@ fn convert_reference(pair: Pair<Rule>) -> Result<e::Reference, Error> {
a::Reference { name, refuri, refid, refname }
))
}
+
+fn convert_substitution(pair: Pair<Rule>) -> Result<e::SubstitutionReference, Error> {
+ let concrete = pair.into_inner().next().unwrap();
+ match concrete.as_rule() {
+ Rule::substitution_name => {
+ let name = whitespace_normalize_name(concrete.as_str());
+ Ok(a::ExtraAttributes::with_extra(
+ a::SubstitutionReference {
+ refname: vec![at::NameToken(name)]
+ }
+ ))
+ }
+ _ => unreachable!()
+ }
+}
diff --git a/src/parser/simplify.rs b/src/parser/simplify.rs
index 8f699e4..bb47760 100644
--- a/src/parser/simplify.rs
+++ b/src/parser/simplify.rs
@@ -25,24 +25,55 @@ use crate::target::Target;
use crate::document_tree::{
Document,
HasChildren,
- attribute_types::ID,
+ attribute_types::{ID, NameToken},
elements as e,
element_categories as c,
};
-enum MaybeDirectTarget {
- IndirectTarget(ID),
- DirectTarget(Target),
+#[derive(Debug)]
+enum NamedTargetType {
+ NumberedFootnote(usize),
+ LabeledFootnote(usize),
+ Citation,
+ InternalLink,
+ ExternalLink(Target),
+ IndirectLink(NameToken),
+ SectionTitle
+}
+impl NamedTargetType {
+ fn is_implicit_target(&self) -> bool {
+ match self {
+ NamedTargetType::SectionTitle => true,
+ _ => false
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+struct Substitution {
+ content: e::ImageInline,
+ // If `ltrim` is true and the sibling before the reference is a text node,
+ // the text node gets right-trimmed. Same for `rtrim` with the sibling after
+ // getting left-trimmed.
+ ltrim: bool,
+ rtrim: bool
+}
+
+#[derive(Default, Debug)]
+struct TargetsCollected {
+ named_targets: HashMap<NameToken, NamedTargetType>,
+ substitutions: HashMap<String, Substitution>,
+ normalized_substitutions: HashMap<String, Substitution>
}
trait ResolvableRefs {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>);
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self;
+ fn populate_targets(&self, refs: &mut TargetsCollected);
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self;
}
pub fn resolve_references(mut doc: Document) -> Document {
- let mut references = HashMap::new();
+ let mut references: TargetsCollected = Default::default();
for c in doc.children() {
c.populate_targets(&mut references);
}
@@ -50,32 +81,32 @@ pub fn resolve_references(mut doc: Document) -> Document {
Document::with_children(new)
}
-fn sub_pop<P, C>(parent: &P, refs: &mut HashMap<&ID, Target>) where P: HasChildren<C>, C: ResolvableRefs {
+fn sub_pop<P, C>(parent: &P, refs: &mut TargetsCollected) where P: HasChildren<C>, C: ResolvableRefs {
for c in parent.children() {
c.populate_targets(refs);
}
}
-fn sub_res<P, C>(mut 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();
+fn sub_res<P, C>(mut parent: P, refs: &TargetsCollected) -> 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
}
-fn sub_sub_pop<P, C1, C2>(parent: &P, refs: &mut HashMap<&ID, Target>) where P: HasChildren<C1>, C1: HasChildren<C2>, C2: ResolvableRefs {
+fn sub_sub_pop<P, C1, C2>(parent: &P, refs: &mut TargetsCollected) where P: HasChildren<C1>, C1: HasChildren<C2>, C2: ResolvableRefs {
for c in parent.children() {
sub_pop(c, refs);
}
}
-fn sub_sub_res<P, C1, C2>(mut parent: P, refs: &HashMap<&ID, Target>) -> P where P: e::Element + HasChildren<C1>, C1: e::Element + HasChildren<C2>, C2: ResolvableRefs {
+fn sub_sub_res<P, C1, C2>(mut parent: P, refs: &TargetsCollected) -> P where P: e::Element + HasChildren<C1>, C1: e::Element + HasChildren<C2>, C2: ResolvableRefs {
let new: Vec<_> = parent.children_mut().drain(..).map(|c| sub_res(c, refs)).collect();
parent.children_mut().extend(new);
parent
}
impl ResolvableRefs for c::StructuralSubElement {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::StructuralSubElement::*;
match self {
Title(e) => sub_pop(&**e, refs),
@@ -85,7 +116,7 @@ impl ResolvableRefs for c::StructuralSubElement {
SubStructure(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::StructuralSubElement::*;
match self {
Title(e) => sub_res(*e, refs).into(),
@@ -98,7 +129,7 @@ impl ResolvableRefs for c::StructuralSubElement {
}
impl ResolvableRefs for c::SubStructure {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubStructure::*;
match self {
Topic(e) => sub_pop(&**e, refs),
@@ -110,7 +141,7 @@ impl ResolvableRefs for c::SubStructure {
BodyElement(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubStructure::*;
match self {
Topic(e) => sub_res(*e, refs).into(),
@@ -123,7 +154,8 @@ impl ResolvableRefs for c::SubStructure {
}
impl ResolvableRefs for c::BodyElement {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
+ use crate::document_tree::extra_attributes::ExtraAttributes;
use c::BodyElement::*;
match self {
Paragraph(e) => sub_pop(&**e, refs),
@@ -133,8 +165,30 @@ impl ResolvableRefs for c::BodyElement {
// TODO
},
Rubric(e) => sub_pop(&**e, refs),
- SubstitutionDefinition(e) => sub_pop(&**e, refs),
- Comment(e) => sub_pop(&**e, refs),
+ SubstitutionDefinition(e) => {
+ use e::Element;
+ let subst_content = if let [c::TextOrInlineElement::ImageInline(content)] = &e.children()[..] {
+ content.as_ref()
+ } else {
+ panic!("Unexpected substitution contents.")
+ };
+ let subst = Substitution {
+ content: subst_content.clone(),
+ ltrim: e.extra().ltrim,
+ rtrim: e.extra().rtrim
+ };
+ for NameToken(name) in e.names() {
+ if refs.substitutions.contains_key(name) {
+ // TODO: Duplicate substitution name (level 3 system message).
+ }
+ // Intentionally overriding any previous values.
+ refs.substitutions.insert(name.clone(), subst.clone());
+ refs.normalized_substitutions.insert(name.to_lowercase(), subst.clone());
+ }
+ },
+ Comment(e) => {
+ // TODO
+ },
Pending(e) => {
// TODO
},
@@ -173,7 +227,7 @@ impl ResolvableRefs for c::BodyElement {
Table(e) => sub_pop(&**e, refs)
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::BodyElement::*;
match self {
Paragraph(e) => sub_res(*e, refs).into(),
@@ -181,8 +235,8 @@ impl ResolvableRefs for c::BodyElement {
DoctestBlock(e) => sub_res(*e, refs).into(),
MathBlock(e) => MathBlock(e),
Rubric(e) => sub_res(*e, refs).into(),
- SubstitutionDefinition(e) => sub_res(*e, refs).into(),
- Comment(e) => sub_res(*e, refs).into(),
+ SubstitutionDefinition(e) => SubstitutionDefinition(e),
+ Comment(e) => Comment(e),
Pending(e) => Pending(e),
Target(e) => Target(e),
Raw(e) => Raw(e),
@@ -216,7 +270,7 @@ impl ResolvableRefs for c::BodyElement {
}
impl ResolvableRefs for c::BibliographicElement {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::BibliographicElement::*;
match self {
Author(e) => sub_pop(&**e, refs),
@@ -232,7 +286,7 @@ impl ResolvableRefs for c::BibliographicElement {
Field(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::BibliographicElement::*;
match self {
Author(e) => sub_res(*e, refs).into(),
@@ -251,7 +305,7 @@ impl ResolvableRefs for c::BibliographicElement {
}
impl ResolvableRefs for c::TextOrInlineElement {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::TextOrInlineElement::*;
match self {
c::TextOrInlineElement::String(e) => {
@@ -286,7 +340,7 @@ impl ResolvableRefs for c::TextOrInlineElement {
}
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::TextOrInlineElement::*;
match self {
c::TextOrInlineElement::String(e) => c::TextOrInlineElement::String(e),
@@ -296,7 +350,38 @@ impl ResolvableRefs for c::TextOrInlineElement {
Reference(e) => sub_res(*e, refs).into(),
FootnoteReference(e) => sub_res(*e, refs).into(),
CitationReference(e) => sub_res(*e, refs).into(),
- SubstitutionReference(e) => sub_res(*e, refs).into(),
+ SubstitutionReference(e) => {
+ use crate::document_tree::extra_attributes::ExtraAttributes;
+ if e.extra().refname.len() != 1 {
+ panic!("Expected exactly one name in a substitution reference.");
+ }
+ let name = e.extra().refname[0].0.clone();
+ let substitution = refs.substitutions.get(&name).or_else(|| {
+ refs.normalized_substitutions.get(&name.to_lowercase())
+ });
+ match substitution {
+ Some(Substitution {content, ltrim, rtrim}) => {
+ // TODO: Check if the substitution would expand circularly
+ // (level 3 system message).
+ // TODO: Ltrim and rtrim.
+ ImageInline(Box::new(content.clone()))
+ },
+ None => {
+ // Undefined substitution name (level 3 system message).
+ // TODO: This replaces the reference by a Problematic node.
+ // The corresponding SystemMessage node should go in a generated
+ // section with class "system-messages" at the end of the document.
+ use crate::document_tree::{Problematic, element_categories::TextOrInlineElement};
+ let mut replacement: Box<Problematic> = Box::new(Default::default());
+ replacement.children_mut().push(
+ TextOrInlineElement::String(Box::new(format!("|{}|", name)))
+ );
+ // TODO: Create an ID for replacement for the system_message to reference.
+ // TODO: replacement.refid pointing to the system_message.
+ Problematic(replacement)
+ }
+ }
+ },
TitleReference(e) => sub_res(*e, refs).into(),
Abbreviation(e) => sub_res(*e, refs).into(),
Acronym(e) => sub_res(*e, refs).into(),
@@ -314,7 +399,7 @@ impl ResolvableRefs for c::TextOrInlineElement {
}
impl ResolvableRefs for c::AuthorInfo {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::AuthorInfo::*;
match self {
Author(e) => sub_pop(&**e, refs),
@@ -323,7 +408,7 @@ impl ResolvableRefs for c::AuthorInfo {
Contact(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::AuthorInfo::*;
match self {
Author(e) => sub_res(*e, refs).into(),
@@ -335,14 +420,14 @@ impl ResolvableRefs for c::AuthorInfo {
}
impl ResolvableRefs for c::DecorationElement {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::DecorationElement::*;
match self {
Header(e) => sub_pop(&**e, refs),
Footer(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::DecorationElement::*;
match self {
Header(e) => sub_res(*e, refs).into(),
@@ -352,14 +437,14 @@ impl ResolvableRefs for c::DecorationElement {
}
impl ResolvableRefs for c::SubTopic {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubTopic::*;
match self {
Title(e) => sub_pop(&**e, refs),
BodyElement(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubTopic::*;
match self {
Title(e) => sub_res(*e, refs).into(),
@@ -369,7 +454,7 @@ impl ResolvableRefs for c::SubTopic {
}
impl ResolvableRefs for c::SubSidebar {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubSidebar::*;
match self {
Topic(e) => sub_pop(&**e, refs),
@@ -378,7 +463,7 @@ impl ResolvableRefs for c::SubSidebar {
BodyElement(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubSidebar::*;
match self {
Topic(e) => sub_res(*e, refs).into(),
@@ -390,7 +475,7 @@ impl ResolvableRefs for c::SubSidebar {
}
impl ResolvableRefs for c::SubDLItem {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubDLItem::*;
match self {
Term(e) => sub_pop(&**e, refs),
@@ -398,7 +483,7 @@ impl ResolvableRefs for c::SubDLItem {
Definition(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubDLItem::*;
match self {
Term(e) => sub_res(*e, refs).into(),
@@ -409,14 +494,14 @@ impl ResolvableRefs for c::SubDLItem {
}
impl ResolvableRefs for c::SubField {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubField::*;
match self {
FieldName(e) => sub_pop(&**e, refs),
FieldBody(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubField::*;
match self {
FieldName(e) => sub_res(*e, refs).into(),
@@ -426,14 +511,14 @@ impl ResolvableRefs for c::SubField {
}
impl ResolvableRefs for c::SubOptionListItem {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubOptionListItem::*;
match self {
OptionGroup(e) => sub_sub_pop(&**e, refs),
Description(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubOptionListItem::*;
match self {
OptionGroup(e) => sub_sub_res(*e, refs).into(),
@@ -443,7 +528,7 @@ impl ResolvableRefs for c::SubOptionListItem {
}
impl ResolvableRefs for c::SubOption {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubOption::*;
match self {
OptionString(e) => {
@@ -454,7 +539,7 @@ impl ResolvableRefs for c::SubOption {
},
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubOption::*;
match self {
OptionString(e) => OptionString(e),
@@ -464,14 +549,14 @@ impl ResolvableRefs for c::SubOption {
}
impl ResolvableRefs for c::SubLineBlock {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubLineBlock::*;
match self {
LineBlock(e) => sub_pop(&**e, refs),
Line(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubLineBlock::*;
match self {
LineBlock(e) => sub_res(*e, refs).into(),
@@ -481,14 +566,14 @@ impl ResolvableRefs for c::SubLineBlock {
}
impl ResolvableRefs for c::SubBlockQuote {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubBlockQuote::*;
match self {
Attribution(e) => sub_pop(&**e, refs),
BodyElement(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubBlockQuote::*;
match self {
Attribution(e) => sub_res(*e, refs).into(),
@@ -498,14 +583,14 @@ impl ResolvableRefs for c::SubBlockQuote {
}
impl ResolvableRefs for c::SubFootnote {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubFootnote::*;
match self {
Label(e) => sub_pop(&**e, refs),
BodyElement(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubFootnote::*;
match self {
Label(e) => sub_res(*e, refs).into(),
@@ -515,7 +600,7 @@ impl ResolvableRefs for c::SubFootnote {
}
impl ResolvableRefs for c::SubFigure {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubFigure::*;
match self {
Caption(e) => sub_pop(&**e, refs),
@@ -523,7 +608,7 @@ impl ResolvableRefs for c::SubFigure {
BodyElement(e) => e.populate_targets(refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubFigure::*;
match self {
Caption(e) => sub_res(*e, refs).into(),
@@ -534,14 +619,14 @@ impl ResolvableRefs for c::SubFigure {
}
impl ResolvableRefs for c::SubTable {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubTable::*;
match self {
Title(e) => sub_pop(&**e, refs),
TableGroup(e) => sub_pop(&**e, refs),
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubTable::*;
match self {
Title(e) => sub_res(*e, refs).into(),
@@ -551,7 +636,7 @@ impl ResolvableRefs for c::SubTable {
}
impl ResolvableRefs for c::SubTableGroup {
- fn populate_targets(&self, refs: &mut HashMap<&ID, Target>) {
+ fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubTableGroup::*;
match self {
TableColspec(e) => {
@@ -569,7 +654,7 @@ impl ResolvableRefs for c::SubTableGroup {
},
}
}
- fn resolve_refs(self, refs: &HashMap<&ID, Target>) -> Self {
+ fn resolve_refs(self, refs: &TargetsCollected) -> Self {
use c::SubTableGroup::*;
match self {
TableColspec(e) => TableColspec(e),
@@ -585,4 +670,4 @@ impl ResolvableRefs for c::SubTableGroup {
},
}
}
-} \ No newline at end of file
+}
diff --git a/src/rst.pest b/src/rst.pest
index 9934f44..b9c60e9 100644
--- a/src/rst.pest
+++ b/src/rst.pest
@@ -101,6 +101,7 @@ blank_line = _{ !marker ~ !inline ~ " "* ~ NEWLINE }
inlines = _{ !marker ~ inline+ ~ ( NEWLINE ~ (PEEK[..] ~ !marker ~ inline+ ~ NEWLINE)+ )? }
inline = _{
reference
+ | substitution_ref
| str
// link ✓
// | str ✓
@@ -121,7 +122,7 @@ inline = _{
// | symbol
}
-str = { (!(NEWLINE | reference) ~ ANY)+ }
+str = { (!(NEWLINE | reference | substitution_ref) ~ ANY)+ }
// inline links
reference = { reference_target | reference_explicit | reference_auto }
@@ -144,6 +145,7 @@ reference_embedded_source = { ( !("<"|":"|"`") ~ ( " " | nonspacechar | blank_li
reference_auto_url = { ASCII_ALPHA+ ~ "://" ~ (!(NEWLINE|">") ~ ANY)+ }
reference_auto_email = { "<" ~ "mailto:"? ~ (ASCII_ALPHANUMERIC|"-"|"+"|"_"|"."|"/"|"!"|"%"|"~"|"$")+ ~ "@" ~ (!(NEWLINE | ">") ~ ANY)+ ~ ">" }
+substitution_ref = { "|" ~ substitution_name ~ "|" }
/*
* character classes