File Coverage

blib/lib/App/ansicolumn/Util.pm
Criterion Covered Total %
statement 35 136 25.7
branch 0 46 0.0
condition 0 36 0.0
subroutine 12 39 30.7
pod 0 22 0.0
total 47 279 16.8


line stmt bran cond sub pod time code
1             package App::ansicolumn;
2              
3 1     1   14 use v5.14;
  1         3  
4 1     1   5 use warnings;
  1         2  
  1         28  
5 1     1   5 use utf8;
  1         12  
  1         4  
6              
7             ######################################################################
8             # Object interface
9             ######################################################################
10              
11             sub get_border {
12 0 0   0 0   my $border = shift->{BORDER} or return "";
13 0           $border->get(@_);
14             }
15              
16             sub border_width {
17 1     1   97 use List::Util qw(sum);
  1         2  
  1         111  
18 0     0 0   my $obj = shift;
19 0           sum map length($obj->get_border($_)), @_;
20             }
21              
22 1     1   7 use Text::ANSI::Fold qw(:constants);
  1         2  
  1         394  
23              
24             my %lb_flag = (
25             '' => LINEBREAK_NONE,
26             none => LINEBREAK_NONE,
27             runin => LINEBREAK_RUNIN,
28             runout => LINEBREAK_RUNOUT,
29             all => LINEBREAK_ALL,
30             );
31              
32             sub lb_flag {
33 0     0 0   $lb_flag{shift->linebreak};
34             }
35              
36             sub runin_margin {
37 0     0 0   my $obj = shift;
38 0 0         if ($lb_flag{$obj->linebreak} & LINEBREAK_RUNIN) {
39 0           $obj->runin;
40             } else {
41 0           0;
42             }
43             }
44              
45             sub term_size {
46 0   0 0 0   @{ shift->{TERM_SIZE} //= [ terminal_size() ] };
  0            
47             }
48              
49             sub term_width {
50 0     0 0   (shift->term_size)[0];
51             }
52              
53             sub term_height {
54 0     0 0   (shift->term_size)[1];
55             }
56              
57             sub get_width {
58 0     0 0   my $obj = shift;
59 0 0         $obj->width || $obj->term_width;
60             }
61              
62             sub effective_height {
63 0     0 0   my $obj = shift;
64 0           $obj->height - $obj->border_height;
65             }
66              
67             sub foldobj {
68 0     0 0   my $obj = shift;
69 0           my $width = shift;
70 1     1   14 use Text::ANSI::Fold;
  1         2  
  1         802  
71 0           my $fold = Text::ANSI::Fold->new(
72             width => $width,
73             boundary => $obj->boundary,
74             linebreak => $obj->lb_flag,
75             runin => $obj->runin,
76             runout => $obj->runout,
77             ambiguous => $obj->ambiguous,
78             padchar => $obj->padchar,
79             padding => 1,
80             );
81 0 0         if ($obj->discard_el) {
82 0           $fold->configure(discard => [ 'EL' ] );
83             }
84 0           $fold;
85             }
86              
87             sub foldsub {
88 0     0 0   my $obj = shift;
89 0           my $width = shift;
90 0           my $fold = $obj->foldobj($width);
91 0 0         if ((my $ls = $obj->linestyle) eq 'truncate') {
    0          
92 0     0     sub { ($fold->fold($_[0]))[0] };
  0            
93             } elsif ($ls eq 'wrap') {
94 0     0     sub { $fold->text($_[0])->chops };
  0            
95             } else {
96 0           undef;
97             }
98             }
99              
100             sub set_layout {
101 0     0 0   my $obj = shift;
102 0           my $dp = shift;
103 0           $obj->do_pagebreak($dp)
104             ->do_space_layout($dp)
105             ->do_fillup($dp);
106 0           return $obj;
107             }
108              
109             sub do_space_layout {
110 0     0 0   my $obj = shift;
111 0           my($dp) = @_;
112 0   0       my $height = $obj->effective_height || die;
113 0 0         return if $height <= 0;
114 0           for (my $page = 0; (my $top = $page * $height) < @$dp; $page++) {
115 0 0 0       if ($height >= 4 and $top > 2 and !$obj->isolation) {
      0        
116 0 0 0       if ($dp->[$top - 2] !~ /\S/ and
      0        
117             $dp->[$top - 1] =~ /\S/ and
118             $dp->[$top ] =~ /\S/
119             ) {
120 0           splice @$dp, $top - 1, 0, '';
121 0           next;
122             }
123             }
124 0 0         if (not $obj->white_space) {
125 0   0       while ($top < @$dp and $dp->[$top] !~ /\S/) {
126 0           splice @$dp, $top, 1;
127             }
128             }
129             }
130 0           return $obj;
131             }
132              
133             sub _fillup {
134 0     0     my($dp, $len, $str) = @_;
135 0 0         if (my $remmant = @$dp % $len) {
136 0           push @$dp, ($str) x ($len - $remmant);
137             }
138             }
139              
140             sub do_fillup {
141 0     0 0   my $obj = shift;
142 0           my $dp = shift;
143 0   0       my $line = $obj->effective_height || die;
144 0 0 0       defined $obj->fillup and $obj->fillup !~ /^(?:no|none)$/
145             or return;
146 0   0       $obj->{fillup} ||= 'pane';
147 0 0         $line *= $obj->panes if $obj->fillup eq 'page';
148 0           _fillup $dp, $line, $obj->fillup_str;
149 0           return $obj;
150             }
151              
152             sub do_pagebreak {
153 0     0 0   my $obj = shift;
154 0 0         $obj->pagebreak or return;
155 0           my $dp = shift;
156 0   0       my $height = $obj->effective_height || die;
157 0           my @up;
158 1     1   7 use List::Util qw(first);
  1         3  
  1         391  
159 0     0     while (defined(my $i = first { $dp->[$_] =~ /\f/ } 0 .. $#{$dp})) {
  0            
  0            
160 0           push @up, splice @$dp, 0, $i;
161 0 0         $dp->[0] =~ s/^([^\f]*)\f// or die;
162 0 0         push @up, $1, if $1 ne '';
163 0           _fillup \@up, $height, $obj->fillup_str;
164             }
165 0 0         unshift @$dp, @up if @up;
166 0           return $obj;
167             }
168              
169             ######################################################################
170              
171             sub newlist {
172 0     0 0   my %arg = (count => 0);
173 0   0       while (@_ and not ref $_[0]) {
174 0           my($name, $value) = splice(@_, 0, 2);
175 0           $arg{$name} = $value;
176             }
177 0           my @list = ($arg{default}) x $arg{count};
178 0           while (my($index, $value) = splice(@_, 0, 2)) {
179 0 0         $index = [ $index ] if not ref $index;
180 0           @list[@$index] = ($value) x @$index;
181             }
182 0           @list;
183             }
184              
185             sub div {
186 1     1   7 use integer;
  1         2  
  1         5  
187 0     0 0   my($a, $b) = @_;
188 0           ($a + $b - 1) / $b;
189             }
190              
191             sub roundup ($$;$) {
192 1     1   71 use integer;
  1         3  
  1         3  
193 0     0 0   my($a, $b, $c) = @_;
194 0 0         return $a if $b == 0;
195 0   0       div($a + ($c // 0), $b) * $b;
196             }
197              
198             sub terminal_size {
199 1     1   555 use Term::ReadKey;
  1         1981  
  1         133  
200 0     0 0   my @default = (80, 24);
201 0           my @size;
202 0 0         if (open my $tty, ">", "/dev/tty") {
203             # Term::ReadKey 2.31 on macOS 10.15 has a bug in argument handling
204             # and the latest version 2.38 fails to install.
205             # This code should work on both versions.
206 0           @size = GetTerminalSize $tty, $tty;
207             }
208 0 0         @size ? @size : @default;
209             }
210              
211             sub xpose {
212 1     1   7 use List::Util 1.56 qw(zip);
  1         21  
  1         108  
213 0     0 0   map { [ grep { defined } @$_ ] } zip @_;
  0            
  0            
214             }
215              
216             sub insert_space {
217 1     1   7 use List::Util qw(reduce);
  1         1  
  1         177  
218 0           map { @$_ } reduce {
219 0 0 0 0     [ @$a, (@$a && $a->[-1] ne '' && $b ne '' ? '' : ()), $b ]
220 0     0 0   } [], @_;
221             }
222              
223             sub decode_argv {
224             map {
225 0 0   0 0   utf8::is_utf8($_) ? $_ : decode('utf8', $_);
  0            
226             }
227             @_;
228             }
229              
230             1;