Skip to content

Commit 3e98888

Browse files
committed
Add option to not URL encode links
1 parent 8013026 commit 3e98888

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

src/lib.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ pub enum PostprocessorResult {
216216
StopAndSkipNote,
217217
}
218218

219+
#[derive(Debug, Clone, Copy)]
220+
/// Way to encode links
221+
pub enum LinkStrategy {
222+
/// URL encode links
223+
UrlEncoded,
224+
/// Don't do anything to links
225+
NoEncode,
226+
}
227+
219228
#[derive(Clone)]
220229
/// Exporter provides the main interface to this library.
221230
///
@@ -228,6 +237,7 @@ pub struct Exporter<'a> {
228237
destination: PathBuf,
229238
start_at: PathBuf,
230239
frontmatter_strategy: FrontmatterStrategy,
240+
link_strategy: LinkStrategy,
231241
vault_contents: Option<Vec<PathBuf>>,
232242
walk_options: WalkOptions<'a>,
233243
process_embeds_recursively: bool,
@@ -241,6 +251,7 @@ impl<'a> fmt::Debug for Exporter<'a> {
241251
.field("root", &self.root)
242252
.field("destination", &self.destination)
243253
.field("frontmatter_strategy", &self.frontmatter_strategy)
254+
.field("link_strategy", &self.link_strategy)
244255
.field("vault_contents", &self.vault_contents)
245256
.field("walk_options", &self.walk_options)
246257
.field(
@@ -271,6 +282,7 @@ impl<'a> Exporter<'a> {
271282
root,
272283
destination,
273284
frontmatter_strategy: FrontmatterStrategy::Auto,
285+
link_strategy: LinkStrategy::UrlEncoded,
274286
walk_options: WalkOptions::default(),
275287
process_embeds_recursively: true,
276288
vault_contents: None,
@@ -300,6 +312,12 @@ impl<'a> Exporter<'a> {
300312
self
301313
}
302314

315+
/// Set the [`LinkStrategy`] to be used for this exporter.
316+
pub fn link_strategy(&mut self, strategy: LinkStrategy) -> &mut Exporter<'a> {
317+
self.link_strategy = strategy;
318+
self
319+
}
320+
303321
/// Set the behavior when recursive embeds are encountered.
304322
///
305323
/// When `recursive` is true (the default), emdeds are always processed recursively. This may
@@ -381,7 +399,7 @@ impl<'a> Exporter<'a> {
381399
.strip_prefix(&self.start_at.clone())
382400
.expect("file should always be nested under root")
383401
.to_path_buf();
384-
let destination = &self.destination.join(&relative_path);
402+
let destination = &self.destination.join(relative_path);
385403
self.export_note(&file, destination)
386404
})?;
387405
Ok(())
@@ -686,7 +704,12 @@ impl<'a> Exporter<'a> {
686704
.expect("should be able to build relative path when target file is found in vault");
687705

688706
let rel_link = rel_link.to_string_lossy();
689-
let mut link = utf8_percent_encode(&rel_link, PERCENTENCODE_CHARS).to_string();
707+
let mut link = match self.link_strategy {
708+
LinkStrategy::UrlEncoded => {
709+
utf8_percent_encode(&rel_link, PERCENTENCODE_CHARS).to_string()
710+
}
711+
LinkStrategy::NoEncode => rel_link.to_string(), // pulldown_cmark automatically puts it into brackets
712+
};
690713

691714
if let Some(section) = reference.section {
692715
link.push('#');
@@ -732,7 +755,7 @@ fn lookup_filename_in_vault<'a>(
732755

733756
path_normalized.ends_with(&filename_normalized)
734757
|| path_normalized.ends_with(filename_normalized.clone() + ".md")
735-
|| path_normalized_lowered.ends_with(&filename_normalized.to_lowercase())
758+
|| path_normalized_lowered.ends_with(filename_normalized.to_lowercase())
736759
|| path_normalized_lowered.ends_with(filename_normalized.to_lowercase() + ".md")
737760
})
738761
}

src/main.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use eyre::{eyre, Result};
22
use gumdrop::Options;
33
use obsidian_export::postprocessors::softbreaks_to_hardbreaks;
4-
use obsidian_export::{ExportError, Exporter, FrontmatterStrategy, WalkOptions};
4+
use obsidian_export::{ExportError, Exporter, FrontmatterStrategy, LinkStrategy, WalkOptions};
55
use std::{env, path::PathBuf};
66

77
const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -32,6 +32,15 @@ struct Opts {
3232
)]
3333
frontmatter_strategy: FrontmatterStrategy,
3434

35+
#[options(
36+
help = "Link strategy (one of: encoded, none)",
37+
no_short,
38+
long = "link",
39+
parse(try_from_str = "link_strategy_from_str"),
40+
default = "encoded"
41+
)]
42+
link_strategy: LinkStrategy,
43+
3544
#[options(
3645
no_short,
3746
help = "Read ignore patterns from files with this name",
@@ -65,6 +74,14 @@ fn frontmatter_strategy_from_str(input: &str) -> Result<FrontmatterStrategy> {
6574
}
6675
}
6776

77+
fn link_strategy_from_str(input: &str) -> Result<LinkStrategy> {
78+
match input {
79+
"encoded" => Ok(LinkStrategy::UrlEncoded),
80+
"none" => Ok(LinkStrategy::NoEncode),
81+
_ => Err(eyre!("must be one of: encoded, none")),
82+
}
83+
}
84+
6885
fn main() {
6986
// Due to the use of free arguments in Opts, we must bypass Gumdrop to determine whether the
7087
// version flag was specified. Without this, "missing required free argument" would get printed
@@ -87,6 +104,7 @@ fn main() {
87104

88105
let mut exporter = Exporter::new(root, destination);
89106
exporter.frontmatter_strategy(args.frontmatter_strategy);
107+
exporter.link_strategy(args.link_strategy);
90108
exporter.process_embeds_recursively(!args.no_recursive_embeds);
91109
exporter.walk_options(walk_options);
92110

tests/export_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use obsidian_export::{ExportError, Exporter, FrontmatterStrategy};
22
use pretty_assertions::assert_eq;
3-
use std::fs::{create_dir, read_to_string, set_permissions, File, Permissions};
4-
use std::io::prelude::*;
3+
use std::fs::read_to_string;
4+
55
use std::path::PathBuf;
66
use tempfile::TempDir;
77
use walkdir::WalkDir;

0 commit comments

Comments
 (0)