This commit is contained in:
Andrei Stoica 2023-06-25 12:25:59 -04:00
parent 3bb095ca45
commit cd97c18fef
2 changed files with 95 additions and 14 deletions

View File

@ -61,8 +61,8 @@ fn main() {
let arena = Arena::new(); let arena = Arena::new();
let root = parse_todo_file(&file, &arena); let root = parse_todo_file(&file, &arena);
//println!("{:#?}", root); println!("{:#?}", root);
//println!("======================================================="); println!("=======================================================");
let sections = &cfg.sections.unwrap(); let sections = &cfg.sections.unwrap();
let groups = extract_secitons(root, sections); let groups = extract_secitons(root, sections);

View File

@ -15,6 +15,8 @@ pub struct TaskGroup {
pub struct Task { pub struct Task {
pub status: Status, pub status: Status,
pub text: String, pub text: String,
level: u8,
pub subtasks: Option<Vec<Task>>,
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -24,7 +26,7 @@ pub enum Status {
Empty, Empty,
} }
pub enum TaskErorr { pub enum TaskError {
ParsingError(&'static str), ParsingError(&'static str),
} }
@ -39,6 +41,42 @@ impl Task {
} }
text text
} }
fn extract_text<'a>(node: &'a AstNode<'a>) -> Result<String, TaskError> {
let data_ref = node.data.borrow();
if let NodeValue::Text(contents) = &data_ref.value {
Ok(contents.to_string())
} else {
Err(TaskError::ParsingError("Could not get text from element"))
}
}
fn extract_text_from_task<'a>(node: &'a AstNode<'a>) -> Result<String, TaskError> {
let mut text = String::new();
let data_ref = node.data.borrow();
if let NodeValue::Paragraph = data_ref.value {
for child in node.children() {
let child_data_ref = child.data.borrow();
let t = match &child_data_ref.borrow().value {
NodeValue::Text(contents) => contents.clone(),
NodeValue::Emph if child.first_child().is_some() => {
format!("*{}*", Self::extract_text(child.first_child().unwrap())?)
}
NodeValue::Strong if child.first_child().is_some() => {
format!("**{}**", Self::extract_text(child.first_child().unwrap())?)
}
NodeValue::SoftBreak => {
format!("\n{}", " ".repeat(data_ref.sourcepos.start.column))
}
_ => "".into(),
};
text.push_str(&t);
}
Ok(text)
} else {
Err(TaskError::ParsingError("First child is not Paragraph"))
}
}
} }
impl ToString for Task { impl ToString for Task {
@ -48,25 +86,68 @@ impl ToString for Task {
Status::Todo(ch) => ch, Status::Todo(ch) => ch,
Status::Empty => ' ', Status::Empty => ' ',
}; };
format!(" - [{}] {}\n", ch, self.text.trim())
let subtasks = if let Some(subtasks) = &self.subtasks {
let mut text = subtasks
.iter()
.map(|task| task.to_string())
.collect::<Vec<_>>()
.join("\n");
text.insert(0, '\n');
text.trim_end().to_string()
} else {
"".into()
};
format!(
" - [{}] {}{}\n",
ch,
self.text.trim(),
subtasks.replace("\n", "\n ")
)
} }
} }
impl<'a> TryFrom<&'a AstNode<'a>> for Task { impl<'a> TryFrom<&'a AstNode<'a>> for Task {
type Error = TaskErorr; type Error = TaskError;
fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> { fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> {
let data_ref = &node.data.borrow(); let data_ref = &node.data.borrow();
if let NodeValue::TaskItem(ch) = data_ref.value { if let NodeValue::TaskItem(ch) = data_ref.value {
let text = Self::find_text(node); let text = Self::extract_text_from_task(
node.first_child()
.ok_or(TaskError::ParsingError("No childern of node found"))?,
)?;
let status = match ch { let status = match ch {
Some(c) if c == 'x' || c == 'X' => Status::Done(c), Some(c) if c == 'x' || c == 'X' => Status::Done(c),
Some(c) => Status::Todo(c), Some(c) => Status::Todo(c),
_ => Status::Empty, _ => Status::Empty,
}; };
let subtasks = node
.children()
.filter_map(|child| {
if let NodeValue::List(_) = child.data.borrow().value {
Some(child)
} else {
None
}
})
.map(|child| {
child
.children()
.into_iter()
.filter_map(|item_node| Task::try_from(item_node).ok())
.collect()
})
.reduce(|a: Vec<Task>, b: Vec<Task>| [a, b].concat());
Ok(Self { status, text }) Ok(Self {
status,
text,
subtasks,
level: 1,
})
} else { } else {
Err(TaskErorr::ParsingError( Err(TaskError::ParsingError(
"Node being parsed is not a TaskItem", "Node being parsed is not a TaskItem",
)) ))
} }
@ -95,7 +176,7 @@ impl ToString for TaskGroup {
} }
impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup { impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup {
type Error = TaskErorr; type Error = TaskError;
fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> { fn try_from(node: &'a AstNode<'a>) -> Result<Self, Self::Error> {
let node_ref = &node.data.borrow(); let node_ref = &node.data.borrow();
if let NodeValue::Heading(heading) = node_ref.value { if let NodeValue::Heading(heading) = node_ref.value {
@ -104,21 +185,21 @@ impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup {
let first_child = if let Some(child) = first_child_ref.borrow() { let first_child = if let Some(child) = first_child_ref.borrow() {
child child
} else { } else {
return Err(TaskErorr::ParsingError("Node has no children")); return Err(TaskError::ParsingError("Node has no children"));
}; };
let data_ref = &first_child.data.borrow(); let data_ref = &first_child.data.borrow();
let name = if let NodeValue::Text(value) = &data_ref.value { let name = if let NodeValue::Text(value) = &data_ref.value {
value.to_string() value.to_string()
} else { } else {
return Err(TaskErorr::ParsingError( return Err(TaskError::ParsingError(
"Could not get title from heading node", "Could not get title from heading node",
)); ));
}; };
let next_sib = node let next_sib = node
.next_sibling() .next_sibling()
.ok_or(TaskErorr::ParsingError("Empty section at end of file"))?; .ok_or(TaskError::ParsingError("Empty section at end of file"))?;
if let NodeValue::List(_list_meta) = next_sib.data.borrow().value { if let NodeValue::List(_list_meta) = next_sib.data.borrow().value {
let tasks = next_sib let tasks = next_sib
@ -129,12 +210,12 @@ impl<'a> TryFrom<&'a AstNode<'a>> for TaskGroup {
Ok(TaskGroup { name, tasks, level }) Ok(TaskGroup { name, tasks, level })
} else { } else {
Err(TaskErorr::ParsingError( Err(TaskError::ParsingError(
"Next sibling of node is not a list", "Next sibling of node is not a list",
)) ))
} }
} else { } else {
Err(TaskErorr::ParsingError("Node is not a section heading")) Err(TaskError::ParsingError("Node is not a section heading"))
} }
} }
} }