Actions Status MetaCPAN Release

NAME

Text::ANSI::Fold - Text folding library supporting ANSI terminal sequence and Asian wide characters with prohibition character handling.

VERSION

Version 2.3305

SYNOPSIS

use Text::ANSI::Fold qw(ansi_fold);
($folded, $remain) = ansi_fold($text, $width, [ option ]);

use Text::ANSI::Fold;
my $f = Text::ANSI::Fold->new(width => 80, boundary => 'word');
$f->configure(ambiguous => 'wide');
($folded, $remain) = $f->fold($text);

use Text::ANSI::Fold;
while (<>) {
    print join "\n",
        Text::ANSI::Fold->new(width => 40, text => $_)->chops;
}

use Text::ANSI::Fold qw(:constants);
my $fold = Text::ANSI::Fold->new(
    width     => 70,
    boundary  => 'word',
    linebreak => LINEBREAK_ALL,
    runin     => 4,
    runout    => 4,
);

DESCRIPTION

Text::ANSI::Fold provides capability to divide a text into two parts by given width. Text can include ANSI terminal sequences and the width is calculated by its visible representation. If the text is divided in the middle of colored region, reset sequence is appended to the former text, and color recover sequence is inserted before the latter string.

OSC 8 hyperlink sequences are also handled properly. If the text is divided in the middle of a hyperlink, the link is closed at the end of the former text and reopened at the beginning of the latter string.

This module also support Unicode Asian full-width and non-spacing combining characters properly. Japanese text formatting with head-or-end of line prohibition character is also supported. Set the linebreak mode to enable it.

Since the overhead of ANSI escape sequence handling is not significant when the data does not include them, this module can be used for normal text processing with small penalty.

ansi_fold

Use exported ansi_fold function to fold original text, with number of visual columns you want to cut off the text.

($folded, $remain, $w) = ansi_fold($text, $width);

It returns a pair of strings; first one is folded text, and second is the rest.

Additional third result is visual width of the folded text. It is not always same as given width, and you may want to know how many columns returned string takes for further processing.

Negative width value is taken as unlimited. So the string is never folded, but you can use this to expand tabs and to get visual string width.

This function returns at least one character in any situation. If you provide Asian wide string and just one column as width, it trims off the first wide character even if it does not fit to given width.

configure

Default parameter can be set by configure class method:

Text::ANSI::Fold->configure(width => 80, padding => 1);

Then you don't have to pass second argument.

($folded, $remain) = ansi_fold($text);

Because second argument is always taken as width, use undef when using default width with additional parameter:

($folded, $remain) = ansi_fold($text, undef, padding => 1);

Some other easy-to-use interfaces are provided by sister module Text::ANSI::Fold::Util.

OBJECT INTERFACE

You can create an object to hold parameters, which is effective during object life time.

new

Use new method to make a fold object.

my $obj = Text::ANSI::Fold->new(
    width => 80,
    boundary => 'word',
);

This makes an object folding on word boundaries with 80 columns width.

fold

Then you can call fold method without parameters because the object keeps necessary information.

$obj->fold($text);

configure

Use configure method to update parameters:

$obj->configure(padding => 1);

Additional parameter can be specified on each call, and they precede saved value.

$obj->fold($text, width => 40);

STRING OBJECT INTERFACE

You can use a fold object to hold string inside, and take out folded strings from it. Use text method to store data in the object, and retrieve or chops method to take out folded string from it.

text

A fold object can hold string inside by text method.

$obj->text("text");

Method text has an lvalue attribute, so it can be assigned to, as well as can be a subject of mutating operator such as s///.

$obj->text = "text";

retrieve

Folded string can be taken out by retrieve method. It returns empty string if nothing remained.

while ((my $folded = $obj->retrieve) ne '') {
    print $folded;
    print "\n" if $folded !~ /\n\z/;
}

chops

Method chops returns chopped string list. Because the text method returns the object itself when called with a parameter, you can use text and chops in series:

print join "\n", $obj->text($string)->chops;

Actually, text can be set by new or configure method through text parameter. Next program just works.

use Text::ANSI::Fold;
while (<>) {
    print join "\n",
        Text::ANSI::Fold->new(width => 40, text => $_)->chops;
}

chops with multiple width

When using chops method, width parameter can take array reference, and chops text into given width list.

my $fold = Text::ANSI::Fold->new;
my @list = $fold->text("1223334444")->chops(width => [ 1, 2, 3 ]);
# return ("1", "22", "333") and keep "4444"

If the width value is 0, it returns empty string. Negative width value takes all the rest of stored string. In the following code, the fourth width (3) is ignored because the -2 immediately preceding it consumes all remaining strings.

my $fold = Text::ANSI::Fold->new;
my @list = $fold->text("1223334444")->chops(width => [ 1, 0, -2, 3 ]);
# return ("1", "", "223334444")

The padding operation is performed only on the last non-empty element, and no elements corresponding to subsequent items are returned. Also, of course, padding is not performed for negative widths.

OPTIONS

Option parameter can be specified as name-value list for ansi_fold function as well as new and configure method.

ansi_fold($text, $width, boundary => 'word', ...);

Text::ANSI::Fold->configure(boundary => 'word');

my $obj = Text::ANSI::Fold->new(boundary => 'word');

$obj->configure(boundary => 'word');

EXAMPLE

Next code implements almost fully-equipped fold command for multi byte text with Japanese prohibited character handling.

#!/usr/bin/env perl

use strict;
use warnings;
use open IO => 'utf8', ':std';

use Text::ANSI::Fold qw(:constants);
my $fold = Text::ANSI::Fold->new(
    width     => 70,
    boundary  => 'word',
    linebreak => LINEBREAK_ALL,
    runin     => 4,
    runout    => 4,
);

$, = "\n";
while (<>) {
    print $fold->text($_)->chops;
}

CONTROL CHARACTERS

Text::ANSI::Fold handles the following line break related codes specially:

Newline (\n)
Form feed (\f)
Carriage return (\r)
Null (\0)
Line separator (U+2028)
Paragraph separator (U+2029)

These characters are handled as follows:

OSC 8 HYPERLINKS

This module handles OSC 8 hyperlink sequences. The OSC (Operating System Command) is defined in ECMA-48, and OSC 8 is an extension for terminal hyperlinks.

The command string in OSC is defined in ECMA-48 8.3.89 to consist of characters in the range 00/08-00/13 and 02/00-07/14. However, this module extends the definition to accept non-ASCII characters, since they may appear in URLs even though the OSC 8 specification recommends URI encoding. The behavior for non-ASCII is undefined in the spec, but this module tolerates it for practical compatibility.

The only exception is U+009C (STRING TERMINATOR), which is excluded because it terminates the OSC sequence.

SEE ALSO

AUTHOR

Kazumasa Utashiro

LICENSE

Copyright ©︎ 2018-2025 Kazumasa Utashiro.

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