summaryrefslogtreecommitdiff
path: root/src/paragraph
diff options
context:
space:
mode:
Diffstat (limited to 'src/paragraph')
-rw-r--r--src/paragraph/mod.rs61
-rw-r--r--src/paragraph/part.rs247
2 files changed, 308 insertions, 0 deletions
diff --git a/src/paragraph/mod.rs b/src/paragraph/mod.rs
new file mode 100644
index 0000000..32ab429
--- /dev/null
+++ b/src/paragraph/mod.rs
@@ -0,0 +1,61 @@
+//! Paragraph.
+use crate::xml::element::{Element, Elements, FromElements};
+
+mod part;
+
+pub use part::{Error as PartError, Part};
+
+/// A paragraph.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Paragraph
+{
+ parts: Vec<Part>,
+}
+
+impl Paragraph
+{
+ /// Returns a new `Paragraph`.
+ pub fn new(parts: impl IntoIterator<Item = Part>) -> Self
+ {
+ Self {
+ parts: parts.into_iter().collect(),
+ }
+ }
+
+ /// Returns the parts of the paragraph.
+ #[must_use]
+ pub fn parts(&self) -> &[Part]
+ {
+ &self.parts
+ }
+}
+
+impl FromElements for Paragraph
+{
+ type Error = Error;
+
+ fn from_elements(elements: &Elements) -> Result<Self, Self::Error>
+ {
+ let parts = elements
+ .into_iter()
+ .filter_map(|element| {
+ if matches!(element, Element::Comment(_)) {
+ return None;
+ }
+
+ Some(Part::from_elements(&Elements::from([element.clone()])))
+ })
+ .collect::<Result<Vec<_>, _>>()?;
+
+ Ok(Self { parts })
+ }
+}
+
+/// [`Paragraph`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ /// Invalid reference description part.
+ #[error("Invalid part")]
+ InvalidPart(#[from] PartError),
+}
diff --git a/src/paragraph/part.rs b/src/paragraph/part.rs
new file mode 100644
index 0000000..5e5a846
--- /dev/null
+++ b/src/paragraph/part.rs
@@ -0,0 +1,247 @@
+use crate::emphasis::{Emphasis, Error as EmphasisError};
+use crate::itemized_list::{Error as ItemizedListError, ItemizedList};
+use crate::paragraph::{Error as ParagraphError, Paragraph};
+use crate::table::{Error as TableError, Informal as InformalTable, Table};
+use crate::variable_list::{Error as VariableListError, VariableList};
+use crate::xml::element::{Elements, FromElements, Tagged};
+
+/// Paragraph part.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Part
+{
+ /// Text part.
+ Text(String),
+
+ /// <constant>..</constant> part.
+ Constant(String),
+
+ /// <function>..</function> part.
+ Function(String),
+
+ /// <parameter>..</parameter> part.
+ Parameter(String),
+
+ /// Emphasis part.
+ Emphasis(Emphasis),
+
+ /// Code part.
+ Code(String),
+
+ /// Inline equation part.
+ InlineEquation(String),
+
+ /// Program listing part.
+ ProgramListing(String),
+
+ /// Reference entry citation part.
+ Entry(String),
+
+ /// Variable list part.
+ VariableList(VariableList),
+
+ /// Itemized list part.
+ ItemizedList(ItemizedList),
+
+ /// Informal table part.
+ InformalTable(InformalTable),
+
+ /// Paragraph part.
+ Paragraph(Paragraph),
+
+ /// Footnote part.
+ Footnote(Paragraph),
+
+ /// Table part.
+ Table(Table),
+
+ /// Informal equation part.
+ InformalEquation(String),
+
+ /// Superscript part.
+ Superscript(String),
+}
+
+impl FromElements for Part
+{
+ type Error = Error;
+
+ fn from_elements(elements: &Elements) -> Result<Self, Self::Error>
+ {
+ if let Some(tagged_element) = elements.get_first_tagged() {
+ return Self::from_tagged_element(tagged_element);
+ }
+
+ let text = elements
+ .get_first_text_element()
+ .ok_or(Self::Error::ExpectedTextElement)?;
+
+ Ok(Self::Text(text.clone()))
+ }
+}
+
+impl Part
+{
+ fn from_tagged_element(
+ tagged_element: &Tagged,
+ ) -> Result<Self, <Self as FromElements>::Error>
+ {
+ let create: fn(String) -> Self = match tagged_element.name() {
+ "constant" => Self::Constant,
+ "function" => Self::Function,
+ "parameter" => Self::Parameter,
+ "code" => Self::Code,
+ "inlineequation" => Self::InlineEquation,
+ "programlisting" => Self::ProgramListing,
+ "citerefentry" => Self::Entry,
+ "superscript" => Self::Superscript,
+ "variablelist" | "itemizedlist" | "informaltable" | "para" | "footnote"
+ | "table" | "informalequation" | "emphasis" => |_| {
+ unreachable!();
+ },
+ _ => {
+ return Err(<Self as FromElements>::Error::UnknownPart(
+ tagged_element.name().to_string(),
+ ));
+ }
+ };
+
+ if tagged_element.name() == "citerefentry" {
+ let title_element = tagged_element
+ .child_elements()
+ .get_first_tagged_with_name("refentrytitle")
+ .ok_or(<Self as FromElements>::Error::NoEntryTitleFound)?;
+
+ let title = title_element
+ .child_elements()
+ .get_first_text_element()
+ .ok_or(<Self as FromElements>::Error::NoTextInTagged)?;
+
+ return Ok(Self::Entry(title.clone()));
+ }
+
+ if tagged_element.name() == "variablelist" {
+ let variable_list =
+ VariableList::from_elements(tagged_element.child_elements())?;
+
+ return Ok(Self::VariableList(variable_list));
+ }
+
+ if tagged_element.name() == "itemizedlist" {
+ let itemized_list =
+ ItemizedList::from_elements(tagged_element.child_elements())?;
+
+ return Ok(Self::ItemizedList(itemized_list));
+ }
+
+ if tagged_element.name() == "informaltable" {
+ let informal_table =
+ InformalTable::from_elements(tagged_element.child_elements())
+ .map_err(|err| Error::InvalidInformalTable(Box::new(err)))?;
+
+ return Ok(Self::InformalTable(informal_table));
+ }
+
+ if tagged_element.name() == "inlineequation" {
+ return Ok(Self::InlineEquation(
+ tagged_element
+ .child_elements()
+ .into_iter()
+ .map(ToString::to_string)
+ .collect::<String>(),
+ ));
+ }
+
+ if tagged_element.name() == "para" {
+ return Ok(Self::Paragraph(
+ Paragraph::from_elements(tagged_element.child_elements())
+ .map_err(|err| Error::InvalidParagraph(Box::new(err)))?,
+ ));
+ }
+
+ if tagged_element.name() == "footnote" {
+ return Ok(Self::Footnote(
+ Paragraph::from_elements(tagged_element.child_elements())
+ .map_err(|err| Error::InvalidFootnote(Box::new(err)))?,
+ ));
+ }
+
+ if tagged_element.name() == "table" {
+ let table = Table::from_elements(tagged_element.child_elements())
+ .map_err(|err| Error::InvalidInformalTable(Box::new(err)))?;
+
+ return Ok(Self::Table(table));
+ }
+
+ if tagged_element.name() == "informalequation" {
+ return Ok(Self::InlineEquation(
+ tagged_element
+ .child_elements()
+ .into_iter()
+ .map(ToString::to_string)
+ .collect::<String>(),
+ ));
+ }
+
+ if tagged_element.name() == "emphasis" {
+ return Ok(Self::Emphasis(Emphasis::from_tagged_element(
+ tagged_element,
+ )?));
+ }
+
+ let text_element = tagged_element
+ .child_elements()
+ .get_first_text_element()
+ .ok_or(<Self as FromElements>::Error::NoTextInTagged)?;
+
+ Ok(create(text_element.clone()))
+ }
+}
+
+/// [`Part`] error.
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ /// Expected a text element.
+ #[error("Expected a text element")]
+ ExpectedTextElement,
+
+ /// A input element is a unknown paragraph part.
+ #[error("Input element with name '{0}' is a unknown paragraph part")]
+ UnknownPart(String),
+
+ /// No text was found in tagged input element.
+ #[error("No text was found in tagged input element")]
+ NoTextInTagged,
+
+ /// No entry title found.
+ #[error("No entry title found")]
+ NoEntryTitleFound,
+
+ /// Invalid variable list.
+ #[error("Invalid variable list")]
+ InvalidVariableList(#[from] VariableListError),
+
+ /// Invalid itemized list.
+ #[error("Invalid itemized list")]
+ InvalidItemizedList(#[from] ItemizedListError),
+
+ /// Invalid informal table.
+ #[error("Invalid informal table")]
+ InvalidInformalTable(#[source] Box<TableError>),
+
+ /// Invalid paragraph.
+ #[error("Invalid paragraph")]
+ InvalidParagraph(#[source] Box<ParagraphError>),
+
+ /// Invalid footnote.
+ #[error("Invalid footnote")]
+ InvalidFootnote(#[source] Box<ParagraphError>),
+
+ /// Invalid table.
+ #[error("Invalid table")]
+ InvalidTable(#[source] Box<TableError>),
+
+ /// Invalid emphasis.
+ #[error("Invalid emphasis")]
+ InvalidEmphasis(#[from] EmphasisError),
+}