aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin.rs55
-rw-r--r--src/document_tree.rs35
-rw-r--r--src/document_tree/attribute_types.rs155
-rw-r--r--src/document_tree/element_categories.rs130
-rw-r--r--src/document_tree/element_types.rs96
-rw-r--r--src/document_tree/elements.rs288
-rw-r--r--src/document_tree/extra_attributes.rs112
-rw-r--r--src/document_tree/macro_util.rs42
-rw-r--r--src/lib.rs6
-rw-r--r--src/parser.rs28
-rw-r--r--src/parser/conversion.rs165
-rw-r--r--src/parser/conversion/block.rs202
-rw-r--r--src/parser/conversion/inline.rs161
-rw-r--r--src/parser/pair_ext_parse.rs21
-rw-r--r--src/parser/pest_rst.rs7
-rw-r--r--src/parser/simplify.rs662
-rw-r--r--src/parser/tests.rs241
-rw-r--r--src/parser/token.rs16
-rw-r--r--src/renderer.rs24
-rw-r--r--src/renderer/html.rs388
-rw-r--r--src/renderer/html_tests.rs274
-rw-r--r--src/rst.pest474
-rw-r--r--src/url.rs78
23 files changed, 0 insertions, 3660 deletions
diff --git a/src/bin.rs b/src/bin.rs
deleted file mode 100644
index 394b416..0000000
--- a/src/bin.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-#![recursion_limit="256"]
-
-pub mod document_tree;
-pub mod parser;
-pub mod renderer;
-pub mod url;
-
-
-use structopt::StructOpt;
-use clap::{_clap_count_exprs, arg_enum};
-use quicli::{
- fs::read_file,
- prelude::{CliResult,Verbosity},
-};
-
-use self::parser::parse;
-use self::renderer::{
- render_json,
- render_xml,
- render_html,
-};
-
-arg_enum! {
- #[derive(Debug)]
- #[allow(non_camel_case_types)]
- enum Format { json, xml, html }
-}
-
-#[derive(Debug, StructOpt)]
-#[structopt(raw(setting = "structopt::clap::AppSettings::ColoredHelp"))]
-struct Cli {
- #[structopt(
- long = "format", short = "f", default_value = "html", // xml is pretty defunct…
- raw(possible_values = "&Format::variants()", case_insensitive = "true"),
- )]
- format: Format,
- file: String,
- #[structopt(flatten)]
- verbosity: Verbosity,
-}
-
-fn main() -> CliResult {
- let args = Cli::from_args();
- args.verbosity.setup_env_logger("rst")?;
-
- let content = read_file(args.file)?;
- let document = parse(&content)?;
- let stdout = std::io::stdout();
- match args.format {
- Format::json => render_json(&document, stdout)?,
- Format::xml => render_xml (&document, stdout)?,
- Format::html => render_html(&document, stdout, true)?,
- }
- Ok(())
-}
diff --git a/src/document_tree.rs b/src/document_tree.rs
deleted file mode 100644
index 0af47ba..0000000
--- a/src/document_tree.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-///http://docutils.sourceforge.net/docs/ref/doctree.html
-///serves as AST
-
-#[macro_use]
-mod macro_util;
-
-pub mod elements;
-pub mod element_categories;
-pub mod extra_attributes;
-pub mod attribute_types;
-
-pub use self::elements::*; //Element,CommonAttributes,HasExtraAndChildren
-pub use self::extra_attributes::ExtraAttributes;
-pub use self::element_categories::HasChildren;
-
-#[test]
-fn test_imperative() {
- let mut doc = Document::default();
- let mut title = Title::default();
- title.append_child("Hi");
- doc.append_child(title);
-
- println!("{:?}", doc);
-}
-
-#[test]
-fn test_descriptive() {
- let doc = Document::with_children(vec![
- Title::with_children(vec![
- "Hi".into()
- ]).into()
- ]);
-
- println!("{:?}", doc);
-}
diff --git a/src/document_tree/attribute_types.rs b/src/document_tree/attribute_types.rs
deleted file mode 100644
index 30f3767..0000000
--- a/src/document_tree/attribute_types.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use std::str::FromStr;
-
-use failure::{Error,bail,format_err};
-use serde_derive::Serialize;
-use regex::Regex;
-
-use crate::url::Url;
-
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)]
-pub enum EnumeratedListType {
- Arabic,
- LowerAlpha,
- UpperAlpha,
- LowerRoman,
- UpperRoman,
-}
-
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)]
-pub enum FixedSpace { Default, Preserve } // yes, default really is not “Default”
-impl Default for FixedSpace { fn default() -> FixedSpace { FixedSpace::Preserve } }
-
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum AlignH { Left, Center, Right}
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum AlignHV { Top, Middle, Bottom, Left, Center, Right }
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum AlignV { Top, Middle, Bottom }
-
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum TableAlignH { Left, Right, Center, Justify, Char }
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum TableBorder { Top, Bottom, TopBottom, All, Sides, None }
-
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub struct ID(pub String);
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub struct NameToken(pub String);
-
-// The table DTD has the cols attribute of tgroup as required, but having
-// TableGroupCols not implement Default would leave no possible implementation
-// for TableGroup::with_children.
-#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub struct TableGroupCols(pub usize);
-impl Default for TableGroupCols {
- fn default() -> Self {
- TableGroupCols(0)
- }
-}
-
-// no eq for f64
-#[derive(Debug,PartialEq,Serialize,Clone)]
-pub enum Measure { // http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#length-units
- Em(f64),
- Ex(f64),
- Mm(f64),
- Cm(f64),
- In(f64),
- Px(f64),
- Pt(f64),
- Pc(f64),
-}
-
-impl FromStr for AlignHV {
- type Err = Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- use self::AlignHV::*;
- Ok(match s {
- "top" => Top,
- "middle" => Middle,
- "bottom" => Bottom,
- "left" => Left,
- "center" => Center,
- "right" => Right,
- s => bail!("Invalid Alignment {}", s),
- })
- }
-}
-
-impl From<&str> for ID {
- fn from(s: &str) -> Self {
- ID(s.to_owned().replace(' ', "-"))
- }
-}
-
-impl From<&str> for NameToken {
- fn from(s: &str) -> Self {
- NameToken(s.to_owned())
- }
-}
-
-impl FromStr for Measure {
- type Err = Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- use self::Measure::*;
- let re = Regex::new(r"(?P<float>\d+\.\d*|\.?\d+)\s*(?P<unit>em|ex|mm|cm|in|px|pt|pc)").unwrap();
- let caps: regex::Captures = re.captures(s).ok_or_else(|| format_err!("Invalid measure"))?;
- let value: f64 = caps["float"].parse()?;
- Ok(match &caps["unit"] {
- "em" => Em(value),
- "ex" => Ex(value),
- "mm" => Mm(value),
- "cm" => Cm(value),
- "in" => In(value),
- "px" => Px(value),
- "pt" => Pt(value),
- "pc" => Pc(value),
- _ => unreachable!(),
- })
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn test_parse_measure() {
- let _a: Measure = "1.5em".parse().unwrap();
- let _b: Measure = "20 mm".parse().unwrap();
- let _c: Measure = ".5in".parse().unwrap();
- let _d: Measure = "1.pc".parse().unwrap();
- }
-}
-
-pub(crate) trait CanBeEmpty {
- fn is_empty(&self) -> bool;
-}
-
-/* Specialization necessary
-impl<T> CanBeEmpty for T {
- fn is_empty(&self) -> bool { false }
-}
-*/
-macro_rules! impl_cannot_be_empty {
- ($t:ty) => {
- impl CanBeEmpty for $t {
- fn is_empty(&self) -> bool { false }
- }
- };
- ($t:ty, $($ts:ty),*) => {
- impl_cannot_be_empty!($t);
- impl_cannot_be_empty!($($ts),*);
- };
-}
-impl_cannot_be_empty!(Url);
-impl_cannot_be_empty!(TableGroupCols);
-
-impl<T> CanBeEmpty for Option<T> {
- fn is_empty(&self) -> bool { self.is_none() }
-}
-
-impl<T> CanBeEmpty for Vec<T> {
- fn is_empty(&self) -> bool { self.is_empty() }
-}
-
-impl CanBeEmpty for bool {
- fn is_empty(&self) -> bool { !self }
-}
-
-impl CanBeEmpty for FixedSpace {
- fn is_empty(&self) -> bool { self == &FixedSpace::default() }
-}
-
diff --git a/src/document_tree/element_categories.rs b/src/document_tree/element_categories.rs
deleted file mode 100644
index db3f420..0000000
--- a/src/document_tree/element_categories.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-use std::fmt::{self,Debug,Formatter};
-
-use serde_derive::Serialize;
-
-use super::elements::*;
-
-pub trait HasChildren<C> {
- fn with_children(children: Vec<C>) -> Self;
- fn children(&self) -> &Vec<C>;
- fn children_mut(&mut self) -> &mut Vec<C>;
- fn append_child<R: Into<C>>(&mut self, child: R) {
- self.children_mut().push(child.into());
- }
- fn append_children<R: Into<C> + Clone>(&mut self, more: &[R]) {
- let children = self.children_mut();
- children.reserve(more.len());
- for child in more {
- children.push(child.clone().into());
- }
- }
-}
-
-macro_rules! impl_into {
- ([ $( (($subcat:ident :: $entry:ident), $supcat:ident), )+ ]) => {
- $( impl_into!($subcat::$entry => $supcat); )+
- };
- ($subcat:ident :: $entry:ident => $supcat:ident ) => {
- impl Into<$supcat> for $entry {
- fn into(self) -> $supcat {
- $supcat::$subcat(Box::new(self.into()))
- }
- }
- };
-}
-
-macro_rules! synonymous_enum {
- ( $subcat:ident : $($supcat:ident),+ ; $midcat:ident : $supsupcat:ident { $($entry:ident),+ $(,)* } ) => {
- synonymous_enum!($subcat : $( $supcat ),+ , $midcat { $($entry,)* });
- $( impl_into!($midcat::$entry => $supsupcat); )+
- };
- ( $subcat:ident : $($supcat:ident),+ { $($entry:ident),+ $(,)* } ) => {
- synonymous_enum!($subcat { $( $entry, )* });
- cartesian!(impl_into, [ $( ($subcat::$entry) ),+ ], [ $($supcat),+ ]);
- };
- ( $name:ident { $( $entry:ident ),+ $(,)* } ) => {
- #[derive(PartialEq,Serialize,Clone)]
- pub enum $name { $(
- $entry(Box<$entry>),
- )* }
-
- impl Debug for $name {
- fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
- match *self {
- $( $name::$entry(ref inner) => inner.fmt(fmt), )*
- }
- }
- }
-
- $( impl Into<$name> for $entry {
- fn into(self) -> $name {
- $name::$entry(Box::new(self))
- }
- } )*
- };
-}
-
-synonymous_enum!(StructuralSubElement { Title, Subtitle, Decoration, Docinfo, SubStructure });
-synonymous_enum!(SubStructure: StructuralSubElement { Topic, Sidebar, Transition, Section, BodyElement });
-synonymous_enum!(BodyElement: SubTopic, SubSidebar, SubBlockQuote, SubFootnote, SubFigure; SubStructure: StructuralSubElement {
- //Simple
- Paragraph, LiteralBlock, DoctestBlock, MathBlock, Rubric, SubstitutionDefinition, Comment, Pending, Target, Raw, Image,
- //Compound
- Compound, Container,
- BulletList, EnumeratedList, DefinitionList, FieldList, OptionList,
- LineBlock, BlockQuote, Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning, Footnote, Citation, SystemMessage, Figure, Table
-});
-
-synonymous_enum!(BibliographicElement { Author, Authors, Organization, Address, Contact, Version, Revision, Status, Date, Copyright, Field });
-
-synonymous_enum!(TextOrInlineElement {
- String, Emphasis, Strong, Literal, Reference, FootnoteReference, CitationReference, SubstitutionReference, TitleReference, Abbreviation, Acronym, Superscript, Subscript, Inline, Problematic, Generated, Math,
- //also have non-inline versions. Inline image is no figure child, inline target has content
- TargetInline, RawInline, ImageInline
-});
-
-//--------------\\
-//Content Models\\
-//--------------\\
-
-synonymous_enum!(AuthorInfo { Author, Organization, Address, Contact });
-synonymous_enum!(DecorationElement { Header, Footer });
-synonymous_enum!(SubTopic { Title, BodyElement });
-synonymous_enum!(SubSidebar { Topic, Title, Subtitle, BodyElement });
-synonymous_enum!(SubDLItem { Term, Classifier, Definition });
-synonymous_enum!(SubField { FieldName, FieldBody });
-synonymous_enum!(SubOptionListItem { OptionGroup, Description });
-synonymous_enum!(SubOption { OptionString, OptionArgument });
-synonymous_enum!(SubLineBlock { LineBlock, Line });
-synonymous_enum!(SubBlockQuote { Attribution, BodyElement });
-synonymous_enum!(SubFootnote { Label, BodyElement });
-synonymous_enum!(SubFigure { Caption, Legend, BodyElement });
-synonymous_enum!(SubTable { Title, TableGroup });
-synonymous_enum!(SubTableGroup { TableColspec, TableHead, TableBody });
-
-#[cfg(test)]
-mod test {
- use std::default::Default;
- use super::*;
-
- #[test]
- fn test_convert_basic() {
- let _: BodyElement = Paragraph::default().into();
- }
-
- #[test]
- fn test_convert_more() {
- let _: SubStructure = Paragraph::default().into();
- }
-
- #[test]
- fn test_convert_even_more() {
- let _: StructuralSubElement = Paragraph::default().into();
- }
-
- #[test]
- fn test_convert_super() {
- let be: BodyElement = Paragraph::default().into();
- let _: StructuralSubElement = be.into();
- }
-}
diff --git a/src/document_tree/element_types.rs b/src/document_tree/element_types.rs
deleted file mode 100644
index 429573e..0000000
--- a/src/document_tree/element_types.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-
-// enum ElementType {
-// //structual elements
-// Section, Topic, Sidebar,
-//
-// //structural subelements
-// Title, Subtitle, Decoration, Docinfo, Transition,
-//
-// //bibliographic elements
-// Author, Authors, Organization,
-// Address { space: FixedSpace },
-// Contact, Version, Revision, Status,
-// Date, Copyright, Field,
-//
-// //decoration elements
-// Header, Footer,
-//
-// //simple body elements
-// Paragraph,
-// LiteralBlock { space: FixedSpace },
-// DoctestBlock { space: FixedSpace },
-// MathBlock, Rubric,
-// SubstitutionDefinition { ltrim: bool, rtrim: bool },
-// Comment { space: FixedSpace },
-// Pending,
-// Target { refuri: Url, refid: ID, refname: Vec<NameToken>, anonymous: bool },
-// Raw { space: FixedSpace, format: Vec<NameToken> },
-// Image {
-// align: AlignHV,
-// uri: Url,
-// alt: String,
-// height: Measure,
-// width: Measure,
-// scale: f64,
-// },
-//
-// //compound body elements
-// Compound, Container,
-//
-// BulletList { bullet: String },
-// EnumeratedList { enumtype: EnumeratedListType, prefix: String, suffix: String },
-// DefinitionList, FieldList, OptionList,
-//
-// LineBlock, BlockQuote,
-// Admonition, Attention, Hint, Note,
-// Caution, Danger, Error, Important,
-// Tip, Warning,
-// Footnote { backrefs: Vec<ID>, auto: bool },
-// Citation { backrefs: Vec<ID> },
-// SystemMessage { backrefs: Vec<ID>, level: usize, line: usize, type_: NameToken },
-// Figure { align: AlignH, width: usize },
-// Table, //TODO: Table
-//
-// //body sub elements
-// ListItem,
-//
-// DefinitionListItem, Term,
-// Classifier, Definition,
-//
-// FieldName, FieldBody,
-//
-// OptionListItem, OptionGroup, Description, Option_, OptionString,
-// OptionArgument { delimiter: String },
-//
-// Line, Attribution, Label,
-//
-// Caption, Legend,
-//
-// //inline elements
-// Emphasis, Strong, Literal,
-// Reference { name: String, refuri: Url, refid: ID, refname: Vec<NameToken> },
-// FootnoteReference { refid: ID, refname: Vec<NameToken>, auto: bool },
-// CitationReference { refid: ID, refname: Vec<NameToken> },
-// SubstitutionReference { refname: Vec<NameToken> },
-// TitleReference,
-// Abbreviation, Acronym,
-// Superscript, Subscript,
-// Inline,
-// Problematic { refid: ID },
-// Generated, Math,
-//
-// //also have non-inline versions. Inline image is no figure child, inline target has content
-// TargetInline { refuri: Url, refid: ID, refname: Vec<NameToken>, anonymous: bool },
-// RawInline { space: FixedSpace, format: Vec<NameToken> },
-// ImageInline {
-// align: AlignHV,
-// uri: Url,
-// alt: String,
-// height: Measure,
-// width: Measure,
-// scale: f64,
-// },
-//
-// //text element
-// TextElement,
-// }
diff --git a/src/document_tree/elements.rs b/src/document_tree/elements.rs
deleted file mode 100644
index 7406cd7..0000000
--- a/src/document_tree/elements.rs
+++ /dev/null
@@ -1,288 +0,0 @@
-use std::path::PathBuf;
-use serde_derive::Serialize;
-
-use super::attribute_types::{CanBeEmpty,ID,NameToken};
-use super::extra_attributes::{self,ExtraAttributes};
-use super::element_categories::*;
-
-
-//-----------------\\
-//Element hierarchy\\
-//-----------------\\
-
-pub trait Element {
- /// A list containing one or more unique identifier keys
- fn ids (& self) -> & Vec<ID>;
- fn ids_mut(&mut self) -> &mut Vec<ID>;
- /// a list containing the names of an element, typically originating from the element's title or content.
- /// Each name in names must be unique; if there are name conflicts (two or more elements want to the same name),
- /// the contents will be transferred to the dupnames attribute on the duplicate elements.
- /// An element may have at most one of the names or dupnames attributes, but not both.
- fn names (& self) -> & Vec<NameToken>;
- fn names_mut(&mut self) -> &mut Vec<NameToken>;
- fn source (& self) -> & Option<PathBuf>;
- fn source_mut(&mut self) -> &mut Option<PathBuf>;
- fn classes (& self) -> & Vec<String>;
- fn classes_mut(&mut self) -> &mut Vec<String>;
-}
-
-#[derive(Debug,Default,PartialEq,Serialize,Clone)]
-pub struct CommonAttributes {
- #[serde(skip_serializing_if = "CanBeEmpty::is_empty")]
- ids: Vec<ID>,
- #[serde(skip_serializing_if = "CanBeEmpty::is_empty")]
- names: Vec<NameToken>,
- #[serde(skip_serializing_if = "CanBeEmpty::is_empty")]
- source: Option<PathBuf>,
- #[serde(skip_serializing_if = "CanBeEmpty::is_empty")]
- classes: Vec<String>,
- //TODO: dupnames
-}
-
-//----\\
-//impl\\
-//----\\
-
-macro_rules! impl_element { ($name:ident) => (
- impl Element for $name {
- fn ids (& self) -> & Vec<ID> { & self.common.ids }
- fn ids_mut(&mut self) -> &mut Vec<ID> { &mut self.common.ids }
- fn names (& self) -> & Vec<NameToken> { & self.common.names }
- fn names_mut(&mut self) -> &mut Vec<NameToken> { &mut self.common.names }
- fn source (& self) -> & Option<PathBuf> { & self.common.source }
- fn source_mut(&mut self) -> &mut Option<PathBuf> { &mut self.common.source }
- fn classes (& self) -> & Vec<String> { & self.common.classes }
- fn classes_mut(&mut self) -> &mut Vec<String> { &mut self.common.classes }
- }
-)}
-
-macro_rules! impl_children { ($name:ident, $childtype:ident) => (
- impl HasChildren<$childtype> for $name {
- #[allow(clippy::needless_update)]
- fn with_children(children: Vec<$childtype>) -> $name { $name { children: children, ..Default::default() } }
- fn children (& self) -> & Vec<$childtype> { & self.children }
- fn children_mut(&mut self) -> &mut Vec<$childtype> { &mut self.children }
- }
-)}
-
-macro_rules! impl_extra { ($name:ident $($more:tt)*) => (
- impl ExtraAttributes<extra_attributes::$name> for $name {
- #[allow(clippy::needless_update)]
- fn with_extra(extra: extra_attributes::$name) -> $name { $name { common: Default::default(), extra: extra $($more)* } }
- fn extra (& self) -> & extra_attributes::$name { & self.extra }
- fn extra_mut(&mut self) -> &mut extra_attributes::$name { &mut self.extra }
- }
-)}
-
-trait HasExtraAndChildren<C, A> {
- fn with_extra_and_children(extra: A, children: Vec<C>) -> Self;
-}
-
-impl<T, C, A> HasExtraAndChildren<C, A> for T where T: HasChildren<C> + ExtraAttributes<A> {
- #[allow(clippy::needless_update)]
- fn with_extra_and_children(extra: A, mut children: Vec<C>) -> Self {
- let mut r = Self::with_extra(extra);
- r.children_mut().extend(children.drain(..));
- r
- }
-}
-
-macro_rules! impl_new {(
- $(#[$attr:meta])*
- pub struct $name:ident { $(
- $(#[$fattr:meta])*
- $field:ident : $typ:path
- ),* $(,)* }
-) => (
- $(#[$attr])*
- #[derive(Debug,PartialEq,Serialize,Clone)]
- pub struct $name { $(
- $(#[$fattr])* $field: $typ,
- )* }
- impl $name {
- pub fn new( $( $field: $typ, )* ) -> $name { $name { $( $field: $field, )* } }
- }
-)}
-
-macro_rules! impl_elem {
- ($name:ident) => {
- impl_new!(#[derive(Default)] pub struct $name {
- #[serde(flatten)] common: CommonAttributes,
- });
- impl_element!($name);
- };
- ($name:ident; +) => {
- impl_new!(#[derive(Default)] pub struct $name {
- #[serde(flatten)] common: CommonAttributes,
- #[serde(flatten)] extra: extra_attributes::$name,
- });
- impl_element!($name); impl_extra!($name, ..Default::default());
- };
- ($name:ident; *) => { //same as above with no default
- impl_new!(pub struct $name {
- #[serde(flatten)] common: CommonAttributes,
- #[serde(flatten)] extra: extra_attributes::$name
- });
- impl_element!($name); impl_extra!($name);
- };
- ($name:ident, $childtype:ident) => {
- impl_new!(#[derive(Default)] pub struct $name {
- #[serde(flatten)] common: CommonAttributes,
- children: Vec<$childtype>,
- });
- impl_element!($name); impl_children!($name, $childtype);
- };
- ($name:ident, $childtype:ident; +) => {
- impl_new!(#[derive(Default)] pub struct $name {
- #[serde(flatten)] common: CommonAttributes,
- #[serde(flatten)] extra: extra_attributes::$name,
- children: Vec<$childtype>,
- });
- impl_element!($name); impl_extra!($name, ..Default::default()); impl_children!($name, $childtype);
- };
-}
-
-macro_rules! impl_elems { ( $( ($($args:tt)*) )* ) => (
- $( impl_elem!($($args)*); )*
-)}
-
-
-#[derive(Default,Debug,Serialize)]
-pub struct Document { children: Vec<StructuralSubElement> }
-impl_children!(Document, StructuralSubElement);
-
-impl_elems!(
- //structual elements
- (Section, StructuralSubElement)
- (Topic, SubTopic)
- (Sidebar, SubSidebar)
-
- //structural subelements
- (Title, TextOrInlineElement)
- (Subtitle, TextOrInlineElement)
- (Decoration, DecorationElement)
- (Docinfo, BibliographicElement)
- (Transition)
-
- //bibliographic elements
- (Author, TextOrInlineElement)
- (Authors, AuthorInfo)
- (Organization, TextOrInlineElement)
- (Address, TextOrInlineElement; +)
- (Contact, TextOrInlineElement)
- (Version, TextOrInlineElement)
- (Revision, TextOrInlineElement)
- (Status, TextOrInlineElement)
- (Date, TextOrInlineElement)
- (Copyright, TextOrInlineElement)
- (Field, SubField)
-
- //decoration elements
- (Header, BodyElement)
- (Footer, BodyElement)
-
- //simple body elements
- (Paragraph, TextOrInlineElement)
- (LiteralBlock, TextOrInlineElement; +)
- (DoctestBlock, TextOrInlineElement; +)
- (MathBlock, String)
- (Rubric, TextOrInlineElement)
- (SubstitutionDefinition, TextOrInlineElement; +)
- (Comment, TextOrInlineElement; +)
- (Pending)
- (Target; +)
- (Raw, String; +)
- (Image; *)
-
- //compound body elements
- (Compound, BodyElement)
- (Container, BodyElement)
-
- (BulletList, ListItem; +)
- (EnumeratedList, ListItem; +)
- (DefinitionList, DefinitionListItem)
- (FieldList, Field)
- (OptionList, OptionListItem)
-
- (LineBlock, SubLineBlock)
- (BlockQuote, SubBlockQuote)
- (Admonition, SubTopic)
- (Attention, BodyElement)
- (Hint, BodyElement)
- (Note, BodyElement)
- (Caution, BodyElement)
- (Danger, BodyElement)
- (Error, BodyElement)
- (Important, BodyElement)
- (Tip, BodyElement)
- (Warning, BodyElement)
- (Footnote, SubFootnote; +)
- (Citation, SubFootnote; +)
- (SystemMessage, BodyElement; +)
- (Figure, SubFigure; +)
- (Table, SubTable; +)
-
- //table elements
- (TableGroup, SubTableGroup; +)
- (TableHead, TableRow; +)
- (TableBody, TableRow; +)
- (TableRow, TableEntry; +)
- (TableEntry, BodyElement; +)
- (TableColspec; +)
-
- //body sub elements
- (ListItem, BodyElement)
-
- (DefinitionListItem, SubDLItem)
- (Term, TextOrInlineElement)
- (Classifier, TextOrInlineElement)
- (Definition, BodyElement)
-
- (FieldName, TextOrInlineElement)
- (FieldBody, BodyElement)
-
- (OptionListItem, SubOptionListItem)
- (OptionGroup, Option_)
- (Description, BodyElement)
- (Option_, SubOption)
- (OptionString, String)
- (OptionArgument, String; +)
-
- (Line, TextOrInlineElement)
- (Attribution, TextOrInlineElement)
- (Label, TextOrInlineElement)
-
- (Caption, TextOrInlineElement)
- (Legend, BodyElement)
-
- //inline elements
- (Emphasis, TextOrInlineElement)
- (Literal, TextOrInlineElement)
- (Reference, TextOrInlineElement; +)
- (Strong, TextOrInlineElement)
- (FootnoteReference, TextOrInlineElement; +)
- (CitationReference, TextOrInlineElement; +)
- (SubstitutionReference, TextOrInlineElement; +)
- (TitleReference, TextOrInlineElement)
- (Abbreviation, TextOrInlineElement)
- (Acronym, TextOrInlineElement)
- (Superscript, TextOrInlineElement)
- (Subscript, TextOrInlineElement)
- (Inline, TextOrInlineElement)
- (Problematic, TextOrInlineElement; +)
- (Generated, TextOrInlineElement)
- (Math, String)
-
- //also have non-inline versions. Inline image is no figure child, inline target has content
- (TargetInline, String; +)
- (RawInline, String; +)
- (ImageInline; *)
-
- //text element = String
-);
-
-impl<'a> From<&'a str> for TextOrInlineElement {
- fn from(s: &'a str) -> Self {
- s.to_owned().into()
- }
-}
diff --git a/src/document_tree/extra_attributes.rs b/src/document_tree/extra_attributes.rs
deleted file mode 100644
index 55896ab..0000000
--- a/src/document_tree/extra_attributes.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use serde_derive::Serialize;
-
-use crate::url::Url;
-use super::attribute_types::{CanBeEmpty,FixedSpace,ID,NameToken,AlignHV,AlignH,AlignV,TableAlignH,TableBorder,TableGroupCols,Measure,EnumeratedListType};
-
-pub trait ExtraAttributes<A> {
- fn with_extra(extra: A) -> Self;
- fn extra (& self) -> & A;
- fn extra_mut(&mut self) -> &mut A;
-}
-
-macro_rules! impl_extra {
- ( $name:ident { $( $(#[$pattr:meta])* $param:ident : $type:ty ),* $(,)* } ) => (
- impl_extra!(
- #[derive(Default,Debug,PartialEq,Serialize,Clone)]
- $name { $( $(#[$pattr])* $param : $type, )* }
- );
- );
- ( $(#[$attr:meta])+ $name:ident { $( $(#[$pattr:meta])* $param:ident : $type:ty ),* $(,)* } ) => (
- $(#[$attr])+
- pub struct $name { $(
- $(#[$pattr])*
- #[serde(skip_serializing_if = "CanBeEmpty::is_empty")]
- pub $param : $type,
- )* }
- );
-}
-
-impl_extra!(Address { space: FixedSpace });
-impl_extra!(LiteralBlock { space: FixedSpace });
-impl_extra!(DoctestBlock { space: FixedSpace });
-impl_extra!(SubstitutionDefinition { ltrim: bool, rtrim: bool });
-impl_extra!(Comment { space: FixedSpace });
-impl_extra!(Target {
- /// External reference to a URI/URL
- refuri: Option<Url>,
- /// References to ids attributes in other elements
- refid: Option<ID>,
- /// Internal reference to the names attribute of another element. May resolve to either an internal or external reference.
- refname: Vec<NameToken>,
- anonymous: bool,
-});
-impl_extra!(Raw { space: FixedSpace, format: Vec<NameToken> });
-impl_extra!(#[derive(Debug,PartialEq,Serialize,Clone)] Image {
- uri: Url,
- align: Option<AlignHV>,
- alt: Option<String>,
- height: Option<Measure>,
- width: Option<Measure>,
- scale: Option<u8>,
- target: Option<Url>, // Not part of the DTD but a valid argument
-});
-
-//bools usually are XML yesorno. “auto” however either exists and is set to something random like “1” or doesn’t exist
-//does auto actually mean the numbering prefix?
-
-impl_extra!(BulletList { bullet: Option<String> });
-impl_extra!(EnumeratedList { enumtype: Option<EnumeratedListType>, prefix: Option<String>, suffix: Option<String> });
-
-impl_extra!(Footnote { backrefs: Vec<ID>, auto: bool });
-impl_extra!(Citation { backrefs: Vec<ID> });
-impl_extra!(SystemMessage { backrefs: Vec<ID>, level: Option<usize>, line: Option<usize>, type_: Option<NameToken> });
-impl_extra!(Figure { align: Option<AlignH>, width: Option<usize> });
-impl_extra!(Table { frame: Option<TableBorder>, colsep: Option<bool>, rowsep: Option<bool>, pgwide: Option<bool> });
-
-impl_extra!(TableGroup { cols: TableGroupCols, colsep: Option<bool>, rowsep: Option<bool>, align: Option<TableAlignH> });
-impl_extra!(TableHead { valign: Option<AlignV> });
-impl_extra!(TableBody { valign: Option<AlignV> });
-impl_extra!(TableRow { rowsep: Option<bool>, valign: Option<AlignV> });
-impl_extra!(TableEntry { colname: Option<NameToken>, namest: Option<NameToken>, nameend: Option<NameToken>, morerows: Option<usize>, colsep: Option<bool>, rowsep: Option<bool>, align: Option<TableAlignH>, r#char: Option<char>, charoff: Option<usize>, valign: Option<AlignV>, morecols: Option<usize> });
-impl_extra!(TableColspec { colnum: Option<usize>, colname: Option<NameToken>, colwidth: Option<String>, colsep: Option<bool>, rowsep: Option<bool>, align: Option<TableAlignH>, r#char: Option<char>, charoff: Option<usize>, stub: Option<bool> });
-
-impl_extra!(OptionArgument { delimiter: Option<String> });
-
-impl_extra!(Reference {
- name: Option<NameToken>, //TODO: is CDATA in the DTD, so maybe no nametoken?
- /// External reference to a URI/URL
- refuri: Option<Url>,
- /// References to ids attributes in other elements
- refid: Option<ID>,
- /// Internal reference to the names attribute of another element
- refname: Vec<NameToken>,
-});
-impl_extra!(FootnoteReference { refid: Option<ID>, refname: Vec<NameToken>, auto: bool });
-impl_extra!(CitationReference { refid: Option<ID>, refname: Vec<NameToken> });
-impl_extra!(SubstitutionReference { refname: Vec<NameToken> });
-impl_extra!(Problematic { refid: Option<ID> });
-
-//also have non-inline versions. Inline image is no figure child, inline target has content
-impl_extra!(TargetInline {
- /// External reference to a URI/URL
- refuri: Option<Url>,
- /// References to ids attributes in other elements
- refid: Option<ID>,
- /// Internal reference to the names attribute of another element. May resolve to either an internal or external reference.
- refname: Vec<NameToken>,
- anonymous: bool,
-});
-impl_extra!(RawInline { space: FixedSpace, format: Vec<NameToken> });
-pub type ImageInline = Image;
-
-impl Image {
- pub fn new(uri: Url) -> Image { Image {
- uri,
- align: None,
- alt: None,
- height: None,
- width: None,
- scale: None,
- target: None,
- } }
-}
diff --git a/src/document_tree/macro_util.rs b/src/document_tree/macro_util.rs
deleted file mode 100644
index d9b8a3e..0000000
--- a/src/document_tree/macro_util.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-macro_rules! cartesian_impl {
- ($out:tt [] $b:tt $init_b:tt $submacro:tt) => {
- $submacro!{$out}
- };
- ($out:tt [$a:tt, $($at:tt)*] [] $init_b:tt $submacro:tt) => {
- cartesian_impl!{$out [$($at)*] $init_b $init_b $submacro}
- };
- ([$($out:tt)*] [$a:tt, $($at:tt)*] [$b:tt, $($bt:tt)*] $init_b:tt $submacro:tt) => {
- cartesian_impl!{[$($out)* ($a, $b),] [$a, $($at)*] [$($bt)*] $init_b $submacro}
- };
-}
-
-macro_rules! cartesian {
- ( $submacro:tt, [$($a:tt)*], [$($b:tt)*]) => {
- cartesian_impl!{[] [$($a)*,] [$($b)*,] [$($b)*,] $submacro}
- };
-}
-
-
-#[cfg(test)]
-mod test {
- macro_rules! print_cartesian {
- ( [ $(($a1:tt, $a2:tt)),* , ] ) => {
- fn test_f(x:i64, y:i64) -> Result<(i64, i64), ()> {
- match (x, y) {
- $(
- ($a1, $a2) => { Ok(($a1, $a2)) }
- )*
- _ => { Err(()) }
- }
- }
- };
- }
-
- #[test]
- fn test_print_cartesian() {
- cartesian!(print_cartesian, [1, 2, 3], [4, 5, 6]);
- assert_eq!(test_f(1, 4), Ok((1, 4)));
- assert_eq!(test_f(1, 3), Err(()));
- assert_eq!(test_f(3, 5), Ok((3, 5)));
- }
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index 6e39b1a..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![recursion_limit="256"]
-
-pub mod document_tree;
-pub mod parser;
-pub mod renderer;
-pub mod url;
diff --git a/src/parser.rs b/src/parser.rs
deleted file mode 100644
index 00c967d..0000000
--- a/src/parser.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-pub mod token;
-mod conversion;
-mod simplify;
-mod pest_rst;
-mod pair_ext_parse;
-#[cfg(test)]
-pub mod tests;
-
-use failure::Error;
-use pest::Parser;
-
-use crate::document_tree::Document;
-
-use self::pest_rst::{RstParser,Rule};
-use self::conversion::convert_document;
-use self::simplify::resolve_references;
-
-
-/// Parse into a document tree and resolve sections, but not references.
-pub fn parse_only(source: &str) -> Result<Document, Error> {
- let pairs = RstParser::parse(Rule::document, source)?;
- convert_document(pairs)
-}
-
-/// Parse into a document tree and resolve sections and references.
-pub fn parse(source: &str) -> Result<Document, Error> {
- parse_only(source).map(resolve_references)
-}
diff --git a/src/parser/conversion.rs b/src/parser/conversion.rs
deleted file mode 100644
index f9e2a78..0000000
--- a/src/parser/conversion.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-mod block;
-mod inline;
-
-use failure::Error;
-use pest::iterators::Pairs;
-
-use crate::document_tree::{
- Element,HasChildren,
- elements as e,
- element_categories as c,
- attribute_types as at,
-};
-
-use super::pest_rst::Rule;
-
-
-fn ssubel_to_section_unchecked_mut(ssubel: &mut c::StructuralSubElement) -> &mut e::Section {
- match ssubel {
- c::StructuralSubElement::SubStructure(ref mut b) => match **b {
- c::SubStructure::Section(ref mut s) => s,
- _ => unreachable!(),
- },
- _ => unreachable!(),
- }
-}
-
-
-fn get_level<'tl>(toplevel: &'tl mut Vec<c::StructuralSubElement>, section_idxs: &[Option<usize>]) -> &'tl mut Vec<c::StructuralSubElement> {
- let mut level = toplevel;
- for maybe_i in section_idxs {
- if let Some(i) = *maybe_i {
- level = ssubel_to_section_unchecked_mut(&mut level[i]).children_mut();
- }
- }
- level
-}
-
-
-pub fn convert_document(pairs: Pairs<Rule>) -> Result<e::Document, Error> {
- use self::block::TitleOrSsubel::*;
-
- let mut toplevel: Vec<c::StructuralSubElement> = vec![];
- // The kinds of section titles encountered.
- // `section_idx[x]` has the kind `kinds[x]`, but `kinds` can be longer
- let mut kinds: Vec<block::TitleKind> = vec![];
- // Recursive indices into the tree, pointing at the active sections.
- // `None`s indicate skipped section levels:
- // toplevel[section_idxs.flatten()[0]].children[section_idxs.flatten()[1]]...
- let mut section_idxs: Vec<Option<usize>> = vec![];
-
- for pair in pairs {
- if let Some(ssubel) = block::convert_ssubel(pair)? { match ssubel {
- Title(title, kind) => {
- match kinds.iter().position(|k| k == &kind) {
- // Idx points to the level we want to add,
- // so idx-1 needs to be the last valid index.
- Some(idx) => {
- // If idx < len: Remove found section and all below
- section_idxs.truncate(idx);
- // If idx > len: Add None for skipped levels
- // TODO: test skipped levels
- while section_idxs.len() < idx { section_idxs.push(None) }
- },
- None => kinds.push(kind),
- }
- let super_level = get_level(&mut toplevel, &section_idxs);
- let slug = title.names().iter().next().map(|at::NameToken(name)| at::ID(name.to_owned()));
- let mut section = e::Section::with_children(vec![title.into()]);
- section.ids_mut().extend(slug.into_iter());
- super_level.push(section.into());
- section_idxs.push(Some(super_level.len() - 1));
- },
- Ssubel(elem) => get_level(&mut toplevel, &section_idxs).push(elem),
- }}
- }
- 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 {
- use crate::{
- parser::parse,
- document_tree::{
- elements as e,
- element_categories as c,
- HasChildren,
- }
- };
-
- fn ssubel_to_section(ssubel: &c::StructuralSubElement) -> &e::Section {
- match ssubel {
- c::StructuralSubElement::SubStructure(ref b) => match **b {
- c::SubStructure::Section(ref s) => s,
- ref c => panic!("Expected section, not {:?}", c),
- },
- ref c => panic!("Expected SubStructure, not {:?}", c),
- }
- }
-
- const SECTIONS: &str = "\
-Intro before first section title
-
-Level 1
-*******
-
--------
-Level 2
--------
-
-Level 3
-=======
-
-L1 again
-********
-
-L3 again, skipping L2
-=====================
-";
-
- #[test]
- fn convert_skipped_section() {
- let doctree = parse(SECTIONS).unwrap();
- let lvl0 = doctree.children();
- assert_eq!(lvl0.len(), 3, "Should be a paragraph and 2 sections: {:?}", lvl0);
-
- assert_eq!(lvl0[0], e::Paragraph::with_children(vec![
- "Intro before first section title".to_owned().into()
- ]).into(), "The intro text should fit");
-
- let lvl1a = ssubel_to_section(&lvl0[1]).children();
- assert_eq!(lvl1a.len(), 2, "The 1st lvl1 section should have (a title and) a single lvl2 section as child: {:?}", lvl1a);
- //TODO: test title lvl1a[0]
- let lvl2 = ssubel_to_section(&lvl1a[1]).children();
- assert_eq!(lvl2.len(), 2, "The lvl2 section should have (a title and) a single lvl3 section as child: {:?}", lvl2);
- //TODO: test title lvl2[0]
- let lvl3a = ssubel_to_section(&lvl2[1]).children();
- assert_eq!(lvl3a.len(), 1, "The 1st lvl3 section should just a title: {:?}", lvl3a);
- //TODO: test title lvl3a[0]
-
- let lvl1b = ssubel_to_section(&lvl0[2]).children();
- assert_eq!(lvl1b.len(), 2, "The 2nd lvl1 section should have (a title and) a single lvl2 section as child: {:?}", lvl1b);
- //TODO: test title lvl1b[0]
- let lvl3b = ssubel_to_section(&lvl1b[1]).children();
- assert_eq!(lvl3b.len(), 1, "The 2nd lvl3 section should have just a title: {:?}", lvl3b);
- //TODO: test title lvl3b[0]
- }
-}
diff --git a/src/parser/conversion/block.rs b/src/parser/conversion/block.rs
deleted file mode 100644
index b14c2b5..0000000
--- a/src/parser/conversion/block.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-use failure::{Error,bail};
-use pest::iterators::Pair;
-
-use crate::document_tree::{
- Element,HasChildren,ExtraAttributes,
- 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::{whitespace_normalize_name, inline::convert_inlines};
-
-
-#[derive(PartialEq)]
-pub(super) enum TitleKind { Double(char), Single(char) }
-
-pub(super) enum TitleOrSsubel {
- Title(e::Title, TitleKind),
- Ssubel(c::StructuralSubElement),
-}
-
-
-pub(super) fn convert_ssubel(pair: Pair<Rule>) -> Result<Option<TitleOrSsubel>, Error> {
- use self::TitleOrSsubel::*;
- Ok(Some(match pair.as_rule() {
- Rule::title => { let (t, k) = convert_title(pair)?; Title(t, k) },
- //TODO: subtitle, decoration, docinfo
- Rule::EOI => return Ok(None),
- _ => Ssubel(convert_substructure(pair)?.into()),
- }))
-}
-
-
-fn convert_substructure(pair: Pair<Rule>) -> Result<c::SubStructure, Error> {
- Ok(match pair.as_rule() {
- // todo: Topic, Sidebar, Transition
- // no section here, as it’s constructed from titles
- _ => convert_body_elem(pair)?.into(),
- })
-}
-
-
-fn convert_body_elem(pair: Pair<Rule>) -> Result<c::BodyElement, Error> {
- Ok(match pair.as_rule() {
- Rule::paragraph => convert_paragraph(pair)?.into(),
- Rule::target => convert_target(pair)?.into(),
- Rule::substitution_def => convert_substitution_def(pair)?.into(),
- Rule::admonition_gen => convert_admonition_gen(pair)?.into(),
- Rule::image => convert_image::<e::Image>(pair)?.into(),
- Rule::bullet_list => convert_bullet_list(pair)?.into(),
- rule => unimplemented!("unhandled rule {:?}", rule),
- })
-}
-
-
-fn convert_title(pair: Pair<Rule>) -> Result<(e::Title, TitleKind), Error> {
- let mut title: Option<String> = None;
- let mut title_inlines: Option<Vec<c::TextOrInlineElement>> = None;
- let mut adornment_char: Option<char> = None;
- // title_double or title_single. Extract kind before consuming
- let inner_pair = pair.into_inner().next().unwrap();
- let kind = inner_pair.as_rule();
- for p in inner_pair.into_inner() {
- match p.as_rule() {
- Rule::line => {
- title = Some(p.as_str().to_owned());
- title_inlines = Some(convert_inlines(p)?);
- },
- Rule::adornments => adornment_char = Some(p.as_str().chars().next().expect("Empty adornment?")),
- rule => unimplemented!("Unexpected rule in title: {:?}", rule),
- };
- }
- // now we encountered one line of text and one of adornments
- // TODO: emit error if the adornment line is too short (has to match title length)
- let mut elem = e::Title::with_children(title_inlines.expect("No text in title"));
- if let Some(title) = title {
- //TODO: slugify properly
- let slug = title.to_lowercase().replace("\n", "").replace(" ", "-");
- elem.names_mut().push(at::NameToken(slug));
- }
- let title_kind = match kind {
- Rule::title_double => TitleKind::Double(adornment_char.unwrap()),
- Rule::title_single => TitleKind::Single(adornment_char.unwrap()),
- _ => unreachable!(),
- };
- Ok((elem, title_kind))
-}
-
-
-fn convert_paragraph(pair: Pair<Rule>) -> Result<e::Paragraph, Error> {
- Ok(e::Paragraph::with_children(convert_inlines(pair)?))
-}
-
-
-fn convert_target(pair: Pair<Rule>) -> Result<e::Target, Error> {
- 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 => {
- elem.ids_mut().push(p.as_str().into());
- elem.names_mut().push(p.as_str().into());
- },
- // TODO: also handle non-urls
- Rule::link_target => elem.extra_mut().refuri = Some(p.parse()?),
- rule => panic!("Unexpected rule in target: {:?}", rule),
- }
- }
- Ok(elem)
-}
-
-fn convert_substitution_def(pair: Pair<Rule>) -> Result<e::SubstitutionDefinition, Error> {
- let mut pairs = pair.into_inner();
- let name = whitespace_normalize_name(pairs.next().unwrap().as_str()); // Rule::substitution_name
- let inner_pair = pairs.next().unwrap();
- let inner: Vec<c::TextOrInlineElement> = match inner_pair.as_rule() {
- Rule::replace => convert_replace(inner_pair)?,
- Rule::image => vec![convert_image::<e::ImageInline>(inner_pair)?.into()],
- rule => panic!("Unknown substitution rule {:?}", rule),
- };
- let mut subst_def = e::SubstitutionDefinition::with_children(inner);
- subst_def.names_mut().push(at::NameToken(name));
- Ok(subst_def)
-}
-
-fn convert_replace(pair: Pair<Rule>) -> Result<Vec<c::TextOrInlineElement>, Error> {
- let mut pairs = pair.into_inner();
- let paragraph = pairs.next().unwrap();
- convert_inlines(paragraph)
-}
-
-fn convert_image<I>(pair: Pair<Rule>) -> Result<I, Error> where I: Element + ExtraAttributes<a::Image> {
- let mut pairs = pair.into_inner();
- let mut image = I::with_extra(a::Image::new(
- pairs.next().unwrap().as_str().trim().parse()?, // line
- ));
- for opt in pairs {
- let mut opt_iter = opt.into_inner();
- let opt_name = opt_iter.next().unwrap();
- let opt_val = opt_iter.next().unwrap();
- match opt_name.as_str() {
- "class" => image.classes_mut().push(opt_val.as_str().to_owned()),
- "name" => image.names_mut().push(opt_val.as_str().into()),
- "alt" => image.extra_mut().alt = Some(opt_val.as_str().to_owned()),
- "height" => image.extra_mut().height = Some(opt_val.parse()?),
- "width" => image.extra_mut().width = Some(opt_val.parse()?),
- "scale" => image.extra_mut().scale = Some(parse_scale(&opt_val)?),
- "align" => image.extra_mut().align = Some(opt_val.parse()?),
- "target" => image.extra_mut().target = Some(opt_val.parse()?),
- name => bail!("Unknown Image option {}", name),
- }
- }
- Ok(image)
-}
-
-fn parse_scale(pair: &Pair<Rule>) -> Result<u8, Error> {
- let input = if pair.as_str().chars().rev().next() == Some('%') { &pair.as_str()[..pair.as_str().len()-1] } else { pair.as_str() };
- use pest::error::{Error,ErrorVariant};
- Ok(input.parse().map_err(|e: std::num::ParseIntError| {
- let var: ErrorVariant<Rule> = ErrorVariant::CustomError { message: e.to_string() };
- Error::new_from_span(var, pair.as_span())
- })?)
-}
-
-fn convert_admonition_gen(pair: Pair<Rule>) -> Result<c::BodyElement, Error> {
- let mut iter = pair.into_inner();
- let typ = iter.next().unwrap().as_str();
- // TODO: in reality it contains body elements.
- let children: Vec<c::BodyElement> = iter.map(|p| e::Paragraph::with_children(vec![p.as_str().into()]).into()).collect();
- Ok(match typ {
- "attention" => e::Attention::with_children(children).into(),
- "hint" => e::Hint::with_children(children).into(),
- "note" => e::Note::with_children(children).into(),
- "caution" => e::Caution::with_children(children).into(),
- "danger" => e::Danger::with_children(children).into(),
- "error" => e::Error::with_children(children).into(),
- "important" => e::Important::with_children(children).into(),
- "tip" => e::Tip::with_children(children).into(),
- "warning" => e::Warning::with_children(children).into(),
- typ => panic!("Unknown admontion type {}!", typ),
- })
-}
-
-fn convert_bullet_list(pair: Pair<Rule>) -> Result<e::BulletList, Error> {
- Ok(e::BulletList::with_children(pair.into_inner().map(convert_bullet_item).collect::<Result<_, _>>()?))
-}
-
-fn convert_bullet_item(pair: Pair<Rule>) -> Result<e::ListItem, Error> {
- let mut iter = pair.into_inner();
- let mut children: Vec<c::BodyElement> = vec![
- convert_paragraph(iter.next().unwrap())?.into()
- ];
- for p in iter {
- children.push(convert_body_elem(p)?);
- }
- Ok(e::ListItem::with_children(children))
-}
diff --git a/src/parser/conversion/inline.rs b/src/parser/conversion/inline.rs
deleted file mode 100644
index b2fffa5..0000000
--- a/src/parser/conversion/inline.rs
+++ /dev/null
@@ -1,161 +0,0 @@
-use failure::Error;
-use pest::iterators::Pair;
-
-use crate::document_tree::{
- HasChildren,
- 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 crate::url::Url;
-use super::whitespace_normalize_name;
-
-
-pub fn convert_inline(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> {
- Ok(match pair.as_rule() {
- Rule::str | Rule::str_nested => pair.as_str().into(),
- Rule::ws_newline => " ".to_owned().into(),
- Rule::reference => convert_reference(pair)?,
- Rule::substitution_name => convert_substitution_ref(pair)?.into(),
- Rule::emph => e::Emphasis::with_children(convert_inlines(pair)?).into(),
- Rule::strong => e::Strong::with_children(convert_inlines(pair)?).into(),
- Rule::literal => e::Literal::with_children(convert_inlines(pair)?).into(),
- rule => unimplemented!("unknown rule {:?}", rule),
- })
-}
-
-pub fn convert_inlines(pair: Pair<Rule>) -> Result<Vec<c::TextOrInlineElement>, Error> {
- pair.into_inner().map(convert_inline).collect()
-}
-
-fn convert_reference(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> {
- let name;
- let refuri;
- let refid;
- let mut refname = vec![];
- let mut children: Vec<c::TextOrInlineElement> = vec![];
- let concrete = pair.into_inner().next().unwrap();
- match concrete.as_rule() {
- Rule::reference_target => {
- let rt_inner = concrete.into_inner().next().unwrap(); // reference_target_uq or target_name_qu
- match rt_inner.as_rule() {
- Rule::reference_target_uq => {
- refid = None;
- name = Some(rt_inner.as_str().into());
- refuri = None;
- refname.push(rt_inner.as_str().into());
- children.push(rt_inner.as_str().into());
- },
- Rule::reference_target_qu => {
- let (text, reference) = {
- let mut text = None;
- let mut reference = None;
- for inner in rt_inner.clone().into_inner() {
- match inner.as_rule() {
- Rule::reference_text => text = Some(inner),
- Rule::reference_bracketed => reference = Some(inner),
- _ => unreachable!()
- }
- }
- (text, reference)
- };
- let trimmed_text = match (&text, &reference) {
- (Some(text), None) => text.as_str(),
- (_, Some(reference)) => {
- text
- .map(|text| text.as_str().trim_end_matches(|ch| " \n\r".contains(ch)))
- .filter(|text| !text.is_empty())
- .unwrap_or_else(|| reference.clone().into_inner().next().unwrap().as_str())
- }
- (None, None) => unreachable!()
- };
- refid = None;
- name = Some(trimmed_text.into());
- refuri = if let Some(reference) = reference {
- let inner = reference.into_inner().next().unwrap();
- match inner.as_rule() {
- // The URL rules in our parser accept a narrow superset of
- // valid URLs, so we need to handle false positives.
- Rule::url => if let Ok(target) = Url::parse_absolute(inner.as_str()) {
- Some(target)
- } else if inner.as_str().ends_with('_') {
- // like target_name_qu (minus the final underscore)
- let full_str = inner.as_str();
- refname.push(full_str[0..full_str.len() - 1].into());
- None
- } else {
- // like relative_reference
- Some(Url::parse_relative(inner.as_str())?)
- },
- Rule::target_name_qu => {
- refname.push(inner.as_str().into());
- None
- },
- Rule::relative_reference => {
- Some(Url::parse_relative(inner.as_str())?)
- },
- _ => unreachable!()
- }
- } else {
- refname.push(trimmed_text.into());
- None
- };
- children.push(trimmed_text.into());
- },
- _ => unreachable!()
- }
- },
- Rule::reference_explicit => unimplemented!("explicit reference"),
- Rule::reference_auto => {
- let rt_inner = concrete.into_inner().next().unwrap();
- match rt_inner.as_rule() {
- Rule::url_auto => match Url::parse_absolute(rt_inner.as_str()) {
- Ok(target) => {
- refuri = Some(target);
- name = None;
- refid = None;
- children.push(rt_inner.as_str().into());
- },
- // if our parser got a URL wrong, return it as a string
- Err(_) => return Ok(rt_inner.as_str().into())
- },
- Rule::email => {
- let mailto_url = String::from("mailto:") + rt_inner.as_str();
- match Url::parse_absolute(&mailto_url) {
- Ok(target) => {
- refuri = Some(target);
- name = None;
- refid = None;
- children.push(rt_inner.as_str().into());
- },
- // if our parser got a URL wrong, return it as a string
- Err(_) => return Ok(rt_inner.as_str().into())
- }
- },
- _ => unreachable!()
- }
- },
- _ => unreachable!(),
- };
- Ok(e::Reference::new(
- Default::default(),
- a::Reference { name, refuri, refid, refname },
- children
- ).into())
-}
-
-fn convert_substitution_ref(pair: Pair<Rule>) -> Result<e::SubstitutionReference, Error> {
- let name = whitespace_normalize_name(pair.as_str());
- Ok(a::ExtraAttributes::with_extra(
- a::SubstitutionReference {
- refname: vec![at::NameToken(name)]
- }
- ))
-}
diff --git a/src/parser/pair_ext_parse.rs b/src/parser/pair_ext_parse.rs
deleted file mode 100644
index a04b3dd..0000000
--- a/src/parser/pair_ext_parse.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use std::str::FromStr;
-
-use pest::Span;
-use pest::iterators::Pair;
-use pest::error::{Error,ErrorVariant};
-
-
-pub trait PairExt<R> where R: pest::RuleType {
- fn parse<T, E>(&self) -> Result<T, Error<R>> where T: FromStr<Err = E>, E: ToString;
-}
-
-impl<'l, R> PairExt<R> for Pair<'l, R> where R: pest::RuleType {
- fn parse<T, E>(&self) -> Result<T, Error<R>> where T: FromStr<Err = E>, E: ToString {
- self.as_str().parse().map_err(|e| to_parse_error(self.as_span(), &e))
- }
-}
-
-pub(crate) fn to_parse_error<E, R>(span: Span, e: &E) -> Error<R> where E: ToString, R: pest::RuleType {
- let var: ErrorVariant<R> = ErrorVariant::CustomError { message: e.to_string() };
- Error::new_from_span(var, span)
-}
diff --git a/src/parser/pest_rst.rs b/src/parser/pest_rst.rs
deleted file mode 100644
index 74199a8..0000000
--- a/src/parser/pest_rst.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![allow(clippy::redundant_closure)]
-
-use pest_derive::Parser;
-
-#[derive(Parser)]
-#[grammar = "rst.pest"]
-pub struct RstParser;
diff --git a/src/parser/simplify.rs b/src/parser/simplify.rs
deleted file mode 100644
index cc169ee..0000000
--- a/src/parser/simplify.rs
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
-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 https://repo.or.cz/docutils.git/blob/HEAD:/docutils/docutils/transforms/references.py
-*/
-
-use std::collections::HashMap;
-
-use crate::url::Url;
-use crate::document_tree::{
- Document,
- HasChildren,
- attribute_types::NameToken,
- elements::{self as e, Element},
- element_categories as c,
- extra_attributes::ExtraAttributes,
-};
-
-
-#[derive(Debug)]
-enum NamedTargetType {
- NumberedFootnote(usize),
- LabeledFootnote(usize),
- Citation,
- InternalLink,
- ExternalLink(Url),
- IndirectLink(NameToken),
- SectionTitle,
-}
-impl NamedTargetType {
- fn is_implicit_target(&self) -> bool {
- match self {
- NamedTargetType::SectionTitle => true,
- _ => false,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-struct Substitution {
- content: Vec<c::TextOrInlineElement>,
- /// If true and the sibling before the reference is a text node,
- /// the text node gets right-trimmed.
- ltrim: bool,
- /// Same as `ltrim` with the sibling after the reference.
- rtrim: bool,
-}
-
-#[derive(Default, Debug)]
-struct TargetsCollected {
- named_targets: HashMap<NameToken, NamedTargetType>,
- 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 {
- fn populate_targets(&self, refs: &mut TargetsCollected);
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> where Self: Sized;
-}
-
-pub fn resolve_references(mut doc: Document) -> Document {
- let mut references: TargetsCollected = Default::default();
- for c in doc.children() {
- c.populate_targets(&mut references);
- }
- let new: Vec<_> = doc.children_mut().drain(..).flat_map(|c| c.resolve_refs(&references)).collect();
- Document::with_children(new)
-}
-
-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: &TargetsCollected) -> P where P: e::Element + HasChildren<C>, C: ResolvableRefs {
- let new: Vec<_> = parent.children_mut().drain(..).flat_map(|c| c.resolve_refs(refs)).collect();
- parent.children_mut().extend(new);
- parent
-}
-
-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: &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 TargetsCollected) {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::StructuralSubElement::*;
- vec![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) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubStructure {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::SubStructure::*;
- match self {
- Topic(e) => sub_pop(&**e, refs),
- Sidebar(e) => sub_pop(&**e, refs),
- Transition(_) => {},
- Section(e) => sub_pop(&**e, refs),
- BodyElement(e) => e.populate_targets(refs),
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::SubStructure::*;
- vec![match self {
- Topic(e) => sub_res(*e, refs).into(),
- Sidebar(e) => sub_res(*e, refs).into(),
- Transition(e) => Transition(e),
- Section(e) => sub_res(*e, refs).into(),
- BodyElement(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }]
- }
-}
-
-impl ResolvableRefs for c::BodyElement {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::BodyElement::*;
- match self {
- Paragraph(e) => sub_pop(&**e, refs),
- LiteralBlock(e) => sub_pop(&**e, refs),
- DoctestBlock(e) => sub_pop(&**e, refs),
- MathBlock(_) => {},
- Rubric(e) => sub_pop(&**e, refs),
- SubstitutionDefinition(e) => {
- let subst = Substitution {
- content: e.children().clone(),
- ltrim: e.extra().ltrim,
- rtrim: e.extra().rtrim
- };
- 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.0.to_lowercase(), subst.clone());
- }
- },
- Comment(_) => {},
- Pending(_) => {
- unimplemented!();
- },
- Target(e) => {
- 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),
- EnumeratedList(e) => sub_sub_pop(&**e, refs),
- DefinitionList(e) => sub_sub_pop(&**e, refs),
- FieldList(e) => sub_sub_pop(&**e, refs),
- OptionList(e) => sub_sub_pop(&**e, refs),
- LineBlock(e) => sub_pop(&**e, refs),
- BlockQuote(e) => sub_pop(&**e, refs),
- Admonition(e) => sub_pop(&**e, refs),
- Attention(e) => sub_pop(&**e, refs),
- Hint(e) => sub_pop(&**e, refs),
- Note(e) => sub_pop(&**e, refs),
- Caution(e) => sub_pop(&**e, refs),
- Danger(e) => sub_pop(&**e, refs),
- Error(e) => sub_pop(&**e, refs),
- Important(e) => sub_pop(&**e, refs),
- Tip(e) => sub_pop(&**e, refs),
- Warning(e) => sub_pop(&**e, refs),
- Footnote(e) => sub_pop(&**e, refs),
- Citation(e) => sub_pop(&**e, refs),
- SystemMessage(e) => sub_pop(&**e, refs),
- Figure(e) => sub_pop(&**e, refs),
- Table(e) => sub_pop(&**e, refs)
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::BodyElement::*;
- vec![match self {
- Paragraph(e) => sub_res(*e, refs).into(),
- LiteralBlock(e) => sub_res(*e, refs).into(),
- DoctestBlock(e) => sub_res(*e, refs).into(),
- MathBlock(e) => MathBlock(e),
- Rubric(e) => sub_res(*e, refs).into(),
- SubstitutionDefinition(_) => return vec![],
- Comment(e) => Comment(e),
- Pending(e) => Pending(e),
- Target(e) => Target(e),
- Raw(e) => Raw(e),
- Image(e) => Image(e),
- Compound(e) => sub_res(*e, refs).into(),
- Container(e) => sub_res(*e, refs).into(),
- BulletList(e) => sub_sub_res(*e, refs).into(),
- EnumeratedList(e) => sub_sub_res(*e, refs).into(),
- DefinitionList(e) => sub_sub_res(*e, refs).into(),
- FieldList(e) => sub_sub_res(*e, refs).into(),
- OptionList(e) => sub_sub_res(*e, refs).into(),
- LineBlock(e) => sub_res(*e, refs).into(),
- BlockQuote(e) => sub_res(*e, refs).into(),
- Admonition(e) => sub_res(*e, refs).into(),
- Attention(e) => sub_res(*e, refs).into(),
- Hint(e) => sub_res(*e, refs).into(),
- Note(e) => sub_res(*e, refs).into(),
- Caution(e) => sub_res(*e, refs).into(),
- Danger(e) => sub_res(*e, refs).into(),
- Error(e) => sub_res(*e, refs).into(),
- Important(e) => sub_res(*e, refs).into(),
- Tip(e) => sub_res(*e, refs).into(),
- Warning(e) => sub_res(*e, refs).into(),
- Footnote(e) => sub_res(*e, refs).into(),
- Citation(e) => sub_res(*e, refs).into(),
- SystemMessage(e) => sub_res(*e, refs).into(),
- Figure(e) => sub_res(*e, refs).into(),
- Table(e) => sub_res(*e, refs).into()
- }]
- }
-}
-
-impl ResolvableRefs for c::BibliographicElement {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::BibliographicElement::*;
- match self {
- Author(e) => sub_pop(&**e, refs),
- Authors(e) => sub_pop(&**e, refs),
- Organization(e) => sub_pop(&**e, refs),
- Address(e) => sub_pop(&**e, refs),
- Contact(e) => sub_pop(&**e, refs),
- Version(e) => sub_pop(&**e, refs),
- Revision(e) => sub_pop(&**e, refs),
- Status(e) => sub_pop(&**e, refs),
- Date(e) => sub_pop(&**e, refs),
- Copyright(e) => sub_pop(&**e, refs),
- Field(e) => sub_pop(&**e, refs),
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::BibliographicElement::*;
- vec![match self {
- Author(e) => sub_res(*e, refs).into(),
- Authors(e) => sub_res(*e, refs).into(),
- Organization(e) => sub_res(*e, refs).into(),
- Address(e) => sub_res(*e, refs).into(),
- Contact(e) => sub_res(*e, refs).into(),
- Version(e) => sub_res(*e, refs).into(),
- Revision(e) => sub_res(*e, refs).into(),
- Status(e) => sub_res(*e, refs).into(),
- Date(e) => sub_res(*e, refs).into(),
- Copyright(e) => sub_res(*e, refs).into(),
- Field(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::TextOrInlineElement {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::TextOrInlineElement::*;
- match self {
- String(_) => {},
- Emphasis(e) => sub_pop(&**e, refs),
- Strong(e) => sub_pop(&**e, refs),
- Literal(e) => sub_pop(&**e, refs),
- Reference(e) => sub_pop(&**e, refs),
- FootnoteReference(e) => sub_pop(&**e, refs),
- CitationReference(e) => sub_pop(&**e, refs),
- SubstitutionReference(e) => sub_pop(&**e, refs),
- TitleReference(e) => sub_pop(&**e, refs),
- Abbreviation(e) => sub_pop(&**e, refs),
- Acronym(e) => sub_pop(&**e, refs),
- Superscript(e) => sub_pop(&**e, refs),
- Subscript(e) => sub_pop(&**e, refs),
- Inline(e) => sub_pop(&**e, refs),
- Problematic(e) => sub_pop(&**e, refs),
- Generated(e) => sub_pop(&**e, refs),
- Math(_) => {},
- TargetInline(_) => {
- unimplemented!();
- },
- RawInline(_) => {},
- ImageInline(_) => {}
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::TextOrInlineElement::*;
- vec![match self {
- String(e) => String(e),
- Emphasis(e) => sub_res(*e, refs).into(),
- Strong(e) => sub_res(*e, refs).into(),
- Literal(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) => 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);
- }
- return 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(),
- Abbreviation(e) => sub_res(*e, refs).into(),
- Acronym(e) => sub_res(*e, refs).into(),
- Superscript(e) => sub_res(*e, refs).into(),
- Subscript(e) => sub_res(*e, refs).into(),
- Inline(e) => sub_res(*e, refs).into(),
- Problematic(e) => sub_res(*e, refs).into(),
- Generated(e) => sub_res(*e, refs).into(),
- Math(e) => Math(e),
- TargetInline(e) => TargetInline(e),
- RawInline(e) => RawInline(e),
- ImageInline(e) => ImageInline(e)
- }]
- }
-}
-
-impl ResolvableRefs for c::AuthorInfo {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::AuthorInfo::*;
- match self {
- Author(e) => sub_pop(&**e, refs),
- Organization(e) => sub_pop(&**e, refs),
- Address(e) => sub_pop(&**e, refs),
- Contact(e) => sub_pop(&**e, refs),
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::AuthorInfo::*;
- vec![match self {
- Author(e) => sub_res(*e, refs).into(),
- Organization(e) => sub_res(*e, refs).into(),
- Address(e) => sub_res(*e, refs).into(),
- Contact(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::DecorationElement {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::DecorationElement::*;
- vec![match self {
- Header(e) => sub_res(*e, refs).into(),
- Footer(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubTopic {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubTopic::*;
- match self {
- Title(e) => vec![sub_res(*e, refs).into()],
- BodyElement(e) => e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }
- }
-}
-
-impl ResolvableRefs for c::SubSidebar {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::SubSidebar::*;
- match self {
- Topic(e) => sub_pop(&**e, refs),
- Title(e) => sub_pop(&**e, refs),
- Subtitle(e) => sub_pop(&**e, refs),
- BodyElement(e) => e.populate_targets(refs),
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::SubSidebar::*;
- vec![match self {
- Topic(e) => sub_res(*e, refs).into(),
- Title(e) => sub_res(*e, refs).into(),
- Subtitle(e) => sub_res(*e, refs).into(),
- BodyElement(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubDLItem {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::SubDLItem::*;
- match self {
- Term(e) => sub_pop(&**e, refs),
- Classifier(e) => sub_pop(&**e, refs),
- Definition(e) => sub_pop(&**e, refs),
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::SubDLItem::*;
- vec![match self {
- Term(e) => sub_res(*e, refs).into(),
- Classifier(e) => sub_res(*e, refs).into(),
- Definition(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubField {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubField::*;
- vec![match self {
- FieldName(e) => sub_res(*e, refs).into(),
- FieldBody(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubOptionListItem {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubOptionListItem::*;
- vec![match self {
- OptionGroup(e) => sub_sub_res(*e, refs).into(),
- Description(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubOption {
- fn populate_targets(&self, _: &mut TargetsCollected) {}
- fn resolve_refs(self, _: &TargetsCollected) -> Vec<Self> { vec![self] }
-}
-
-impl ResolvableRefs for c::SubLineBlock {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubLineBlock::*;
- vec![match self {
- LineBlock(e) => sub_res(*e, refs).into(),
- Line(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubBlockQuote {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubBlockQuote::*;
- match self {
- Attribution(e) => vec![sub_res(*e, refs).into()],
- BodyElement(e) => e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }
- }
-}
-
-impl ResolvableRefs for c::SubFootnote {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubFootnote::*;
- match self {
- Label(e) => vec![sub_res(*e, refs).into()],
- BodyElement(e) => e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }
- }
-}
-
-impl ResolvableRefs for c::SubFigure {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::SubFigure::*;
- match self {
- Caption(e) => sub_pop(&**e, refs),
- Legend(e) => sub_pop(&**e, refs),
- BodyElement(e) => e.populate_targets(refs),
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::SubFigure::*;
- vec![match self {
- Caption(e) => sub_res(*e, refs).into(),
- Legend(e) => sub_res(*e, refs).into(),
- BodyElement(e) => return e.resolve_refs(refs).drain(..).map(Into::into).collect(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubTable {
- 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: &TargetsCollected) -> Vec<Self> {
- use c::SubTable::*;
- vec![match self {
- Title(e) => sub_res(*e, refs).into(),
- TableGroup(e) => sub_res(*e, refs).into(),
- }]
- }
-}
-
-impl ResolvableRefs for c::SubTableGroup {
- fn populate_targets(&self, refs: &mut TargetsCollected) {
- use c::SubTableGroup::*;
- match self {
- TableColspec(_) => {
- unimplemented!();
- },
- TableHead(e) => {
- for c in e.children() {
- sub_sub_pop(c, refs);
- }
- },
- TableBody(e) => {
- for c in e.children() {
- sub_sub_pop(c, refs);
- }
- },
- }
- }
- fn resolve_refs(self, refs: &TargetsCollected) -> Vec<Self> {
- use c::SubTableGroup::*;
- vec![match self {
- TableColspec(e) => TableColspec(e),
- TableHead(mut e) => {
- let new: Vec<_> = e.children_mut().drain(..).map(|c| sub_sub_res(c, refs)).collect();
- e.children_mut().extend(new);
- TableHead(e)
- },
- TableBody(mut e) => {
- let new: Vec<_> = e.children_mut().drain(..).map(|c| sub_sub_res(c, refs)).collect();
- e.children_mut().extend(new);
- TableBody(e)
- },
- }]
- }
-}
diff --git a/src/parser/tests.rs b/src/parser/tests.rs
deleted file mode 100644
index a034c0e..0000000
--- a/src/parser/tests.rs
+++ /dev/null
@@ -1,241 +0,0 @@
-use pest::consumes_to;
-use pest::parses_to;
-use super::pest_rst::{RstParser, Rule};
-
-#[test]
-fn plain() {
- parses_to! {
- parser: RstParser,
- input: "line\n",
- rule: Rule::paragraph,
- tokens: [
- paragraph(0, 4, [
- str(0, 4)
- ])
- ]
- };
-}
-
-#[test]
-fn emph_only() {
- parses_to! {
- parser: RstParser,
- input: "*emphasis*",
- rule: Rule::emph_outer,
- tokens: [
- emph(1, 9, [str_nested(1, 9)])
- ]
- };
-}
-
-#[test]
-fn emph() {
- parses_to! {
- parser: RstParser,
- input: "line *with markup*\n",
- rule: Rule::paragraph,
- tokens: [
- paragraph(0, 18, [
- str(0, 5),
- emph(6, 17, [str_nested(6, 17)]),
- ])
- ]
- };
-}
-
-#[test]
-fn title() {
- parses_to! {
- parser: RstParser,
- input: "\
-Title
-=====
-",
- rule: Rule::title,
- tokens: [
- title(0, 12, [ title_single(0, 12, [
- line(0, 6, [ str(0, 5) ]),
- adornments(6, 11),
- ]) ])
- ]
- };
-}
-
-#[test]
-fn title_overline() {
- parses_to! {
- parser: RstParser,
- input: "\
------
-Title
------
-",
- rule: Rule::title,
- tokens: [
- title(0, 17, [ title_double(0, 17, [
- adornments(0, 5),
- line(6, 12, [ str(6, 11) ]),
- ]) ])
- ]
- };
-}
-
-#[allow(clippy::cognitive_complexity)]
-#[test]
-fn two_targets() {
- parses_to! {
- parser: RstParser,
- input: "\
-.. _a: http://example.com
-.. _`b_`: https://example.org
-",
- rule: Rule::document,
- tokens: [
- target(0, 26, [
- target_name_uq(4, 5),
- link_target(7, 25),
- ]),
- target(26, 56, [
- target_name_qu(31, 33),
- link_target(36, 55),
- ]),
- ]
- };
-}
-
-#[allow(clippy::cognitive_complexity)]
-#[test]
-fn admonitions() {
- parses_to! {
- parser: RstParser,
- input: "\
-.. note::
- Just next line
-.. admonition:: In line title
-
- Next line
-
-.. danger:: Just this line
-",
- rule: Rule::document,
- tokens: [
- admonition_gen(0, 27, [
- admonition_type(3, 7),
- paragraph(13, 27, [ str(13, 27) ]),
- ]),
- admonition(28, 71, [
- line(43, 58, [ str(43, 57) ]),
- paragraph(62, 71, [ str(62, 71) ]),
- ]),
- admonition_gen(73, 100, [
- admonition_type(76, 82),
- line(84, 100, [ str(84, 99) ]),
- ]),
- ]
- };
-}
-
-
-#[allow(clippy::cognitive_complexity)]
-#[test]
-fn substitutions() {
- parses_to! {
- parser: RstParser,
- input: "\
-A |subst| in-line
-
-.. |subst| replace:: substitution
-.. |subst2| replace:: it can also
- be hanging
-",
- rule: Rule::document,
- tokens: [
- paragraph(0, 17, [
- str(0, 2),
- substitution_name(3, 8),
- str(9, 17),
- ]),
- substitution_def(19, 52, [
- substitution_name(23, 28),
- replace(30, 52, [ paragraph(40, 52, [str(40, 52)]) ]),
- ]),
- substitution_def(53, 101, [
- substitution_name(57, 63),
- replace(65, 101, [ paragraph(75, 101, [
- str(75, 86), ws_newline(86, 87),
- str(88, 100),
- ]) ]),
- ]),
- ]
- };
-}
-
-
-#[allow(clippy::cognitive_complexity)]
-#[test]
-fn substitution_image() {
- parses_to! {
- parser: RstParser,
- input: "\
-.. |subst| image:: thing.png
- :target: foo.html
-",
- rule: Rule::document,
- tokens: [
- substitution_def(0, 50, [
- substitution_name(4, 9),
- image(11, 50, [
- line(18, 29, [ str(18, 28) ]),
- image_option(32, 50, [
- image_opt_name(33, 39),
- line(40, 50, [ str(40, 49) ]),
- ]),
- ]),
- ]),
- ]
- };
-}
-
-// TODO: test images
-
-#[allow(clippy::cognitive_complexity)]
-#[test]
-fn nested_lists() {
- parses_to! {
- parser: RstParser,
- input: "\
-paragraph
-
-- item 1
-- item 2
- more text
- more text 2
- more text 3
- - nested item 1
- - nested item 2
- - nested item 3
-",
- rule: Rule::document,
- tokens: [
- paragraph(0, 9, [ str(0, 9) ]),
- bullet_list(11, 131, [
- bullet_item(11, 21, [
- line(14, 21, [ str(14, 20) ]),
- ]),
- bullet_item(21, 131, [
- line(24, 31, [ str(24, 30) ]),
- paragraph(34, 74, [
- str(34, 43), ws_newline(43, 44),
- str(47, 58), ws_newline(58, 59),
- str(62, 73),
- ]),
- bullet_list(77, 131, [
- bullet_item( 77, 93, [ line( 79, 93, [str( 79, 92)]) ]),
- bullet_item( 96, 112, [ line( 98, 112, [str( 98, 111)]) ]),
- bullet_item(115, 131, [ line(117, 131, [str(117, 130)]) ]),
- ]),
- ]),
- ]),
- ]
- }
-}
diff --git a/src/parser/token.rs b/src/parser/token.rs
deleted file mode 100644
index b3b7bac..0000000
--- a/src/parser/token.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#bullet-lists
-
-// *, +, -, •, ‣, ⁃
-pub enum BulletListType { Ast, Plus, Minus, Bullet, TriBullet, HyphenBullet }
-// 1, A, a, I, i
-pub enum EnumListChar { Arabic, AlphaUpper, AlphaLower, RomanUpper, RomanLower, Auto }
-// 1., (1), 1)
-pub enum EnumListType { Period, ParenEnclosed, Paren }
-// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
-pub enum AdornmentChar {
- Bang, DQuote, Hash, Dollar, Percent, Amp, SQuote, LParen, RParen, Ast, Plus, Comma,
- Minus, Period, Slash, Colon, Semicolon, Less, Eq, More, Question, At, LBrack,
- Backslash, RBrack, Caret, Underscore, Backtick, LBrace, Pipe, RBrace, Tilde,
-}
-// [1], [#], [*], [#foo]
-pub enum FootnoteType { Numbered(usize), AutoNumber, AutoSymbol, AutoNamed(String) }
diff --git a/src/renderer.rs b/src/renderer.rs
deleted file mode 100644
index 82a5826..0000000
--- a/src/renderer.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-mod html;
-#[cfg(test)]
-pub mod html_tests;
-
-
-use std::io::Write;
-
-use failure::Error;
-
-use crate::document_tree::Document;
-
-
-pub fn render_json<W>(document: &Document, stream: W) -> Result<(), Error> where W: Write {
- serde_json::to_writer(stream, &document)?;
- Ok(())
-}
-
-pub fn render_xml<W>(document: &Document, stream: W) -> Result<(), Error> where W: Write {
- serde_xml_rs::to_writer(stream, &document).map_err(failure::SyncFailure::new)?;
- Ok(())
-}
-
-pub use html::render_html;
-
diff --git a/src/renderer/html.rs b/src/renderer/html.rs
deleted file mode 100644
index 6041ec0..0000000
--- a/src/renderer/html.rs
+++ /dev/null
@@ -1,388 +0,0 @@
-use std::io::Write;
-
-use failure::Error;
-
-// use crate::url::Url;
-use crate::document_tree::{
- Document,Element,HasChildren,ExtraAttributes,
- elements as e,
- element_categories as c,
- extra_attributes as a,
-};
-
-
-// static FOOTNOTE_SYMBOLS: [char; 10] = ['*', '†', '‡', '§', '¶', '#', '♠', '♥', '♦', '♣'];
-
-pub fn render_html<W>(document: &Document, stream: W, standalone: bool) -> Result<(), Error> where W: Write {
- let mut renderer = HTMLRenderer { stream, level: 0 };
- if standalone {
- document.render_html(&mut renderer)
- } else {
- for c in document.children() {
- (*c).render_html(&mut renderer)?;
- writeln!(renderer.stream)?;
- }
- Ok(())
- }
-}
-
-fn escape_html(text: &str) -> String {
- text.replace('&', "&amp;")
- .replace('<', "&lt;")
- .replace('>', "&gt;")
- .replace('"', "&quot;")
-}
-
-struct HTMLRenderer<W> where W: Write {
- stream: W,
- level: u8,
-}
-
-trait HTMLRender {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write;
-}
-
-macro_rules! impl_html_render_cat {($cat:ident { $($member:ident),+ }) => {
- impl HTMLRender for c::$cat {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- match self {$(
- c::$cat::$member(elem) => (**elem).render_html(renderer),
- )+}
- }
- }
-}}
-
-macro_rules! impl_html_render_simple {
- (
- $type1:ident => $tag1:ident $( [$($post1:tt)+] )?,
- $( $type:ident => $tag:ident $( [$($post:tt)+] )? ),+
- ) => {
- impl_html_render_simple!($type1 => $tag1 $([$($post1)+])?);
- $( impl_html_render_simple!($type => $tag $([$($post)+])?); )+
- };
- ( $type:ident => $tag:ident ) => {
- impl_html_render_simple!($type => $tag[""]);
- };
- ( $type:ident => $tag:ident [ $post:expr ] ) => {
- impl HTMLRender for e::$type {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- let multiple_children = self.children().len() > 1;
- write!(renderer.stream, "<{}>", stringify!($tag))?;
- if multiple_children { write!(renderer.stream, $post)?; }
- for c in self.children() {
- (*c).render_html(renderer)?;
- if multiple_children { write!(renderer.stream, $post)?; }
- }
- write!(renderer.stream, "</{}>", stringify!($tag))?;
- Ok(())
- }
- }
- };
-}
-
-macro_rules! impl_html_render_simple_nochildren {( $($type:ident => $tag:ident),+ ) => { $(
- impl HTMLRender for e::$type {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- write!(renderer.stream, "<{0}></{0}>", stringify!($tag))?;
- Ok(())
- }
- }
-)+ }}
-
-// Impl
-
-impl HTMLRender for Document {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- writeln!(renderer.stream, "<!doctype html><html>")?;
- for c in self.children() {
- (*c).render_html(renderer)?;
- writeln!(renderer.stream)?;
- }
- writeln!(renderer.stream, "</html>")?;
- Ok(())
- }
-}
-
-impl_html_render_cat!(StructuralSubElement { Title, Subtitle, Decoration, Docinfo, SubStructure });
-impl_html_render_simple!(Subtitle => h2);
-
-impl HTMLRender for e::Title {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- let level = if renderer.level > 6 { 6 } else { renderer.level };
- write!(renderer.stream, "<h{0}>", level)?;
- for c in self.children() {
- (*c).render_html(renderer)?;
- }
- write!(renderer.stream, "</h{0}>", level)?;
- Ok(())
- }
-}
-
-impl HTMLRender for e::Docinfo {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // Like “YAML frontmatter” in Markdown
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::Decoration {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // Header or footer
- unimplemented!();
- }
-}
-
-impl_html_render_cat!(SubStructure { Topic, Sidebar, Transition, Section, BodyElement });
-impl_html_render_simple!(Sidebar => aside);
-
-impl HTMLRender for e::Section {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- renderer.level += 1;
- writeln!(renderer.stream, "<section id=\"{0}\">", self.ids()[0].0)?;
- for c in self.children() {
- (*c).render_html(renderer)?;
- writeln!(renderer.stream)?;
- }
- write!(renderer.stream, "</section>")?;
- Ok(())
- }
-}
-
-impl HTMLRender for e::Transition {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- write!(renderer.stream, "<hr/>")?;
- Ok(())
- }
-}
-
-impl HTMLRender for e::Topic {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // A mini section with title
- unimplemented!();
- }
-}
-
-impl_html_render_cat!(BodyElement { Paragraph, LiteralBlock, DoctestBlock, MathBlock, Rubric, SubstitutionDefinition, Comment, Pending, Target, Raw, Image, Compound, Container, BulletList, EnumeratedList, DefinitionList, FieldList, OptionList, LineBlock, BlockQuote, Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning, Footnote, Citation, SystemMessage, Figure, Table });
-impl_html_render_simple!(Paragraph => p, LiteralBlock => pre, MathBlock => math, Rubric => a, Compound => p, Container => div, BulletList => ul["\n"], EnumeratedList => ol["\n"], DefinitionList => dl["\n"], FieldList => dl["\n"], OptionList => pre, LineBlock => div["\n"], BlockQuote => blockquote, Admonition => aside, Attention => aside, Hint => aside, Note => aside, Caution => aside, Danger => aside, Error => aside, Important => aside, Tip => aside, Warning => aside, Figure => figure);
-impl_html_render_simple_nochildren!(Table => table); //TODO: after implementing the table, move it to elems with children
-
-impl<I> HTMLRender for I where I: e::Element + a::ExtraAttributes<a::Image> {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- let extra = self.extra();
- if let Some(ref target) = extra.target {
- write!(renderer.stream, "<a href=\"{}\">", escape_html(target.as_str()))?;
- }
- write!(renderer.stream, "<img")?;
- if let Some(ref alt) = extra.alt {
- write!(renderer.stream, " alt=\"{}\"", escape_html(alt))?;
- }
- // TODO: align: Option<AlignHV>
- // TODO: height: Option<Measure>
- // TODO: width: Option<Measure>
- // TODO: scale: Option<u8>
- write!(renderer.stream, " src=\"{}\" />", escape_html(extra.uri.as_str()))?;
- if extra.target.is_some() {
- write!(renderer.stream, "</a>")?;
- }
- Ok(())
- }
-}
-
-impl HTMLRender for e::DoctestBlock {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // TODO
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::SubstitutionDefinition {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // TODO: Should those be removed after resolving them
- Ok(())
- }
-}
-
-impl HTMLRender for e::Comment {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- write!(renderer.stream, "<!--")?;
- for c in self.children() {
- (*c).render_html(renderer)?;
- }
- write!(renderer.stream, "-->")?;
- Ok(())
- }
-}
-
-impl HTMLRender for e::Pending {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<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, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // Should be resolved by now
- Ok(())
- }
-}
-
-impl HTMLRender for e::Raw {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- for c in self.children() {
- write!(renderer.stream, "{}", c)?;
- }
- Ok(())
- }
-}
-
-impl HTMLRender for e::Footnote {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::Citation {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::SystemMessage {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- write!(renderer.stream, "<figure><caption>System Message</caption>")?;
- for c in self.children() {
- (*c).render_html(renderer)?;
- }
- write!(renderer.stream, "</figure>")?;
- Ok(())
- }
-}
-
-impl_html_render_cat!(TextOrInlineElement { String, Emphasis, Strong, Literal, Reference, FootnoteReference, CitationReference, SubstitutionReference, TitleReference, Abbreviation, Acronym, Superscript, Subscript, Inline, Problematic, Generated, Math, TargetInline, RawInline, ImageInline });
-impl_html_render_simple!(Emphasis => em, Strong => strong, Literal => code, FootnoteReference => a, CitationReference => a, TitleReference => a, Abbreviation => abbr, Acronym => acronym, Superscript => sup, Subscript => sub, Inline => span, Math => math, TargetInline => a);
-
-impl HTMLRender for String {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- write!(renderer.stream, "{}", escape_html(self))?;
- Ok(())
- }
-}
-
-impl HTMLRender for e::Reference {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- let extra = self.extra();
- write!(renderer.stream, "<a")?;
- if let Some(ref target) = extra.refuri {
- write!(renderer.stream, " href=\"{}\"", escape_html(target.as_str()))?;
- }
- /*
- if let Some(ref name) = extra.name {
- write!(renderer.stream, " title=\"{}\"", escape_html(&name.0))?;
- }
- */
- write!(renderer.stream, ">")?;
- for c in self.children() {
- (*c).render_html(renderer)?;
- }
- write!(renderer.stream, "</a>")?;
- Ok(())
- }
-}
-
-impl HTMLRender for e::SubstitutionReference {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<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, _renderer: &mut HTMLRenderer<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, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // Section numbers and so on
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::RawInline {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- for c in self.children() {
- write!(renderer.stream, "{}", c)?;
- }
- Ok(())
- }
-}
-
-
-//--------------\\
-//Content Models\\
-//--------------\\
-
-impl_html_render_cat!(SubTopic { Title, BodyElement });
-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, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // Term→dt, Definition→dd, Classifier→???
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::Field {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // FieldName→dt, FieldBody→dd
- unimplemented!();
- }
-}
-
-impl HTMLRender for e::OptionListItem {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- // OptionGroup→dt(s), Description→dd
- unimplemented!();
- }
-}
-
-impl_html_render_cat!(SubLineBlock { LineBlock, Line });
-
-impl HTMLRender for e::Line {
- fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- for c in self.children() {
- (*c).render_html(renderer)?;
- }
- write!(renderer.stream, "<br>")?;
- Ok(())
- }
-}
-
-impl_html_render_cat!(SubBlockQuote { Attribution, BodyElement });
-impl_html_render_simple!(Attribution => cite); //TODO: correct?
-
-impl_html_render_cat!(SubFigure { Caption, Legend, BodyElement });
-impl_html_render_simple!(Caption => caption);
-
-impl HTMLRender for e::Legend {
- fn render_html<W>(&self, _renderer: &mut HTMLRenderer<W>) -> Result<(), Error> where W: Write {
- unimplemented!();
- }
-}
-
-//------------\\
-//Things to do\\
-//------------\\
-
-//TODO: prettyprint option list
-//TODO: render admonitions: Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning
-//TODO: properly render tables
-
-//TODO: add reference target: FootnoteReference, CitationReference, TitleReference
-//TODO: add title: Abbr, Acronym
-//TODO: convert math, set display attr
-//TODO: add id: Rubric, Target, TargetInline
diff --git a/src/renderer/html_tests.rs b/src/renderer/html_tests.rs
deleted file mode 100644
index 117b2d4..0000000
--- a/src/renderer/html_tests.rs
+++ /dev/null
@@ -1,274 +0,0 @@
-use pretty_assertions::assert_eq;
-
-use crate::parser::parse;
-use super::html::render_html;
-
-fn check_renders_to(rst: &str, expected: &str) {
- println!("Rendering:\n{}\n---", rst);
- let doc = parse(rst).expect("Cannot parse");
- let mut result_data: Vec<u8> = vec![];
- render_html(&doc, &mut result_data, false).expect("Render error");
- let result = String::from_utf8(result_data).expect("Could not decode");
- assert_eq!(result.as_str().trim(), expected);
-}
-
-#[test]
-fn test_simple_string() {
- check_renders_to(
- "Simple String",
- "<p>Simple String</p>",
- );
-}
-
-#[test]
-fn test_simple_string_with_markup() {
- check_renders_to(
- "Simple String with *emph* and **strong**",
- "<p>Simple String with <em>emph</em> and <strong>strong</strong></p>",
- );
-}
-
-#[test]
-fn test_check_inline_literal() {
- check_renders_to(
- "Simple String with an even simpler ``inline literal``",
- "<p>Simple String with an even simpler <code>inline literal</code></p>",
- );
-}
-
-/*
-#[test]
-fn test_reference_anonymous() {
- check_renders_to("\
-A simple `anonymous reference`__
-
-__ http://www.test.com/test_url
-", "\
-<p>A simple <a href=\"http://www.test.com/test_url\">anonymous reference</a></p>\
-");
-}
-*/
-
-#[test]
-fn test_two_paragraphs() {
- check_renders_to(
- "One paragraph.\n\nTwo paragraphs.",
- "<p>One paragraph.</p>\n<p>Two paragraphs.</p>",
- );
-}
-
-#[test]
-fn test_named_reference() {
- check_renders_to("\
-A simple `named reference`_ with stuff in between the
-reference and the target.
-
-.. _`named reference`: http://www.test.com/test_url
-", "\
-<p>A simple <a href=\"http://www.test.com/test_url\">named reference</a> with stuff in between the \
-reference and the target.</p>\
-");
-}
-
-#[test]
-fn test_substitution() {
- check_renders_to("\
-A |subst|.
-
-.. |subst| replace:: text substitution
-", "<p>A text substitution.</p>");
-}
-
-/*
-#[test]
-fn test_section_hierarchy() {
- check_renders_to("\
-+++++
-Title
-+++++
-
-Subtitle
-========
-
-Some stuff
-
-Section
--------
-
-Some more stuff
-
-Another Section
-...............
-
-And even more stuff
-", "\
-<p>Some stuff</p>
-<section id=\"section\">
-<h1>Section</h1>
-<p>Some more stuff</p>
-<section id=\"another-section\">
-<h2>Another Section</h2>
-<p>And even more stuff</p>
-</section>
-</section>\
-");
-}
-
-#[test]
-fn test_docinfo_title() {
- check_renders_to("\
-+++++
-Title
-+++++
-
-:author: me
-
-Some stuff
-", "\
-<main id=\"title\">
-<h1 class=\"title\">Title</h1>
-<dl class=\"docinfo simple\">
-<dt class=\"author\">Author</dt>
-<dd class=\"author\"><p>me</p></dd>
-</dl>
-<p>Some stuff</p>
-</main>\
-");
-}
-*/
-
-#[test]
-fn test_section_hierarchy() {
- check_renders_to("\
-+++++
-Title
-+++++
-
-Not A Subtitle
-==============
-
-Some stuff
-
-Section
--------
-
-Some more stuff
-
-Another Section
-...............
-
-And even more stuff
-", "\
-<section id=\"title\">
-<h1>Title</h1>
-<section id=\"not-a-subtitle\">
-<h2>Not A Subtitle</h2>
-<p>Some stuff</p>
-<section id=\"section\">
-<h3>Section</h3>
-<p>Some more stuff</p>
-<section id=\"another-section\">
-<h4>Another Section</h4>
-<p>And even more stuff</p>
-</section>
-</section>
-</section>
-</section>\
-");
-}
-
-#[test]
-fn test_bullet_list() {
- check_renders_to("\
-* bullet
-* list
-", "\
-<ul>
-<li><p>bullet</p></li>
-<li><p>list</p></li>
-</ul>\
-");
-}
-
-/*
-#[test]
-fn test_table() {
- check_renders_to("\
-.. table::
- :align: right
-
- +-----+-----+
- | 1 | 2 |
- +-----+-----+
- | 3 | 4 |
- +-----+-----+
-", "\
-<table class=\"align-right\">
-<colgroup>
-<col style=\"width: 50%%\" />
-<col style=\"width: 50%%\" />
-</colgroup>
-<tbody>
-<tr><td><p>1</p></td>
-<td><p>2</p></td>
-</tr>
-<tr><td><p>3</p></td>
-<td><p>4</p></td>
-</tr>
-</tbody>
-</table>\
-");
-}
-*/
-
-/*
-#[test]
-fn test_field_list() {
- check_renders_to("\
-Not a docinfo.
-
-:This: .. _target:
-
- is
-:a:
-:simple:
-:field: list
-", "\
-<p>Not a docinfo.</p>
-<dl class=\"field-list\">
-<dt>This</dt>
-<dd><p id=\"target\">is</p>
-</dd>
-<dt>a</dt>
-<dd><p></p></dd>
-<dt>simple</dt>
-<dd><p></p></dd>
-<dt>field</dt>
-<dd><p>list</p>
-</dd>
-</dl>\
-");
-}
-*/
-
-/*
-#[test]
-fn test_field_list_long() {
- check_renders_to("\
-Not a docinfo.
-
-:This is: a
-:simple field list with loooong field: names
-", "\
-<p>Not a docinfo.</p>
-<dl class=\"field-list\">
-<dt>This is</dt>
-<dd><p>a</p>
-</dd>
-<dt>simple field list with loooong field</dt>
-<dd><p>names</p>
-</dd>
-</dl>\
-");
-}
-*/
diff --git a/src/rst.pest b/src/rst.pest
deleted file mode 100644
index f3a1516..0000000
--- a/src/rst.pest
+++ /dev/null
@@ -1,474 +0,0 @@
-// Entry point: the document.
-
-// This grammar is aligned to the doctree names when possible.
-// It will however contain blocks, as we can’t parse sections:
-// Section headers define the hierarchy by their delimiters,
-// and pest only has one stack that we need for indentation.
-
-document = _{ SOI ~ blocks ~ EOI }
-blocks = _{ block ~ (blank_line* ~ block)* ~ blank_line? }
-block = _{ PEEK[..] ~ hanging_block }
-
-// This is the list of all block-level elements
-// They’re defined hanging, i.e. without the first PEEK[..]
-// This is d
-hanging_block = _{
- substitution_def
- | image_directive
- | admonition
- | admonition_gen
- | target
- | title
- | bullet_list
- | paragraph
-// TODO: implement all those things:
-// | block_quote
-// | verbatim
-// | image ✓
-// | code_block
-// | doctest_block
-// | admonition ✓
-// | target ✓
-// | horizontal_rule
-// | title ✓
-// | table
-// | ordered_list
-// | bullet_list ✓
-// | paragraph ✓
-// | plain
-}
-
-// Substitution definition. A block type
-substitution_def = { ".." ~ PUSH(" "+) ~ "|" ~ substitution_name ~ "|" ~ " "+ ~ inline_dirblock ~ DROP }
-substitution_name = { !" " ~ (!(" "|"|") ~ ANY)+ ~ (" "+ ~ (!(" "|"|") ~ ANY)+)* }
-inline_dirblock = _{ replace | image } // TODO: implement others
-
-// Target. A block type
-target = { target_qu | target_uq }
-target_uq = _{ ".. _" ~ target_name_uq ~ ":" ~ (" " ~ link_target)? ~ " "* ~ NEWLINE }
-target_qu = _{ ".. _`" ~ !"``" ~ target_name_qu ~ !"``:" ~ "`:" ~ (" " ~ link_target)? ~ " "* ~ NEWLINE }
-target_name_uq = { ( !("_"|":"|"`") ~ !NEWLINE ~ ANY )* }
-target_name_qu = { ( !(":"|"`"|"_>") ~ ANY )* }
-link_target = { nonspacechar+ }
-
-// Title. A block type
-title = { title_double | title_single }
-title_double = { PUSH(adornments) ~ NEWLINE ~ PEEK[..-1] ~ " "* ~ line ~ PEEK[..-1] ~ POP }
-title_single = { line ~ PEEK[..] ~ adornments ~ NEWLINE }
-
-// Bullet list. A block type.
-bullet_list = { bullet_item ~ (PEEK[..] ~ bullet_item)* }
-bullet_item = { bullet_marker ~ PUSH(" "+) ~ line ~ blank_line* ~ blist_body? ~ DROP }
-blist_body = _{ PEEK[..-1] ~ PUSH(" " ~ POP) ~ hanging_block ~ block* }
-
-// paragraph. A block type.
-paragraph = { inlines }
-
-
-/* Directives: http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#directives
- * .. name:: arguments ~ :options: ~ blank_line+ ~ content
- * Everything except for the first argument has to be indented
- */
-
-
-// Directives with options can have these or specific ones:
-common_opt_name = { "class" | "name" }
-
-// Replace. A directive only usable in substitutions.
-
-replace = { ^"replace::" ~ " "* ~ paragraph }
-
-// Image. A directive.
-
-image_directive = _{ ".." ~ PUSH(" "+) ~ image ~ DROP }
-image = { ^"image::" ~ line ~ image_opt_block? }
-image_opt_block = _{ PEEK[..-1] ~ PUSH(" " ~ POP) ~ image_option } //TODO: merge with other directives?
-image_option = { ":" ~ image_opt_name ~ ":" ~ line }
-image_opt_name = { common_opt_name | "alt" | "height" | "width" | "scale" | "align" | "target" }
-
-// Admonition. A directive. The generic one has a title
-
-admonition = { ".." ~ PUSH(" "+) ~ ^"admonition::" ~ line ~ blank_line* ~ admonition_content? ~ DROP }
-admonition_gen = { ".." ~ PUSH(" "+) ~ admonition_type ~ "::" ~ (blank_line | line) ~ blank_line* ~ admonition_content? ~ DROP }
-admonition_type = { ^"attention" | ^"caution" | ^"danger" | ^"error" | ^"hint" | ^"important" | ^"note" | ^"tip" | ^"warning" }
-admonition_content = _{ PEEK[..-1] ~ PUSH(" " ~ POP) ~ hanging_block ~ block* } //TODO: merge with other directives?
-
-
-
-/*
- * inlines
- */
-
-
-line = { !marker ~ inline+ ~ NEWLINE }
-blank_line = _{ !marker ~ !inline ~ " "* ~ NEWLINE }
-
-inlines = _{ !marker ~ inline+ ~ ( ( ws_newline ~ PEEK[..] ~ !marker ~ inline+ )+ ~ NEWLINE )? }
-ws_newline = { NEWLINE }
-inline = _{ inline_special | str }
-inline_special = _{
- reference
- | substitution_ref
- | emph_outer
- | strong_outer
- | literal_outer
-// | ul_or_star_line
-// | space
-// | note_reference
-// | footnote
-// //| citation
-// | code
-// | application_depent
-// | entity
-// | escaped_char
-// | smart
-// | symbol
-}
-
-str = { (!(NEWLINE | inline_special) ~ ANY)+ }
-
-// simple formatting
-inline_nested = _{ inline_special | str_nested }
-str_nested = { word_nested ~ ( " "+ ~ word_nested)* }
-// TODO: allow ` in emph and * in literal
-word_nested = _{ (!(NEWLINE | " " | inline_special | "*" | "`") ~ ANY)+ }
-
-emph_outer = _{ "*" ~ emph ~ "*" }
-emph = { (!("*"|" ") ~ inline_nested)+ ~ (" "+ ~ (!("*"|" ") ~ inline_nested)+)* }
-strong_outer = _{ "**" ~ strong ~ "**" }
-strong = { (!("*"|" ") ~ inline_nested)+ ~ (" "+ ~ (!("*"|" ") ~ inline_nested)+)* }
-literal_outer = _{ "``" ~ literal ~ "``" }
-literal = { (!("`"|" ") ~ inline_nested)+ ~ (" "+ ~ (!("`"|" ") ~ inline_nested)+)* }
-
-// inline links
-reference = { reference_target | reference_explicit | reference_auto }
-
-reference_target = { reference_target_uq ~ "_" | reference_target_qu }
-reference_target_uq = { (!("_"|":"|"`") ~ nonspacechar)+ }
-reference_target_qu = { ( !("`"? ~ "`_") ~ "`" ~ !"``" ) ~ reference_text? ~ ("<" ~ reference_bracketed ~ ">")? ~ ( "`" ~ !"``" ) ~ "_" }
-reference_text = { !"<" ~ ( !("`"|"<") ~ ANY )+ }
-reference_bracketed = { url | (target_name_qu ~ "_") | relative_reference }
-relative_reference = { (!("`"|">") ~ ANY)+ }
-
-reference_explicit = { reference_label ~ "(" ~ " "* ~ reference_source ~ " "* ~ (NEWLINE ~ PEEK[..])? ~ reference_title ~ " "* ~ ")" }
-reference_label = { "[" ~ !"^" ~ (!"]" ~ inline)* ~ "]" }
-reference_source = { reference_source_contents }
-reference_source_contents = _{ ( (!("("|")"|">") ~ nonspacechar)+ | "(" ~ reference_source_contents ~ ")" )* }
-reference_title = { ( reference_title_single | reference_title_double | "" ) }
-reference_title_single = { "'" ~ ( !("'" ~ " "+ ~ (")" | NEWLINE)) ~ ANY )* ~ "'" }
-reference_title_double = { "\"" ~ ( !("\"" ~ " "+ ~ (")" | NEWLINE)) ~ ANY )* ~ "\"" }
-
-// Emails can't end with punctuation, but URLs must use a separate rule.
-reference_auto = { url_auto | email }
-//reference_embedded = { "`" ~ reference_embedded_source ~ "<" ~ absolute_url_with_fragment ~ ">`_" ~ "_"? }
-//reference_embedded_source = { ( !("<"|":"|"`") ~ ( " " | nonspacechar | blank_line ) )* }
-
-substitution_ref = _{ "|" ~ substitution_name ~ "|" }
-
-/* URLs as defined by the WHATWG URL standard. */
-url = { absolute_url_no_query ~ ("?" ~ url_unit*)? ~ ("#" ~ url_unit*)? }
-absolute_url_no_query = {
- ( special_url_scheme ~ ":" ~ scheme_relative_special_url ) |
- ( ^"file:" ~ scheme_relative_file_url ) |
- ( arbitrary_scheme ~ ":" ~ relative_url )
-}
-scheme_relative_special_url = { "//" ~ host ~ (":" ~ url_port)? ~ path_absolute_url? }
-path_absolute_url = { "/" ~ path_relative_url }
-path_relative_url = { ( url_path_segment_unit* ~ "/" )* ~ url_path_segment_unit* }
-url_path_segment_unit = { !("/"|"?") ~ url_unit }
-url_port = { ASCII_DIGIT* }
-scheme_relative_file_url = { "//" ~ ( host ~ !("/:/"|"/|/") )? ~ path_absolute_url }
-relative_url = { ( "//" ~ host ~ (":" ~ url_port)? ~ path_absolute_url? ) | path_absolute_url | (!(arbitrary_scheme ~ ":") ~ path_relative_url) }
-/* this is approximately a superset of valid hosts and opaque hosts */
-host = { ( !(":"|"/"|"?"|"#") ~ url_unit)+ | ("["~(ASCII_HEX_DIGIT|"."|":")+~"]") }
-special_url_scheme = { ^"ftp" | (^"http" | ^"ws") ~ ^"s"? } /* doesn't include "file" */
-arbitrary_scheme = { ASCII_ALPHA ~ ASCII_ALPHANUMERIC* }
-url_unit = {
- ASCII_ALPHANUMERIC |
- "!"|"$"|"&"|"'"|"("|")"|"*"|"+"|","|"-"|"."|"/"|":"|";"|"="|"?"|"@"|"_"|"~" |
- (!(SURROGATE|NONCHARACTER_CODE_POINT) ~ '\u{A0}'..'\u{10FFFD}') |
- ("%" ~ ASCII_HEX_DIGIT{2})
-}
-
-/*
- * Rules for URLs that don't end in punctuation.
- * This is a modification of the rules above to incorporate the docutils rules
- * for the final character in an auto URL and for the character after it.
- * The patterns used here to emulate the behavior of docutils' regex are taken
- * from <http://www.inf.puc-rio.br/~roberto/docs/ry10-01.pdf>.
- */
-url_auto = {
- ( absolute_url_no_query ~ ("?" ~ url_unit*)? ~ "#" ~ url_units_auto ) |
- ( absolute_url_no_query ~ "?" ~ url_units_auto ) |
- ( special_url_scheme ~ "://" ~ host ~ (":" ~ url_port)? ~ path_absolute_url_auto ) |
- ( special_url_scheme ~ "://" ~ host ~ ":" ~ url_port ~ &follows_auto_url ) |
- ( special_url_scheme ~ "://" ~ ( domain_host_auto | "["~(ASCII_HEX_DIGIT|"."|":")+~"]" ~ &follows_auto_url ) ) |
- ( ^"file://" ~ ( host ~ !("/:/"|"/|/") )? ~ path_absolute_url_auto ) |
- ( arbitrary_scheme ~ ":" ~ relative_url_auto )
-}
-domain_host_auto = {
- ( !(":"|"/"|"?"|"#") ~ url_unit ~ url_units_auto ) |
- ( !(":"|"/"|"?"|"#") ~ url_unit ~ &">" ) |
- ( (ASCII_ALPHANUMERIC|"_"|"~"|"*"|"/"|"="|"+") ~ &follows_auto_url )
-}
-path_absolute_url_auto = { "/" ~ path_relative_url_auto }
-path_relative_url_auto = { prua1 | prua2 | &follows_auto_url }
-prua1 = { ( url_path_segment_unit ~ prua1 ) | ( "/" ~ path_relative_url_auto ) }
-prua2 = { ( url_path_segment_unit ~ prua2 ) | ( (ASCII_ALPHANUMERIC|"_"|"~"|"*"|"="|"+") ~ &follows_auto_url ) }
-relative_url_auto = {
- ( "//" ~ host ~ (":" ~ url_port)? ~ path_absolute_url_auto ) |
- ( "//" ~ host ~ ":" ~ url_port ~ &follows_auto_url ) |
- ( "//" ~ ( domain_host_auto | "["~(ASCII_HEX_DIGIT|"."|":")+~"]" ~ &follows_auto_url ) ) |
- path_absolute_url_auto |
- // (prua1|prua2) is path_relative_url_auto minus the &follows_auto_url case
- (!(arbitrary_scheme ~ ":") ~ (prua1 | prua2))
-}
-url_units_auto = {
- ( url_unit ~ url_units_auto ) |
- ( url_unit ~ &">" ~ &follows_auto_url ) |
- ( (ASCII_ALPHANUMERIC|"_"|"~"|"*"|"/"|"="|"+") ~ &follows_auto_url )
-}
-follows_auto_url = {
- EOI|"\x00"|WHITE_SPACE|">"|"\u{201A}"|"\u{201E}"|
- (!(CONNECTOR_PUNCTUATION|OPEN_PUNCTUATION|"#"|"%"|"&"|"*"|"@") ~ PUNCTUATION)
-}
-
-/* Rules for emails as defined by the HTML standard */
-email = { ( email_atext | "." )+ ~ "@" ~ email_label ~ ( "." ~ email_label )* }
-email_atext = { ASCII_ALPHANUMERIC|"!"|"#"|"$"|"%"|"&"|"'"|"/"|"="|"?"|"^"|"_"|"`"|"{"|"|"|"}"|"~" }
-email_label = { ASCII_ALPHANUMERIC ~ ( !("-"+ ~ !ASCII_ALPHANUMERIC) ~ (ASCII_ALPHANUMERIC|"-") ){0,62} }
-
-/*
- * character classes
- */
-
-
-bullet_marker = _{ "+" | "*" | "-" }
-adornments = {
- // recommended
- "="+ | "-"+ | "`"+ | ":"+ | "."+ | "'"+ | "\""+ | "~"+ | "^"+ | "_"+ | "*"+ | "+"+ | "#"+ |
- // parentheses
- "("+ | ")"+ | "["+ | "]"+ | "{"+ | "}"+ |
- // punctuation
- ","+ | ";"+ | "!"+ | "?"+ |
- // operators
- "&"+ | "|"+ | "/"+ | "%"+ | "<"+ | ">"+ |
- // misc
- "$"+ | "@"+ | "\\"+
-}
-nonspacechar = _{ !(" " | NEWLINE) ~ ANY }
-
-
-/*
- * lookaheads. do not use in another position
- */
-
-
-marker = _{ (bullet_marker | "..") ~ " " }
-
-
-
-//#################################################################################
-
-
-
-// code_block = {
-// ".. code" ~ "-block"? ~ ":: " ~ source ~ blank_line ~
-// NEWLINE ~ verbatim_chunk+
-// }
-
-// doctest_block = { (doctest_line+ ~ (!(">" | blank_line) ~ line)*)+ }
-
-// block_quote_raw = { ":" ~ blank_line ~ NEWLINE ~ nonblank_indented_line+ }
-
-// block_quote_chunk = {
-// !"::" ~ ":" ~ blank_line ~
-// NEWLINE ~
-// blank_line* ~
-// nonblank_indented_line+
-// }
-
-// block_quote = { block_quote_chunk+ }
-
-// nonblank_indented_line = { !blank_line ~ indented_line }
-
-// verbatim_chunk = { blank_line* ~ nonblank_indented_line+ }
-
-// verbatim = { verbatim_chunk+ }
-
-// horizontal_rule = {
-// ( "=" ~ sp ~ "=" ~ sp ~ "=" ~ (sp ~ "=")*
-// | "-" ~ sp ~ "-" ~ sp ~ "-" ~ (sp ~ "-")*
-// | "*" ~ sp ~ "*" ~ sp ~ "*" ~ (sp ~ "*")*
-// | "^" ~ sp ~ "^" ~ sp ~ "^" ~ (sp ~ "^")*
-// | "~" ~ sp ~ "~" ~ sp ~ "~" ~ (sp ~ "~")*
-// | "_" ~ sp ~ "_" ~ sp ~ "_" ~ (sp ~ "_")*
-// ) ~
-// sp ~ NEWLINE ~ blank_line+
-// }
-
-// table = { grid_table | header_less_grid_table | simple_table }
-
-// simple_table = { "NotImplemented" ~ "simple_table" }
-
-// grid_table = { grid_table_header ~ grid_table_header_sep ~ grid_table_body+ }
-// header_less_grid_table = { grid_table_sep ~ grid_table_body+ }
-// grid_table_header = { sp ~ "+" ~ ( "-"+ ~ "+" )+ ~ blank_line ~ grid_table_row+ }
-// grid_table_body = { ( grid_table_row ~ grid_table_sep )+ }
-// grid_table_row = { sp ~ "|" ~ sp ~ ( table_cell ~ sp ~ "|" )+ ~ blank_line }
-// table_cell = { ( ":" | ">" | "<" | "/" | "-" | spacechar | escaped_char | alphanumeric )+ }
-// grid_table_header_sep = { sp ~ "+" ~ ( "="+ ~ "+" )+ ~ blank_line }
-// grid_table_sep = { sp ~ "+" ~ ( "-"+ ~ "+" )+ ~ blank_line }
-
-// bullet = { !horizontal_rule ~ ("+" | "*" | "-") ~ spacechar+ }
-
-// bullet_list = { &bullet ~ (list_tight | list_loose) }
-
-// list_tight = { list_item_tight+ ~ blank_line* ~ !(bullet | enumerator | def_marker) }
-// list_loose = { ( list_item ~ blank_line* )+ }
-
-// list_item = { (bullet | enumerator | def_marker) ~ list_block ~ list_continuation_block* }
-// list_item_tight = {
-// (bullet | enumerator | def_marker) ~
-// list_block ~
-// (!blank_line ~ list_continuation_block)* ~
-// !list_continuation_block
-// }
-
-// list_block = { !blank_line ~ line ~ list_block_line* }
-
-// list_continuation_block = { blank_line* ~ ( indent ~ list_block )+ }
-
-// enumerator = { (ASCII_DIGIT+ | "#"+) ~ "." ~ spacechar+ }
-
-// ordered_list = { &enumerator ~ (list_tight | list_loose) }
-
-// list_block_line = {
-// !blank_line ~
-// !( (indent? ~ (bullet | enumerator)) | def_marker ) ~
-// !horizontal_rule ~
-// optionally_indented_line
-// }
-
-
-
-// space = _{ spacechar+ }
-
-// str = { normal_char+ ~ str_chunk* }
-// str_chunk = _{ (normal_char | "_"+ ~ &alphanumeric)+ }
-
-// escaped_char = { "\\" ~ !NEWLINE ~ ("-" | "\\" | "`" | "|" | "*" | "_" | "{" | "}" | "[" | "]" | "(" | ")" | "#" | "+" | "." | "!" | ">" | "<") }
-
-// entity = { hex_entity | dec_entity | char_entity }
-
-// endline = _{ line_break | terminal_endline | normal_endline }
-// normal_endline = _{ sp ~ NEWLINE ~ !(blank_line | ">" | line ~ ("="+ | "-"+) ~ NEWLINE) }
-// terminal_endline = _{ sp ~ NEWLINE ~ EOI }
-// line_break = _{ " " ~ normal_endline }
-
-// symbol = { special_char }
-
-// application_depent = { !("`_" | "``_") ~ "`" ~ !"``" ~ target_name_qu ~ "`" ~ !("``" | "_") }
-
-// // This keeps the parser from getting bogged down on long strings of "*" or "_",
-// // or strings of "*" or "_" with space on each side:
-// ul_or_star_line = { ul_line | star_line }
-// star_line = { "****" ~ "*"* | spacechar ~ "*"+ ~ &spacechar }
-// ul_line = { "____" ~ "_"* | spacechar ~ "_"+ ~ &spacechar }
-
-
-// empty_title = { "" }
-
-// ticks_2 = { "``" ~ !"`" }
-
-// code = { ticks_2 ~ ( (!"`" ~ nonspacechar)+ | "_" | !ticks_2 ~ "`" | !(sp ~ ticks_2) ~ (spacechar | NEWLINE ~ !blank_line) )+ ~ ticks_2 }
-
-
-// quoted = {
-// "\"" ~ (!"\"" ~ ANY)* ~ "\"" |
-// "'" ~ (!"'" ~ ANY)* ~ "'"
-// }
-// spacechar = _{ " " | "\t" }
-// sp = _{ spacechar* }
-// spnl = _{ sp ~ (NEWLINE ~ sp)? }
-// special_char = _{ "~" | "*" | "_" | "`" | "&" | "[" | "]" | "(" | ")" | "<" | "!" | "#" | "\\" | "\"" | "'" | extended_special_char }
-// normal_char = _{ !( special_char | spacechar | NEWLINE ) ~ ANY }
-// alphanumeric = {
-// ASCII_ALPHANUMERIC |
-// "\u{200}" | "\u{201}" | "\u{202}" | "\u{203}" | "\u{204}" | "\u{205}" | "\u{206}" | "\u{207}" |
-// "\u{210}" | "\u{211}" | "\u{212}" | "\u{213}" | "\u{214}" | "\u{215}" | "\u{216}" | "\u{217}" |
-// "\u{220}" | "\u{221}" | "\u{222}" | "\u{223}" | "\u{224}" | "\u{225}" | "\u{226}" | "\u{227}" |
-// "\u{230}" | "\u{231}" | "\u{232}" | "\u{233}" | "\u{234}" | "\u{235}" | "\u{236}" | "\u{237}" |
-// "\u{240}" | "\u{241}" | "\u{242}" | "\u{243}" | "\u{244}" | "\u{245}" | "\u{246}" | "\u{247}" |
-// "\u{250}" | "\u{251}" | "\u{252}" | "\u{253}" | "\u{254}" | "\u{255}" | "\u{256}" | "\u{257}" |
-// "\u{260}" | "\u{261}" | "\u{262}" | "\u{263}" | "\u{264}" | "\u{265}" | "\u{266}" | "\u{267}" |
-// "\u{270}" | "\u{271}" | "\u{272}" | "\u{273}" | "\u{274}" | "\u{275}" | "\u{276}" | "\u{277}" |
-// "\u{300}" | "\u{301}" | "\u{302}" | "\u{303}" | "\u{304}" | "\u{305}" | "\u{306}" | "\u{307}" |
-// "\u{310}" | "\u{311}" | "\u{312}" | "\u{313}" | "\u{314}" | "\u{315}" | "\u{316}" | "\u{317}" |
-// "\u{320}" | "\u{321}" | "\u{322}" | "\u{323}" | "\u{324}" | "\u{325}" | "\u{326}" | "\u{327}" |
-// "\u{330}" | "\u{331}" | "\u{332}" | "\u{333}" | "\u{334}" | "\u{335}" | "\u{336}" | "\u{337}" |
-// "\u{340}" | "\u{341}" | "\u{342}" | "\u{343}" | "\u{344}" | "\u{345}" | "\u{346}" | "\u{347}" |
-// "\u{350}" | "\u{351}" | "\u{352}" | "\u{353}" | "\u{354}" | "\u{355}" | "\u{356}" | "\u{357}" |
-// "\u{360}" | "\u{361}" | "\u{362}" | "\u{363}" | "\u{364}" | "\u{365}" | "\u{366}" | "\u{367}" |
-// "\u{370}" | "\u{371}" | "\u{372}" | "\u{373}" | "\u{374}" | "\u{375}" | "\u{376}" | "\u{377}"
-// }
-
-// hex_entity = { "&#" ~ ("X"|"x") ~ ('0'..'9' | 'a'..'f' | 'A'..'F')+ ~ ";" }
-// dec_entity = { "&#" ~ ASCII_DIGIT+ ~ ";" }
-// char_entity = { "&" ~ ASCII_ALPHANUMERIC+ ~ ";" }
-
-// indent = _{ "\t" | " " }
-// indented_line = { indent ~ line }
-// optionally_indented_line = { indent? ~ line }
-
-// doctest_line = { ">>> " ~ raw_line }
-
-// line = _{ raw_line }
-
-// raw_line = _{ (!NEWLINE ~ ANY)* ~ NEWLINE | (!EOI ~ ANY)+ ~ EOI }
-
-// // Syntax extensions
-
-// extended_special_char = {
-// //&{ extension(EXT_SMART) } ~
-// ("." | "-" | "\"" | "'") |
-// //&{ extension(EXT_NOTES) } ~
-// "^"
-// }
-
-// smart = {
-// //&{ extension(EXT_SMART) } ~
-// ( ellipsis | dash | single_quoted | double_quoted | apostrophe )
-// }
-
-// apostrophe = { "'" }
-
-// ellipsis = { "..." | ". . ." }
-
-// dash = { em_dash | en_dash }
-// en_dash = { "-" ~ &ASCII_DIGIT }
-// em_dash = { "---" | "--" }
-
-// single_quote_start = { "'" ~ !(spacechar | NEWLINE) }
-// single_quote_end = { "'" ~ !alphanumeric }
-// single_quoted = { single_quote_start ~ ( !single_quote_end ~ inline )+ ~ single_quote_end }
-
-// double_quote_start = { "\"" }
-// double_quote_end = { "\"" }
-// double_quoted = { double_quote_start ~ ( !double_quote_end ~ inline )+ ~ double_quote_end }
-
-// footnote = { "[#" ~ (!"]" ~ inline)+ ~ "]_" }
-
-// definition = {
-// &( (!defmark ~ nonspacechar ~ raw_line) ~ blank_line? ~ defmark) ~
-// d_list_title+ ~
-// (def_tight | def_loose)
-// }
-// d_list_title = { !defmark ~ &nonspacechar ~ (!endline ~ inline)+ ~ sp ~ NEWLINE }
-// def_tight = { &defmark ~ list_tight }
-// def_loose = { blank_line ~ &defmark ~ list_loose }
-// defmark = { (":" | "~") ~ spacechar+ }
-// def_marker = {
-// //&{ extension(EXT_DLISTS) } ~
-// defmark
-// }
diff --git a/src/url.rs b/src/url.rs
deleted file mode 100644
index 31a0536..0000000
--- a/src/url.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use std::fmt;
-use std::str::FromStr;
-
-use url::{self,ParseError};
-use serde_derive::Serialize;
-
-
-fn starts_with_scheme(input: &str) -> bool {
- let scheme = input.split(':').next().unwrap();
- if scheme == input || scheme.is_empty() {
- return false;
- }
- let mut chars = input.chars();
- // First character.
- if !chars.next().unwrap().is_ascii_alphabetic() {
- return false;
- }
- for ch in chars {
- if !ch.is_ascii_alphanumeric() && ch != '+' && ch != '-' && ch != '.' {
- return false;
- }
- }
- true
-}
-
-/// The string representation of a URL, either absolute or relative, that has
-/// been verified as a valid URL on construction.
-#[derive(Debug,PartialEq,Serialize,Clone)]
-#[serde(transparent)]
-pub struct Url(String);
-
-impl Url {
- pub fn parse_absolute(input: &str) -> Result<Self, ParseError> {
- Ok(url::Url::parse(input)?.into())
- }
- pub fn parse_relative(input: &str) -> Result<Self, ParseError> {
- // We're assuming that any scheme through which RsT documents are being
- // accessed is a hierarchical scheme, and so we can parse relative to a
- // random hierarchical URL.
- if input.starts_with('/') || !starts_with_scheme(input) {
- // Continue only if the parse succeeded, disregarding its result.
- let random_base_url = url::Url::parse("https://a/b").unwrap();
- url::Url::options()
- .base_url(Some(&random_base_url))
- .parse(input)?;
- Ok(Url(input.into()))
- } else {
- // If this is a URL at all, it's an absolute one.
- // There's no appropriate variant of url::ParseError really.
- Err(ParseError::SetHostOnCannotBeABaseUrl)
- }
- }
- pub fn as_str(&self) -> &str {
- self.0.as_str()
- }
-}
-
-impl From<url::Url> for Url {
- fn from(url: url::Url) -> Self {
- Url(url.into_string())
- }
-}
-
-
-impl fmt::Display for Url {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.as_str())
- }
-}
-
-
-impl FromStr for Url {
- type Err = ParseError;
- fn from_str(input: &str) -> Result<Self, Self::Err> {
- Url::parse_absolute(input)
- .or_else(|_| Url::parse_relative(input))
- }
-}