Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli/format-table: handling ANSI escape codes #102

Closed
eval opened this issue Jul 29, 2024 · 6 comments · Fixed by #103
Closed

cli/format-table: handling ANSI escape codes #102

eval opened this issue Jul 29, 2024 · 6 comments · Fixed by #103

Comments

@eval
Copy link
Contributor

eval commented Jul 29, 2024

problem

Currently cli/format-table can't handle ANSI escape codes.

Given for example:

(cli/format-table {:rows [["foo" "<- something plain"]
                          ["\033[31mbar\033[0m" "<- something red"]]})

...the foo- and bar-cell have the same width when printed (ie 3). But as the bar-cell is considered to have a width of 12, the foo-cell gets padded to this length as well, making it look off when printed.

Less common, but same idea when using emoji's: (count "🚀 bar") ;;=> 6 (but 5 when printed).

possible approaches

provide widths

Providing the width of every cell, e.g. via metadata on a row:

user=> rows
[^{:column-widths [3 18]}
 ["foo" "<- something plain"]
 ^{:column-widths [3 16]}
 ["\033[31mbar\033[0m" "<- something red"]]

This metadata would be used instead of (map count row) in #cli/pad-cells:

cli/src/babashka/cli.cljc

Lines 526 to 532 in 836b15f

(defn pad-cells [rows]
(let [widths (reduce
(fn [widths row]
(map max (map count row) widths)) (repeat 0) rows)
pad-row (fn [row]
(map (fn [width col] (pad width col)) widths row))]
(map pad-row rows)))

This solution would also double as a solution to the problem 'how to customise spacing between columns'.

Happy to provide a PR.

@borkdude
Copy link
Contributor

Perhaps there's a better solution to decide the actual printed width for a string? I wouldn't be surprised if more people have had this problem in the past.

@borkdude
Copy link
Contributor

I found this: https://stackoverflow.com/a/64677848/6264

@borkdude
Copy link
Contributor

I also found this as a solution for emojis:

(let [s  "🚀 bar"] (.codePointCount s 0 (count s)) )

@borkdude
Copy link
Contributor

but perhaps in the emoji example, 6 is the right answer since the rocket takes up more space than a single digit? I'm not sure :)

@borkdude
Copy link
Contributor

This one is weird though:

user=> (let [s "🤦‍♂️"] (.codePointCount s 0 (count s)) )
4

Let's just adjust the ansi escape codes then with the regex maybe as a first attempt?

@eval
Copy link
Contributor Author

eval commented Jul 29, 2024

Getting that logic on board is an option as well. I looked at https://github.com/lambdaisland/ansi/blob/main/src/lambdaisland/ansi.cljc for inspiration.

but perhaps in the emoji example, 6 is the right answer since the rocket takes up more space than a single digit? I'm not sure :)

Seems to work indeed for some emoji's

podman run -it babashka/babashka bash -c 'bb -e '"'"'(require (quote [babashka.cli :as cli]))(println (cli/format-table {:rows [["🆘 foo" "description of foo"] ["bar" "Description of bar"]] :indent 2}))'"'"''

But facepalm is off indeed.

Let's just adjust the ansi escape codes then with the regex maybe as a first attempt?

Will take a stab at that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants