feat(headline): minor refactors

This commit is contained in:
PoiScript 2019-11-05 19:59:42 +08:00
parent 6483ef745f
commit e3d051145f

View file

@ -15,7 +15,10 @@ use crate::{
/// ///
/// Each `Org` struct only has one `Document`. /// Each `Org` struct only has one `Document`.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Document(Headline); pub struct Document {
doc_n: NodeId,
sec_n: Option<NodeId>,
}
impl Document { impl Document {
pub(crate) fn from_org(org: &Org) -> Document { pub(crate) fn from_org(org: &Org) -> Document {
@ -23,21 +26,20 @@ impl Document {
.first_child() .first_child()
.and_then(|n| match org[n] { .and_then(|n| match org[n] {
Element::Section => Some(n), Element::Section => Some(n),
_ => None, Element::Headline { .. } => None,
_ => unreachable!("Document should only contains section and headline."),
}); });
// document can be treated as zero-level headline without title
Document(Headline { Document {
lvl: 0, doc_n: org.root,
hdl_n: org.root,
ttl_n: org.root,
sec_n, sec_n,
}) }
} }
/// Returns the ID of the section element of this document, /// Returns the ID of the section element of this document,
/// or `None` if it has no section. /// or `None` if it has no section.
pub fn section_node(self) -> Option<NodeId> { pub fn section_node(self) -> Option<NodeId> {
self.0.sec_n self.sec_n
} }
/// Returns an iterator of this document's children. /// Returns an iterator of this document's children.
@ -65,11 +67,10 @@ impl Document {
/// assert!(iter.next().is_none()); /// assert!(iter.next().is_none());
/// ``` /// ```
pub fn children<'a>(self, org: &'a Org) -> impl Iterator<Item = Headline> + 'a { pub fn children<'a>(self, org: &'a Org) -> impl Iterator<Item = Headline> + 'a {
self.0 self.doc_n
.hdl_n
.children(&org.arena) .children(&org.arena)
// skip sec_n if exists // skip section if exists
.skip(if self.0.sec_n.is_some() { 1 } else { 0 }) .skip(if self.sec_n.is_some() { 1 } else { 0 })
.map(move |n| match org[n] { .map(move |n| match org[n] {
Element::Headline { level } => Headline::from_node(n, level, org), Element::Headline { level } => Headline::from_node(n, level, org),
_ => unreachable!(), _ => unreachable!(),
@ -104,11 +105,10 @@ impl Document {
/// assert!(org.document().first_child(&org).is_none()); /// assert!(org.document().first_child(&org).is_none());
/// ``` /// ```
pub fn first_child(self, org: &Org) -> Option<Headline> { pub fn first_child(self, org: &Org) -> Option<Headline> {
self.0 self.doc_n
.hdl_n
.children(&org.arena) .children(&org.arena)
// skip sec_n if exists // skip section if exists
.nth(if self.0.sec_n.is_some() { 1 } else { 0 }) .nth(if self.sec_n.is_some() { 1 } else { 0 })
.map(move |n| match org[n] { .map(move |n| match org[n] {
Element::Headline { level } => Headline::from_node(n, level, org), Element::Headline { level } => Headline::from_node(n, level, org),
_ => unreachable!(), _ => unreachable!(),
@ -143,7 +143,13 @@ impl Document {
/// assert!(org.document().last_child(&org).is_none()); /// assert!(org.document().last_child(&org).is_none());
/// ``` /// ```
pub fn last_child(self, org: &Org) -> Option<Headline> { pub fn last_child(self, org: &Org) -> Option<Headline> {
self.0.last_child(org) org.arena[self.doc_n]
.last_child()
.and_then(|n| match org[n] {
Element::Headline { level } => Some(Headline::from_node(n, level, org)),
Element::Section => None,
_ => unreachable!("Document should only contains section and headline."),
})
} }
/// Changes the section content of this document. /// Changes the section content of this document.
@ -177,24 +183,22 @@ impl Document {
where where
S: Into<Cow<'a, str>>, S: Into<Cow<'a, str>>,
{ {
let sec_n = if let Some(sec_n) = self.0.sec_n { if let Some(sec_n) = self.sec_n {
let children: Vec<_> = sec_n.children(&org.arena).collect(); let children: Vec<_> = sec_n.children(&org.arena).collect();
for child in children { for child in children {
child.detach(&mut org.arena); child.detach(&mut org.arena);
} }
sec_n
} else { } else {
let sec_n = org.arena.new_node(Element::Section); let sec_n = org.arena.new_node(Element::Section);
self.0.sec_n = Some(sec_n); self.sec_n = Some(sec_n);
self.0.hdl_n.prepend(sec_n, &mut org.arena); self.doc_n.prepend(sec_n, &mut org.arena);
sec_n }
};
match content.into() { match content.into() {
Cow::Borrowed(content) => parse_container( Cow::Borrowed(content) => parse_container(
&mut org.arena, &mut org.arena,
Container::Block { Container::Block {
node: sec_n, node: self.sec_n.unwrap(),
content, content,
}, },
&ParseConfig::default(), &ParseConfig::default(),
@ -202,7 +206,7 @@ impl Document {
Cow::Owned(ref content) => parse_container( Cow::Owned(ref content) => parse_container(
&mut OwnedArena::new(&mut org.arena), &mut OwnedArena::new(&mut org.arena),
Container::Block { Container::Block {
node: sec_n, node: self.sec_n.unwrap(),
content, content,
}, },
&ParseConfig::default(), &ParseConfig::default(),
@ -261,7 +265,19 @@ impl Document {
/// assert!(d.append(h4, &mut org).is_err()); /// assert!(d.append(h4, &mut org).is_err());
/// ``` /// ```
pub fn append(self, hdl: Headline, org: &mut Org) -> ValidationResult<()> { pub fn append(self, hdl: Headline, org: &mut Org) -> ValidationResult<()> {
self.0.append(hdl, org) hdl.check_detached(org)?;
if let Some(last) = self.last_child(org) {
hdl.check_level(1..=last.lvl)?;
} else {
hdl.check_level(1..=usize::max_value())?;
}
self.doc_n.append(hdl.hdl_n, &mut org.arena);
org.debug_validate();
Ok(())
} }
/// Prepends a new child to this document. /// Prepends a new child to this document.
@ -316,13 +332,13 @@ impl Document {
if let Some(first) = self.first_child(org) { if let Some(first) = self.first_child(org) {
hdl.check_level(first.lvl..=usize::MAX)?; hdl.check_level(first.lvl..=usize::MAX)?;
} else { } else {
hdl.check_level(self.0.lvl + 1..=usize::MAX)?; hdl.check_level(1..=usize::MAX)?;
} }
if let Some(sec_n) = self.0.sec_n { if let Some(sec_n) = self.sec_n {
sec_n.insert_after(hdl.hdl_n, &mut org.arena); sec_n.insert_after(hdl.hdl_n, &mut org.arena);
} else { } else {
self.0.hdl_n.prepend(hdl.hdl_n, &mut org.arena); self.doc_n.prepend(hdl.hdl_n, &mut org.arena);
} }
org.debug_validate(); org.debug_validate();
@ -623,24 +639,22 @@ impl Headline {
where where
S: Into<Cow<'a, str>>, S: Into<Cow<'a, str>>,
{ {
let sec_n = if let Some(sec_n) = self.sec_n { if let Some(sec_n) = self.sec_n {
let children: Vec<_> = sec_n.children(&org.arena).collect(); let children: Vec<_> = sec_n.children(&org.arena).collect();
for child in children { for child in children {
child.detach(&mut org.arena); child.detach(&mut org.arena);
} }
sec_n
} else { } else {
let sec_n = org.arena.new_node(Element::Section); let sec_n = org.arena.new_node(Element::Section);
self.sec_n = Some(sec_n); self.sec_n = Some(sec_n);
self.ttl_n.insert_after(sec_n, &mut org.arena); self.ttl_n.insert_after(sec_n, &mut org.arena);
sec_n }
};
match content.into() { match content.into() {
Cow::Borrowed(content) => parse_container( Cow::Borrowed(content) => parse_container(
&mut org.arena, &mut org.arena,
Container::Block { Container::Block {
node: sec_n, node: self.sec_n.unwrap(),
content, content,
}, },
&ParseConfig::default(), &ParseConfig::default(),
@ -648,7 +662,7 @@ impl Headline {
Cow::Owned(ref content) => parse_container( Cow::Owned(ref content) => parse_container(
&mut OwnedArena::new(&mut org.arena), &mut OwnedArena::new(&mut org.arena),
Container::Block { Container::Block {
node: sec_n, node: self.sec_n.unwrap(),
content, content,
}, },
&ParseConfig::default(), &ParseConfig::default(),
@ -722,6 +736,7 @@ impl Headline {
pub fn children<'a>(self, org: &'a Org) -> impl Iterator<Item = Headline> + 'a { pub fn children<'a>(self, org: &'a Org) -> impl Iterator<Item = Headline> + 'a {
self.hdl_n self.hdl_n
.children(&org.arena) .children(&org.arena)
// skip title and section
.skip(if self.sec_n.is_some() { 2 } else { 1 }) .skip(if self.sec_n.is_some() { 2 } else { 1 })
.filter_map(move |n| match org[n] { .filter_map(move |n| match org[n] {
Element::Headline { level } => Some(Headline::from_node(n, level, org)), Element::Headline { level } => Some(Headline::from_node(n, level, org)),
@ -757,6 +772,7 @@ impl Headline {
pub fn first_child(self, org: &Org) -> Option<Headline> { pub fn first_child(self, org: &Org) -> Option<Headline> {
self.hdl_n self.hdl_n
.children(&org.arena) .children(&org.arena)
// skip title and section
.nth(if self.sec_n.is_some() { 2 } else { 1 }) .nth(if self.sec_n.is_some() { 2 } else { 1 })
.map(|n| match org[n] { .map(|n| match org[n] {
Element::Headline { level } => Headline::from_node(n, level, org), Element::Headline { level } => Headline::from_node(n, level, org),
@ -795,7 +811,7 @@ impl Headline {
.and_then(|n| match org[n] { .and_then(|n| match org[n] {
Element::Headline { level } => Some(Headline::from_node(n, level, org)), Element::Headline { level } => Some(Headline::from_node(n, level, org)),
Element::Section | Element::Title(_) => None, Element::Section | Element::Title(_) => None,
_ => unreachable!(), _ => unreachable!("Headline should only contains section and headline."),
}) })
} }