From 517cabe8ec54d0bf5f5f9cc9089d76a1fad7bb6a Mon Sep 17 00:00:00 2001 From: Minijackson Date: Sun, 7 Nov 2021 23:09:34 +0100 Subject: initial commit with PoC --- src/filters.rs | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/filters.rs (limited to 'src/filters.rs') 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 @@ +use std::{collections::HashMap, path::Path}; + +use log::trace; +use pandoc_ast::MutVisitor; + +// If a link points to `./a/b/c.ext`, and a file in the output directory `pdbook/./a/b/c.html` +// exists, rewrite that link. +pub struct RelativizeUrls<'a> { + pub config: &'a crate::config::Config, + pub extension: &'a str, + pub build_dir: &'a Path, + pub source_dir: &'a Path, +} + +impl<'a> pandoc_ast::MutVisitor for RelativizeUrls<'a> { + fn walk_inline(&mut self, inline: &mut pandoc_ast::Inline) { + let link = match inline { + pandoc_ast::Inline::Link(_, _, target) => &mut target.0, + _ => return, + }; + + if link.starts_with('#') || link.contains("://") { + return; + } + + let link_path = self.source_dir.join(&link); + + if link_path.is_absolute() { + return; + } + + let mut output_path = self.build_dir.join(&link_path); + if !output_path.set_extension(self.extension) { + return; + } + + trace!("Checking output_path: {:?}", output_path); + + // TODO: warn when referencing a "markdown or other" file not specified in the summary + if output_path.exists() { + // TODO: relativize from URL root + + trace!("Relativizing link '{}'", link_path.display()); + + *link = Path::new(link) + .with_extension(&self.extension) + .to_str() + .expect("Path constructed from UTF-8 valid strings in not UTF-8 valid") + .to_string(); + + trace!("-> into '{}'", link); + } + } +} + +// Applied just to the summary +pub struct RelativizeSummary { + level: usize, +} + +impl pandoc_ast::MutVisitor for RelativizeSummary { + fn walk_inline(&mut self, inline: &mut pandoc_ast::Inline) { + if self.level == 0 { + return; + } + + let link = match inline { + pandoc_ast::Inline::Link(_, _, target) => &mut target.0, + _ => return, + }; + + // Assume link is to a managed file + for _ in 0..self.level { + link.insert_str(0, "../"); + } + } +} + +pub fn relativize_summary(summary: &pandoc_ast::Pandoc, level: usize) -> pandoc_ast::Pandoc { + use std::sync::RwLock; + + lazy_static::lazy_static! { + static ref CACHE: RwLock> = RwLock::new(HashMap::new()); + } + + CACHE + .write() + .expect("Relativized summary cache poison") + .entry(level) + .or_insert_with(|| { + let mut summary = summary.clone(); + RelativizeSummary { level }.walk_pandoc(&mut summary); + summary + }) + .clone() +} + +pub struct InsertSummary<'a> { + pub summary: &'a pandoc_ast::Pandoc, + pub level: usize, +} + +impl<'a> pandoc_ast::MutVisitor for InsertSummary<'a> { + fn walk_pandoc(&mut self, pandoc: &mut pandoc_ast::Pandoc) { + let summary = relativize_summary(self.summary, self.level); + + pandoc.blocks.insert( + 0, + pandoc_ast::Block::Div( + (String::new(), vec!["summary".to_string()], vec![]), + summary.blocks, + ), + ); + } +} -- cgit v1.2.3