summaryrefslogtreecommitdiffstats
path: root/src/filters.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/filters.rs')
-rw-r--r--src/filters.rs115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/filters.rs b/src/filters.rs
new file mode 100644
index 0000000..1b06920
--- /dev/null
+++ b/src/filters.rs
@@ -0,0 +1,115 @@
1use std::{collections::HashMap, path::Path};
2
3use log::trace;
4use pandoc_ast::MutVisitor;
5
6// If a link points to `./a/b/c.ext`, and a file in the output directory `pdbook/./a/b/c.html`
7// exists, rewrite that link.
8pub struct RelativizeUrls<'a> {
9 pub config: &'a crate::config::Config,
10 pub extension: &'a str,
11 pub build_dir: &'a Path,
12 pub source_dir: &'a Path,
13}
14
15impl<'a> pandoc_ast::MutVisitor for RelativizeUrls<'a> {
16 fn walk_inline(&mut self, inline: &mut pandoc_ast::Inline) {
17 let link = match inline {
18 pandoc_ast::Inline::Link(_, _, target) => &mut target.0,
19 _ => return,
20 };
21
22 if link.starts_with('#') || link.contains("://") {
23 return;
24 }
25
26 let link_path = self.source_dir.join(&link);
27
28 if link_path.is_absolute() {
29 return;
30 }
31
32 let mut output_path = self.build_dir.join(&link_path);
33 if !output_path.set_extension(self.extension) {
34 return;
35 }
36
37 trace!("Checking output_path: {:?}", output_path);
38
39 // TODO: warn when referencing a "markdown or other" file not specified in the summary
40 if output_path.exists() {
41 // TODO: relativize from URL root
42
43 trace!("Relativizing link '{}'", link_path.display());
44
45 *link = Path::new(link)
46 .with_extension(&self.extension)
47 .to_str()
48 .expect("Path constructed from UTF-8 valid strings in not UTF-8 valid")
49 .to_string();
50
51 trace!("-> into '{}'", link);
52 }
53 }
54}
55
56// Applied just to the summary
57pub struct RelativizeSummary {
58 level: usize,
59}
60
61impl pandoc_ast::MutVisitor for RelativizeSummary {
62 fn walk_inline(&mut self, inline: &mut pandoc_ast::Inline) {
63 if self.level == 0 {
64 return;
65 }
66
67 let link = match inline {
68 pandoc_ast::Inline::Link(_, _, target) => &mut target.0,
69 _ => return,
70 };
71
72 // Assume link is to a managed file
73 for _ in 0..self.level {
74 link.insert_str(0, "../");
75 }
76 }
77}
78
79pub fn relativize_summary(summary: &pandoc_ast::Pandoc, level: usize) -> pandoc_ast::Pandoc {
80 use std::sync::RwLock;
81
82 lazy_static::lazy_static! {
83 static ref CACHE: RwLock<HashMap<usize, pandoc_ast::Pandoc>> = RwLock::new(HashMap::new());
84 }
85
86 CACHE
87 .write()
88 .expect("Relativized summary cache poison")
89 .entry(level)
90 .or_insert_with(|| {
91 let mut summary = summary.clone();
92 RelativizeSummary { level }.walk_pandoc(&mut summary);
93 summary
94 })
95 .clone()
96}
97
98pub struct InsertSummary<'a> {
99 pub summary: &'a pandoc_ast::Pandoc,
100 pub level: usize,
101}
102
103impl<'a> pandoc_ast::MutVisitor for InsertSummary<'a> {
104 fn walk_pandoc(&mut self, pandoc: &mut pandoc_ast::Pandoc) {
105 let summary = relativize_summary(self.summary, self.level);
106
107 pandoc.blocks.insert(
108 0,
109 pandoc_ast::Block::Div(
110 (String::new(), vec!["summary".to_string()], vec![]),
111 summary.blocks,
112 ),
113 );
114 }
115}