summaryrefslogtreecommitdiff
path: root/crates/typst-cli/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-10-15 13:55:55 +0200
committerGitHub <noreply@github.com>2024-10-15 11:55:55 +0000
commit89cecb188d3905ecf98f2a6be93cbd7cf6bf8a64 (patch)
tree80caeac50074e5c4d1ff7d4f7da044463cb07c00 /crates/typst-cli/src
parent382787d7995775cc85052419896e308a2de8de28 (diff)
Greet users who run `typst` for the first time (#5210)
Diffstat (limited to 'crates/typst-cli/src')
-rw-r--r--crates/typst-cli/src/args.rs31
-rw-r--r--crates/typst-cli/src/greet.rs66
-rw-r--r--crates/typst-cli/src/main.rs13
3 files changed, 106 insertions, 4 deletions
diff --git a/crates/typst-cli/src/args.rs b/crates/typst-cli/src/args.rs
index 65259ab7..7436d25c 100644
--- a/crates/typst-cli/src/args.rs
+++ b/crates/typst-cli/src/args.rs
@@ -13,9 +13,36 @@ use semver::Version;
/// in environment variables.
const ENV_PATH_SEP: char = if cfg!(windows) { ';' } else { ':' };
-/// The Typst compiler.
+/// The overall structure of the help.
+#[rustfmt::skip]
+const HELP_TEMPLATE: &str = "\
+Typst {version}
+
+{usage-heading} {usage}
+
+{all-args}{after-help}\
+";
+
+/// Adds a list of useful links after the normal help.
+#[rustfmt::skip]
+const AFTER_HELP: &str = color_print::cstr!("\
+<s><u>Resources:</></>
+ <s>Tutorial:</> https://typst.app/docs/tutorial/
+ <s>Reference documentation:</> https://typst.app/docs/reference/
+ <s>Templates & Packages:</> https://typst.app/universe/
+ <s>Forum for questions:</> https://forum.typst.app/
+");
+
+/// The Typst compiler
#[derive(Debug, Clone, Parser)]
-#[clap(name = "typst", version = crate::typst_version(), author)]
+#[clap(
+ name = "typst",
+ version = crate::typst_version(),
+ author,
+ help_template = HELP_TEMPLATE,
+ after_help = AFTER_HELP,
+ max_term_width = 80,
+)]
pub struct CliArguments {
/// The command to run
#[command(subcommand)]
diff --git a/crates/typst-cli/src/greet.rs b/crates/typst-cli/src/greet.rs
new file mode 100644
index 00000000..01f273fc
--- /dev/null
+++ b/crates/typst-cli/src/greet.rs
@@ -0,0 +1,66 @@
+use std::io::{self, Read};
+
+/// This is shown to users who just type `typst` the first time.
+#[rustfmt::skip]
+const GREETING: &str = color_print::cstr!("\
+<s>Welcome to Typst, we are glad to have you here!</> ❤️
+
+If you are new to Typst, <s>start with the tutorial</> at \
+<u>https://typst.app/docs/tutorial/</>. To get a quick start with your first \
+project, <s>choose a template</> on <u>https://typst.app/universe/</>.
+
+Here are the <s>most important commands</> you will be using:
+
+- Compile a file once: <c!>typst compile file.typ</>
+- Compile a file on every change: <c!>typst watch file.typ</>
+- Set up a project from a template: <c!>typst init @preview/<<TEMPLATE>></>
+
+Learn more about these commands by running <c!>typst help</>.
+
+If you have a question, we and our community would be glad to help you out on \
+the <s>Typst Forum</> at <u>https://forum.typst.app/</>.
+
+Happy Typsting!
+");
+
+/// Greets (and exists) if not yet greeted.
+pub fn greet() {
+ let Some(data_dir) = dirs::data_dir() else { return };
+ let path = data_dir.join("typst").join("greeted");
+
+ let prev_greet = std::fs::read_to_string(&path).ok();
+ if prev_greet.as_deref() == Some(crate::typst_version()) {
+ return;
+ };
+
+ std::fs::write(&path, crate::typst_version()).ok();
+ print_and_exit(GREETING);
+}
+
+/// Prints a colorized and line-wrapped message.
+fn print_and_exit(message: &'static str) -> ! {
+ // Abuse clap for line wrapping ...
+ let err = clap::Command::new("typst")
+ .max_term_width(80)
+ .help_template("{about}")
+ .about(message)
+ .try_get_matches_from(["typst", "--help"])
+ .unwrap_err();
+ let _ = err.print();
+
+ // Windows users might have double-clicked the .exe file and have no chance
+ // to read it before the terminal closes.
+ if cfg!(windows) {
+ pause();
+ }
+
+ std::process::exit(err.exit_code());
+}
+
+/// Waits for the user.
+#[allow(clippy::unused_io_amount)]
+fn pause() {
+ eprintln!();
+ eprintln!("Press enter to continue...");
+ io::stdin().lock().read(&mut [0]).unwrap();
+}
diff --git a/crates/typst-cli/src/main.rs b/crates/typst-cli/src/main.rs
index 283d17e2..b14e687e 100644
--- a/crates/typst-cli/src/main.rs
+++ b/crates/typst-cli/src/main.rs
@@ -2,6 +2,7 @@ mod args;
mod compile;
mod download;
mod fonts;
+mod greet;
mod init;
mod package;
mod query;
@@ -16,6 +17,7 @@ use std::cell::Cell;
use std::io::{self, Write};
use std::process::ExitCode;
+use clap::error::ErrorKind;
use clap::Parser;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::WriteColor;
@@ -30,8 +32,15 @@ thread_local! {
static EXIT: Cell<ExitCode> = const { Cell::new(ExitCode::SUCCESS) };
}
-/// The parsed commandline arguments.
-static ARGS: Lazy<CliArguments> = Lazy::new(CliArguments::parse);
+/// The parsed command line arguments.
+static ARGS: Lazy<CliArguments> = Lazy::new(|| {
+ CliArguments::try_parse().unwrap_or_else(|error| {
+ if error.kind() == ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand {
+ crate::greet::greet();
+ }
+ error.exit();
+ })
+});
/// Entry point.
fn main() -> ExitCode {