summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2021-04-09 16:59:06 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2021-04-09 16:59:06 +0100
commit595d78b39667be7e15fb0a0b35176a98c3e550c0 (patch)
tree88e275979ca173117bfd91e74f32d7c45d6245d0
parente093e297f39e2c8602ae5ac5f60ffad1158c78a0 (diff)
downloadsubplot-595d78b39667be7e15fb0a0b35176a98c3e550c0.tar.gz
subplot: Copy in sp-docgen content
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
-rw-r--r--src/bin/subplot.rs97
1 files changed, 96 insertions, 1 deletions
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<String>,
+}
+
+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();