The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Text::ANSI::Util - Routines for text containing ANSI escape codes

VERSION

version 0.06

SYNOPSIS

 use Text::ANSI::Util qw(
     ta_detect ta_length ta_mbpad ta_mbswidth ta_mbswidth_height ta_mbwrap
     ta_pad ta_strip ta_wrap);

 # detect whether text has ANSI escape codes?
 say ta_detect("red");         # => false
 say ta_detect("\x1b[31mred"); # => true

 # calculate length of text (excluding the ANSI escape codes)
 say ta_length("red");         # => 3
 say ta_length("\x1b[31mred"); # => 3

 # calculate visual width of text if printed on terminal (can handle Unicode
 # wide characters and exclude the ANSI escape codes)
 say ta_mbswidth("\x1b[31mred"); # => 3
 say ta_mbswidth("\x1b[31m红色"); # => 4

 # ditto, but also return the number of lines
 say ta_mbswidth_height("\x1b[31mred\n红色"); # => [4, 2]

 # strip ANSI escape codes
 say ta_strip("\x1b[31mred"); # => "red"

 # split codes (ANSI codes are always on the even positions)
 my @parts = ta_split_codes("\x1b[31mred"); # => ("", "\x1b[31m", "red")

 # wrap text to a certain column width, handle ANSI escape codes
 say ta_wrap("....", 40);

 # ditto, but handle wide characters
 say ta_mbwrap(...);

 # pad (left, right, center) text to a certain width, handles multiple lines
 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"

 # ditto, but handle wide characters
 say ta_mbpad(...);

 # truncate text to a certain width while still passing ANSI escape 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"

 # ditto, but handle wide characters
 say ta_mbtrunc(...);

DESCRIPTION

This module provides routines for dealing with text containing ANSI escape codes (mainly ANSI color codes).

Current caveats:

  • All codes are assumed to have zero width

    This is true for color codes and some other codes, but there are also codes to alter cursor positions which means they can have negative or undefined width.

  • Single-character CSI (control sequence introducer) currently ignored

    Only ESC+[ (two-character CSI) is currently parsed.

    BTW, in ASCII terminals, single-character CSI is 0x9b. In UTF-8 terminals, it is 0xc2, 0x9b (2 bytes).

  • Private-mode- and trailing-intermediate character currently not parsed

FUNCTIONS

ta_detect($text) => BOOL

Return true if $text contains ANSI escape codes, false otherwise.

ta_length($text) => INT

Count the number of bytes in $text, while ignoring ANSI escape codes. Equivalent to length(ta_strip($text). See also: ta_mbswidth().

ta_mbswidth($text) => INT

Return visual width of $text (in number of columns) if printed on terminal. Equivalent to Text::CharWidth::mbswidth(ta_strip($text)). This function can be used e.g. in making sure that your text aligns vertically when output to the terminal in tabular/table format.

Note: mbswidth() handles \0 correctly (regard it as having zero width) but currently does not handle control characters like \n, \t, \b, \r, etc well (they are just counted as having -1). So make sure that your text does not contain those characters.

But at least ta_mbswidth() handles multiline text correctly, e.g.: ta_mbswidth("foo\nbarbaz") gives 6 instead of 3-1+8 = 8. It splits the input text first against /\r?\n/.

ta_mbswidth_height($text) => [INT, INT]

Like ta_mbswidth(), but also gives height (number of lines). For example, ta_mbswidth_height("foobar\nb\n") gives [6, 3].

ta_strip($text) => STR

Strip ANSI escape codes from $text, returning the stripped text.

ta_split_codes($text) => LIST

Split $text to a list containing alternating ANSI escape codes and text. ANSI escape codes are always on the second element, 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_wrap($text, $width) => STR

Wrap $text to $width columns.

$width defaults to 80 if not specified.

Note: currently performance is rather abysmal (~ 1200/s on my Core i5-2400 3.1GHz desktop for a ~ 1KB of text), so call this routine sparingly ;-).

ta_mbwrap($text, $width) => STR

Like ta_wrap(), but it uses ta_mbswidth() instead of ta_length(), so it can handle wide characters.

Note: for text which does not have whitespaces between words, like Chinese, you will have to separate the words first (e.g. using Lingua::ZH::WordSegmenter). The module also currently does not handle whitespace-like characters other than ASCII 32 (for example, the Chinese dot 。).

Note: currently performance is rather abysmal (~ 1000/s on my Core i5-2400 3.1GHz desktop for a ~ 1KB of text), so call this routine sparingly ;-).

ta_pad($text, $width[, $which[, $padchar[, $truncate]]]) => STR

Return $text padded with $padchar to $width columns. $which is either "r" or "right" for padding on the right (the default if not specified), "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 string having the width of 1 column.

Does *not* handle multiline text; you can split text by /\r?\n/ yourself.

ta_mbpad => STR

Like ta_pad() but it uses ta_mbswidth() instead of ta_length(), so it can handle wide characters.

ta_trunc($text, $width) => STR

Truncate $text to $width columns while still including all the ANSI escape codes. This ensures that truncated text still reset colors, etc.

Does *not* handle multiline text; you can split text by /\r?\n/ yourself.

ta_mbtrunc($text, $width) => STR

Like ta_trunc() but it uses ta_mbswidth() instead of ta_length(), so it can handle wide characters.

FAQ

How do I truncate string based on number of characters?

You can simply use Perl's ta_trunc() even on text containing wide characters. ta_trunc() uses Perl's length() which works on a per-character basis.

TODOS

SEE ALSO

Term::ANSIColor

AUTHOR

Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by Steven Haryanto.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 286:

Non-ASCII character seen before =encoding in 'ta_mbswidth("\x1b[31m红色");'. Assuming CP1252