Repository: dathere/qsv (language: rust)

Issue:
`headers`: add `--just-count` option
I think having a way to get the column count similar to `qsv count` can work well so `--just-count` makes sense for my use case.

_Originally posted by @rzmk in https://github.com/jqnatividad/qsv/discussions/1993#discussioncomment-10166538_


Discussion / hints:

Fix patch:
diff --git a/src/cmd/headers.rs b/src/cmd/headers.rs
index 0029961bf..4ba3c00d3 100644
--- a/src/cmd/headers.rs
+++ b/src/cmd/headers.rs
@@ -26,6 +26,7 @@ headers options:
     -j, --just-names       Only show the header names (hide column index).
                            This is automatically enabled if more than one
                            input is given.
+    -J, --just-count       Only show the number of headers.
     --intersect            Shows the intersection of all headers in all of
                            the inputs given.
     --trim                 Trim space & quote characters from header name.
@@ -47,6 +48,7 @@ use crate::{config::Delimiter, util, CliResult};
 struct Args {
     arg_input:       Vec<PathBuf>,
     flag_just_names: bool,
+    flag_just_count: bool,
     flag_intersect:  bool,
     flag_trim:       bool,
     flag_delimiter:  Option<Delimiter>,
@@ -69,25 +71,29 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
         }
     }
 
-    let mut wtr: Box<dyn io::Write> = if args.flag_just_names {
+    let mut wtr: Box<dyn io::Write> = if args.flag_just_names || args.flag_just_count {
         Box::new(io::stdout())
     } else {
         Box::new(TabWriter::new(io::stdout()))
     };
-    for (i, header) in headers.iter().enumerate() {
-        if num_inputs == 1 && !args.flag_just_names {
-            write!(&mut wtr, "{}\t", i + 1)?;
-        }
-        if args.flag_trim {
-            wtr.write_all(
-                std::string::String::from_utf8_lossy(header)
-                    .trim_matches(|c| c == '"' || c == ' ')
-                    .as_bytes(),
-            )?;
-        } else {
-            wtr.write_all(header)?;
+    if args.flag_just_count {
+        writeln!(wtr, "{}", headers.len())?;
+    } else {
+        for (i, header) in headers.iter().enumerate() {
+            if num_inputs == 1 && !args.flag_just_names {
+                write!(&mut wtr, "{}\t", i + 1)?;
+            }
+            if args.flag_trim {
+                wtr.write_all(
+                    std::string::String::from_utf8_lossy(header)
+                        .trim_matches(|c| c == '"' || c == ' ')
+                        .as_bytes(),
+                )?;
+            } else {
+                wtr.write_all(header)?;
+            }
+            wtr.write_all(b"\n")?;
         }
-        wtr.write_all(b"\n")?;
     }
     Ok(wtr.flush()?)
 }


Test patch:
diff --git a/tests/test_headers.rs b/tests/test_headers.rs
index 62dd36f7b..6a81b0071 100644
--- a/tests/test_headers.rs
+++ b/tests/test_headers.rs
@@ -39,6 +39,16 @@ h2";
     assert_eq!(got, expected.to_string());
 }
 
+#[test]
+fn headers_just_count() {
+    let (wrk, mut cmd) = setup("headers_just_count");
+    cmd.arg("--just-count");
+
+    let got: String = wrk.stdout(&mut cmd);
+    let expected = "2";
+    assert_eq!(got, expected.to_string());
+}
+
 #[test]
 fn headers_notrim() {
     let wrk = Workdir::new("headers_notrim");
@@ -159,6 +169,16 @@ h3";
     assert_eq!(got, expected.to_string());
 }
 
+#[test]
+fn headers_multiple_just_count() {
+    let (wrk, mut cmd) = setup("headers_multiple_just_count");
+    cmd.arg("in2.csv").arg("--just-count");
+
+    let got: String = wrk.stdout(&mut cmd);
+    let expected = "4";
+    assert_eq!(got, expected.to_string());
+}
+
 #[test]
 fn headers_intersect() {
     let (wrk, mut cmd) = setup("headers_intersect");
@@ -186,7 +206,7 @@ fn headers_infile() {
 
     wrk.create_from_string("testdata.infile-list", "in1.csv\nin2.csv\nin3.csv\n");
 
-    let mut cmd = wrk.command("headers");
+    let mut cmd: process::Command = wrk.command("headers");
     cmd.arg("testdata.infile-list");
 
     let got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
@@ -203,6 +223,13 @@ fn headers_infile() {
         ["g"],
     ];
     assert_eq!(got, expected);
+
+    let mut cmd: process::Command = wrk.command("headers");
+    cmd.arg("testdata.infile-list").arg("--just-count");
+
+    let got: String = wrk.stdout(&mut cmd);
+    let expected = "10";
+    assert_eq!(got, expected.to_string());
 }
 
 #[test]