moved to comrak 0.52
All checks were successful
Test / test (push) Successful in 47s

This commit is contained in:
2026-04-14 22:05:31 -04:00
parent 181be6c4e3
commit ce03c9c171
6 changed files with 599 additions and 51 deletions

View File

@@ -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
);
}
}

View File

@@ -8,19 +8,19 @@ use chrono::naive::NaiveDate;
use chrono::{Datelike, Local, TimeDelta};
use clap::Parser;
use cli::Args;
use comrak::{format_commonmark, Arena, ComrakOptions, ExtensionOptions, ParseOptions};
use comrak::options::{Extension, Parse};
use comrak::{format_commonmark, Arena, Options};
use config::Config;
use log;
use logging::get_logging_level;
use resolve_path::PathResolveExt;
use simple_logger::init_with_level;
use std::fs;
use std::io::BufWriter;
use std::path::Path;
use std::process::Command;
use todo::{File as TodoFile, TaskGroup};
use crate::file::{create_new_doc, extract_sections, process_doc_tree};
use crate::file::{extract_sections, process_doc_tree};
fn main() {
// setup
@@ -124,16 +124,16 @@ fn main() {
let current_file = match latest_file {
// copy old file if the user specifies today's notes but it does not exist
Some(todo_file) if todo_file.date < today && args.previous == 0 => {
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 sections = &cfg.sections;
log::info!("looking for sections: {:?}", sections);
@@ -160,13 +160,12 @@ fn main() {
process_doc_tree(root, &date, &sections);
let mut new_content = BufWriter::new(Vec::new());
let mut new_content = String::new();
format_commonmark(new_doc, options, &mut new_content);
let text = String::from_utf8(new_content.into_inner().expect(""));
let file_path = file::get_filepath(&data_dir, &today);
log::info!("writing to file: {}", file_path.to_string_lossy());
file::write_file(&file_path, &text.expect(""));
file::write_file(&file_path, &new_content);
// return file name
file_path
}

View File

@@ -1,7 +1,6 @@
use std::borrow::Borrow;
use comrak::nodes::AstNode;
use comrak::nodes::NodeValue;
use comrak::nodes::{AstNode, NodeTaskItem, NodeValue};
#[derive(Debug, Clone, PartialEq)]
pub struct TaskGroup {
@@ -46,7 +45,7 @@ impl Task {
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::Text(contents) => contents.to_string(),
NodeValue::Emph if child.first_child().is_some() => {
format!("*{}*", Self::extract_text(child.first_child().unwrap())?)
}
@@ -101,8 +100,14 @@ impl<'a> TryFrom<&'a AstNode<'a>> for Task {
.ok_or(TaskError::ParsingError("No childern of node found"))?,
)?;
let status = match ch {
Some(c) if c == 'x' || c == 'X' => Status::Done(c),
Some(c) => Status::Todo(c),
NodeTaskItem {
symbol: Some(c),
symbol_sourcepos: _,
} if c == 'x' || c == 'X' => Status::Done(c),
NodeTaskItem {
symbol: Some(c),
symbol_sourcepos: _,
} => Status::Todo(c),
_ => Status::Empty,
};
let subtasks = node