From 17b10fab16bc5df3a969826150e92f50e88a99b9 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Sun, 28 Nov 2021 00:19:12 +0100 Subject: add css and html template, refactor build --- Cargo.lock | 96 +++++++++++++ Cargo.toml | 1 + res/style.css | 171 +++++++++++++++++++++++ res/template.html | 72 ++++++++++ src/build.rs | 411 +++++++++++++++++++++--------------------------------- src/filters.rs | 23 +-- src/utils.rs | 18 ++- 7 files changed, 519 insertions(+), 273 deletions(-) create mode 100644 res/style.css create mode 100644 res/template.html diff --git a/Cargo.lock b/Cargo.lock index 5a17968..81f5135 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.26.1" @@ -390,6 +401,7 @@ dependencies = [ "pandoc", "pandoc_ast", "serde 1.0.130", + "tempfile", ] [[package]] @@ -408,6 +420,12 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +[[package]] +name = "ppv-lite86" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -450,6 +468,55 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.5.4" @@ -467,6 +534,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "rust-ini" version = "0.13.0" @@ -566,6 +642,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -688,6 +778,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 365b07b..e8783c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ pandoc = "0.8" # TODO: change this when new version is released pandoc_ast = { git = "https://github.com/oli-obk/pandoc-ast", rev = "d73a7d0a065f568d60bcee6cff2340f75065273e" } serde = { version = "1", features = [ "derive" ] } +tempfile = "3" diff --git a/res/style.css b/res/style.css new file mode 100644 index 0000000..54ee84e --- /dev/null +++ b/res/style.css @@ -0,0 +1,171 @@ +/* from here */ + +.summary { + position: fixed; + top: 0; + bottom: 0; + left: 0; + border-right: 1px solid #1a1a1a; + /* TODO: ugly */ + background-color: hsl(0, 0%, 80%); + transition: transform .2s; +} + +.summary.hidden { + transform: translateX(-100%); +} + +.summary::before { + content: "x"; + position: absolute; + right: 1em; + top: 0.5em; +} + +.summary > ul { + padding-right: 1em; +} + +.summary .generated { + color: #5a5a5a; +} + +/* from pandoc */ +html { + line-height: 1.5; + font-family: Georgia, serif; + font-size: 20px; + color: #1a1a1a; + background-color: #fdfdfd; +} +body { + margin: 0 auto; + max-width: 36em; + padding-left: 50px; + padding-right: 50px; + padding-top: 50px; + padding-bottom: 50px; + hyphens: auto; + word-wrap: break-word; + text-rendering: optimizeLegibility; + font-kerning: normal; +} +@media (max-width: 600px) { + body { + font-size: 0.9em; + padding: 1em; + } +} +@media print { + body { + background-color: transparent; + color: black; + font-size: 12pt; + } + p, h2, h3 { + orphans: 3; + widows: 3; + } + h2, h3, h4 { + page-break-after: avoid; + } +} +p { + margin: 1em 0; +} +a { + color: #1a1a1a; +} +a:visited { + color: #1a1a1a; +} +img { + max-width: 100%; +} +h1, h2, h3, h4, h5, h6 { + margin-top: 1.4em; +} +h5, h6 { + font-size: 1em; + font-style: italic; +} +h6 { + font-weight: normal; +} +ol, ul { + padding-left: 1.7em; + margin-top: 1em; +} +li > ol, li > ul { + margin-top: 0; +} +blockquote { + margin: 1em 0 1em 1.7em; + padding-left: 1em; + border-left: 2px solid #e6e6e6; + color: #606060; +} +code { + font-family: Menlo, Monaco, 'Lucida Console', Consolas, monospace; + font-size: 85%; + margin: 0; +} +pre { + margin: 1em 0; + overflow: auto; +} +pre code { + padding: 0; + overflow: visible; +} +.sourceCode { + background-color: transparent; + overflow: visible; +} +hr { + background-color: #1a1a1a; + border: none; + height: 1px; + margin: 1em 0; +} +table { + margin: 1em 0; + border-collapse: collapse; + width: 100%; + overflow-x: auto; + display: block; + font-variant-numeric: lining-nums tabular-nums; +} +table caption { + margin-bottom: 0.75em; +} +tbody { + margin-top: 0.5em; + border-top: 1px solid #1a1a1a; + border-bottom: 1px solid #1a1a1a; +} +th { + border-top: 1px solid #1a1a1a; + padding: 0.25em 0.5em 0.25em 0.5em; +} +td { + padding: 0.125em 0.5em 0.25em 0.5em; +} +header { + margin-bottom: 4em; + text-align: center; +} +#TOC li { + list-style: none; +} +#TOC a:not(:hover) { + text-decoration: none; +} +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +span.underline{text-decoration: underline;} +div.column{display: inline-block; vertical-align: top; width: 50%;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +q { quotes: "“" "”" "‘" "’"; } +.display.math{display: block; text-align: center; margin: 0.5rem auto;} diff --git a/res/template.html b/res/template.html new file mode 100644 index 0000000..bacb376 --- /dev/null +++ b/res/template.html @@ -0,0 +1,72 @@ + + + + + + +$for(author-meta)$ + +$endfor$ +$if(date-meta)$ + +$endif$ +$if(keywords)$ + +$endif$ +$if(description-meta)$ + +$endif$ + $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$ + +$for(css)$ + +$endfor$ +$if(math)$ + $math$ +$endif$ + +$for(header-includes)$ + $header-includes$ +$endfor$ + + + +
+$for(include-before)$ +$include-before$ +$endfor$ +$if(title)$ +
+

$title$

+$if(subtitle)$ +

$subtitle$

+$endif$ +$for(author)$ +

$author$

+$endfor$ +$if(date)$ +

$date$

+$endif$ +
+$endif$ +$if(toc)$ + +$endif$ +$body$ +$for(include-after)$ +$include-after$ +$endfor$ +
+ + diff --git a/src/build.rs b/src/build.rs index 0b0c646..1c12476 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,20 +1,29 @@ use std::path::{Path, PathBuf}; -use eyre::{eyre, ContextCompat, Result, WrapErr}; +use eyre::{eyre, Result, WrapErr}; use log::{debug, error, log_enabled, trace, warn}; use pandoc_ast::MutVisitor; use crate::{ - filters, - utils::{AutoIdentifier, PandocMeta, PandocOutputExt}, + filters::{self, relativize_summary}, + utils::{AutoIdentifier, PandocMeta, PandocOutputExt, PathExt}, }; +const CSS: &str = include_str!("../res/style.css"); +const HTML_TEMPLATE: &str = include_str!("../res/template.html"); + pub fn do_build(config: &crate::config::Config) -> Result<()> { - let summary = Summary::try_from_file(&config.book.summary)?; + let tmpdir = tempfile::tempdir().wrap_err("Could not create temporary directory")?; + debug!("Created temporary directory at: '{}'", tmpdir.path().display()); + let template_path = tmpdir.path().join("template.html"); + trace!("Writing HTML template to: '{}'", template_path.display()); + std::fs::write(&template_path, HTML_TEMPLATE) + .wrap_err("Could not save HTML template in temporary directory")?; + let source_root = Path::new(&config.book.summary) .parent() .expect("Summary has no parent"); - let files = summary.collect_source_files(source_root)?; + let (summary, files) = process_summary(&config.book.summary, source_root)?; let build_dir = Path::new(&config.build.build_dir); trace!("Creating build directory: '{}'", build_dir.display()); @@ -25,6 +34,10 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { ) })?; + let style_path = build_dir.join("style.css"); + debug!("Generating file: '{}'", style_path.display()); + std::fs::write(&style_path, CSS).wrap_err("Could not create style.css")?; + // Pre-create files so that we know which links to relativize for SourceFile { path, .. } in &files { let output_file = build_dir.join(path.with_extension("html")); @@ -47,7 +60,7 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { })?; } - for SourceFile { path, source } in &files { + for SourceFile { path, source, .. } in &files { let mut pandoc_command = pandoc::new(); let output_file = build_dir.join(path.with_extension("html")); @@ -61,25 +74,36 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { .expect("Source file has no parent") .to_path_buf(); let build_dir_clone = build_dir.to_path_buf(); - let summary_clone = summary.source.clone(); + + let level = source_dir + .components() + .skip_while(|c| matches!(c, std::path::Component::CurDir)) + .count(); + + let summary = relativize_summary(&summary.source, level); + let mut source = source.clone(); + source.meta.insert( + "summary".to_string(), + pandoc_ast::MetaValue::MetaBlocks(summary.blocks), + ); + + let style_path = std::iter::repeat(std::path::Component::ParentDir) + .take(level) + .collect::() + .join("style.css"); pandoc_command .set_input(pandoc::InputKind::Pipe(source.to_json())) .set_input_format(pandoc::InputFormat::Json, vec![]) .set_output(pandoc::OutputKind::File(output_file)) .set_output_format(pandoc::OutputFormat::Html5, vec![]) - .add_options(&[pandoc::PandocOption::SelfContained]) + .add_options(&[ + pandoc::PandocOption::Css(style_path.to_string()), + pandoc::PandocOption::SectionDivs, + pandoc::PandocOption::Standalone, + pandoc::PandocOption::Template(template_path.clone()), + ]) .add_filter(move |source| { - let level = source_dir - .components() - .skip_while(|c| matches!(c, std::path::Component::CurDir)) - .count(); - - let mut insert_summary_filter = filters::InsertSummary { - level, - summary: &summary_clone, - }; - let mut relativize_urls_filter = filters::RelativizeUrls { config: &config_clone, // TODO: other output formats @@ -89,7 +113,6 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { }; let mut source = pandoc_ast::Pandoc::from_json(&source); - insert_summary_filter.walk_pandoc(&mut source); relativize_urls_filter.walk_pandoc(&mut source); source.to_json() }); @@ -109,7 +132,7 @@ pub fn do_build(config: &crate::config::Config) -> Result<()> { // TODO: move that into generated.rs fn generate_source( title: Vec, - children: Vec<(PandocMeta, PathBuf)>, + children: &[(&PandocMeta, &Path)], level: usize, ) -> Result { // TODO: make that text configurable @@ -117,8 +140,8 @@ fn generate_source( "Here are the articles in this section:".to_string(), )])]; - for (mut child, file) in children { - let title = match child.remove("title") { + for (child, file) in children { + let title = match child.get("title").cloned() { None => { warn!("Missing title for file: '{}'", file.display()); vec![pandoc_ast::Inline::Str("Untitled page".to_string())] @@ -174,17 +197,13 @@ fn list_content(block: &mut pandoc_ast::Block) -> Result<&mut Vec>) -> Result> { - vec.iter_mut().map(Node::try_from_vec_block).collect() -} - // TODO: support separators like these: // --------- #[derive(Debug)] pub struct Summary { source: pandoc_ast::Pandoc, - nodes: Vec, + //nodes: Vec, } #[derive(Debug)] @@ -194,258 +213,150 @@ struct SourceFile { } // TODO: move that into summary.rs -impl Summary { - fn try_from_file(file: &str) -> Result { - debug!("Parsing summary"); - let mut pandoc_command = pandoc::new(); - pandoc_command - .add_input(file) - .set_output_format(pandoc::OutputFormat::Json, vec![]) - .set_output(pandoc::OutputKind::Pipe); +fn process_summary(file: &str, source_root: &Path) -> Result<(Summary, Vec)> { + debug!("Parsing summary"); + let mut pandoc_command = pandoc::new(); + pandoc_command + .add_input(file) + .set_output_format(pandoc::OutputFormat::Json, vec![]) + .set_output(pandoc::OutputKind::Pipe); + + if log_enabled!(log::Level::Trace) { + pandoc_command.set_show_cmdline(true); + } - trace!("Launching pandoc command"); + let output = pandoc_command + .execute() + .wrap_err("Could not execute pandoc")? + .buffer(); - if log_enabled!(log::Level::Trace) { - pandoc_command.set_show_cmdline(true); - } - - let output = pandoc_command - .execute() - .wrap_err("Could not execute pandoc")? - .buffer(); - - let document = pandoc_ast::Pandoc::from_json(&output); - - let summary: Self = document.try_into()?; - if summary.has_files_missing( - Path::new(file) - .parent() - .expect("Summary file has no parent"), - ) { - return Err(eyre!("Files from the summary are missing, aborting")); - } + let mut document = pandoc_ast::Pandoc::from_json(&output); - Ok(summary) + if document.blocks.len() != 1 { + return Err(eyre!("Summary does not contain a single list")); } - fn has_files_missing(&self, root: &Path) -> bool { - // Do not use `.any()` to prevent short-circuiting, we want to report all missing files - self.nodes.iter().fold(false, |acc, node| { - let missing = node.has_files_missing(root); - acc || missing - }) - } + let root = &mut document.blocks[0]; - /// Get a list of source files. - /// - /// If a file is a generated file, generate it and store it in memory. - fn collect_source_files(&self, root: &Path) -> Result> { - let mut result = Vec::new(); + let list = list_content(root)?; - for node in &self.nodes { - node.collect_source_files(&mut result, root, Path::new("."), 0)?; - } + let mut source_files = Vec::new(); - Ok(result) + for element in list.iter_mut() { + process_summary_element(element, Path::new("./"), source_root, &mut source_files)?; } -} - -impl TryFrom for Summary { - type Error = eyre::Error; - fn try_from(mut document: pandoc_ast::Pandoc) -> Result { - if document.blocks.len() != 1 { - return Err(eyre!("Summary does not contain a single list")); - } + Ok((Summary { source: document }, source_files)) +} - let root = &mut document.blocks[0]; +fn process_summary_element( + element: &mut Vec, + parent: &Path, + source_root: &Path, + source_files: &mut Vec, +) -> Result<()> { + if element.len() != 1 && element.len() != 2 { + // TODO: better error message? + return Err(eyre!("Summary element does not contain a single list")); + } - let list = list_content(root)?; + trace!("Parsing summary element"); + let mut value = element.iter_mut(); - let nodes = list - .iter_mut() - .map(Node::try_from_vec_block) - .collect::>()?; + let item = match value.next().unwrap() { + pandoc_ast::Block::Plain(inlines) => inlines, + pandoc_ast::Block::Para(inlines) => inlines, + _ => return Err(eyre!("List item is not a link or plain text")), + }; - Ok(Summary { - source: document, - nodes, - }) + if item.is_empty() { + return Err(eyre!("Summary list items cannot be empty")); } -} -#[derive(Debug)] -pub enum Node { - Provided { - file: String, - children: Vec, - }, - Generated { - file: String, - title: Vec, - children: Vec, - }, -} - -impl Node { - fn children(&self) -> &[Node] { - match self { - Node::Provided { children, .. } => children, - Node::Generated { children, .. } => children, + let child_parent = match &item[0] { + pandoc_ast::Inline::Link(_, _, target) => { + let file = &target.0; + Path::new(&file).with_extension("") } - } - - fn has_files_missing(&self, root: &Path) -> bool { - if let Node::Provided { file, .. } = self { - if !root.join(file).exists() { - error!("File '{}' specified in summary does not exists", file); - return true; - } + _ => { + let title = item.clone(); + let id = AutoIdentifier::from(title.as_slice()); + parent.join(&id.0) } + }; + trace!("Summary element is {:?}", child_parent); - // Do not use `.any()` to prevent short-circuiting, we want to report all missing files - self.children().iter().fold(false, |acc, node| { - let missing = node.has_files_missing(root); - acc || missing - }) + let previous_source_len = source_files.len(); + if let Some(children) = value.next() { + for child in list_content(children)? { + process_summary_element(child, &child_parent, source_root, source_files)?; + } } - fn collect_source_files( - &self, - result: &mut Vec, - root: &Path, - parent: &Path, - level: usize, - ) -> Result<()> { - let new_parent; - let children_; - let path; - let source: Box _>; - - match self { - Node::Provided { file, children } => { - trace!("Parsing file: '{}'", file); - - // TODO: some filters here? not all filters, since we may want to filter generated - // files too - let mut pandoc_command = pandoc::new(); - pandoc_command - .add_input(&root.join(file)) - .set_output(pandoc::OutputKind::Pipe) - .set_output_format(pandoc::OutputFormat::Json, vec![]); - - if log_enabled!(log::Level::Trace) { - pandoc_command.set_show_cmdline(true); - } - - let raw_source = pandoc_command - .execute() - .wrap_err_with(|| format!("Failed to parse '{}'", file))? - .buffer(); - source = Box::new(move |_| Ok(pandoc_ast::Pandoc::from_json(&raw_source))); - - let file = Path::new(&file); - let stem = file.file_stem().expect("No file name"); - let id = - AutoIdentifier::from(stem.to_str().wrap_err("Invalid unicode in file name")?); - - path = file.into(); - new_parent = file.parent().expect("Source file has no parent").join(&*id); - children_ = children; + match &item[0] { + pandoc_ast::Inline::Link(_, _, target) => { + if item.len() != 1 { + return Err(eyre!("Summary list item not a single link or plain text")); } - Self::Generated { - file, - title, - children, - } => { - trace!("Found file to generate: '{}'", file); - - path = file.into(); - - source = Box::new(move |direct_children| { - generate_source(title.clone(), direct_children, level) - }); - new_parent = Path::new(file).with_extension(""); - children_ = children; - } - }; - - let mut direct_children = Vec::with_capacity(children_.len()); - - for child in children_ { - child.collect_source_files(result, root, &new_parent, level + 1)?; - let direct_child = result.last().unwrap(); - direct_children.push((direct_child.source.meta.clone(), direct_child.path.clone())); + let file = target.0.clone(); + source_files.push(parse_file(&file, source_root)?); } - - result.push(SourceFile { - path, - source: source(direct_children)?, - }); - - Ok(()) - } - - // Wil also modify the block to linkify generated pages - fn try_from_vec_block(value: &mut Vec) -> Result { - if value.len() != 1 && value.len() != 2 { - // TODO: better error message? - return Err(eyre!("Summary does not contain a single list")); - } - - let mut value = value.iter_mut(); - - let item = match value.next().unwrap() { - pandoc_ast::Block::Plain(inlines) => inlines, - pandoc_ast::Block::Para(inlines) => inlines, - _ => return Err(eyre!("List item is not a link or plain text")), - }; - - if item.is_empty() { - return Err(eyre!("Summary list items cannot be empty")); + _ => { + let title = item.clone(); + + let id = AutoIdentifier::from(title.as_slice()); + + *item = vec![pandoc_ast::Inline::Link( + (String::new(), vec!["generated".to_string()], vec![]), + item.clone(), + ( + parent.join(&id.0).with_extension("html").to_string(), + String::new(), + ), + )]; + + // TODO: this shows children recursively (and has a bug when in a subdirectory) + let children_metadata = source_files[previous_source_len..source_files.len()] + .iter() + .map(|source| (&source.source.meta, source.path.as_ref())) + .collect::>(); + + let source = generate_source(title, &children_metadata, 0)?; + + source_files.push(SourceFile { + path: child_parent.with_extension("html"), + source, + }); } + } - let children = if let Some(children) = value.next() { - try_into_node_vec(list_content(children)?)? - } else { - vec![] - }; - - match &item[0] { - pandoc_ast::Inline::Link(_, _, target) => { - if item.len() != 1 { - return Err(eyre!("Summary list item not a single link or plain text")); - } - - let file = target.0.clone(); - - Ok(Node::Provided { file, children }) - } - _ => { - let title = item.clone(); + Ok(()) +} - let id = AutoIdentifier::from(title.as_slice()); +fn parse_file(file: &str, source_root: &Path) -> Result { + trace!("Parsing file: '{}'", file); - // TODO: missing parent + // TODO: some filters here? not all filters, since we may want to filter generated + // files too + let mut pandoc_command = pandoc::new(); + pandoc_command + .add_input(&source_root.join(file)) + .set_output(pandoc::OutputKind::Pipe) + .set_output_format(pandoc::OutputFormat::Json, vec![]); - // Move generate page into this pass - //let mut file = parent.join(&*id); - //file.set_extension("md"); + if log_enabled!(log::Level::Trace) { + pandoc_command.set_show_cmdline(true); + } - // TODO: Attribute to style them differently - *item = vec![pandoc_ast::Inline::Link( - (String::new(), vec!["generated".to_string()], vec![]), - item.clone(), - (id.0.clone(), String::new()), - )]; + let raw_source = pandoc_command + .execute() + .wrap_err_with(|| format!("Failed to parse '{}'", file))? + .buffer(); + let source = pandoc_ast::Pandoc::from_json(&raw_source); - Ok(Node::Generated { - file: id.0, - title, - children, - }) - } - } - } + Ok(SourceFile { + path: file.into(), + source, + }) } diff --git a/src/filters.rs b/src/filters.rs index 1b06920..8dbe578 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -40,15 +40,13 @@ impl<'a> pandoc_ast::MutVisitor for RelativizeUrls<'a> { 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); + trace!("Relativizing link '{}' -> into '{}'", link_path.display(), link); } } } @@ -94,22 +92,3 @@ pub fn relativize_summary(summary: &pandoc_ast::Pandoc, level: usize) -> pandoc_ }) .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, - ), - ); - } -} diff --git a/src/utils.rs b/src/utils.rs index 8928cfb..828ae46 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; pub fn pandoc_stringify(inlines: &[pandoc_ast::Inline]) -> String { fn pandoc_stringify_(result: &mut String, inlines: &[pandoc_ast::Inline]) { @@ -114,3 +114,19 @@ impl PandocOutputExt for pandoc::PandocOutput { } pub type PandocMeta = pandoc_ast::Map; + +pub trait PathExt { + fn to_string(&self) -> String; +} + +impl PathExt for Path { + fn to_string(&self) -> String { + self.to_str().expect("Path is not valid UTF-8").to_string() + } +} + +impl PathExt for PathBuf { + fn to_string(&self) -> String { + self.to_str().expect("Path is not valid UTF-8").to_string() + } +} -- cgit v1.2.3