For text with color codes, how to wrap it to a fixed length in the terminal?
Text without color codes wraps nicely with fold
:
echo -e "12345678901234567890" | fold -w 10 1234567890 1234567890
But this red text wraps wrong:
echo -e "u001b[31m12345678901234567890" | fold -w 10 12345 6789012345 67890
Note: While the red text is wrapped wrong, it still is printed in red, which is the desired behavior.
(My use case is line wrapping the output of git log --color=always --oneline --graph
.)
Advertisement
Answer
When determining the (printable) width of a prompt (eg, PS1
) the special characters – [
and ]
– are used to designate a series of non-printing characters (see this, this, this and this).
So far I’ve been unable to find a way to use [
and ]
outside the scope of a prompt hence this awk
hack …
Assumptions:
- we don’t know the color codes in advance
- for this exercise it is sufficient to deal with color codes of the format
e[...m
(e[m
turns off color) - may have to deal with multiple color codes in the input
We’ll wrap one awk
idea in a bash
function (for easier use):
myfold() { awk -v n="${1:-10}" ' # default wrap is 10 (printable) characters BEGIN { regex="[[:cntrl:]][[][^m]*m" # regex == "e[*m" #regex="x1b[[][^m]*m" # alternatives #regex="33[[][^m]*m" } { input=$0 while (input != "" ) { # repeatedly strip off "n" characters until we have processed the entire line count=n output="" while ( count > 0 ) { # repeatedly strip off color control codes and characters until we have stripped of "n" characters match(input,regex) if (RSTART && RSTART <= count) { output=output substr(input,1,RSTART+RLENGTH-1) input=substr(input,RSTART+RLENGTH) count=count - (RSTART > 1 ? RSTART-1 : 0) } else { output=output substr(input,1,count) input=substr(input,count+1) count=0 } } print output } } ' }
NOTES:
- other non-color, non-printing characters will throw off the count
- the regex could be expanded to address other non-printing color and/or character codes
Test run:
$ echo -e "e[31m123456789012345e[m67890e[32mABCDe[m" 12345678901234567890ABCD $ echo -e "e[31m123456789012345e[m67890e[32mABCDe[m" | myfold 10 1234567890 1234567890 ABCD $ echo -e "e[31m123456789012345e[m67890e[32mABCDe[m" | myfold 7 1234567 8901234 567890A BCD
Displaying colors: