This commit is contained in:
@@ -2,10 +2,9 @@ use crate::todo::{File as TodoFile, Status as TaskStatus};
|
||||
use crate::NaiveDate;
|
||||
use crate::TaskGroup;
|
||||
use chrono::Datelike;
|
||||
use comrak::nodes::{Ast, AstNode, LineColumn, NodeHeading, NodeValue};
|
||||
use comrak::{
|
||||
format_commonmark, parse_document, Arena, ComrakOptions, ExtensionOptions, ParseOptions,
|
||||
};
|
||||
use comrak::nodes::{Ast, AstNode, LineColumn, NodeHeading, NodeTaskItem, NodeValue};
|
||||
use comrak::options::{Extension, Parse};
|
||||
use comrak::{parse_document, Arena, Options};
|
||||
use indexmap::IndexMap;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
@@ -64,17 +63,17 @@ pub fn load_file(file: &TodoFile) -> String {
|
||||
}
|
||||
|
||||
/// Parse contents of markdown file with Comrak ( relaxed tasklist matching is enabled)
|
||||
pub fn parse_todo_file<'a>(contents: &String, arena: &'a Arena<AstNode<'a>>) -> &'a AstNode<'a> {
|
||||
let mut extension_options = ExtensionOptions::default();
|
||||
pub fn parse_todo_file<'a>(contents: &String, arena: &'a Arena<'a>) -> &'a AstNode<'a> {
|
||||
let mut extension_options = Extension::default();
|
||||
extension_options.tasklist = true;
|
||||
|
||||
let mut parse_options = ParseOptions::default();
|
||||
let mut parse_options = Parse::default();
|
||||
parse_options.relaxed_tasklist_matching = true;
|
||||
|
||||
let options = &ComrakOptions {
|
||||
let options = &Options {
|
||||
extension: extension_options,
|
||||
parse: parse_options,
|
||||
..ComrakOptions::default()
|
||||
..Options::default()
|
||||
};
|
||||
parse_document(arena, contents, options)
|
||||
}
|
||||
@@ -143,13 +142,16 @@ fn remove_task_nodes<'a>(root: &'a AstNode<'a>) {
|
||||
remove_task_nodes(child_node)
|
||||
}
|
||||
match node.data.borrow().value {
|
||||
NodeValue::TaskItem(Some(status)) if status == 'x' || status == 'X' => node.detach(),
|
||||
NodeValue::TaskItem(NodeTaskItem {
|
||||
symbol: Some(status),
|
||||
symbol_sourcepos: _,
|
||||
}) if status == 'x' || status == 'X' => node.detach(),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_title<'a>(arena: &'a Arena<AstNode<'a>>, date: &str) -> &'a AstNode<'a> {
|
||||
fn create_title<'a>(arena: &'a Arena<'a>, date: &str) -> &'a AstNode<'a> {
|
||||
let mut text = String::new();
|
||||
text.push_str("Today's tasks ");
|
||||
text.push_str(date);
|
||||
@@ -157,20 +159,22 @@ fn create_title<'a>(arena: &'a Arena<AstNode<'a>>, date: &str) -> &'a AstNode<'a
|
||||
create_heading(arena, 1, &text)
|
||||
}
|
||||
|
||||
fn create_heading<'a>(arena: &'a Arena<AstNode<'a>>, level: u8, text: &str) -> &'a AstNode<'a> {
|
||||
fn create_heading<'a>(arena: &'a Arena<'a>, level: u8, text: &str) -> &'a AstNode<'a> {
|
||||
let heading_node = arena.alloc(AstNode::new(
|
||||
Ast::new(
|
||||
NodeValue::Heading(NodeHeading {
|
||||
level,
|
||||
setext: false,
|
||||
closed: false,
|
||||
}),
|
||||
LineColumn { line: 0, column: 0 },
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
|
||||
let text_node = arena.alloc(AstNode::new(
|
||||
Ast::new(
|
||||
NodeValue::Text(text.to_string()),
|
||||
NodeValue::Text(text.to_string().into()),
|
||||
LineColumn { line: 0, column: 2 },
|
||||
)
|
||||
.into(),
|
||||
@@ -182,7 +186,7 @@ fn create_heading<'a>(arena: &'a Arena<AstNode<'a>>, level: u8, text: &str) -> &
|
||||
}
|
||||
|
||||
pub fn create_new_doc<'a>(
|
||||
arena: &'a Arena<AstNode<'a>>,
|
||||
arena: &'a Arena<'a>,
|
||||
new_date: &str,
|
||||
sections: IndexMap<String, Option<Vec<&'a AstNode<'a>>>>,
|
||||
) -> &'a AstNode<'a> {
|
||||
@@ -228,7 +232,7 @@ pub fn extract_sections<'a>(
|
||||
|
||||
let mut heading_content_ref = heading_content_node.data.borrow_mut();
|
||||
if let NodeValue::Text(text) = &mut heading_content_ref.value {
|
||||
if sections.contains(text) {
|
||||
if sections.contains(&text.to_string()) {
|
||||
let mut content = Vec::new();
|
||||
let mut following = node.following_siblings();
|
||||
let _ = following.next().unwrap();
|
||||
@@ -272,10 +276,11 @@ pub fn process_doc_tree<'a>(root: &'a AstNode<'a>, new_date: &str, sections: &Ve
|
||||
let re = Regex::new(r"Today's tasks \d+-\d+-\d+")
|
||||
.expect("title regex is not parsable");
|
||||
if matches!(re.find(text), Some(_)) {
|
||||
text.clear();
|
||||
text.push_str("Today's tasks ");
|
||||
text.push_str(new_date);
|
||||
} else if !sections.contains(text) {
|
||||
let text_mut = text.to_mut();
|
||||
text_mut.clear();
|
||||
text_mut.push_str("Today's tasks ");
|
||||
text_mut.push_str(new_date);
|
||||
} else if !sections.contains(&text.to_string()) {
|
||||
remove_heading(node, heading.level);
|
||||
};
|
||||
}
|
||||
@@ -290,8 +295,9 @@ pub fn process_doc_tree<'a>(root: &'a AstNode<'a>, new_date: &str, sections: &Ve
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::todo::{Status, Task};
|
||||
use std::io::BufWriter;
|
||||
use crate::todo::Status;
|
||||
use crate::todo::Task;
|
||||
use comrak::format_commonmark;
|
||||
|
||||
#[test]
|
||||
fn test_extract_sections() {
|
||||
@@ -487,16 +493,16 @@ mod test {
|
||||
"Last".to_string(),
|
||||
];
|
||||
let arena = Arena::new();
|
||||
let mut extension_options = ExtensionOptions::default();
|
||||
let mut extension_options = Extension::default();
|
||||
extension_options.tasklist = true;
|
||||
|
||||
let mut parse_options = ParseOptions::default();
|
||||
let mut parse_options = Parse::default();
|
||||
parse_options.relaxed_tasklist_matching = true;
|
||||
|
||||
let options = &ComrakOptions {
|
||||
let options = &Options {
|
||||
extension: extension_options,
|
||||
parse: parse_options,
|
||||
..ComrakOptions::default()
|
||||
..Options::default()
|
||||
};
|
||||
|
||||
let ast = parse_document(&arena, md, options);
|
||||
@@ -507,12 +513,10 @@ mod test {
|
||||
|
||||
process_doc_tree(ast, new_date, &groups);
|
||||
|
||||
let mut output = BufWriter::new(Vec::new());
|
||||
let mut output = String::new(); //BufWriter::new(Vec::new());
|
||||
|
||||
assert!(format_commonmark(new_doc, options, &mut output).is_ok());
|
||||
|
||||
let bytes = output.into_inner().expect("should be a vec");
|
||||
let text = String::from_utf8(bytes).expect("should be convertable to string");
|
||||
assert_eq!(
|
||||
"\
|
||||
# Today's tasks 2024-01-02
|
||||
@@ -533,7 +537,7 @@ mod test {
|
||||
|
||||
## Last
|
||||
",
|
||||
text
|
||||
output
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user