diff --git a/src/lib.rs b/src/lib.rs index bb3f7e5..21f5362 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -216,6 +216,15 @@ pub enum PostprocessorResult { StopAndSkipNote, } +#[derive(Debug, Clone, Copy)] +/// Way to encode links +pub enum LinkStrategy { + /// URL encode links + UrlEncoded, + /// Don't do anything to links + NoEncode, +} + #[derive(Clone)] /// Exporter provides the main interface to this library. /// @@ -228,6 +237,7 @@ pub struct Exporter<'a> { destination: PathBuf, start_at: PathBuf, frontmatter_strategy: FrontmatterStrategy, + link_strategy: LinkStrategy, vault_contents: Option>, walk_options: WalkOptions<'a>, process_embeds_recursively: bool, @@ -241,6 +251,7 @@ impl<'a> fmt::Debug for Exporter<'a> { .field("root", &self.root) .field("destination", &self.destination) .field("frontmatter_strategy", &self.frontmatter_strategy) + .field("link_strategy", &self.link_strategy) .field("vault_contents", &self.vault_contents) .field("walk_options", &self.walk_options) .field( @@ -271,6 +282,7 @@ impl<'a> Exporter<'a> { root, destination, frontmatter_strategy: FrontmatterStrategy::Auto, + link_strategy: LinkStrategy::UrlEncoded, walk_options: WalkOptions::default(), process_embeds_recursively: true, vault_contents: None, @@ -300,6 +312,12 @@ impl<'a> Exporter<'a> { self } + /// Set the [`LinkStrategy`] to be used for this exporter. + pub fn link_strategy(&mut self, strategy: LinkStrategy) -> &mut Exporter<'a> { + self.link_strategy = strategy; + self + } + /// Set the behavior when recursive embeds are encountered. /// /// When `recursive` is true (the default), emdeds are always processed recursively. This may @@ -686,7 +704,12 @@ impl<'a> Exporter<'a> { .expect("should be able to build relative path when target file is found in vault"); let rel_link = rel_link.to_string_lossy(); - let mut link = utf8_percent_encode(&rel_link, PERCENTENCODE_CHARS).to_string(); + let mut link = match self.link_strategy { + LinkStrategy::UrlEncoded => { + utf8_percent_encode(&rel_link, PERCENTENCODE_CHARS).to_string() + } + LinkStrategy::NoEncode => rel_link.to_string(), // pulldown_cmark automatically puts it into brackets + }; if let Some(section) = reference.section { link.push('#'); diff --git a/src/main.rs b/src/main.rs index 902783d..c92f7f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use eyre::{eyre, Result}; use gumdrop::Options; use obsidian_export::postprocessors::softbreaks_to_hardbreaks; -use obsidian_export::{ExportError, Exporter, FrontmatterStrategy, WalkOptions}; +use obsidian_export::{ExportError, Exporter, FrontmatterStrategy, LinkStrategy, WalkOptions}; use std::{env, path::PathBuf}; const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -32,6 +32,15 @@ struct Opts { )] frontmatter_strategy: FrontmatterStrategy, + #[options( + help = "Link strategy (one of: encoded, none)", + no_short, + long = "link", + parse(try_from_str = "link_strategy_from_str"), + default = "encoded" + )] + link_strategy: LinkStrategy, + #[options( no_short, help = "Read ignore patterns from files with this name", @@ -65,6 +74,14 @@ fn frontmatter_strategy_from_str(input: &str) -> Result { } } +fn link_strategy_from_str(input: &str) -> Result { + match input { + "encoded" => Ok(LinkStrategy::UrlEncoded), + "none" => Ok(LinkStrategy::NoEncode), + _ => Err(eyre!("must be one of: encoded, none")), + } +} + 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 @@ -87,6 +104,7 @@ fn main() { let mut exporter = Exporter::new(root, destination); exporter.frontmatter_strategy(args.frontmatter_strategy); + exporter.link_strategy(args.link_strategy); exporter.process_embeds_recursively(!args.no_recursive_embeds); exporter.walk_options(walk_options);