Skip to content

Commit db3e312

Browse files
author
Johan Förberg
committed
Parse Obsidian-style comments
In addition to normal HTML comment style, Obsidian supports comments enclosed by "%%".
1 parent a695e2b commit db3e312

File tree

5 files changed

+95
-1
lines changed

5 files changed

+95
-1
lines changed

src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use std::path::PathBuf;
33

44
use eyre::{eyre, Result};
55
use gumdrop::Options;
6-
use obsidian_export::postprocessors::{filter_by_tags, softbreaks_to_hardbreaks};
6+
use obsidian_export::postprocessors::{
7+
filter_by_tags, parse_obsidian_comments, softbreaks_to_hardbreaks,
8+
};
79
use obsidian_export::{ExportError, Exporter, FrontmatterStrategy, WalkOptions};
810

911
const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -107,6 +109,8 @@ fn main() {
107109
exporter.preserve_mtime(args.preserve_mtime);
108110
exporter.walk_options(walk_options);
109111

112+
exporter.add_postprocessor(&parse_obsidian_comments);
113+
110114
if args.hard_linebreaks {
111115
exporter.add_postprocessor(&softbreaks_to_hardbreaks);
112116
}

src/postprocessors.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,62 @@ pub fn softbreaks_to_hardbreaks(
1919
PostprocessorResult::Continue
2020
}
2121

22+
/// In addition to HTML comments "<!-- my comment -->", Obsidian syntax includes a second comment
23+
/// syntax "%% my comment %%". This function converts Obsidian-style comments to the standard HTML
24+
/// style.
25+
///
26+
/// Because this step is done when the document is already parsed from markdown, any embedded
27+
/// markup inside comments will be elided from the output.
28+
pub fn parse_obsidian_comments(
29+
context: &mut Context,
30+
events: &mut MarkdownEvents<'_>,
31+
) -> PostprocessorResult {
32+
let mut in_comment = false;
33+
let mut comment_acc = String::new();
34+
let input = std::mem::take(events);
35+
let mut output = MarkdownEvents::new();
36+
37+
for event in input {
38+
match event {
39+
Event::Text(s) => {
40+
for (idx, text) in s.split("%%").enumerate() {
41+
if idx > 0 {
42+
if in_comment && !comment_acc.is_empty() {
43+
output.push(Event::InlineHtml(format!("<!--{comment_acc}-->").into()));
44+
comment_acc.clear();
45+
}
46+
47+
in_comment = !in_comment;
48+
}
49+
50+
if !text.is_empty() {
51+
if in_comment {
52+
comment_acc.push_str(text);
53+
} else {
54+
output.push(Event::Text(text.to_owned().into()));
55+
}
56+
}
57+
}
58+
}
59+
_ => {
60+
if !in_comment {
61+
output.push(event);
62+
}
63+
}
64+
}
65+
}
66+
67+
assert!(
68+
!in_comment,
69+
"Unmatched comment delimiter in {}",
70+
context.destination.display()
71+
);
72+
73+
std::mem::swap(events, &mut output);
74+
75+
PostprocessorResult::Continue
76+
}
77+
2278
pub fn filter_by_tags(
2379
skip_tags: Vec<String>,
2480
only_tags: Vec<String>,

tests/export_test.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::io::prelude::*;
66
use std::os::unix::fs::PermissionsExt;
77
use std::path::PathBuf;
88

9+
use obsidian_export::postprocessors::parse_obsidian_comments;
910
use obsidian_export::{ExportError, Exporter, FrontmatterStrategy};
1011
use pretty_assertions::assert_eq;
1112
use tempfile::TempDir;
@@ -459,3 +460,20 @@ fn test_same_filename_different_directories() {
459460
let actual = read_to_string(tmp_dir.path().join(PathBuf::from("Note.md"))).unwrap();
460461
assert_eq!(expected, actual);
461462
}
463+
464+
#[test]
465+
fn test_parse_obsidian_comments() {
466+
let tmp_dir = TempDir::new().expect("failed to make tempdir");
467+
468+
let mut exporter = Exporter::new(
469+
PathBuf::from("tests/testdata/input/comments/"),
470+
tmp_dir.path().to_path_buf(),
471+
);
472+
exporter.add_postprocessor(&parse_obsidian_comments);
473+
exporter.run().expect("exporter returned error");
474+
475+
assert_eq!(
476+
read_to_string("tests/testdata/expected/comments/note.md").unwrap(),
477+
read_to_string(tmp_dir.path().join(PathBuf::from("note.md"))).unwrap(),
478+
);
479+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Test
2+
3+
<!-- A comment -->
4+
5+
Test2
6+
<!-- A comment containing embedded markup -->
7+
8+
This sentence is <!-- not --> true.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Test
2+
3+
%% A comment %%
4+
5+
Test2
6+
%% A comment containing [[embedded]] **markup** %%
7+
8+
This sentence is %% not %% true.

0 commit comments

Comments
 (0)