pub mod archive_parser;
pub mod archive_serializer;
pub mod inbox_parser;
pub mod inbox_serializer;
pub mod span;
pub mod task_parser;
pub mod task_serializer;
pub mod track_parser;
pub mod track_serializer;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum LineEnding {
#[default]
Lf,
Crlf,
}
impl LineEnding {
pub fn detect(source: &str) -> Self {
let crlf = source.matches("\r\n").count();
let total = source.matches('\n').count();
if crlf * 2 > total {
LineEnding::Crlf
} else {
LineEnding::Lf
}
}
pub fn apply(self, text: String) -> String {
match self {
LineEnding::Lf => text,
LineEnding::Crlf => text.replace('\n', "\r\n"),
}
}
}
pub(crate) fn has_continuation_at_indent(
lines: &[String],
after_blank: usize,
min_indent: usize,
) -> bool {
for line in lines.iter().skip(after_blank) {
if line.trim().is_empty() {
continue;
}
return count_indent(line) >= min_indent;
}
false
}
pub(crate) fn count_indent(line: &str) -> usize {
line.len() - line.trim_start_matches(' ').len()
}
pub(crate) fn pop_trailing_blanks(lines: &mut Vec<String>) {
while lines.last().is_some_and(|l| l.trim().is_empty()) {
lines.pop();
}
}
pub use archive_parser::parse_archive;
pub use archive_serializer::serialize_archive;
pub use inbox_parser::parse_inbox;
pub use inbox_serializer::serialize_inbox;
pub use task_parser::{parse_tasks, parse_title_and_tags};
pub use task_serializer::serialize_tasks;
pub use track_parser::parse_track;
pub use track_serializer::serialize_track;