diff options
Diffstat (limited to 'src/filters.rs')
-rw-r--r-- | src/filters.rs | 115 |
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 @@ | |||
1 | use std::{collections::HashMap, path::Path}; | ||
2 | |||
3 | use log::trace; | ||
4 | use 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. | ||
8 | pub 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 | |||
15 | impl<'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 | ||
57 | pub struct RelativizeSummary { | ||
58 | level: usize, | ||
59 | } | ||
60 | |||
61 | impl 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 | |||
79 | pub 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 | |||
98 | pub struct InsertSummary<'a> { | ||
99 | pub summary: &'a pandoc_ast::Pandoc, | ||
100 | pub level: usize, | ||
101 | } | ||
102 | |||
103 | impl<'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 | } | ||