aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp A2019-11-09 14:59:37 +0100
committerPhilipp A2019-11-09 14:59:37 +0100
commit603fbf0b91c643cfa0921aadb6865ae9d7c094bf (patch)
tree2061e0987d4e731464ddf9cd37766083bdd0d621
parentdf6b7645d845a022ca7eeba08b1ecb761a020195 (diff)
downloadrust-rst-603fbf0b91c643cfa0921aadb6865ae9d7c094bf.tar.bz2
Simple indirect links
-rw-r--r--src/parser/conversion/block.rs15
-rw-r--r--src/parser/conversion/inline.rs1
-rw-r--r--src/parser/simplify.rs188
-rw-r--r--src/parser/tests.rs6
-rw-r--r--src/renderer/html.rs44
5 files changed, 124 insertions, 130 deletions
diff --git a/src/parser/conversion/block.rs b/src/parser/conversion/block.rs
index 9552539..0de86b5 100644
--- a/src/parser/conversion/block.rs
+++ b/src/parser/conversion/block.rs
@@ -74,21 +74,20 @@ fn convert_paragraph(pair: Pair<Rule>) -> Result<e::Paragraph, Error> {
fn convert_target(pair: Pair<Rule>) -> Result<e::Target, Error> {
- let mut attrs = a::Target {
- anonymous: false,
- ..Default::default()
- };
+ let mut elem: e::Target = Default::default();
+ elem.extra_mut().anonymous = false;
for p in pair.into_inner() {
match p.as_rule() {
Rule::target_name_uq | Rule::target_name_qu => {
- attrs.refid = Some(p.as_str().into());
- attrs.refname.push(p.as_str().into());
+ elem.ids_mut().push(p.as_str().into());
+ elem.names_mut().push(p.as_str().into());
},
- Rule::link_target => attrs.refuri = Some(p.parse()?),
+ // TODO: also handle non-urls
+ Rule::link_target => elem.extra_mut().refuri = Some(p.parse()?),
rule => panic!("Unexpected rule in target: {:?}", rule),
}
}
- Ok(e::Target::new(Default::default(), attrs))
+ Ok(elem)
}
fn convert_substitution_def(pair: Pair<Rule>) -> Result<e::SubstitutionDefinition, Error> {
diff --git a/src/parser/conversion/inline.rs b/src/parser/conversion/inline.rs
index c942732..94f99b4 100644
--- a/src/parser/conversion/inline.rs
+++ b/src/parser/conversion/inline.rs
@@ -2,7 +2,6 @@ use failure::Error;
use pest::iterators::Pair;
use crate::document_tree::{
- ExtraAttributes,
elements as e,
element_categories as c,
extra_attributes as a,
diff --git a/src/parser/simplify.rs b/src/parser/simplify.rs
index f6f0e8a..ab79343 100644
--- a/src/parser/simplify.rs
+++ b/src/parser/simplify.rs
@@ -16,7 +16,7 @@ or:
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
+TODO: continue documenting how it’s done via https://repo.or.cz/docutils.git/blob/HEAD:/docutils/docutils/transforms/references.py
*/
use std::collections::HashMap;
@@ -25,9 +25,10 @@ use crate::url::Url;
use crate::document_tree::{
Document,
HasChildren,
- attribute_types::{ID, NameToken},
- elements as e,
+ attribute_types::NameToken,
+ elements::{self as e, Element},
element_categories as c,
+ extra_attributes::ExtraAttributes,
};
@@ -39,13 +40,13 @@ enum NamedTargetType {
InternalLink,
ExternalLink(Url),
IndirectLink(NameToken),
- SectionTitle
+ SectionTitle,
}
impl NamedTargetType {
fn is_implicit_target(&self) -> bool {
match self {
NamedTargetType::SectionTitle => true,
- _ => false
+ _ => false,
}
}
}
@@ -53,18 +54,42 @@ impl NamedTargetType {
#[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.
+ /// If true and the sibling before the reference is a text node,
+ /// the text node gets right-trimmed.
ltrim: bool,
- rtrim: bool
+ /// Same as `ltrim` with the sibling after the reference.
+ rtrim: bool,
}
#[derive(Default, Debug)]
struct TargetsCollected {
named_targets: HashMap<NameToken, NamedTargetType>,
- substitutions: HashMap<String, Substitution>,
- normalized_substitutions: HashMap<String, Substitution>
+ substitutions: HashMap<NameToken, Substitution>,
+ normalized_substitutions: HashMap<String, Substitution>,
+}
+impl TargetsCollected {
+ fn target_url<'t>(self: &'t TargetsCollected, refname: &[NameToken]) -> Option<&'t Url> {
+ // TODO: Check if the target would expand circularly
+ if refname.len() != 1 {
+ panic!("Expected exactly one name in a reference.");
+ }
+ let name = refname[0].clone();
+ match self.named_targets.get(&name)? {
+ NamedTargetType::ExternalLink(url) => Some(url),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn substitution<'t>(self: &'t TargetsCollected, refname: &[NameToken]) -> Option<&'t Substitution> {
+ // TODO: Check if the substitution would expand circularly
+ if refname.len() != 1 {
+ panic!("Expected exactly one name in a substitution reference.");
+ }
+ let name = refname[0].clone();
+ self.substitutions.get(&name).or_else(|| {
+ self.normalized_substitutions.get(&name.0.to_lowercase())
+ })
+ }
}
trait ResolvableRefs {
@@ -134,9 +159,7 @@ impl ResolvableRefs for c::SubStructure {
match self {
Topic(e) => sub_pop(&**e, refs),
Sidebar(e) => sub_pop(&**e, refs),
- Transition(e) => {
- // TODO
- },
+ Transition(_) => {},
Section(e) => sub_pop(&**e, refs),
BodyElement(e) => e.populate_targets(refs),
}
@@ -155,18 +178,14 @@ impl ResolvableRefs for c::SubStructure {
impl ResolvableRefs for c::BodyElement {
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),
LiteralBlock(e) => sub_pop(&**e, refs),
DoctestBlock(e) => sub_pop(&**e, refs),
- MathBlock(e) => {
- // TODO
- },
+ MathBlock(_) => {},
Rubric(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 {
@@ -177,30 +196,30 @@ impl ResolvableRefs for c::BodyElement {
ltrim: e.extra().ltrim,
rtrim: e.extra().rtrim
};
- for NameToken(name) in e.names() {
+ for 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());
+ refs.normalized_substitutions.insert(name.0.to_lowercase(), subst.clone());
}
},
- Comment(e) => {
- // TODO
- },
- Pending(e) => {
- // TODO
+ Comment(_) => {},
+ Pending(_) => {
+ unimplemented!();
},
Target(e) => {
- // TODO
- },
- Raw(e) => {
- // TODO
- },
- Image(e) => {
- // TODO
+ if let Some(uri) = &e.extra().refuri {
+ for name in e.names() {
+ refs.named_targets.insert(name.clone(), NamedTargetType::ExternalLink(uri.clone()));
+ }
+ }
+ // TODO: as is, people can only refer to the target directly containing the URL.
+ // add refid and refnames to some HashMap and follow those later.
},
+ Raw(_) => {},
+ Image(_) => {},
Compound(e) => sub_pop(&**e, refs),
Container(e) => sub_pop(&**e, refs),
BulletList(e) => sub_sub_pop(&**e, refs),
@@ -308,9 +327,7 @@ impl ResolvableRefs for c::TextOrInlineElement {
fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::TextOrInlineElement::*;
match self {
- c::TextOrInlineElement::String(e) => {
- // TODO
- },
+ String(_) => {},
Emphasis(e) => sub_pop(&**e, refs),
Strong(e) => sub_pop(&**e, refs),
Literal(e) => sub_pop(&**e, refs),
@@ -326,18 +343,12 @@ impl ResolvableRefs for c::TextOrInlineElement {
Inline(e) => sub_pop(&**e, refs),
Problematic(e) => sub_pop(&**e, refs),
Generated(e) => sub_pop(&**e, refs),
- Math(e) => {
- // TODO
- },
- TargetInline(e) => {
- // TODO
+ Math(_) => {},
+ TargetInline(_) => {
+ unimplemented!();
},
- RawInline(e) => {
- // TODO
- },
- ImageInline(e) => {
- // TODO
- }
+ RawInline(_) => {},
+ ImageInline(_) => {}
}
}
fn resolve_refs(self, refs: &TargetsCollected) -> Self {
@@ -347,39 +358,38 @@ impl ResolvableRefs for c::TextOrInlineElement {
Emphasis(e) => sub_res(*e, refs).into(),
Strong(e) => sub_res(*e, refs).into(),
Literal(e) => sub_res(*e, refs).into(),
- Reference(e) => sub_res(*e, refs).into(),
+ Reference(mut e) => {
+ if e.extra().refuri.is_none() {
+ if let Some(uri) = refs.target_url(&e.extra().refname) {
+ e.extra_mut().refuri = Some(uri.clone());
+ }
+ }
+ (*e).into()
+ },
FootnoteReference(e) => sub_res(*e, refs).into(),
CitationReference(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)
+ SubstitutionReference(e) => match refs.substitution(&e.extra().refname) {
+ Some(Substitution {content, ltrim, rtrim}) => {
+ // (level 3 system message).
+ // TODO: ltrim and rtrim.
+ if *ltrim || *rtrim {
+ dbg!(content, ltrim, 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;
+ let mut replacement: Box<Problematic> = Box::new(Default::default());
+ replacement.children_mut().push(
+ c::TextOrInlineElement::String(Box::new(format!("|{}|", e.extra().refname[0].0)))
+ );
+ // 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(),
@@ -528,24 +538,8 @@ impl ResolvableRefs for c::SubOptionListItem {
}
impl ResolvableRefs for c::SubOption {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::SubOption::*;
- match self {
- OptionString(e) => {
- // TODO
- },
- OptionArgument(e) => {
- // TODO
- },
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Self {
- use c::SubOption::*;
- match self {
- OptionString(e) => OptionString(e),
- OptionArgument(e) => OptionArgument(e),
- }
- }
+ fn populate_targets(&self, _: &mut TargetsCollected) {}
+ fn resolve_refs(self, _: &TargetsCollected) -> Self { self }
}
impl ResolvableRefs for c::SubLineBlock {
@@ -639,8 +633,8 @@ impl ResolvableRefs for c::SubTableGroup {
fn populate_targets(&self, refs: &mut TargetsCollected) {
use c::SubTableGroup::*;
match self {
- TableColspec(e) => {
- // TODO
+ TableColspec(_) => {
+ unimplemented!();
},
TableHead(e) => {
for c in e.children() {
diff --git a/src/parser/tests.rs b/src/parser/tests.rs
index b2ee623..c498159 100644
--- a/src/parser/tests.rs
+++ b/src/parser/tests.rs
@@ -53,7 +53,7 @@ Title
};
}
-#[allow(clippy::cyclomatic_complexity)]
+#[allow(clippy::cognitive_complexity)]
#[test]
fn two_targets() {
parses_to! {
@@ -76,7 +76,7 @@ fn two_targets() {
};
}
-#[allow(clippy::cyclomatic_complexity)]
+#[allow(clippy::cognitive_complexity)]
#[test]
fn admonitions() {
parses_to! {
@@ -111,7 +111,7 @@ fn admonitions() {
// TODO: test substitutions
// TODO: test images
-#[allow(clippy::cyclomatic_complexity)]
+#[allow(clippy::cognitive_complexity)]
#[test]
fn nested_lists() {
parses_to! {
diff --git a/src/renderer/html.rs b/src/renderer/html.rs
index 876e21b..421d511 100644
--- a/src/renderer/html.rs
+++ b/src/renderer/html.rs
@@ -2,16 +2,18 @@ use std::io::Write;
use failure::Error;
+// use crate::url::Url;
use crate::document_tree::{
Document,
HasChildren,
ExtraAttributes,
elements as e,
element_categories as c,
+ // extra_attributes as a,
};
-static FOOTNOTE_SYMBOLS: [char; 10] = ['*', '†', '‡', '§', '¶', '#', '♠', '♥', '♦', '♣'];
+// static FOOTNOTE_SYMBOLS: [char; 10] = ['*', '†', '‡', '§', '¶', '#', '♠', '♥', '♦', '♣'];
pub fn render_html<W>(document: &Document, mut stream: W) -> Result<(), Error> where W: Write {
document.render_html(stream.by_ref())
@@ -70,14 +72,14 @@ impl_html_render_cat!(StructuralSubElement { Title, Subtitle, Decoration, Docinf
impl_html_render_simple!(Title => h1, Subtitle => h2);
impl HTMLRender for e::Docinfo {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Like “YAML frontmatter” in Markdown
unimplemented!();
}
}
impl HTMLRender for e::Decoration {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Header or footer
unimplemented!();
}
@@ -88,7 +90,7 @@ impl_html_render_simple!(Sidebar => aside, Section => section);
impl_html_render_simple_nochildren!(Transition => hr);
impl HTMLRender for e::Topic {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// A mini section with title
unimplemented!();
}
@@ -99,14 +101,14 @@ impl_html_render_simple!(Paragraph => p, LiteralBlock => pre, MathBlock => math,
impl_html_render_simple_nochildren!(Image => img, Table => table); //TODO: after implementing the table, move it to elems with children
impl HTMLRender for e::DoctestBlock {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
//
unimplemented!();
}
}
impl HTMLRender for e::SubstitutionDefinition {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// TODO: Should those be removed after resolving them
Ok(())
}
@@ -124,16 +126,16 @@ impl HTMLRender for e::Comment {
}
impl HTMLRender for e::Pending {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Will those be resolved by the time we get here?
unimplemented!();
}
}
impl HTMLRender for e::Target {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Should be resolved by now
- unimplemented!();
+ Ok(())
}
}
@@ -147,13 +149,13 @@ impl HTMLRender for e::Raw {
}
impl HTMLRender for e::Footnote {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
unimplemented!();
}
}
impl HTMLRender for e::Citation {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
unimplemented!();
}
}
@@ -185,12 +187,12 @@ impl HTMLRender for e::Reference {
let extra = self.extra();
write!(stream, "<a")?;
if let Some(ref target) = extra.refuri {
- write!(stream, "href=\"{}\"", target)?;
+ write!(stream, " href=\"{}\"", target)?;
}
- write!(stream, ">")?;
if let Some(ref name) = extra.name {
- write!(stream, "{}", name.0)?;
+ write!(stream, " title=\"{}\"", name.0)?;
}
+ write!(stream, ">")?;
for c in self.children() {
(*c).render_html(stream)?;
}
@@ -200,21 +202,21 @@ impl HTMLRender for e::Reference {
}
impl HTMLRender for e::SubstitutionReference {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Will those be resolved by the time we get here?
unimplemented!();
}
}
impl HTMLRender for e::Problematic {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Broken inline markup leads to insertion of this in docutils
unimplemented!();
}
}
impl HTMLRender for e::Generated {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Section numbers and so on
unimplemented!();
}
@@ -239,21 +241,21 @@ impl_html_render_cat!(SubSidebar { Topic, Title, Subtitle, BodyElement });
impl_html_render_simple!(ListItem => li);
impl HTMLRender for e::DefinitionListItem {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// Term→dt, Definition→dd, Classifier→???
unimplemented!();
}
}
impl HTMLRender for e::Field {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// FieldName→dt, FieldBody→dd
unimplemented!();
}
}
impl HTMLRender for e::OptionListItem {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
// OptionGroup→dt(s), Description→dd
unimplemented!();
}
@@ -278,7 +280,7 @@ impl_html_render_cat!(SubFigure { Caption, Legend, BodyElement });
impl_html_render_simple!(Caption => caption);
impl HTMLRender for e::Legend {
- fn render_html<W>(&self, stream: &mut W) -> Result<(), Error> where W: Write {
+ fn render_html<W>(&self, _stream: &mut W) -> Result<(), Error> where W: Write {
unimplemented!();
}
}