From 595d78b39667be7e15fb0a0b35176a98c3e550c0 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Fri, 9 Apr 2021 16:59:06 +0100 Subject: subplot: Copy in sp-docgen content Signed-off-by: Daniel Silverstone --- src/bin/subplot.rs | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/bin/subplot.rs b/src/bin/subplot.rs index fabb0f2..6e1945d 100644 --- a/src/bin/subplot.rs +++ b/src/bin/subplot.rs @@ -3,14 +3,17 @@ use anyhow::Result; +use chrono::{Local, TimeZone}; use structopt::StructOpt; use subplot::{resource, DataFile, Document, Style}; use std::convert::TryFrom; -use std::fs::{write, File}; +use std::ffi::OsString; +use std::fs::{self, write, File}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::process; +use std::time::UNIX_EPOCH; mod cli; @@ -34,6 +37,7 @@ enum Cmd { Extract(Extract), Filter(Filter), Metadata(Metadata), + Docgen(Docgen), } impl Cmd { @@ -42,6 +46,7 @@ impl Cmd { Cmd::Extract(e) => e.run(), Cmd::Filter(f) => f.run(), Cmd::Metadata(m) => m.run(), + Cmd::Docgen(d) => d.run(), } } } @@ -181,6 +186,96 @@ impl Metadata { } } +#[derive(Debug, StructOpt)] +/// Typeset subplot document +/// +/// Process a subplot document and typeset it using Pandoc. +struct Docgen { + // Input Subplot document + #[structopt(parse(from_os_str))] + input: PathBuf, + + // Output document filename + #[structopt(name = "FILE", long = "--output", short = "-o", parse(from_os_str))] + output: PathBuf, + + // Set date. + #[structopt(name = "DATE", long = "--date")] + date: Option, +} + +impl Docgen { + fn run(&self) -> Result<()> { + let mut style = Style::default(); + if self.output.extension() == Some(&OsString::from("pdf")) { + style.typeset_links_as_notes(); + } + let mut doc = cli::load_document(&self.input, style)?; + doc.lint()?; + if !doc.check_named_files_exist()? { + eprintln!("Continuing despite warnings"); + } + + let mut pandoc = pandoc::new(); + // Metadata date from command line or file mtime. However, we + // can't set it directly, since we don't want to override the date + // in the actual document, if given, so we only set + // user-provided-date. Our parsing code will use that if date is + // not document metadata. + let date = if let Some(date) = self.date.clone() { + date + } else if let Some(date) = doc.meta().date() { + date.to_string() + } else { + Self::mtime_formatted(Self::mtime(&self.input)?) + }; + pandoc.add_option(pandoc::PandocOption::Meta("date".to_string(), Some(date))); + pandoc.add_option(pandoc::PandocOption::TableOfContents); + pandoc.add_option(pandoc::PandocOption::Standalone); + pandoc.add_option(pandoc::PandocOption::NumberSections); + + if Self::need_output(&mut doc, &self.output) { + doc.typeset(); + pandoc.set_input_format(pandoc::InputFormat::Json, vec![]); + pandoc.set_input(pandoc::InputKind::Pipe(doc.ast()?)); + pandoc.set_output(pandoc::OutputKind::File(self.output.clone())); + pandoc.execute()?; + } + + Ok(()) + } + + fn mtime(filename: &Path) -> Result<(u64, u32)> { + let mtime = fs::metadata(filename)?.modified()?; + let mtime = mtime.duration_since(UNIX_EPOCH)?; + Ok((mtime.as_secs(), mtime.subsec_nanos())) + } + + fn mtime_formatted(mtime: (u64, u32)) -> String { + let secs: i64 = format!("{}", mtime.0).parse().unwrap_or(0); + let dt = Local.timestamp(secs, mtime.1); + dt.format("%Y-%m-%d %H:%M").to_string() + } + + fn need_output(doc: &mut subplot::Document, output: &Path) -> bool { + let output = match Self::mtime(output) { + Err(_) => return true, + Ok(ts) => ts, + }; + + for filename in doc.sources() { + let source = match Self::mtime(&filename) { + Err(_) => return true, + Ok(ts) => ts, + }; + if source >= output { + return true; + } + } + false + } +} + fn main() { let args = Toplevel::from_args(); args.resources.handle(); -- cgit v1.2.1