Skip to content

Commit d4c4451

Browse files
committed
Greet users who run typst for the first time (#5210)
1 parent b206dfd commit d4c4451

File tree

6 files changed

+161
-7
lines changed

6 files changed

+161
-7
lines changed

Cargo.lock

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ bytemuck = "1"
3838
chinese-number = { version = "0.7.2", default-features = false, features = ["number-to-chinese"] }
3939
chrono = { version = "0.4.24", default-features = false, features = ["clock", "std"] }
4040
ciborium = "0.2.1"
41-
clap = { version = "4.4", features = ["derive", "env"] }
41+
clap = { version = "4.4", features = ["derive", "env", "wrap_help"] }
4242
clap_complete = "4.2.1"
4343
clap_mangen = "0.2.10"
44-
ctrlc = "3.4.1"
4544
codespan-reporting = "0.11"
45+
color-print = "0.3.6"
4646
comemo = "0.4"
4747
csv = "1"
48+
ctrlc = "3.4.1"
4849
dirs = "5"
4950
ecow = { version = "0.2", features = ["serde"] }
5051
env_proxy = "0.4"
@@ -84,8 +85,8 @@ png = "0.17"
8485
portable-atomic = "1.6"
8586
proc-macro2 = "1"
8687
pulldown-cmark = "0.9"
87-
quote = "1"
8888
qcms = "0.3.0"
89+
quote = "1"
8990
rayon = "1.7.0"
9091
regex = "1"
9192
resvg = { version = "0.43", default-features = false, features = ["raster-images"] }

crates/typst-cli/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typst-svg = { workspace = true }
2828
typst-timing = { workspace = true }
2929
chrono = { workspace = true }
3030
clap = { workspace = true }
31+
color-print = { workspace = true }
3132
codespan-reporting = { workspace = true }
3233
comemo = { workspace = true }
3334
dirs = { workspace = true }
@@ -59,6 +60,7 @@ chrono = { workspace = true }
5960
clap = { workspace = true, features = ["string"] }
6061
clap_complete = { workspace = true }
6162
clap_mangen = { workspace = true }
63+
color-print = { workspace = true }
6264
semver = { workspace = true }
6365

6466
[features]

crates/typst-cli/src/args.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,36 @@ use semver::Version;
1313
/// in environment variables.
1414
const ENV_PATH_SEP: char = if cfg!(windows) { ';' } else { ':' };
1515

16-
/// The Typst compiler.
16+
/// The overall structure of the help.
17+
#[rustfmt::skip]
18+
const HELP_TEMPLATE: &str = "\
19+
Typst {version}
20+
21+
{usage-heading} {usage}
22+
23+
{all-args}{after-help}\
24+
";
25+
26+
/// Adds a list of useful links after the normal help.
27+
#[rustfmt::skip]
28+
const AFTER_HELP: &str = color_print::cstr!("\
29+
<s><u>Resources:</></>
30+
<s>Tutorial:</> https://typst.app/docs/tutorial/
31+
<s>Reference documentation:</> https://typst.app/docs/reference/
32+
<s>Templates & Packages:</> https://typst.app/universe/
33+
<s>Forum for questions:</> https://forum.typst.app/
34+
");
35+
36+
/// The Typst compiler
1737
#[derive(Debug, Clone, Parser)]
18-
#[clap(name = "typst", version = crate::typst_version(), author)]
38+
#[clap(
39+
name = "typst",
40+
version = crate::typst_version(),
41+
author,
42+
help_template = HELP_TEMPLATE,
43+
after_help = AFTER_HELP,
44+
max_term_width = 80,
45+
)]
1946
pub struct CliArguments {
2047
/// The command to run
2148
#[command(subcommand)]

crates/typst-cli/src/greet.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use std::io::{self, Read};
2+
3+
/// This is shown to users who just type `typst` the first time.
4+
#[rustfmt::skip]
5+
const GREETING: &str = color_print::cstr!("\
6+
<s>Welcome to Typst, we are glad to have you here!</> ❤️
7+
8+
If you are new to Typst, <s>start with the tutorial</> at \
9+
<u>https://typst.app/docs/tutorial/</>. To get a quick start with your first \
10+
project, <s>choose a template</> on <u>https://typst.app/universe/</>.
11+
12+
Here are the <s>most important commands</> you will be using:
13+
14+
- Compile a file once: <c!>typst compile file.typ</>
15+
- Compile a file on every change: <c!>typst watch file.typ</>
16+
- Set up a project from a template: <c!>typst init @preview/<<TEMPLATE>></>
17+
18+
Learn more about these commands by running <c!>typst help</>.
19+
20+
If you have a question, we and our community would be glad to help you out on \
21+
the <s>Typst Forum</> at <u>https://forum.typst.app/</>.
22+
23+
Happy Typsting!
24+
");
25+
26+
/// Greets (and exists) if not yet greeted.
27+
pub fn greet() {
28+
let Some(data_dir) = dirs::data_dir() else { return };
29+
let path = data_dir.join("typst").join("greeted");
30+
31+
let prev_greet = std::fs::read_to_string(&path).ok();
32+
if prev_greet.as_deref() == Some(crate::typst_version()) {
33+
return;
34+
};
35+
36+
std::fs::write(&path, crate::typst_version()).ok();
37+
print_and_exit(GREETING);
38+
}
39+
40+
/// Prints a colorized and line-wrapped message.
41+
fn print_and_exit(message: &'static str) -> ! {
42+
// Abuse clap for line wrapping ...
43+
let err = clap::Command::new("typst")
44+
.max_term_width(80)
45+
.help_template("{about}")
46+
.about(message)
47+
.try_get_matches_from(["typst", "--help"])
48+
.unwrap_err();
49+
let _ = err.print();
50+
51+
// Windows users might have double-clicked the .exe file and have no chance
52+
// to read it before the terminal closes.
53+
if cfg!(windows) {
54+
pause();
55+
}
56+
57+
std::process::exit(err.exit_code());
58+
}
59+
60+
/// Waits for the user.
61+
#[allow(clippy::unused_io_amount)]
62+
fn pause() {
63+
eprintln!();
64+
eprintln!("Press enter to continue...");
65+
io::stdin().lock().read(&mut [0]).unwrap();
66+
}

crates/typst-cli/src/main.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod args;
22
mod compile;
33
mod download;
44
mod fonts;
5+
mod greet;
56
mod init;
67
mod package;
78
mod query;
@@ -16,6 +17,7 @@ use std::cell::Cell;
1617
use std::io::{self, Write};
1718
use std::process::ExitCode;
1819

20+
use clap::error::ErrorKind;
1921
use clap::Parser;
2022
use codespan_reporting::term;
2123
use codespan_reporting::term::termcolor::WriteColor;
@@ -30,8 +32,15 @@ thread_local! {
3032
static EXIT: Cell<ExitCode> = const { Cell::new(ExitCode::SUCCESS) };
3133
}
3234

33-
/// The parsed commandline arguments.
34-
static ARGS: Lazy<CliArguments> = Lazy::new(CliArguments::parse);
35+
/// The parsed command line arguments.
36+
static ARGS: Lazy<CliArguments> = Lazy::new(|| {
37+
CliArguments::try_parse().unwrap_or_else(|error| {
38+
if error.kind() == ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand {
39+
crate::greet::greet();
40+
}
41+
error.exit();
42+
})
43+
});
3544

3645
/// Entry point.
3746
fn main() -> ExitCode {

0 commit comments

Comments
 (0)