From e617747c50ee45ecc1b92e30033ca2e1cf40b7ae Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 9 Oct 2024 16:44:28 -0700 Subject: [PATCH 1/6] Highlight backticks in list https://github.com/casey/just/issues/2272 --- src/color.rs | 4 ++++ src/subcommand.rs | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/color.rs b/src/color.rs index ccdf218546..ba437effeb 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 b1f1359215..2f82480352 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -414,12 +414,28 @@ impl Subcommand { if let Some(doc) = doc { if !doc.is_empty() && doc.lines().count() <= 1 { print!( - "{:padding$}{} {}", + "{:padding$}{} ", "", config.color.stdout().doc().paint("#"), - config.color.stdout().doc().paint(doc), padding = max_signature_width.saturating_sub(signature_widths[name]) + 1, ); + + let mut within_backticks = false; + for chunk in doc.split('`') { + if within_backticks { + let color = config.color.stdout().doc_backtick(); + print!( + "{}{}{}", + color.paint("`"), + color.paint(chunk), + color.paint("`") + ); + } else { + let color = config.color.stdout().doc(); + print!("{}", color.paint(chunk)); + } + within_backticks = !within_backticks; + } } } println!(); From b5a0e32ebe2e6de74445f0c7223582bcbd4ef153 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Thu, 10 Oct 2024 01:08:20 -0700 Subject: [PATCH 2/6] Don't print extraneous ` if it doesn't appear --- src/subcommand.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/subcommand.rs b/src/subcommand.rs index 2f82480352..dd8903104e 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -421,18 +421,13 @@ impl Subcommand { ); let mut within_backticks = false; - for chunk in doc.split('`') { + for chunk in doc.split_inclusive('`') { if within_backticks { let color = config.color.stdout().doc_backtick(); - print!( - "{}{}{}", - color.paint("`"), - color.paint(chunk), - color.paint("`") - ); + print!("{}{}", color.paint("`"), color.paint(chunk),); } else { let color = config.color.stdout().doc(); - print!("{}", color.paint(chunk)); + print!("{}", color.paint(chunk.split('`').next().unwrap())); } within_backticks = !within_backticks; } From 6abb79e91767d8e0b7c118682287ab7f01317492 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Fri, 11 Oct 2024 00:46:00 -0700 Subject: [PATCH 3/6] Tests --- justfile | 2 +- tests/list.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/justfile b/justfile index d0ff455c67..5ab153626e 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/tests/list.rs b/tests/list.rs index db7b669e44..974ca75f62 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -438,3 +438,31 @@ fn no_space_before_submodules_not_following_groups() { ) .run(); } + +#[test] +fn backticks_highlighted() { + Test::new() + .justfile( + " + # Comment `` `with backticks` + recipe: + ", + ) + .args(["--list", "--color=always"]) + .stdout("Available recipes:\n recipe \u{1b}[34m#\u{1b}[0m \u{1b}[34mComment \u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[34m \u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[40;37mwith backticks`\u{1b}[0m\n") + .run(); +} + +#[test] +fn unclosed_backticks() { + Test::new() + .justfile( + " + # Comment `with unclosed backick + recipe: + ", + ) + .args(["--list", "--color=always"]) + .stdout("Available recipes:\n recipe \u{1b}[34m#\u{1b}[0m \u{1b}[34mComment \u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[40;37mwith unclosed backick\u{1b}[0m\n") + .run(); +} From f805cb7d01d91434f5d9b0ee96943d93f84463d4 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 9 Nov 2024 10:53:07 -0800 Subject: [PATCH 4/6] Search for backticks using regex --- src/lib.rs | 2 +- src/subcommand.rs | 27 +++++++++++++++++---------- tests/list.rs | 12 ++++++++++-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 75e3332be4..9756027ef1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ pub(crate) use { process::{self, Command, ExitStatus, Stdio}, rc::Rc, str::{self, Chars}, - sync::{Mutex, MutexGuard, OnceLock}, + sync::{LazyLock, Mutex, MutexGuard, OnceLock}, vec, }, strum::{Display, EnumDiscriminants, EnumString, IntoStaticStr}, diff --git a/src/subcommand.rs b/src/subcommand.rs index dd8903104e..f0879e0839 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -2,6 +2,8 @@ use {super::*, clap_mangen::Man}; const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n"; +static BACKTICK_RE: LazyLock = LazyLock::new(|| Regex::new("(`.*?`)|(`[^`]*$)").unwrap()); + #[derive(PartialEq, Clone, Debug)] pub(crate) enum Subcommand { Changelog, @@ -413,26 +415,31 @@ impl Subcommand { ) { if let Some(doc) = doc { if !doc.is_empty() && doc.lines().count() <= 1 { + let color = config.color.stdout(); print!( "{:padding$}{} ", "", - config.color.stdout().doc().paint("#"), + color.doc().paint("#"), padding = max_signature_width.saturating_sub(signature_widths[name]) + 1, ); - let mut within_backticks = false; - for chunk in doc.split_inclusive('`') { - if within_backticks { - let color = config.color.stdout().doc_backtick(); - print!("{}{}", color.paint("`"), color.paint(chunk),); - } else { - let color = config.color.stdout().doc(); - print!("{}", color.paint(chunk.split('`').next().unwrap())); + 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)); } - within_backticks = !within_backticks; + 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 974ca75f62..396a337afd 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -449,7 +449,11 @@ fn backticks_highlighted() { ", ) .args(["--list", "--color=always"]) - .stdout("Available recipes:\n recipe \u{1b}[34m#\u{1b}[0m \u{1b}[34mComment \u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[34m \u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[40;37mwith backticks`\u{1b}[0m\n") + .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 + ") .run(); } @@ -463,6 +467,10 @@ fn unclosed_backticks() { ", ) .args(["--list", "--color=always"]) - .stdout("Available recipes:\n recipe \u{1b}[34m#\u{1b}[0m \u{1b}[34mComment \u{1b}[0m\u{1b}[40;37m`\u{1b}[0m\u{1b}[40;37mwith unclosed backick\u{1b}[0m\n") + .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 445551bd916a61073c8907c161a5eac8dcbffcec Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 9 Nov 2024 10:55:42 -0800 Subject: [PATCH 5/6] Add test for trailing text --- tests/list.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/list.rs b/tests/list.rs index 396a337afd..f7ea7528af 100644 --- a/tests/list.rs +++ b/tests/list.rs @@ -444,7 +444,7 @@ fn backticks_highlighted() { Test::new() .justfile( " - # Comment `` `with backticks` + # Comment `` `with backticks` and trailing text recipe: ", ) @@ -452,7 +452,7 @@ fn backticks_highlighted() { .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 + 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(); } From fb7994b98d1a67d043e8042be1bdcbe7adddbb45 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 9 Nov 2024 11:03:49 -0800 Subject: [PATCH 6/6] Use oncelock --- src/lib.rs | 2 +- src/subcommand.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9756027ef1..75e3332be4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ pub(crate) use { process::{self, Command, ExitStatus, Stdio}, rc::Rc, str::{self, Chars}, - sync::{LazyLock, Mutex, MutexGuard, OnceLock}, + sync::{Mutex, MutexGuard, OnceLock}, vec, }, strum::{Display, EnumDiscriminants, EnumString, IntoStaticStr}, diff --git a/src/subcommand.rs b/src/subcommand.rs index f0879e0839..40795496ed 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -2,7 +2,10 @@ use {super::*, clap_mangen::Man}; const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n"; -static BACKTICK_RE: LazyLock = LazyLock::new(|| Regex::new("(`.*?`)|(`[^`]*$)").unwrap()); +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 { @@ -424,7 +427,7 @@ impl Subcommand { ); let mut end = 0; - for backtick in BACKTICK_RE.find_iter(doc) { + for backtick in backtick_re().find_iter(doc) { let prefix = &doc[end..backtick.start()]; if !prefix.is_empty() { print!("{}", color.doc().paint(prefix));