package Indent::Word;
use strict;
use warnings;
use Class::Utils qw(set_params);
use English qw(-no_match_vars);
use Error::Pure qw(err);
use Indent::Utils qw(line_size_check);
use Readonly;
# Constants.
Readonly::Scalar my $EMPTY_STR => q{};
Readonly::Scalar my $LINE_SIZE => 79;
our $VERSION = 0.08;
# Constructor.
sub new {
my ($class, @params) = @_;
my $self = bless {}, $class;
# Use with ANSI sequences.
$self->{'ansi'} = undef;
# Options.
$self->{'line_size'} = $LINE_SIZE;
$self->{'next_indent'} = "\t";
# Output.
$self->{'output_separator'} = "\n";
# Process params.
set_params($self, @params);
# 'line_size' check.
line_size_check($self);
if (! defined $self->{'ansi'}) {
if (exists $ENV{'NO_COLOR'}) {
$self->{'ansi'} = 0;
} elsif (defined $ENV{'COLOR'}) {
$self->{'ansi'} = 1;
} else {
$self->{'ansi'} = 0;
}
}
# Check rutine for removing ANSI sequences.
if ($self->{'ansi'}) {
eval {
require Text::ANSI::Util;
};
if ($EVAL_ERROR) {
err "Cannot load 'Text::ANSI::Util' module.";
}
}
# Object.
return $self;
}
# Indent text by words to line_size block size.
sub indent {
my ($self, $data, $indent, $non_indent) = @_;
# 'indent' initialization.
if (! defined $indent) {
$indent = $EMPTY_STR;
}
# If non_indent data, than return.
if ($non_indent) {
return $indent.$data;
}
my ($first, $second) = (undef, $indent.$data);
my $last_second_length = 0;
my @data;
my $one = 1;
while ($self->_length($second) >= $self->{'line_size'}
&& $second =~ /^\s*\S+\s+/ms
&& $last_second_length != $self->_length($second)) {
# Last length of non-parsed part of data.
$last_second_length = $self->_length($second);
# Parse to indent length.
($first, my $tmp) = $self->_parse_to_indent_length($second);
# If string is non-breakable in indent length, than parse to
# blank char.
if (! $first
|| $self->_length($first) < $self->_length($indent)
|| $first =~ /^$indent\s*$/ms) {
($first, $tmp) = $second
=~ /^($indent\s*[^\s]+?)\s(.*)$/msx;
}
# If parsing is right.
if ($tmp) {
# Non-parsed part of data.
$second = $tmp;
# Add next_indent to string.
if ($one == 1) {
$indent .= $self->{'next_indent'};
}
$one = 0;
$second = $indent.$second;
# Parsed part of data to @data array.
push @data, $first;
}
}
# Add other data to @data array.
$second =~ s/\s+$//ms;
if ($second) {
push @data, $second;
}
# Return as array or one line with output separator between its.
return wantarray ? @data : join($self->{'output_separator'}, @data);
}
# Get length.
sub _length {
my ($self, $string) = @_;
if ($self->{'ansi'}) {
return length Text::ANSI::Util::ta_strip($string);
} else {
return length $string;
}
}
# Parse to indent length.
sub _parse_to_indent_length {
my ($self, $string) = @_;
my @ret;
if ($self->{'ansi'}) {
my $string_wo_ansi = Text::ANSI::Util::ta_strip($string);
# First part.
my ($first_wo_ansi) = $string_wo_ansi
=~ m/^(.{0,$self->{'line_size'}})\s+(.*)$/msx;
push @ret, Text::ANSI::Util::ta_trunc($string, length $first_wo_ansi);
# Second part. (Remove first part + whitespace from string.)
my $other_string_wo_ansi = Text::ANSI::Util::ta_strip(
Text::ANSI::Util::ta_substr($string, length $first_wo_ansi,
Text::ANSI::Util::ta_length($string))
);
$other_string_wo_ansi =~ m/^(\s*)/ms;
my $count_of_spaces = length $1;
push @ret, Text::ANSI::Util::ta_substr($string, 0, (length $first_wo_ansi)
+ $count_of_spaces, '');
} else {
@ret = $string =~ m/^(.{0,$self->{'line_size'}})\s+(.*)$/msx;
}
return @ret;
}
1;
__END__
=pod
=encoding utf8
=head1 NAME
Indent::Word - Class for word indenting.
=head1 SYNOPSIS
use Indent::Word;
my $obj = Indent::Word->new(%parameters);
my $string = $obj->indent('text text text');
my @data = $obj->indent('text text text');
=head1 METHODS
=head2 C<new>
my $obj = Indent::Word->new(%parameters);
Constructor.
Returns instance of object.
=over 8
=item * C<ansi>
Use with ANSI sequences.
Default value is:
- 1 if COLOR env variable is set
- 0 if NO_COLOR env variable is set
- 0 otherwise
=item * C<line_size>
Sets indent line size value.
Default value is 79.
=item * C<next_indent>
Sets output separator between indented datas for string context.
Default value is "\t" (tabelator).
=item * C<output_separator>
Output separator between data in scalar context.
Default value is "\n" (new line).
=back
=head2 C<indent>
my $string = $obj->indent('text text text');
or
my @data = $obj->indent('text text text');
Indent text by words to line_size block size.
$act_indent - Actual indent string. Will be in each output string.
$non_indent - Is flag for non indenting. Default is 0.
Returns string or array with data to print.
=head1 ENVIRONMENT
Output is controlled by env variables C<NO_COLOR> and C<COLOR>.
See L<https://no-color.org/>.
=head1 ERRORS
new():
Cannot load 'Text::ANSI::Util' module.
From Class::Utils::set_params():
Unknown parameter '%s'.
From Indent::Utils::line_size_check():
'line_size' parameter must be a positive number.
line_size => %s
=head1 EXAMPLE1
use strict;
use warnings;
use Indent::Word;
# Object.
my $i = Indent::Word->new(
'line_size' => 20,
);
# Indent.
print $i->indent(join(' ', ('text') x 7))."\n";
# Output:
# text text text text
# <--tab->text text text
=head1 EXAMPLE2
use strict;
use warnings;
use Indent::Word;
use Term::ANSIColor;
# Object.
my $i = Indent::Word->new(
'ansi' => 1,
'line_size' => 20,
);
# Indent.
print $i->indent('text text '.color('cyan').'text'.color('reset').
' text '.color('red').'text'.color('reset').' text text')."\n";
# Output:
# text text text text
# <--tab->text text text
=head1 DEPENDENCIES
L<Class::Utils>,
L<English>,
L<Error::Pure>,
L<Indent::Utils>,
L<Readonly>.
L<Text::ANSI::Util> for situation with 'ansi' => 1.
=head1 SEE ALSO
=over
=item L<Indent>
Class for indent handling.
=item L<Indent::Block>
Class for block indenting.
=item L<Indent::Data>
Class for data indenting.
=item L<Indent::String>
Class for text indenting.
=item L<Indent::Utils>
Utilities for Indent classes.
=item L<Text::Wrap>
line wrapping to form simple paragraphs
=back
=head1 REPOSITORY
L<https://github.com/michal-josef-spacek/Indent>
=head1 AUTHOR
Michal Josef Špaček L<mailto:skim@cpan.org>
L<http://skim.cz>
=head1 LICENSE AND COPYRIGHT
© 2005-2021 Michal Josef Špaček
BSD 2-Clause License
=head1 VERSION
0.08
=cut