Repository: casey/just
Pull request #2423 (2024-10-09 23:45:25)

Highlight text within backticks when listing recipes
https://github.com/casey/just/issues/2272

casey: Seems reasonable! Needs some tests though. Should definitely test edge cases, like an unclosed backtick, etc.
casey: I could not wrap my head around what `split_inclusive` was doing, so I replaced it with a regex. This also avoids color codes sometimes when they aren't needed.

Patch:
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<Regex> = 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!();
     }
 


Test patch:
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();
+}