From 2d1598e51d10bfe4e331c1ad6ca7899c5cdbb468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20d=27Herbais=20de=20Thun?= Date: Tue, 4 Apr 2023 14:12:19 +0200 Subject: [PATCH] CLI: open flag (#480) --- Cargo.lock | 16 +++++++++++++ cli/Cargo.toml | 1 + cli/src/main.rs | 64 +++++++++++++++++++++++++++++++++++-------------- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e11dc187..4d88b341a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -952,12 +952,27 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "open" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075c5203b3a2b698bc72c6c10b1f6263182135751d5013ea66e8a4b3d0562a43" +dependencies = [ + "pathdiff", +] + [[package]] name = "paste" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pdf-writer" version = "0.6.0" @@ -1539,6 +1554,7 @@ dependencies = [ "memmap2", "notify", "once_cell", + "open", "same-file", "siphasher", "typst", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index f484bf322..8b0f35173 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,6 +27,7 @@ same-file = "1" siphasher = "0.3" walkdir = "2" clap = { version = "4.2.1", features = ["derive"] } +open = "4.0.1" [features] default = ["embed-fonts"] diff --git a/cli/src/main.rs b/cli/src/main.rs index 8726a301c..98c7aa6ae 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -57,7 +57,7 @@ enum Command { /// Watches the input file and recompiles on changes #[command(visible_alias = "w")] - Watch(WatchCommand), + Watch(CompileCommand), /// List all discovered fonts in system and custom font paths Fonts(FontsCommand), @@ -71,22 +71,16 @@ pub struct CompileCommand { /// Path to output PDF file output: Option, -} -/// Watches the input file and recompiles on changes -#[derive(Debug, Clone, Parser)] -pub struct WatchCommand { - /// 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 { - /// Add additional directories to search for fonts + /// Also list style variants of each font family #[arg(long)] variants: bool, } @@ -107,6 +101,9 @@ struct CompileSettings { /// The paths to search for fonts. font_paths: Vec, + + /// The open command to use. + open: Option>, } impl CompileSettings { @@ -117,13 +114,13 @@ impl CompileSettings { watch: bool, root: Option, font_paths: Vec, + open: Option>, ) -> Self { let output = match output { Some(path) => path, None => input.with_extension("pdf"), }; - - Self { input, output, watch, root, font_paths } + Self { input, output, watch, root, font_paths, open } } /// Create a new compile settings from the CLI arguments and a compile command. @@ -131,12 +128,13 @@ impl CompileSettings { /// # Panics /// Panics if the command is not a compile or watch command. pub fn with_arguments(args: CliArguments) -> Self { - let (input, output, watch) = match args.command { - Command::Compile(command) => (command.input, command.output, false), - Command::Watch(command) => (command.input, command.output, true), + let watch = matches!(args.command, Command::Watch(_)); + let CompileCommand { input, output, open } = match args.command { + Command::Compile(command) => command, + Command::Watch(command) => command, _ => unreachable!(), }; - Self::new(input, output, watch, args.root, args.font_paths) + Self::new(input, output, watch, args.root, args.font_paths, open) } } @@ -195,7 +193,7 @@ fn print_error(msg: &str) -> io::Result<()> { } /// Execute a compilation command. -fn compile(command: CompileSettings) -> StrResult<()> { +fn compile(mut command: CompileSettings) -> StrResult<()> { let root = if let Some(root) = &command.root { root.clone() } else if let Some(dir) = command @@ -215,6 +213,14 @@ fn compile(command: CompileSettings) -> StrResult<()> { // Perform initial compilation. let failed = compile_once(&mut world, &command)?; + + // open the file if requested, this must be done on the first **successful** compilation + if !failed { + if let Some(open) = command.open.take() { + open_file(open.as_deref(), &command.output)?; + } + } + if !command.watch { // Return with non-zero exit code in case of error. if failed { @@ -258,6 +264,11 @@ fn compile(command: CompileSettings) -> StrResult<()> { if recompile { compile_once(&mut world, &command)?; comemo::evict(30); + + // open the file if requested, this must be done on the first **successful** compilation + if let Some(open) = command.open.take() { + open_file(open.as_deref(), &command.output)?; + } } } } @@ -381,6 +392,23 @@ fn print_diagnostics( Ok(()) } +/// Opens the given file using: +/// - The default file viewer if `open` is `None`. +/// - The given viewer provided by `open` if it is `Some`. +fn open_file(open: Option<&str>, path: &Path) -> StrResult<()> { + if let Some(app) = open { + open::with(path, app).map_err(|err| { + format!("failed to open `{}` with `{}`, reason: {}", path.display(), app, err) + })?; + } else { + open::that(path).map_err(|err| { + format!("failed to open `{}`, reason: {}", path.display(), err) + })?; + } + + Ok(()) +} + /// Execute a font listing command. fn fonts(command: FontsSettings) -> StrResult<()> { let mut searcher = FontSearcher::new();