From f9d56cf899fedb0cfe8486a77fab23feb7001881 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Tue, 9 Apr 2024 15:58:55 +0800 Subject: [PATCH] feat: Timestamp::time_delta & Headline::is_todo & Headline::is_done --- src/ast/headline.rs | 256 ++++--------------------------------------- src/ast/timestamp.rs | 13 +++ 2 files changed, 37 insertions(+), 232 deletions(-) diff --git a/src/ast/headline.rs b/src/ast/headline.rs index 39c99dd..304914b 100644 --- a/src/ast/headline.rs +++ b/src/ast/headline.rs @@ -76,6 +76,30 @@ impl Headline { }) } + /// ```rust + /// use orgize::{Org, ast::Headline}; + /// + /// let hdl = Org::parse("* TODO a").first_node::().unwrap(); + /// assert!(hdl.is_todo()); + /// let hdl = Org::parse("* a").first_node::().unwrap(); + /// assert!(!hdl.is_todo()); + /// ``` + pub fn is_todo(&self) -> bool { + matches!(self.todo_type(), Some(TodoType::Todo)) + } + + /// ```rust + /// use orgize::{Org, ast::Headline}; + /// + /// let hdl = Org::parse("* DONE a").first_node::().unwrap(); + /// assert!(hdl.is_done()); + /// let hdl = Org::parse("* a").first_node::().unwrap(); + /// assert!(!hdl.is_done()); + /// ``` + pub fn is_done(&self) -> bool { + matches!(self.todo_type(), Some(TodoType::Done)) + } + /// Returns parsed title /// /// ```rust @@ -250,235 +274,3 @@ impl Headline { .flat_map(|x| x.children().filter_map(Clock::cast)) } } - -// pub enum DocumentOrHeadline { -// Document(Document), -// Headline(Headline), -// } - -// impl From for DocumentOrHeadline { -// fn from(value: Document) -> Self { -// DocumentOrHeadline::Document(value) -// } -// } - -// impl From for DocumentOrHeadline { -// fn from(value: Headline) -> Self { -// DocumentOrHeadline::Headline(value) -// } -// } - -// impl DocumentOrHeadline { -// pub fn section(&self) -> Option
{ -// match self { -// DocumentOrHeadline::Document(v) => v.section(), -// DocumentOrHeadline::Headline(v) => v.section(), -// } -// } -// } - -// impl Org { -// /// set the title of this headline -// /// -// /// ```rust -// /// use orgize::Org; -// /// -// /// let mut org = Org::parse("* [#A]"); -// /// let hdl = org.document().first_headline().unwrap(); -// /// org.set_title(hdl, "world"); -// /// assert_eq!(org.to_org(), "* [#A] world"); -// /// let hdl = org.document().first_headline().unwrap(); -// /// org.set_title(hdl, "world!"); -// /// assert_eq!(org.to_org(), "* [#A] world!"); -// /// ``` -// pub fn set_title(&mut self, headline: Headline, title: &str) -> Option { -// let bytes = title.as_bytes(); -// let title = match memchr(b'\n', bytes) { -// Some(i) if i > 0 && bytes[i] == b'\r' => &title[0..i - 1], -// Some(i) => &title[0..i], -// _ => title, -// }; -// let new_title = node(HEADLINE_TITLE, object_nodes(self.create_input(title))); - -// if let Some(title) = headline.title() { -// self.green = title.syntax.replace_with(new_title.into_node().unwrap()); - -// return Some(title); -// } - -// let mut child: Vec<_> = headline -// .syntax -// .green() -// .children() -// .map(|ch| ch.to_owned()) -// .collect(); - -// let index = support::child -// .iter() -// .enumerate() -// .filter_map(|(idx, it)| { -// if it.kind() == HEADLINE_STARS.into() -// || it.kind() == HEADLINE_KEYWORD.into() -// || it.kind() == HEADLINE_PRIORITY.into() -// { -// Some(idx + 1) -// } else { -// None -// } -// }) -// .last() -// .unwrap_or_default(); - -// if index == child.len() { -// child.push(token(WHITESPACE, " ")); -// child.push(new_title); -// } else if child[index].kind() != WHITESPACE.into() { -// child.insert(index, token(WHITESPACE, " ")); -// child.insert(index + 1, new_title); -// } else { -// child.insert(index, new_title); -// } - -// self.green = headline -// .syntax -// .replace_with(node(HEADLINE, child).into_node().unwrap()); - -// None -// } - -// /// set the section of this document or headline -// /// -// /// ```rust -// /// use orgize::Org; -// /// -// /// let mut org = Org::parse("* hello"); -// /// -// /// let hdl = org.document().first_headline().unwrap(); -// /// org.set_section(hdl, "world"); -// /// assert_eq!(org.to_org(), "* hello\nworld\n"); -// /// -// /// let hdl = org.document().first_headline().unwrap(); -// /// org.set_section(hdl, "world!"); -// /// assert_eq!(org.to_org(), "* hello\nworld!\n"); -// /// -// /// let doc = org.document(); -// /// org.set_section(doc, "doc"); -// /// assert_eq!(org.to_org(), "doc\n* hello\nworld!\n"); -// /// ``` -// pub fn set_section( -// &mut self, -// document_or_headline: impl Into, -// section: &str, -// ) -> Option
{ -// let document_or_headline = document_or_headline.into(); - -// let section = section_text(self.create_input(section)).ok()?.1.as_str(); - -// let section = if section.ends_with('\n') { -// section_node(self.create_input(section)).map(|(_, s)| s) -// } else { -// section_node(self.create_input(&format!("{section}\n"))).map(|(_, s)| s) -// } -// .ok()?; - -// if let Some(old) = document_or_headline.section() { -// self.green = old.syntax.replace_with(section.into_node().unwrap()); - -// return Some(old); -// } - -// match document_or_headline { -// DocumentOrHeadline::Document(document) => { -// let mut child: Vec<_> = document -// .syntax -// .green() -// .children() -// .map(|ch| ch.to_owned()) -// .collect(); - -// let headline_idx = child.iter().position(|it| it.kind() == HEADLINE.into()); - -// if let Some(idx) = headline_idx { -// child.insert(idx, section); -// } else { -// child.push(section); -// } - -// self.green = document -// .syntax -// .replace_with(GreenNode::new(DOCUMENT.into(), child)); - -// None -// } -// DocumentOrHeadline::Headline(headline) => { -// let mut child: Vec<_> = headline -// .syntax -// .green() -// .children() -// .map(|ch| ch.to_owned()) -// .collect(); - -// let new_line_idx = support::child -// .iter() -// .position(|it| it.kind() == NEW_LINE.into()); - -// if let Some(idx) = new_line_idx { -// // add section *after* newline -// if idx < support::child.len() { -// support::child.insert(idx, section); -// } else { -// support::child.push(section); -// } -// } else { -// support::child.push(token(NEW_LINE, "\n")); -// support::child.push(section); -// } - -// self.green = headline -// .syntax -// .replace_with(GreenNode::new(HEADLINE.into(), support::child)); - -// None -// } -// } -// } - -// /// set the level of this headline -// /// -// /// ```rust -// /// use orgize::Org; -// /// -// /// let mut org = Org::parse("** 1\n** 2"); -// /// -// /// let hdl = org.document().last_headline().unwrap(); -// /// org.set_level(hdl, 1); -// /// assert_eq!(org.to_org(), "** 1\n* 2"); -// /// -// /// let hdl = org.document().last_headline().unwrap(); -// /// org.set_level(hdl, 3); -// /// assert_eq!(org.to_org(), "** 1\n* 2"); -// /// ``` -// pub fn set_level(&mut self, headline: Headline, level: usize) { -// if level == 0 { -// return; -// } - -// let min_level_in_siblings = headline -// .syntax -// .siblings(rowan::Direction::Next) -// .chain(headline.syntax.siblings(rowan::Direction::Prev)) -// .filter_map(Headline::cast) -// .filter_map(|headline| headline.level()) -// .min() -// .unwrap_or(1); - -// if level <= min_level_in_siblings { -// if let Some(stars) = headline.stars() { -// self.green = stars.replace_with(GreenToken::new( -// SyntaxKind::HEADLINE_STARS.into(), -// "*".repeat(level).as_str(), -// )); -// } -// } -// } -// } diff --git a/src/ast/timestamp.rs b/src/ast/timestamp.rs index 14fc3a5..6d8a1d6 100644 --- a/src/ast/timestamp.rs +++ b/src/ast/timestamp.rs @@ -285,4 +285,17 @@ impl Timestamp { )?, )) } + + /// Returns chrono::TimeDelta between timestamp start and end + /// + /// ```rust + /// use orgize::{Org, ast::Timestamp}; + /// + /// let ts = Org::parse("[2003-09-16 Tue 09:39-10:39]").first_node::().unwrap(); + /// assert_eq!(ts.time_delta().unwrap().num_hours(), 1); + /// ``` + #[cfg(feature = "chrono")] + pub fn time_delta(&self) -> Option { + Some(self.end_to_chrono()? - self.start_to_chrono()?) + } }