Adding CommentStrategy enum to be used in main.rs for the command flag. Putting the Regex definition in a LazyCell. Adding logic to pop off codeblocks if they are inside a comment. Adding edge case to test.

This commit is contained in:
Jason Thompson 2024-08-05 23:14:30 -04:00
parent b938375acc
commit 6373f19343
4 changed files with 72 additions and 16 deletions

View File

@ -3,7 +3,12 @@ use std::path::PathBuf;
use eyre::{eyre, Result};
use gumdrop::Options;
use obsidian_export::postprocessors::{filter_by_tags, softbreaks_to_hardbreaks};
use obsidian_export::postprocessors::{
filter_by_tags,
remove_obsidian_comments,
softbreaks_to_hardbreaks,
CommentStrategy,
};
use obsidian_export::{ExportError, Exporter, FrontmatterStrategy, WalkOptions};
const VERSION: &str = env!("CARGO_PKG_VERSION");
@ -65,17 +70,20 @@ struct Opts {
preserve_mtime: bool,
#[options(
help = "Comment strategy (one of: keep-unchanged or remove)",
no_short,
help = "Convert soft line breaks to hard line breaks. This mimics Obsidian's 'Strict line breaks' setting",
default = "false"
)]
hard_linebreaks: bool,
#[options(
no_short,
help = "Remove Obsidian style comments from exported file",
default = "false"
long = "comments",
parse(try_from_str = "comment_strategy_from_str"),
default = "keep-unchanged"
)]
remove_obsidian_comments: bool,
comment_strategy: CommentStrategy,
}
fn frontmatter_strategy_from_str(input: &str) -> Result<FrontmatterStrategy> {
@ -87,6 +95,14 @@ fn frontmatter_strategy_from_str(input: &str) -> Result<FrontmatterStrategy> {
}
}
fn comment_strategy_from_str(input: &str) -> Result<CommentStrategy> {
match input {
"keep-unchanged" => Ok(CommentStrategy::KeepUnchanged),
"remove" => Ok(CommentStrategy::Remove),
_ => Err(eyre!("must be one of: keep-unchanged or remove")),
}
}
fn main() {
// Due to the use of free arguments in Opts, we must bypass Gumdrop to determine whether the
// version flag was specified. Without this, "missing required free argument" would get printed
@ -117,7 +133,7 @@ fn main() {
exporter.add_postprocessor(&softbreaks_to_hardbreaks);
}
if args.remove_obsidian_comments {
if matches!(args.comment_strategy, CommentStrategy::Remove) {
exporter.add_postprocessor(&remove_obsidian_comments);
}

View File

@ -1,9 +1,9 @@
//! A collection of officially maintained [postprocessors][crate::Postprocessor].
use super::{Context, MarkdownEvents, PostprocessorResult};
use std::cell::LazyCell;
use pulldown_cmark::{CowStr, Event, Tag};
use regex::Regex;
use serde_yaml::Value;
use super::{Context, MarkdownEvents, PostprocessorResult};
@ -55,15 +55,27 @@ fn filter_by_tags_(
}
}
//Available strategies for what to do with comments
#[derive(Debug)]
#[non_exhaustive]
pub enum CommentStrategy {
// Leave comments alone and export them as normal
KeepUnchanged,
// Remove any comments from the output
Remove,
}
#[allow(clippy::else_if_without_else, clippy::arithmetic_side_effects)]
/// This postprocessor removes all Obsidian comments from a file excluding codeblocks. Enabling this
/// prohibits comments from being exported but leaves them untouched in the original files
pub fn remove_obsidian_comments(
_context: &mut Context,
events: &mut MarkdownEvents,
events: &mut MarkdownEvents<'_>,
) -> PostprocessorResult {
let mut output = Vec::with_capacity(events.len());
let mut inside_comment = false;
let mut inside_codeblock = false;
let re = LazyCell::new(|| Regex::new(r"%%.*?%%").unwrap());
for event in &mut *events {
output.push(event.to_owned());
@ -87,7 +99,6 @@ pub fn remove_obsidian_comments(
}
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;
@ -96,14 +107,25 @@ pub fn remove_obsidian_comments(
inside_comment = true;
}
Event::Start(Tag::CodeBlock(_)) => {
inside_codeblock = true;
if inside_comment {
output.pop();
} else {
inside_codeblock = true;
}
}
Event::End(Tag::CodeBlock(_)) => {
inside_codeblock = false;
if inside_comment {
output.pop();
} else {
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.
if output.len() >= 2
&& output.get(output.len() - 2) == Option::from(&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();
}

View File

@ -1,11 +1,13 @@
use obsidian_export::postprocessors::{
filter_by_tags, remove_obsidian_comments, softbreaks_to_hardbreaks,
};
use std::collections::HashSet;
use std::fs::{read_to_string, remove_file};
use std::path::PathBuf;
use std::sync::Mutex;
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};

View File

@ -9,3 +9,19 @@ This is
a block comment
that should be removed
%%
%%
None of the below should be visible in output:
## Header
Code block:
```
foo
```
---
%%