From d375fadcf00f57243818c46abebb62ed726ea535 Mon Sep 17 00:00:00 2001 From: lread Date: Sun, 13 Apr 2025 14:48:12 -0400 Subject: [PATCH 1/2] `format-table` now formats multiline cells Closes #119 --- CHANGELOG.md | 5 +++++ src/babashka/cli.cljc | 38 ++++++++++++++++++++++++++++++++++--- test/babashka/cli_test.cljc | 14 ++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93fe328..8837d75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ For breaking changes, check [here](#breaking-changes). [Babashka CLI](https://github.com/babashka/cli): turn Clojure functions into CLIs! +## Unreleased + +- [#119](https://github.com/babashka/cli/issues/119): `format-table` now formats multiline cells appropriately +([@lread](https://github.com/lread)) + ## v0.8.64 - Remove `pom.xml` and `project.clj` for cljdoc diff --git a/src/babashka/cli.cljc b/src/babashka/cli.cljc index 6e30652..3f9f822 100644 --- a/src/babashka/cli.cljc +++ b/src/babashka/cli.cljc @@ -548,8 +548,20 @@ (map pad widths row))] (map pad-row rows))) +(defn- expand-multiline-cells [rows] + (let [col-cnt (count (first rows))] + (->> (for [row rows] + (let [row-lines (mapv str/split-lines row) + max-lines-cell (reduce max (mapv count row-lines))] + (for [line-ndx (range max-lines-cell)] + (for [col-ndx (range col-cnt)] + (get-in row-lines [col-ndx line-ndx] ""))))) + (into [] cat)))) + (defn format-table [{:keys [rows indent] :or {indent 2}}] - (let [rows (pad-cells rows) + (let [rows (-> rows + expand-multiline-cells + pad-cells) fmt-row (fn [leader divider trailer row] (str leader (apply str (interpose divider row)) @@ -565,9 +577,29 @@ (def rows [["a" "fooo" "bara" "bazzz" "aa"] ["foo" "bar" "bazzz"] ["fooo" "bara" "bazzz"]]) + (pad-cells rows) - (format-table {:rows rows - :indent 2})) + (-> (format-table {:rows rows + :indent 2}) + str/split-lines) + ;; => [" a fooo bara bazzz aa" + ;; " foo bar bazzz" + ;; " fooo bara bazzz"] + + (-> (format-table {:rows [["r1c1\nr1c1 l2" "r1c2" "r1c3"] + ["r2c1 wider" "r2c2\nr2c2 l2\nr2c2 l3" "r2c3\nr2c3 l2"] + ["r3c1" "r3c2 wider" "r3c3\nr3c3 l2\nr3c3 l3"]] + :indent 5}) + str/split-lines) + ;; => [" r1c1 r1c2 r1c3" + ;; " r1c1 l2" + ;; " r2c1 wider r2c2 r2c3" + ;; " r2c2 l2 r2c3 l2" + ;; " r2c2 l3" + ;; " r3c1 r3c2 wider r3c3" + ;; " r3c3 l2" + ;; " r3c3 l3"] + ) (defn opts->table [{:keys [spec order]}] (let [columns (set (mapcat (fn [[_ s]] (keys s)) spec))] diff --git a/test/babashka/cli_test.cljc b/test/babashka/cli_test.cljc index 59700f7..aeedabc 100644 --- a/test/babashka/cli_test.cljc +++ b/test/babashka/cli_test.cljc @@ -519,6 +519,20 @@ (contains-row-matching #"bar <-" table))))) +(deftest format-multiline-celled-table-test + (is (= [" r1c1 r1c2 r1c3" + " r1c1 l2" + " r2c1 wider r2c2 r2c3" + " r2c2 l2 r2c3 l2" + " r2c2 l3" + " r3c1 r3c2 wider r3c3" + " r3c3 l2" + " r3c3 l3"] + (-> (cli/format-table {:rows [["r1c1\nr1c1 l2" "r1c2" "r1c3"] + ["r2c1 wider" "r2c2\nr2c2 l2\nr2c2 l3" "r2c3\nr2c3 l2"] + ["r3c1" "r3c2 wider" "r3c3\nr3c3 l2\nr3c3 l3"]]}) + str/split-lines)))) + (deftest require-test (is (thrown-with-msg? Exception #"Required option: :bar" From e162f4a3f4c23736c07933e1b485fdeda28a24c6 Mon Sep 17 00:00:00 2001 From: lread Date: Mon, 14 Apr 2025 09:19:56 -0400 Subject: [PATCH 2/2] review feedback: please don't use for I also got rid of eagerness and stayed lazy which seems to match other code here. --- src/babashka/cli.cljc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/babashka/cli.cljc b/src/babashka/cli.cljc index 3f9f822..4077abf 100644 --- a/src/babashka/cli.cljc +++ b/src/babashka/cli.cljc @@ -549,14 +549,16 @@ (map pad-row rows))) (defn- expand-multiline-cells [rows] - (let [col-cnt (count (first rows))] - (->> (for [row rows] - (let [row-lines (mapv str/split-lines row) - max-lines-cell (reduce max (mapv count row-lines))] - (for [line-ndx (range max-lines-cell)] - (for [col-ndx (range col-cnt)] - (get-in row-lines [col-ndx line-ndx] ""))))) - (into [] cat)))) + (if (empty? rows) + [] + (let [col-cnt (count (first rows))] + (mapcat (fn [row] + (let [row-lines (mapv #(str/split-lines (str %)) row) + max-lines (reduce max (map count row-lines))] + (map (fn [line-idx] + (map #(get-in row-lines [% line-idx] "") (range col-cnt))) + (range max-lines)))) + rows)))) (defn format-table [{:keys [rows indent] :or {indent 2}}] (let [rows (-> rows