File Coverage

blib/lib/Term/Choose/LineFold.pm
Criterion Covered Total %
statement 32 117 27.3
branch 1 44 2.2
condition 0 12 0.0
subroutine 9 10 90.0
pod 1 1 100.0
total 43 184 23.3


line stmt bran cond sub pod time code
1             package Term::Choose::LineFold;
2              
3 3     3   17 use warnings;
  3         4  
  3         157  
4 3     3   14 use strict;
  3         4  
  3         58  
5 3     3   29 use 5.10.1;
  3         10  
6              
7             our $VERSION = '1.782';
8              
9 3     3   15 use Exporter qw( import );
  3         3  
  3         177  
10              
11             our @EXPORT_OK = qw( char_width print_columns cut_to_printwidth adjust_to_printwidth line_fold );
12              
13 3     3   14 use Carp qw( croak );
  3         4  
  3         154  
14              
15 3     3   13 use Term::Choose::Constants qw( PH SGR_ES EXTRA_W );
  3         5  
  3         162  
16 3     3   1493 use Term::Choose::Screen qw( get_term_size );
  3         32  
  3         945  
17              
18             BEGIN {
19 3     3   10 my $module;
20             eval {
21 3         564 require Term::Choose::LineFold::XS;
22 0         0 Term::Choose::LineFold::XS->VERSION( 0.001 );
23 0         0 $module = 'Term::Choose::LineFold::XS';
24 0         0 1;
25 3 50       7 } or do {
26 3         2544 require Term::Choose::LineFold::PP;
27 3         14 $module = 'Term::Choose::LineFold::PP';
28             };
29 3     3   41 no strict qw( refs );
  3         6  
  3         351  
30 3         9 for my $func ( qw( char_width print_columns cut_to_printwidth adjust_to_printwidth ) ) {
31 12         19 *{"Term::Choose::LineFold::$func"} = \&{"${module}::$func"};
  12         4969  
  12         85  
32             }
33             }
34             #BEGIN {
35             # my $module;
36             # eval {
37             # require Term::Choose::LineFold::XS;
38             # Term::Choose::LineFold::XS->VERSION( 0.001 );
39             # $module = 'Term::Choose::LineFold::XS';
40             # 1;
41             # } or do {
42             # require Term::Choose::LineFold::PP;
43             # $module = 'Term::Choose::LineFold::PP';
44             # };
45             # *Term::Choose::LineFold::char_width = \&{"${module}::char_width"};
46             # *Term::Choose::LineFold::print_columns = \&{"${module}::print_columns"};
47             # *Term::Choose::LineFold::cut_to_printwidth = \&{"${module}::cut_to_printwidth"};
48             # *Term::Choose::LineFold::adjust_to_printwidth = \&{"${module}::adjust_to_printwidth"};
49             #}
50              
51              
52             sub line_fold {
53 0     0 1   my ( $str, $opt ) = @_; # copy $str
54 0 0         if ( ! length $str ) {
55 0           return $str;
56             }
57 0   0       $opt //= {};
58 0   0       $opt->{join} //= 1;
59 0   0       $opt->{truncate_long_tabs} //= 1;
60 0 0         if ( ! defined $opt->{width} ) {
    0          
61 0           my ( $term_width, undef ) = get_term_size();
62 0           $opt->{width} = $term_width + EXTRA_W;
63             }
64             elsif ( $opt->{width} !~ /^[1-9][0-9]*\z/ ) {
65 0           croak "Option 'width': '$opt->{width}' is not an Integer 1 or greater!";
66             }
67 0           my $max_tab_width = int( $opt->{width} / 2 );
68 0           for ( $opt->{init_tab}, $opt->{subseq_tab} ) {
69 0 0         if ( length ) {
70 0 0         if ( /^[0-9]+\z/ ) {
71 0           $_ = ' ' x $_;
72             }
73             else {
74 0           s/\t/ /g;
75 0           s/\v+/\ \ /g; ##
76 0           s/[\p{Cc}\p{Noncharacter_Code_Point}\p{Cs}]//g;
77             }
78 0 0 0       if ( $opt->{truncate_long_tabs} && length > $max_tab_width ) {
79 0           $_ = cut_to_printwidth( $_, $max_tab_width );
80             }
81             }
82             else {
83 0           $_ = '';
84             }
85             }
86 0           my @color;
87 0 0         if ( $opt->{color} ) {
88 0           $str =~ s/${\PH}//g;
  0            
89 0 0         $str =~ s/(${\SGR_ES})/push( @color, $1 ) && ${\PH}/ge;
  0            
  0            
  0            
90             }
91 0 0 0       if ( $opt->{binary_filter} && substr( $str, 0, 100 ) =~ /[\x00-\x08\x0B-\x0C\x0E-\x1F]/ ) {
92             #$str = $self->{binary_filter} == 2 ? sprintf("%v02X", $_[0]) =~ tr/./ /r : 'BNRY'; # perl 5.14
93 0 0         if ( $opt->{binary_filter} == 2 ) {
94 0           ( $str = sprintf( "%v02X", $_[0] ) ) =~ tr/./ /; # use unmodified string
95             }
96             else {
97 0           $str = 'BNRY';
98             }
99             }
100 0           $str =~ s/\t/ /g;
101 0           $str =~ s/[^\v\P{Cc}]//g; # remove control chars but keep vertical spaces
102 0           $str =~ s/[\p{Noncharacter_Code_Point}\p{Cs}]//g;
103 0           my @paragraphs;
104              
105 0           for my $row ( split /\R/, $str, -1 ) { # -1 to keep trailing empty fields
106 0           my @lines;
107 0           $row =~ s/\s+\z//;
108 0           my @words = split( /(?<=\S)(?=\s)/, $row );
109 0           my $line = $opt->{init_tab};
110              
111 0           for my $i ( 0 .. $#words ) {
112 0 0         if ( print_columns( $line . $words[$i] ) <= $opt->{width} ) {
113 0           $line .= $words[$i];
114             }
115             else {
116 0           my $tmp;
117 0 0         if ( $i == 0 ) {
118 0           $tmp = $opt->{init_tab} . $words[$i];
119             }
120             else {
121 0           push( @lines, $line );
122 0           $words[$i] =~ s/^\s+//;
123 0           $tmp = $opt->{subseq_tab} . $words[$i];
124             }
125 0           ( $line, my $remainder ) = cut_to_printwidth( $tmp, $opt->{width} );
126 0           while ( length $remainder ) {
127 0           push( @lines, $line );
128 0           $tmp = $opt->{subseq_tab} . $remainder;
129 0           ( $line, $remainder ) = cut_to_printwidth( $tmp, $opt->{width} );
130             }
131             }
132 0 0         if ( $i == $#words ) {
133 0           push( @lines, $line );
134             }
135             }
136 0 0         if ( $opt->{join} ) {
137 0           push( @paragraphs, join( "\n", @lines ) );
138             }
139             else {
140 0 0         if ( @lines ) {
141 0           push( @paragraphs, @lines );
142             }
143             else {
144 0           push( @paragraphs, '' );
145             }
146             }
147             }
148 0 0         if ( @color ) {
149 0           my $last_color;
150 0           for my $paragraph ( @paragraphs ) {
151 0 0         if ( ! $opt->{join} ) {
152 0 0         if ( $last_color ) {
153 0           $paragraph = $last_color . $paragraph;
154             }
155 0           my $count = () = $paragraph =~ /${\PH}/g;
  0            
156 0 0         if ( $count ) {
157 0           $last_color = $color[$count - 1];
158             }
159             }
160 0           $paragraph =~ s/${\PH}/shift @color/ge;
  0            
  0            
161 0 0         if ( ! @color ) {
162 0           last;
163             }
164             }
165 0           $paragraphs[-1] .= "\e[0m";
166             }
167 0 0         if ( $opt->{join} ) {
168 0           return join( "\n", @paragraphs );
169             }
170             else {
171 0           return @paragraphs;
172             }
173             }
174              
175              
176              
177             1;
178              
179             __END__