From 1c324765e92c23826dff4f37d3b01761a3ac6ef4 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 6 Apr 2023 14:14:01 -0400 Subject: [PATCH] Add shell completions and man pages (#582) --- Cargo.lock | 27 +++++++++++++++++++++ cli/Cargo.toml | 5 ++++ cli/build.rs | 52 +++++++++++++++++++++++++++++++++++----- cli/src/args.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++ cli/src/main.rs | 63 ++++++------------------------------------------- flake.nix | 15 +++++++++++- 6 files changed, 157 insertions(+), 63 deletions(-) create mode 100644 cli/src/args.rs diff --git a/Cargo.lock b/Cargo.lock index 9b8917273..41ad4239f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,6 +231,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.2.0" @@ -249,6 +258,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +[[package]] +name = "clap_mangen" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4237e29de9c6949982ba87d51709204504fb8ed2fd38232fcb1e5bf7d4ba48c8" +dependencies = [ + "clap", + "roff", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1215,6 +1234,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "roff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" + [[package]] name = "roxmltree" version = "0.14.1" @@ -1612,6 +1637,8 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "clap_complete", + "clap_mangen", "codespan-reporting", "comemo", "dirs", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 656dd0d94..6bffca2e4 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -29,6 +29,11 @@ walkdir = "2" clap = { version = "4.2.1", features = ["derive"] } open = "4.0.1" +[build-dependencies] +clap = { version = "4.2.1", features = ["derive", "string"] } +clap_complete = "4.2.0" +clap_mangen = "0.2.10" + [features] default = ["embed-fonts"] diff --git a/cli/build.rs b/cli/build.rs index 014960f4f..75e8492af 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -1,9 +1,15 @@ +use std::env; +use std::fs::{create_dir_all, File}; +use std::path::Path; use std::process::Command; -fn main() { - println!("cargo:rerun-if-env-changed=TYPST_VERSION"); - if option_env!("TYPST_VERSION").is_some() { - return; +use clap::{CommandFactory, ValueEnum}; +use clap_complete::{generate_to, Shell}; +use clap_mangen::Man; + +pub fn typst_version() -> String { + if let Some(version) = option_env!("TYPST_VERSION") { + return version.to_owned(); } let pkg = env!("CARGO_PKG_VERSION"); @@ -13,7 +19,41 @@ fn main() { .ok() .filter(|output| output.status.success()) .and_then(|output| String::from_utf8(output.stdout.get(..8)?.into()).ok()) - .unwrap_or_else(|| "(unknown hash)".into()); + .unwrap_or_else(|| "unknown hash".into()); - println!("cargo:rustc-env=TYPST_VERSION={pkg} ({hash})"); + format!("{pkg} ({hash})") +} + +mod args { + include!("src/args.rs"); +} + +fn main() { + println!("cargo:rerun-if-env-changed=TYPST_VERSION"); + println!("cargo:rerun-if-env-changed=GEN_ARTIFACTS"); + + if option_env!("TYPST_VERSION").is_none() { + println!("cargo:rustc-env=TYPST_VERSION={}", typst_version()); + } + + if let Some(dir) = env::var_os("GEN_ARTIFACTS") { + let out = &Path::new(&dir); + create_dir_all(out).unwrap(); + let cmd = &mut args::CliArguments::command(); + + Man::new(cmd.clone()) + .render(&mut File::create(out.join("typst.1")).unwrap()) + .unwrap(); + + for subcmd in cmd.get_subcommands() { + let name = format!("typst-{}", subcmd.get_name()); + Man::new(subcmd.clone().name(&name)) + .render(&mut File::create(out.join(format!("{name}.1"))).unwrap()) + .unwrap(); + } + + for shell in Shell::value_variants() { + generate_to(*shell, cmd, "typst", out).unwrap(); + } + } } diff --git a/cli/src/args.rs b/cli/src/args.rs new file mode 100644 index 000000000..c88c9a21b --- /dev/null +++ b/cli/src/args.rs @@ -0,0 +1,58 @@ +use std::path::PathBuf; + +use clap::{ArgAction, Parser, Subcommand}; + +/// typst creates PDF files from .typ files +#[derive(Debug, Clone, Parser)] +#[clap(name = "typst", version = crate::typst_version(), author)] +pub struct CliArguments { + /// Add additional directories to search for fonts + #[clap(long = "font-path", value_name = "DIR", action = ArgAction::Append)] + pub font_paths: Vec, + + /// Configure the root for absolute paths + #[clap(long = "root", value_name = "DIR")] + pub root: Option, + + /// The typst command to run + #[command(subcommand)] + pub command: Command, +} + +/// What to do. +#[derive(Debug, Clone, Subcommand)] +#[command()] +pub enum Command { + /// Compiles the input file into a PDF file + #[command(visible_alias = "c")] + Compile(CompileCommand), + + /// Watches the input file and recompiles on changes + #[command(visible_alias = "w")] + Watch(CompileCommand), + + /// List all discovered fonts in system and custom font paths + Fonts(FontsCommand), +} + +/// Compiles the input file into a PDF file +#[derive(Debug, Clone, Parser)] +pub struct CompileCommand { + /// Path to input Typst file + pub input: PathBuf, + + /// Path to output PDF file + pub output: Option, + + /// Opens the output file after compilation using the default PDF viewer + #[arg(long = "open")] + pub open: Option>, +} + +/// List all discovered fonts in system and custom font paths +#[derive(Debug, Clone, Parser)] +pub struct FontsCommand { + /// Also list style variants of each font family + #[arg(long)] + pub variants: bool, +} diff --git a/cli/src/main.rs b/cli/src/main.rs index d0dcc2bd7..1190232d2 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,3 +1,5 @@ +mod args; + use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::fs::{self, File}; @@ -6,7 +8,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process; -use clap::{ArgAction, Parser, Subcommand}; +use clap::Parser; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::term::{self, termcolor}; use comemo::Prehashed; @@ -25,64 +27,13 @@ use typst::util::{Buffer, PathExt}; use typst::World; use walkdir::WalkDir; +use crate::args::{CliArguments, Command, CompileCommand}; + type CodespanResult = Result; type CodespanError = codespan_reporting::files::Error; -const TYPST_VERSION: &str = env!("TYPST_VERSION"); - -/// typst creates PDF files from .typ files -#[derive(Debug, Clone, Parser)] -#[clap(name = "typst", version = TYPST_VERSION, author)] -pub struct CliArguments { - /// Add additional directories to search for fonts - #[clap(long = "font-path", value_name = "DIR", action = ArgAction::Append)] - font_paths: Vec, - - /// Configure the root for absolute paths - #[clap(long = "root", value_name = "DIR")] - root: Option, - - /// The typst command to run - #[command(subcommand)] - command: Command, -} - -/// What to do. -#[derive(Debug, Clone, Subcommand)] -#[command()] -enum Command { - /// Compiles the input file into a PDF file - #[command(visible_alias = "c")] - Compile(CompileCommand), - - /// Watches the input file and recompiles on changes - #[command(visible_alias = "w")] - Watch(CompileCommand), - - /// List all discovered fonts in system and custom font paths - Fonts(FontsCommand), -} - -/// Compiles the input file into a PDF file -#[derive(Debug, Clone, Parser)] -pub struct CompileCommand { - /// Path to input Typst file - input: PathBuf, - - /// Path to output PDF file - output: Option, - - /// Opens the output file after compilation using the default PDF viewer - #[arg(long = "open")] - open: Option>, -} - -/// List all discovered fonts in system and custom font paths -#[derive(Debug, Clone, Parser)] -pub struct FontsCommand { - /// Also list style variants of each font family - #[arg(long)] - variants: bool, +pub fn typst_version() -> &'static str { + env!("TYPST_VERSION") } /// A summary of the input arguments relevant to compilation. diff --git a/flake.nix b/flake.nix index 9d95aa824..0e2bf47ca 100644 --- a/flake.nix +++ b/flake.nix @@ -10,6 +10,7 @@ ; inherit (nixpkgs.lib) genAttrs + importTOML optionals ; @@ -39,11 +40,23 @@ allowBuiltinFetchGit = true; }; + nativeBuildInputs = [ + pkgs.installShellFiles + ]; + buildInputs = optionals pkgs.stdenv.isDarwin [ pkgs.darwin.apple_sdk.frameworks.CoreServices ]; - TYPST_VERSION = rev "(unknown version)"; + postInstall = '' + installManPage cli/artifacts/*.1 + installShellCompletion \ + cli/artifacts/typst.{bash,fish} \ + --zsh cli/artifacts/_typst + ''; + + GEN_ARTIFACTS = "artifacts"; + TYPST_VERSION = "${(importTOML ./cli/Cargo.toml).package.version} (${rev "unknown hash"})"; }; in {