Text::ANSI::Util(3pm)
Text::ANSI::Util π
okay bestie, welcome to Text::ANSI::Util(3pm) β it's a User Contributed Perl Documentation page, and it's literally the glow-up your terminal text needed. We're talking routines for text that has ANSI color codes all up in it. Periodt.
β¨ NAME β¨
Text::ANSI::Util β Routines for text containing ANSI color codes π
πΈ VERSION πΈ
This document describes version 0.234 of Text::ANSI::Util (from Perl distribution Text-ANSI-Util), released on 2023-02-27.
π¦ SYNOPSIS π¦
use Text::ANSI::Util qw(
ta_add_color_resets
ta_detect
ta_extract_codes
ta_highlight
ta_highlight_all
ta_length
ta_length_height
ta_pad
ta_split_codes
ta_split_codes_single
ta_strip
ta_substr
ta_trunc
ta_wrap
);
# detect whether text has ANSI color codes?
say ta_detect("red"); # => false
say ta_detect("\e[31mred"); # => true
# calculate length of text (excluding the ANSI color codes)
say ta_length("red"); # => 3
say ta_length("\e[31mred"); # => 3
# strip ANSI color codes
say ta_strip("\e[31mred"); # => "red"
# split codes (ANSI color codes are always on the even positions)
my @parts = ta_split_codes("\e[31mred"); # => ("", "\e[31m", "red")
# wrap text to a certain column width, handle ANSI color codes
say ta_wrap("....", 40);
# pad (left, right, center) text to a certain width
say ta_pad("foo", 10); # => "foo "
say ta_pad("foo", 10, "left"); # => " foo"
say ta_pad("foo\nbarbaz\n", 10, "center", "."); # => "...foo....\n..barbaz..\n"
# truncate text to a certain width while still passing ANSI color codes
use Term::ANSIColor;
my $text = color("red")."red text".color("reset"); # => "\e[31mred text\e[0m"
say ta_trunc($text, 5); # => "\e[31mred t\e[0m"
# highlight the first occurrence of some string within text
say ta_highlight("some text", "ome", "\e[7m\e[31m");
# ditto, but highlight all occurrences
say ta_highlight_all(...);
# get substring
my $substr = ta_substr("...", $pos, $len);
# return text but with substring replaced with replacement
say ta_substr("...", $pos, $len, $replacement);
π DESCRIPTION π
So this module hands you routines for dealing with text that's got ANSI color codes sprinkled all through it β like figuring out how long/wide it actually is (color codes don't count, bestie π), stripping the codes out, pulling the codes out on their own, all of that.
If you need the functions that also do wide characters, go see Text::ANSI::WideUtil β that's a whole separate vibe.
Current caveats (read these, they're giving "important"):
- Other ANSI codes (non-color codes) are ignored β we're talking codes like the ones for moving the cursor around and stuff.
- Single-character CSI (control sequence introducer) currently ignored β only
ESC+[(two-character CSI) is parsed right now. BTW, in ASCII terminals, single-character CSI is0x9b. In UTF-8 terminals, it's0xc2, 0x9b(2 bytes). iykyk. - Private-mode- and trailing-intermediate character currently not parsed
- Only color reset code
\e[0mis recognized β for simplicity, multiple SGR parameters inside a single ANSI color code are not parsed right now. Meaning color reset codes like"\e[1;0m"or"\e[31;47;0m"don't get recognized, only"\e[0m"does. The author believes this shouldn't be a problem with most real-world text out there, and honestly? fair.
π₯ FUNCTIONS π₯
ta_add_color_resets(@text) => LIST π«Ά
This one makes sure a color reset command (adds "\e[0m") gets tacked onto the end of every element, and a replay of all the color codes from the previous element (from the last color reset) gets slapped onto the start of the next element, and so on and so on. Returns the new list. β¨
This is the move that makes each element safe to combine with other arrays of text into a single line β say, in a multicolumn/tabular layout. Example time:
Without color resets:
my @col1 = split /\n/, "\e[31mred\nmerah\e[0m";
my @col2 = split /\n/, "\e[32mgreen\e[1m\nhijau tebal\e[0m";
printf "%s | %s\n", $col1[0], $col2[0];
printf "%s | %s\n", $col1[1], $col2[1];
the printed output:
\e[31mred | \e[32mgreen
merah\e[0m | \e[1mhijau tebal\e[0m
See how the "merah" text on the second line becomes green? π That's because of the effect of the last color command printed ("\e[32m"). Not the vibe we want. But with ta_add_color_resets():
my @col1 = ta_add_color_resets(split /\n/, "\e[31mred\nmerah\e[0m");
my @col2 = ta_add_color_resets(split /\n/, "\e[32mgreen\e[1m\nhijau tebal\e[0m");
printf "%s | %s\n", $col1[0], $col2[0];
printf "%s | %s\n", $col1[1], $col2[1];
the printed output β and the "<...>" marks the code that ta_add_color_resets() added:
\e[31mred<\e[0m> | \e[32mgreen\e[1m<\e[0m>
<\e[31m>merah\e[0m | <\e[32m\e[1m>hijau tebal\e[0m
All the cells print with the intended colors. Iconic. π
ta_detect($text) => BOOL π
Returns true if $text contains ANSI color codes, false otherwise. Simple as.
ta_extract_codes($text) => STR π
This is the opposite of "ta_strip()" β it returns only the ANSI codes in $text.
ta_highlight($text, $needle, $color) => STR π
Highlights the first occurrence of $needle in $text with <$color>, being super careful not to mess up the colors that are already there.
$needle can be a string or a Regexp object.
Implementation note, because this part is lowkey genius: to not mess up colors, we save up all the color codes from the last reset ("\e[0m") before inserting the highlight color + highlight text. Then we issue "\e[0m" and the saved-up color code to return back to the color state that existed before the highlight got inserted. Same technique as described in "ta_add_color_resets()". Slay.
ta_highlight_all($text, $needle, $color) => STR π
Like "ta_highlight()", but highlights all the occurrences instead of only the first. Obsessed.
ta_length($text) => INT πΈ
Counts the number of characters in $text, while ignoring ANSI color codes. Equivalent to "length(ta_strip($text))". See also: "ta_mbswidth()" in Text::ANSI::WideUtil.
ta_length_height($text) => [INT, INT] π§
Like "ta_length()", but also gives you the height (number of lines). For example, "ta_length_height("foobar\nb\n")" gives "[6, 3]".
See also: "ta_mbswidth_height()" in Text::ANSI::WideUtil.
ta_pad($text, $width[, $which[, $padchar[, $truncate]]]) => STR π
Returns $text padded with $padchar to $width columns. $which is either "r" or "right" for padding on the right (this is the default if you don't specify anything), "l" or "left" for padding on the right, or "c" or "center" or "centre" for left+right padding to center the text.
$padchar is whitespace if not specified. It should be a string having the width of 1 column.
β οΈ Does not handle multiline text β you can split text by "/\r?\n/" yourself, bestie.
See also: "ta_mbpad()" in Text::ANSI::WideUtil.
ta_split_codes($text) => LIST β
Splits $text into a list containing alternating ANSI color codes and text. The ANSI color codes are always on the second element, the fourth, and so on. Example:
ta_split_codes(""); # => ()
ta_split_codes("a"); # => ("a")
ta_split_codes("a\e[31m"); # => ("a", "\e[31m")
ta_split_codes("\e[31ma"); # => ("", "\e[31m", "a")
ta_split_codes("\e[31ma\e[0m"); # => ("", "\e[31m", "a", "\e[0m")
ta_split_codes("\e[31ma\e[0mb"); # => ("", "\e[31m", "a", "\e[0m", "b")
ta_split_codes("\e[31m\e[0mb"); # => ("", "\e[31m\e[0m", "b")
so you can do something like:
my @parts = ta_split_codes($text);
while (my ($text, $ansicode) = splice(@parts, 0, 2)) {
...
}
ta_split_codes_single($text) => LIST π¦
Like "ta_split_codes()" but each ANSI color code gets split separately, instead of being grouped together. This routine is currently used internally, e.g. for "ta_wrap()" and "ta_highlight()", to trace color reset/replay codes.
ta_strip($text) => STR π
Strips ANSI color codes from $text, returning the stripped text. Clean girl aesthetic.
ta_substr($text, $pos, $len[ , $replacement ]) => STR π
A bit like Perl's "substr()". If $replacement is not specified, it'll return the substring. If $replacement is specified, it'll return $text with the substring replaced by $replacement.
See also: "ta_mbsubstr()" in Text::ANSI::WideUtil.
ta_trunc($text, $width) => STR βοΈ
Truncates $text to $width columns while still including all the ANSI color codes. This ensures the truncated text still resets colors, etc.
β οΈ Does not handle multiline text β split text by "/\r?\n/" yourself, fr fr.
See also: "ta_mbtrunc()" in Text::ANSI::WideUtil.
ta_wrap($text, $width, %opts) => STR π₯
Like Text::WideChar::Util's "wrap()", except it handles ANSI color codes. It performs a color reset at the end of each line and a color replay at the start of the subsequent line, so the text is safe for combining in a multicolumn/tabular layout. Main character energy only.
Options:
flindent=> STR β First line indent. Currently must not contain ANSI color codes or wide characters.slindent=> STR β Subsequent line indent. Currently must not contain ANSI color codes or wide characters.tab_width=> INT (default: 8)pad=> BOOL (default: 0) β If set to true, it'll pad each line to$width. This is convenient if you need the lines padded β saves you calls tota_pad().return_stats=> BOOL (default: 0) β If set to true, then instead of returning the wrapped string, the function returns"[$wrapped, $stats]"where$statsis a hash containing some information like"max_word_width","min_word_width".keep_trailing_space=> BOOL (default: 0) β If set to true, then the trailing space that separates words will be kept at the end of wrapped lines. This option is useful if you want to rejoin the lines later. Without this option set to true, wrapping this line at width=4 (quotes shown):
"some long line"
will result in:
"some"
"long"
"line"
While if this option is set to true, the result will be:
"some "
"long "
"line"
Performance: ~500/s on the author's Core i5 1.7GHz laptop for a ~1KB of text (with zero to moderate amount of color codes).
See also: "ta_mbwrap()" in Text::ANSI::WideUtil.
π FAQ π
Why split functionalities of wide character and color support into multiple modules/distributions?
Performance (see the numbers in the function description), dependency (Unicode::GCString is used for wide character support), and overhead (loading Unicode::GCString).
How do I highlight a string case-insensitively?
You can currently use a regex for the $needle and use the "i" modifier. Example:
use Term::ANSIColor;
ta_highlight($text, qr/\b(foo)\b/i, color("bold red"));
π HOMEPAGE π
Please visit the project's homepage at <https://metacpan.org/release/Text-ANSI-Util>. π«Ά
π SOURCE π
Source repository is at <https://github.com/perlancar/perl-Text-ANSI-Util>. π
π SEE ALSO β¨
okay so if Text::ANSI::Util isn't quite your girl, here's her friend group π:
String::Padβ gives you a padding function for strings that have no ASCII escape codes and no wide characters. clean, simple, no drama.Text::NonWideChar::Utilβ has some other functions for strings that also have no ASCII escape codes and no wide characters. same vibe, different toolbox π§°Text::WideChar::Utilβ utilities for strings that have no ANSI escape codes but do have wide characters πText::ANSI::WideUtilβ utilities for the full chaos combo: strings that have ANSI escape codes and wide characters π₯
π AUTHOR
perlancar <perlancar@cpan.org> β the icon, the legend, the one who wrote all this π
π«Ά CONTRIBUTOR
Steven Haryanto <stevenharyanto@gmail.com> β bestie showed up and helped, we love to see it πΈ
π CONTRIBUTING
want in? yes bestie, come through β¨ you can send patches by email/via RT, or send pull requests on GitHub.
ngl tho β most of the time you do NOT need to build the distribution yourself. just edit the code, then test it with:
% prove -l
and if you do want to build the distribution (like, say, to try installing it locally on your system), then you'll want to install Dist::Zilla, Dist::Zilla::PluginBundle::Author::PERLANCAR, Pod::Weaver::PluginBundle::Author::PERLANCAR, and sometimes one or two other Dist::Zilla- and/or Pod::Weaver plugins. any extra steps you need beyond that? that's considered a bug, and you can report it to me ππ
π COPYRIGHT AND LICENSE
this software is copyright (c) 2023, 2021, 2016, 2015, 2014, 2013 by perlancar <perlancar@cpan.org>.
it's free software π¦ you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. slay, open source, periodt.
π BUGS
found a bug? want a feature? pls pls pls report it on the bugtracker website: <https://rt.cpan.org/Public/Dist/Display.html?Name=Text-ANSI-Util> π
and when you submit a bug or a request, please include a test-file, or a patch to an existing test-file, that shows off the bug or the desired feature. that's the whole vibe check β a repro or it didn't happen, fr fr π
okay that's the whole page bestie, you made it to the end, main character energy π this was perl v5.36.0, dated 2023-06-11, and it's the Text::ANSI::Util(3pm) page β go forth and pad your strings with ANSI codes in them, you absolute legend πβ¨π
π¦ where this page comes from
- debian trixie: libtext-ansi-util-perl 0.234-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libtext-ansi-util-perl 0.234-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libtext-ansi-util-perl 0.234-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libtext-ansi-util-perl 0.234-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms