first draft
This commit is contained in:
parent
80130260e9
commit
a012c3f25a
27
src/lib.rs
27
src/lib.rs
@ -5,6 +5,7 @@ pub extern crate serde_yaml;
|
|||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
|
mod preprocessors;
|
||||||
mod frontmatter;
|
mod frontmatter;
|
||||||
pub mod postprocessors;
|
pub mod postprocessors;
|
||||||
mod references;
|
mod references;
|
||||||
@ -132,7 +133,8 @@ pub type MarkdownEvents<'a> = Vec<Event<'a>>;
|
|||||||
/// exporter.add_postprocessor(&foo_to_bar);
|
/// exporter.add_postprocessor(&foo_to_bar);
|
||||||
/// # exporter.run().unwrap();
|
/// # exporter.run().unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
|
pub type Preprocessor =
|
||||||
|
dyn Fn(&mut Context, &mut String) -> PostprocessorResult + Send + Sync;
|
||||||
pub type Postprocessor =
|
pub type Postprocessor =
|
||||||
dyn Fn(&mut Context, &mut MarkdownEvents) -> PostprocessorResult + Send + Sync;
|
dyn Fn(&mut Context, &mut MarkdownEvents) -> PostprocessorResult + Send + Sync;
|
||||||
type Result<T, E = ExportError> = std::result::Result<T, E>;
|
type Result<T, E = ExportError> = std::result::Result<T, E>;
|
||||||
@ -231,6 +233,7 @@ pub struct Exporter<'a> {
|
|||||||
vault_contents: Option<Vec<PathBuf>>,
|
vault_contents: Option<Vec<PathBuf>>,
|
||||||
walk_options: WalkOptions<'a>,
|
walk_options: WalkOptions<'a>,
|
||||||
process_embeds_recursively: bool,
|
process_embeds_recursively: bool,
|
||||||
|
preprocessors: Vec<&'a Preprocessor>,
|
||||||
postprocessors: Vec<&'a Postprocessor>,
|
postprocessors: Vec<&'a Postprocessor>,
|
||||||
embed_postprocessors: Vec<&'a Postprocessor>,
|
embed_postprocessors: Vec<&'a Postprocessor>,
|
||||||
}
|
}
|
||||||
@ -274,6 +277,7 @@ impl<'a> Exporter<'a> {
|
|||||||
walk_options: WalkOptions::default(),
|
walk_options: WalkOptions::default(),
|
||||||
process_embeds_recursively: true,
|
process_embeds_recursively: true,
|
||||||
vault_contents: None,
|
vault_contents: None,
|
||||||
|
preprocessors: vec![&preprocessors::remove_ignore_blocks],
|
||||||
postprocessors: vec![],
|
postprocessors: vec![],
|
||||||
embed_postprocessors: vec![],
|
embed_postprocessors: vec![],
|
||||||
}
|
}
|
||||||
@ -381,7 +385,7 @@ impl<'a> Exporter<'a> {
|
|||||||
.strip_prefix(&self.start_at.clone())
|
.strip_prefix(&self.start_at.clone())
|
||||||
.expect("file should always be nested under root")
|
.expect("file should always be nested under root")
|
||||||
.to_path_buf();
|
.to_path_buf();
|
||||||
let destination = &self.destination.join(&relative_path);
|
let destination = &self.destination.join(relative_path);
|
||||||
self.export_note(&file, destination)
|
self.export_note(&file, destination)
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -398,7 +402,7 @@ impl<'a> Exporter<'a> {
|
|||||||
fn parse_and_export_obsidian_note(&self, src: &Path, dest: &Path) -> Result<()> {
|
fn parse_and_export_obsidian_note(&self, src: &Path, dest: &Path) -> Result<()> {
|
||||||
let mut context = Context::new(src.to_path_buf(), dest.to_path_buf());
|
let mut context = Context::new(src.to_path_buf(), dest.to_path_buf());
|
||||||
|
|
||||||
let (frontmatter, mut markdown_events) = self.parse_obsidian_note(src, &context)?;
|
let (frontmatter, mut markdown_events) = self.parse_obsidian_note(src, &mut context)?;
|
||||||
context.frontmatter = frontmatter;
|
context.frontmatter = frontmatter;
|
||||||
for func in &self.postprocessors {
|
for func in &self.postprocessors {
|
||||||
match func(&mut context, &mut markdown_events) {
|
match func(&mut context, &mut markdown_events) {
|
||||||
@ -432,14 +436,17 @@ impl<'a> Exporter<'a> {
|
|||||||
fn parse_obsidian_note<'b>(
|
fn parse_obsidian_note<'b>(
|
||||||
&self,
|
&self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
context: &Context,
|
context: &mut Context,
|
||||||
) -> Result<(Frontmatter, MarkdownEvents<'b>)> {
|
) -> Result<(Frontmatter, MarkdownEvents<'b>)> {
|
||||||
if context.note_depth() > NOTE_RECURSION_LIMIT {
|
if context.note_depth() > NOTE_RECURSION_LIMIT {
|
||||||
return Err(ExportError::RecursionLimitExceeded {
|
return Err(ExportError::RecursionLimitExceeded {
|
||||||
file_tree: context.file_tree(),
|
file_tree: context.file_tree(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let content = fs::read_to_string(path).context(ReadSnafu { path })?;
|
let mut content = fs::read_to_string(path).context(ReadSnafu { path })?;
|
||||||
|
for preprocessor in &self.preprocessors {
|
||||||
|
preprocessor(context, &mut content);
|
||||||
|
}
|
||||||
let (frontmatter, content) =
|
let (frontmatter, content) =
|
||||||
matter::matter(&content).unwrap_or(("".to_string(), content.to_string()));
|
matter::matter(&content).unwrap_or(("".to_string(), content.to_string()));
|
||||||
let frontmatter =
|
let frontmatter =
|
||||||
@ -598,7 +605,7 @@ impl<'a> Exporter<'a> {
|
|||||||
|
|
||||||
let events = match path.extension().unwrap_or(&no_ext).to_str() {
|
let events = match path.extension().unwrap_or(&no_ext).to_str() {
|
||||||
Some("md") => {
|
Some("md") => {
|
||||||
let (frontmatter, mut events) = self.parse_obsidian_note(path, &child_context)?;
|
let (frontmatter, mut events) = self.parse_obsidian_note(path, &mut child_context)?;
|
||||||
child_context.frontmatter = frontmatter;
|
child_context.frontmatter = frontmatter;
|
||||||
if let Some(section) = note_ref.section {
|
if let Some(section) = note_ref.section {
|
||||||
events = reduce_to_section(events, section);
|
events = reduce_to_section(events, section);
|
||||||
@ -647,9 +654,9 @@ impl<'a> Exporter<'a> {
|
|||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_link_to_file<'b, 'c>(
|
fn make_link_to_file<'c>(
|
||||||
&self,
|
&self,
|
||||||
reference: ObsidianNoteReference<'b>,
|
reference: ObsidianNoteReference<'_>,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
) -> MarkdownEvents<'c> {
|
) -> MarkdownEvents<'c> {
|
||||||
let target_file = reference
|
let target_file = reference
|
||||||
@ -732,7 +739,7 @@ fn lookup_filename_in_vault<'a>(
|
|||||||
|
|
||||||
path_normalized.ends_with(&filename_normalized)
|
path_normalized.ends_with(&filename_normalized)
|
||||||
|| path_normalized.ends_with(filename_normalized.clone() + ".md")
|
|| path_normalized.ends_with(filename_normalized.clone() + ".md")
|
||||||
|| path_normalized_lowered.ends_with(&filename_normalized.to_lowercase())
|
|| path_normalized_lowered.ends_with(filename_normalized.to_lowercase())
|
||||||
|| path_normalized_lowered.ends_with(filename_normalized.to_lowercase() + ".md")
|
|| path_normalized_lowered.ends_with(filename_normalized.to_lowercase() + ".md")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -783,7 +790,7 @@ fn is_markdown_file(file: &Path) -> bool {
|
|||||||
|
|
||||||
/// Reduce a given `MarkdownEvents` to just those elements which are children of the given section
|
/// Reduce a given `MarkdownEvents` to just those elements which are children of the given section
|
||||||
/// (heading name).
|
/// (heading name).
|
||||||
fn reduce_to_section<'a, 'b>(events: MarkdownEvents<'a>, section: &'b str) -> MarkdownEvents<'a> {
|
fn reduce_to_section<'a>(events: MarkdownEvents<'a>, section: &'_ str) -> MarkdownEvents<'a> {
|
||||||
let mut filtered_events = Vec::with_capacity(events.len());
|
let mut filtered_events = Vec::with_capacity(events.len());
|
||||||
let mut target_section_encountered = false;
|
let mut target_section_encountered = false;
|
||||||
let mut currently_in_target_section = false;
|
let mut currently_in_target_section = false;
|
||||||
|
20
src/preprocessors.rs
Normal file
20
src/preprocessors.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//! A collection of officially maintained [postprocessors][crate::Postprocessor].
|
||||||
|
|
||||||
|
use super::{Context, PostprocessorResult};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
const IGNORE_REGEX_0: &str = r"%% EXPORT_IGNORE_BEGIN %%(.|\n)*?%% EXPORT_IGNORE_END %%";
|
||||||
|
const IGNORE_REGEX_1: &str = r"# EXPORT_IGNORE_BEGIN(.|\n)*?# EXPORT_IGNORE_END";
|
||||||
|
|
||||||
|
/// This postprocessor removes all
|
||||||
|
pub fn remove_ignore_blocks(
|
||||||
|
_context: &mut Context,
|
||||||
|
string: &mut String,
|
||||||
|
) -> PostprocessorResult {
|
||||||
|
let re = Regex::new(IGNORE_REGEX_0).unwrap();
|
||||||
|
*string = re.replace_all(string, "").to_string();
|
||||||
|
|
||||||
|
let re = Regex::new(IGNORE_REGEX_1).unwrap();
|
||||||
|
*string = re.replace_all(string, "").to_string();
|
||||||
|
PostprocessorResult::Continue
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user