diff --git a/src/postprocessors.rs b/src/postprocessors.rs index 2ca4183..157f4b0 100644 --- a/src/postprocessors.rs +++ b/src/postprocessors.rs @@ -1,7 +1,8 @@ //! A collection of officially maintained [postprocessors][crate::Postprocessor]. use super::{Context, MarkdownEvents, PostprocessorResult}; -use pulldown_cmark::Event; +use pulldown_cmark::{CowStr, Event, Tag}; +use regex::Regex; use serde_yaml::Value; /// This postprocessor converts all soft line breaks to hard line breaks. Enabling this mimics @@ -51,6 +52,68 @@ fn filter_by_tags_( } } +pub fn remove_obsidian_comments( + _context: &mut Context, + events: &mut MarkdownEvents, +) -> PostprocessorResult { + let mut output = Vec::with_capacity(events.len()); + let mut inside_comment = false; + let mut inside_codeblock = false; + + for event in &mut *events { + output.push(event.to_owned()); + + match event { + Event::Text(ref text) => { + if !text.contains("%%") { + if inside_comment { + output.pop(); //Inside block comment so remove + } + continue; + } else if inside_codeblock { + continue; //Skip anything inside codeblocks + } + + output.pop(); + + if inside_comment { + inside_comment = false; + continue; + } + + if !text.eq(&CowStr::from("%%")) { + let re = Regex::new(r"%%.*?%%").unwrap(); + let result = re.replace_all(text, "").to_string(); + output.push(Event::Text(CowStr::from(result))); + continue; + } + + inside_comment = true; + } + Event::Start(Tag::CodeBlock(_)) => { + inside_codeblock = true; + } + Event::End(Tag::CodeBlock(_)) => { + inside_codeblock = false; + } + Event::End(Tag::Paragraph) => { + if output[output.len() - 2] == Event::Start(Tag::Paragraph) { + // If the comment was the only item on the line remove the start and end paragraph events to remove the \n in the output file. + output.pop(); + output.pop(); + } + } + _ => { + if inside_comment { + output.pop(); + } + } + } + } + *events = output; + PostprocessorResult::Continue +} + #[test] fn test_filter_tags() { let tags = vec![ diff --git a/tests/postprocessors_test.rs b/tests/postprocessors_test.rs index c04c7c5..d4cdc36 100644 --- a/tests/postprocessors_test.rs +++ b/tests/postprocessors_test.rs @@ -1,4 +1,6 @@ -use obsidian_export::postprocessors::{filter_by_tags, softbreaks_to_hardbreaks}; +use obsidian_export::postprocessors::{ + filter_by_tags, remove_obsidian_comments, softbreaks_to_hardbreaks, +}; use obsidian_export::{Context, Exporter, MarkdownEvents, PostprocessorResult}; use pretty_assertions::assert_eq; use pulldown_cmark::{CowStr, Event}; @@ -290,3 +292,20 @@ fn test_filter_by_tags() { ); } } + +#[test] +fn test_remove_obsidian_comments() { + let tmp_dir = TempDir::new().expect("failed to make tempdir"); + let mut exporter = Exporter::new( + PathBuf::from("tests/testdata/input/remove-comments/"), + tmp_dir.path().to_path_buf(), + ); + exporter.add_postprocessor(&remove_obsidian_comments); + exporter.run().unwrap(); + + let expected = + read_to_string("tests/testdata/expected/remove-comments/test_comments.md").unwrap(); + let actual = read_to_string(tmp_dir.path().join(PathBuf::from("test_comments.md"))).unwrap(); + + assert_eq!(expected, actual); +} diff --git a/tests/testdata/expected/remove-comments/test_comments.md b/tests/testdata/expected/remove-comments/test_comments.md new file mode 100644 index 0000000..7143b6a --- /dev/null +++ b/tests/testdata/expected/remove-comments/test_comments.md @@ -0,0 +1,6 @@ +Not a comment + + +````md +%% Comment in code block should be kept %% +```` diff --git a/tests/testdata/input/remove-comments/test_comments.md b/tests/testdata/input/remove-comments/test_comments.md new file mode 100644 index 0000000..0eae644 --- /dev/null +++ b/tests/testdata/input/remove-comments/test_comments.md @@ -0,0 +1,11 @@ +Not a comment +%% Comment should be removed %% +```md +%% Comment in code block should be kept %% +``` + +%% +This is +a block comment +that should be removed +%%