diff --git a/src/discover/registry.rs b/src/discover/registry.rs
index ee5f7a7be..bbb766a73 100644
--- a/src/discover/registry.rs
+++ b/src/discover/registry.rs
@@ -62,12 +62,16 @@ lazy_static! {
// --git-dir
, --work-tree , and flag-only options (#163)
static ref GIT_GLOBAL_OPT: Regex =
Regex::new(r"^(?:(?:-C\s+\S+|-c\s+\S+|--git-dir(?:=\S+|\s+\S+)|--work-tree(?:=\S+|\s+\S+)|--no-pager|--no-optional-locks|--bare|--literal-pathspecs)\s+)+").unwrap();
- static ref HEAD_N: Regex = Regex::new(r"^head\s+-(\d+)\s+(.+)$").unwrap();
- static ref HEAD_LINES: Regex = Regex::new(r"^head\s+--lines=(\d+)\s+(.+)$").unwrap();
- static ref TAIL_N: Regex = Regex::new(r"^tail\s+-(\d+)\s+(.+)$").unwrap();
- static ref TAIL_N_SPACE: Regex = Regex::new(r"^tail\s+-n\s+(\d+)\s+(.+)$").unwrap();
- static ref TAIL_LINES_EQ: Regex = Regex::new(r"^tail\s+--lines=(\d+)\s+(.+)$").unwrap();
- static ref TAIL_LINES_SPACE: Regex = Regex::new(r"^tail\s+--lines\s+(\d+)\s+(.+)$").unwrap();
+ // Issue #1362: each capture expects a SINGLE file argument (`\S+$`). Multi-file
+ // invocations like `head -3 a b c` fail to match so the segment is passed through
+ // to the native `head`/`tail` binary — which already handles multi-file with
+ // `==> name <==` banners that `rtk read --max-lines` cannot reproduce.
+ static ref HEAD_N: Regex = Regex::new(r"^head\s+-(\d+)\s+(\S+)$").unwrap();
+ static ref HEAD_LINES: Regex = Regex::new(r"^head\s+--lines=(\d+)\s+(\S+)$").unwrap();
+ static ref TAIL_N: Regex = Regex::new(r"^tail\s+-(\d+)\s+(\S+)$").unwrap();
+ static ref TAIL_N_SPACE: Regex = Regex::new(r"^tail\s+-n\s+(\d+)\s+(\S+)$").unwrap();
+ static ref TAIL_LINES_EQ: Regex = Regex::new(r"^tail\s+--lines=(\d+)\s+(\S+)$").unwrap();
+ static ref TAIL_LINES_SPACE: Regex = Regex::new(r"^tail\s+--lines\s+(\d+)\s+(\S+)$").unwrap();
}
const GOLANGCI_GLOBAL_OPT_WITH_VALUE: &[&str] = &[
@@ -1668,6 +1672,48 @@ mod tests {
assert_eq!(rewrite_command("tail src/main.rs", &[]), None);
}
+ // --- Issue #1362: head/tail with multiple files falls back to native command ---
+ //
+ // `rtk read --max-lines N` only accepts a single positional file path in
+ // a shape that maps cleanly to `head -N`. Rewriting `head -N a b c` to
+ // `rtk read a b c --max-lines N` previously produced a command where `rtk read`
+ // would concatenate the files without the `==> name <==` banners that native
+ // `head` emits, so the fix is to skip the rewrite and let the shell run the
+ // real `head`/`tail` binary.
+
+ #[test]
+ fn test_rewrite_head_numeric_flag_multi_file_skipped() {
+ assert_eq!(rewrite_command("head -3 /tmp/a /tmp/b /tmp/c", &[]), None);
+ }
+
+ #[test]
+ fn test_rewrite_head_lines_long_flag_multi_file_skipped() {
+ assert_eq!(
+ rewrite_command("head --lines=50 src/main.rs src/lib.rs", &[]),
+ None
+ );
+ }
+
+ #[test]
+ fn test_rewrite_tail_numeric_flag_multi_file_skipped() {
+ assert_eq!(rewrite_command("tail -20 a.log b.log", &[]), None);
+ }
+
+ #[test]
+ fn test_rewrite_tail_n_space_flag_multi_file_skipped() {
+ assert_eq!(rewrite_command("tail -n 12 a.log b.log c.log", &[]), None);
+ }
+
+ #[test]
+ fn test_rewrite_tail_lines_eq_multi_file_skipped() {
+ assert_eq!(rewrite_command("tail --lines=7 a.log b.log", &[]), None);
+ }
+
+ #[test]
+ fn test_rewrite_tail_lines_space_multi_file_skipped() {
+ assert_eq!(rewrite_command("tail --lines 7 a.log b.log", &[]), None);
+ }
+
// --- New registry entries ---
#[test]