File Coverage

blib/lib/Text/Wrap.pm
Criterion Covered Total %
statement 65 67 97.0
branch 30 36 83.3
condition 8 9 88.8
subroutine 11 11 100.0
pod 0 2 0.0
total 114 125 91.2


line stmt bran cond sub pod time code
1 18     18   16563 use strict; use warnings;
  18     18   125  
  18         483  
  18         92  
  18         29  
  18         790  
2              
3             package Text::Wrap;
4              
5 18     18   108 use warnings::register;
  18         35  
  18         3605  
6              
7 18     18   119 BEGIN { require Exporter; *import = \&Exporter::import }
  18         2150  
8              
9             our @EXPORT = qw( wrap fill );
10             our @EXPORT_OK = qw( $columns $break $huge );
11              
12             our $VERSION = '2023.0509';
13             our $SUBVERSION = 'modern'; # back-compat vestige
14              
15 18     18   5680 BEGIN { eval sprintf 'sub REGEXPS_USE_BYTES () { %d }', pack('U*', 0x80) =~ /\xc2/ }
16              
17             my $brkspc = "\x{a0}\x{202f}" =~ /\s/ ? '[^\x{a0}\x{202f}\S]' : '\s';
18              
19             our $columns = 76; # <= screen width
20             our $break = '(?>\n|\r\n|'.$brkspc.'\pM*)';
21             our $huge = 'wrap'; # alternatively: 'die' or 'overflow'
22             our $unexpand = 1;
23             our $tabstop = 8;
24             our $separator = "\n";
25             our $separator2 = undef;
26              
27 17     17   10116 sub _xlen { $_[0] =~ /^\pM/ + ( () = $_[0] =~ /\PM/g ) }
  17     221   235  
  17         268  
  221         956  
28              
29 18     18   386246 use Text::Tabs qw(expand unexpand);
  18         91  
  18         4584  
30              
31             sub wrap
32             {
33 110 100   110 0 9211 my ($ip, $xp, @t) = map +( defined $_ ? $_ : '' ), @_;
34              
35 110         248 local($Text::Tabs::tabstop) = $tabstop;
36 110         170 my $r = "";
37 110         173 my $tail = pop(@t);
38 110 100       2445 my $t = expand(join("", (map { /\s+\z/ ? ( $_ ) : ($_, ' ') } @t), $tail));
  57         296  
39 110         399 my $lead = $ip;
40 110         260 my $nll = $columns - _xlen(expand($xp)) - 1;
41 110 100 100     344 if ($nll <= 0 && $xp ne '') {
42 1         4 my $nc = _xlen(expand($xp)) + 2;
43 1         249 warnings::warnif "Increasing \$Text::Wrap::columns from $columns to $nc to accommodate length of subsequent tab";
44 1         10 $columns = $nc;
45 1         4 $nll = 1;
46             }
47 110         268 my $ll = $columns - _xlen(expand($ip)) - 1;
48 110 100       277 $ll = 0 if $ll < 0;
49 110         171 my $nl = "";
50 110         150 my $remainder = "";
51              
52 18     18   134 use re 'taint';
  18         38  
  18         9203  
53              
54 110         5811 pos($t) = 0;
55 110         1375 while ($t !~ /\G(?:$break)*\Z/gc) {
56 395 100 100     9419 if ($t =~ /\G((?>(?!\n)\PM\pM*|(?
    100 66        
    100          
    50          
    50          
57 355 50       126362 $r .= $unexpand
58             ? unexpand($nl . $lead . $1)
59             : $nl . $lead . $1;
60 355         882 $remainder = $2;
61             } elsif ($huge eq 'wrap' && $t =~ /\G((?>(?!\n)\PM\pM*|(?
62 27 50       15907 $r .= $unexpand
63             ? unexpand($nl . $lead . $1)
64             : $nl . $lead . $1;
65 27 100       84 $remainder = defined($separator2) ? $separator2 : $separator;
66             } elsif ($huge eq 'overflow' && $t =~ /\G([^\n]*?)(?!(?
67 12 50       2425 $r .= $unexpand
68             ? unexpand($nl . $lead . $1)
69             : $nl . $lead . $1;
70 12         33 $remainder = $2;
71             } elsif ($huge eq 'die') {
72 0         0 die "couldn't wrap '$t'";
73             } elsif ($columns < 2) {
74 1         262 warnings::warnif "Increasing \$Text::Wrap::columns from $columns to 2";
75 1         11 $columns = 2;
76 1         4 return @_;
77             } else {
78 0         0 die "This shouldn't happen";
79             }
80            
81 394         1121 $lead = $xp;
82 394         570 $ll = $nll;
83 394 100       2298 $nl = defined($separator2)
    100          
84             ? ($remainder eq "\n"
85             ? "\n"
86             : $separator2)
87             : $separator;
88             }
89 109         400 $r .= $remainder;
90              
91 109 50       317 $r .= $lead . substr($t, pos($t), length($t) - pos($t))
92             if pos($t) ne length($t);
93              
94             # the 5.6 regexp engine ignores the UTF8 flag, so using capture buffers acts as an implicit _utf8_off
95             # that means on 5.6 we now have to manually set UTF8=on on the output if the input had it, for which
96             # we extract just the UTF8 flag from the input and check if it forces chr(0x80) to become multibyte
97 109         405 return REGEXPS_USE_BYTES && (substr($t,0,0)."\x80") =~ /\xc2/ ? pack('U0a*', $r) : $r;
98             }
99              
100             sub fill
101             {
102 2 100   2 0 68 my ($ip, $xp, @raw) = map +( defined $_ ? $_ : '' ), @_;
103 2         8 my @para;
104             my $pp;
105              
106 2         25 for $pp (split(/\n\s+/, join("\n",@raw))) {
107 11         134 $pp =~ s/\s+/ /g;
108 11         30 my $x = wrap($ip, $xp, $pp);
109 11         27 push(@para, $x);
110             }
111              
112             # if paragraph_indent is the same as line_indent,
113             # separate paragraphs with blank lines
114              
115 2 100       9 my $ps = ($ip eq $xp) ? "\n\n" : "\n";
116 2         10 return join ($ps, @para);
117             }
118              
119             1;
120              
121             __END__