From 7eea77278543e93a04b46f751a98d60f30822df9 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Wed, 6 Nov 2024 01:49:04 -0800 Subject: [PATCH 1/4] Fix shell function example in readme (#2454) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b596ca8..a0a126b7 100644 --- a/README.md +++ b/README.md @@ -1578,11 +1578,11 @@ file. and can be changed with `set shell := […]`. `command` is passed as the first argument, so if the command is `'echo $@'`, - the full command line, with the default shell command `shell -cu` and `args` + the full command line, with the default shell command `sh -cu` and `args` `'foo'` and `'bar'` will be: ``` - 'shell' '-cu' 'echo $@' 'echo $@' 'foo' 'bar' + 'sh' '-cu' 'echo $@' 'echo $@' 'foo' 'bar' ``` This is so that `$@` works as expected, and `$1` refers to the first From a93b0bf3890de6c48d46b40e2cbcc73c97e3bd41 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Wed, 6 Nov 2024 17:53:51 -0500 Subject: [PATCH 2/4] Update setup-just version in README (#2456) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0a126b7..6ec0e0f6 100644 --- a/README.md +++ b/README.md @@ -401,7 +401,7 @@ Using package managers pre-installed on GitHub Actions runners on MacOS with With [extractions/setup-just](https://github.com/extractions/setup-just): ```yaml -- uses: extractions/setup-just@v1 +- uses: extractions/setup-just@v2 with: just-version: 1.5.0 # optional semver specification, otherwise latest ``` From 1ae6a6d6568652e8b21afa1e4d0c2327e06351fe Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sat, 9 Nov 2024 11:05:58 -0800 Subject: [PATCH 3/4] Highlight backticks in docs when listing recipes (#2423) --- justfile | 2 +- src/color.rs | 4 ++++ src/subcommand.rs | 27 ++++++++++++++++++++++++--- tests/list.rs | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/justfile b/justfile index d0ff455c..5ab15362 100755 --- a/justfile +++ b/justfile @@ -29,7 +29,7 @@ fuzz: run: cargo run -# only run tests matching PATTERN +# only run tests matching `PATTERN` [group: 'test'] filter PATTERN: cargo test {{PATTERN}} diff --git a/src/color.rs b/src/color.rs index ccdf2185..ba437eff 100644 --- a/src/color.rs +++ b/src/color.rs @@ -66,6 +66,10 @@ impl Color { self.restyle(Style::new().fg(Blue)) } + pub(crate) fn doc_backtick(self) -> Self { + self.restyle(Style::new().fg(White).on(Black)) + } + pub(crate) fn error(self) -> Self { self.restyle(Style::new().fg(Red).bold()) } diff --git a/src/subcommand.rs b/src/subcommand.rs index b1f13592..40795496 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -2,6 +2,11 @@ use {super::*, clap_mangen::Man}; const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n"; +fn backtick_re() -> &'static Regex { + static BACKTICK_RE: OnceLock = OnceLock::new(); + BACKTICK_RE.get_or_init(|| Regex::new("(`.*?`)|(`[^`]*$)").unwrap()) +} + #[derive(PartialEq, Clone, Debug)] pub(crate) enum Subcommand { Changelog, @@ -413,15 +418,31 @@ impl Subcommand { ) { if let Some(doc) = doc { if !doc.is_empty() && doc.lines().count() <= 1 { + let color = config.color.stdout(); print!( - "{:padding$}{} {}", + "{:padding$}{} ", "", - config.color.stdout().doc().paint("#"), - config.color.stdout().doc().paint(doc), + color.doc().paint("#"), padding = max_signature_width.saturating_sub(signature_widths[name]) + 1, ); + + let mut end = 0; + for backtick in backtick_re().find_iter(doc) { + let prefix = &doc[end..backtick.start()]; + if !prefix.is_empty() { + print!("{}", color.doc().paint(prefix)); + } + print!("{}", color.doc_backtick().paint(backtick.as_str())); + end = backtick.end(); + } + + let suffix = &doc[end..]; + if !suffix.is_empty() { + print!("{}", color.doc().paint(suffix)); + } } } + println!(); } diff --git a/tests/list.rs b/tests/list.rs index db7b669e..f7ea7528 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -438,3 +438,39 @@ fn no_space_before_submodules_not_following_groups() { ) .run(); } + +#[test] +fn backticks_highlighted() { + Test::new() + .justfile( + " + # Comment `` `with backticks` and trailing text + recipe: + ", + ) + .args(["--list", "--color=always"]) + .stdout( + " + Available recipes: + recipe \u{1b}[34m#\u{1b}[0m \u{1b}[34mComment \u{1b}[0m\u{1b}[40;37m``\u{1b}[0m\u{1b}[34m \u{1b}[0m\u{1b}[40;37m`with backticks`\u{1b}[0m\u{1b}[34m and trailing text\u{1b}[0m + ") + .run(); +} + +#[test] +fn unclosed_backticks() { + Test::new() + .justfile( + " + # Comment `with unclosed backick + recipe: + ", + ) + .args(["--list", "--color=always"]) + .stdout( + " + Available recipes: + recipe \u{1b}[34m#\u{1b}[0m \u{1b}[34mComment \u{1b}[0m\u{1b}[40;37m`with unclosed backick\u{1b}[0m + ") + .run(); +} From bbc087294781ee36d2b7c0fbb64d70ac2959558f Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Mon, 11 Nov 2024 14:30:06 -0800 Subject: [PATCH 4/4] Terminal escape sequence constants (#2461) --- README.md | 46 ++++++++++++++++++++++++++++++++++- justfile | 4 +++ src/constants.rs | 63 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 102 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6ec0e0f6..b318a5db 100644 --- a/README.md +++ b/README.md @@ -1877,6 +1877,30 @@ A number of constants are predefined: | `HEX`1.27.0 | `"0123456789abcdef"` | | `HEXLOWER`1.27.0 | `"0123456789abcdef"` | | `HEXUPPER`1.27.0 | `"0123456789ABCDEF"` | +| `CLEAR`master | `"\ec"` | +| `NORMAL`master | `"\e[0m"` | +| `BOLD`master | `"\e[1m"` | +| `ITALIC`master | `"\e[3m"` | +| `UNDERLINE`master | `"\e[4m"` | +| `INVERT`master | `"\e[7m"` | +| `HIDE`master | `"\e[8m"` | +| `STRIKETHROUGH`master | `"\e[9m"` | +| `BLACK`master | `"\e[30m"` | +| `RED`master | `"\e[31m"` | +| `GREEN`master | `"\e[32m"` | +| `YELLOW`master | `"\e[33m"` | +| `BLUE`master | `"\e[34m"` | +| `MAGENTA`master | `"\e[35m"` | +| `CYAN`master | `"\e[36m"` | +| `WHITE`master | `"\e[37m"` | +| `BG_BLACK`master | `"\e[40m"` | +| `BG_RED`master | `"\e[41m"` | +| `BG_GREEN`master | `"\e[42m"` | +| `BG_YELLOW`master | `"\e[43m"` | +| `BG_BLUE`master | `"\e[44m"` | +| `BG_MAGENTA`master | `"\e[45m"` | +| `BG_CYAN`master | `"\e[46m"` | +| `BG_WHITE`master | `"\e[47m"` | ```just @foo: @@ -1888,9 +1912,29 @@ $ just foo 0123456789abcdef ``` +Constants starting with `\e` are +[ANSI escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code). + +`CLEAR` clears the screen, similar to the `clear` command. The rest are of the +form `\e[Nm`, where `N` is an integer, and set terminal display attributes. + +Terminal display attribute escape sequences can be combined, for example text +weight `BOLD`, text style `STRIKETHROUGH`, foreground color `CYAN`, and +background color `BG_BLUE`. They should be followed by `NORMAL`, to reset the +terminal back to normal. + +Escape sequences should be quoted, since `[` is treated as a special character +by some shells. + +```just +@foo: + echo '{{BOLD + STRIKETHROUGH + CYAN + BG_BLUE}}Hi!{{NORMAL}}' +``` + ### Attributes -Recipes, `mod` statements, and aliases may be annotated with attributes that change their behavior. +Recipes, `mod` statements, and aliases may be annotated with attributes that +change their behavior. | Name | Type | Description | |------|------|-------------| diff --git a/justfile b/justfile index 5ab15362..e975d506 100755 --- a/justfile +++ b/justfile @@ -169,6 +169,10 @@ build-book: mdbook build book/en mdbook build book/zh +[group: 'dev'] +print-readme-constants-table: + cargo test constants::tests::readme_table -- --nocapture + # run all polyglot recipes [group: 'demo'] polyglot: _python _js _perl _sh _ruby diff --git a/src/constants.rs b/src/constants.rs index e9007ea7..5dd17681 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,15 +1,58 @@ use super::*; -pub(crate) fn constants() -> &'static HashMap<&'static str, &'static str> { - static CONSTANTS: OnceLock> = OnceLock::new(); +const CONSTANTS: [(&str, &str, &str); 27] = [ + ("HEX", "0123456789abcdef", "1.27.0"), + ("HEXLOWER", "0123456789abcdef", "1.27.0"), + ("HEXUPPER", "0123456789ABCDEF", "1.27.0"), + ("CLEAR", "\x1bc", "master"), + ("NORMAL", "\x1b[0m", "master"), + ("BOLD", "\x1b[1m", "master"), + ("ITALIC", "\x1b[3m", "master"), + ("UNDERLINE", "\x1b[4m", "master"), + ("INVERT", "\x1b[7m", "master"), + ("HIDE", "\x1b[8m", "master"), + ("STRIKETHROUGH", "\x1b[9m", "master"), + ("BLACK", "\x1b[30m", "master"), + ("RED", "\x1b[31m", "master"), + ("GREEN", "\x1b[32m", "master"), + ("YELLOW", "\x1b[33m", "master"), + ("BLUE", "\x1b[34m", "master"), + ("MAGENTA", "\x1b[35m", "master"), + ("CYAN", "\x1b[36m", "master"), + ("WHITE", "\x1b[37m", "master"), + ("BG_BLACK", "\x1b[40m", "master"), + ("BG_RED", "\x1b[41m", "master"), + ("BG_GREEN", "\x1b[42m", "master"), + ("BG_YELLOW", "\x1b[43m", "master"), + ("BG_BLUE", "\x1b[44m", "master"), + ("BG_MAGENTA", "\x1b[45m", "master"), + ("BG_CYAN", "\x1b[46m", "master"), + ("BG_WHITE", "\x1b[47m", "master"), +]; - CONSTANTS.get_or_init(|| { - vec![ - ("HEX", "0123456789abcdef"), - ("HEXLOWER", "0123456789abcdef"), - ("HEXUPPER", "0123456789ABCDEF"), - ] - .into_iter() - .collect() +pub(crate) fn constants() -> &'static HashMap<&'static str, &'static str> { + static MAP: OnceLock> = OnceLock::new(); + MAP.get_or_init(|| { + CONSTANTS + .into_iter() + .map(|(name, value, _version)| (name, value)) + .collect() }) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn readme_table() { + println!("| Name | Value |"); + println!("|------|-------------|"); + for (name, value, version) in CONSTANTS { + println!( + "| `{name}`{version} | `\"{}\"` |", + value.replace('\x1b', "\\e") + ); + } + } +}