File Coverage

blib/lib/App/sdif/Util.pm
Criterion Covered Total %
statement 67 93 72.0
branch 21 38 55.2
condition 6 11 54.5
subroutine 14 19 73.6
pod 0 9 0.0
total 108 170 63.5


line stmt bran cond sub pod time code
1             package App::sdif::Util;
2              
3 14     14   1831 use v5.14;
  14         51  
4 14     14   80 use warnings;
  14         26  
  14         931  
5 14     14   100 use Carp;
  14         23  
  14         1190  
6              
7 14     14   97 use Exporter 'import';
  14         28  
  14         1461  
8              
9             our @EXPORT = qw(
10             &read_line &read_until
11             &read_unified_sub &read_unified &read_unified_2
12             &range &terminal_width
13             );
14              
15             our @EXPORT_OK = qw(
16             &read_unified_3
17             );
18              
19 14     14   105 use Data::Dumper;
  14         52  
  14         1022  
20 14     14   88 use List::Util qw(sum);
  14         27  
  14         12508  
21              
22             our $MINILLA_CHANGES = 1;
23             our $NO_WARNINGS = 0;
24              
25             sub read_line ($$;@) {
26 13     13 0 80 local *FH = shift;
27 13         22 my $c = shift;
28 13         25 my @buf = @_;
29 13         132 while ($c--) {
30 42 50       77 last if eof FH;
31 42         139 push @buf, scalar ;
32             }
33 13 100       84 wantarray ? @buf : join '', @buf;
34             }
35              
36             sub read_until (&$) {
37 0     0 0 0 my($sub, $fh) = @_;
38 0         0 my @lines;
39 0         0 while (<$fh>) {
40 0         0 push @lines, $_;
41 0 0       0 return @lines if &$sub;
42             }
43 0         0 (@lines, undef);
44             }
45              
46             sub read_unified_2 {
47             map {
48 5     5 0 28 [ $_->collect(qr/[\t ]/) ], # common
  15         82  
49             [ $_->collect('-') ], # old
50             [ $_->collect('+') ], # new
51             } &read_unified;
52             }
53              
54             sub nth_re {
55 0     0 0 0 state @regex;
56 0         0 my $n = shift;
57 0   0     0 $regex[$n] //= do {
58 0         0 my $regex = sprintf "^(?:.{%d}-|(?=.*\\+).{%d}[ ])", $n, $n;
59 0         0 qr/$regex/;
60             };
61             }
62              
63             sub read_unified_3 {
64             map {
65 0     0 0 0 [ $_->collect(q/ / ) ], # common
  0         0  
66             [ $_->collect(nth_re(0)) ], # old ^(?:.{0}-|(?=.*\+).{0}[ ])
67             [ $_->collect(nth_re(1)) ], # new ^(?:.{1}-|(?=.*\+).{1}[ ])
68             [ $_->collect(qr/\+/ ) ], # merge
69             } &read_unified;
70             }
71              
72             sub read_unified_sub {
73 0     0 0 0 my $column = shift;
74 0         0 my @re = ( ' ' x ($column - 1),
75             map(nth_re($_), 0 .. $column - 2),
76             qr/\+/ );
77             sub {
78             map {
79 0     0   0 my $ent = $_;
  0         0  
80 0         0 map { [ $ent->collect($_) ] } @re;
  0         0  
81             } &read_unified;
82             }
83 0         0 }
84              
85             sub read_unified {
86             # Option: prefix, ORDER, NOWARN
87 15 50   15 0 66 my $opt = ref $_[0] eq 'HASH' ? shift : {};
88 15         58 my $FH = shift;
89 15         82 my $column = @_;
90 15         107 my $total = sum @_;
91 15   100     90 my $prefix = $opt->{prefix} // '';
92              
93 14     14   6967 use App::sdif::LabelStack;
  14         64  
  14         11251  
94              
95 15         43 my $mark_length = $column - 1;
96 15         42 my $start_label = ' ' x $mark_length;
97 15         29 my @lsopt = do {
98 15         65 map { $_->[0] => $_->[1] }
99 30         162 grep { $_->[1] }
100             ( [ START => $start_label ],
101 15         151 [ ORDER => $opt->{ORDER} ] );
102             };
103              
104             state $marklines = sub {
105 231     231   393 local $_ = shift;
106 231 100       1134 tr/-/-/ || tr/ / / + 1;
107 15         96 };
108              
109 15         214 my @stack = App::sdif::LabelStack->new(@lsopt);
110 15         120 while (<$FH>) {
111 231 100       640 if ($prefix) {
112 171 50       1296 s/^\Q$prefix// or do {
113 0 0       0 warn "Unexpected: $_" unless $NO_WARNINGS;
114             };
115 171 50       416 if ($MINILLA_CHANGES) {
116             # Minilla removes single space mark in git commit message.
117             # This is not perfect but mostly works.
118 171         436 s/^(?![-+ ])/ /;
119             }
120             }
121 231 50       1753 /^([-+ ]{$mark_length}|\t)/p or do {
122             # `git diff' produces message like this:
123             # "\ No newline at end of file"
124 0 0       0 if (/^\\ /) {
125 0         0 [$stack[-1]->lists]->[-1][-1] =~ s/\n\z//;
126             } else {
127 0 0       0 warn "Unexpected line: $_" unless $NO_WARNINGS;
128             }
129 0         0 next;
130             };
131 231         603 my $mark = $1;
132 231 50 66     661 if (($mark ne $stack[-1]->lastlabel) and
      66        
133             ($stack[-1]->exists($mark)
134             # all +
135             or $stack[-1]->lastlabel !~ /[^+]/
136             # no + after +
137             or ($stack[-1]->lastlabel =~ /[+]/ and $mark !~ /[+]/))) {
138 30         151 push @stack, App::sdif::LabelStack->new(@lsopt);
139             }
140 231         711 $stack[-1]->append($mark, $_);
141 231 50       676 $total -= $mark =~ /^\t/ ? $column : $marklines->($mark);
142 231 100       1251 last if $total <= 0;
143             }
144 15         89 @stack;
145             }
146              
147             sub range {
148 128     128 0 334 local $_ = shift;
149 128 100       1018 my($from, $to) = /,/ ? split(/,/) : ($_, $_);
150 128 100       822 wantarray ? ($from, $to) : $to - $from + 1;
151             }
152              
153             sub terminal_width {
154 14     14   8951 use Term::ReadKey;
  14         39412  
  14         2820  
155 1     1 0 9 my $default = 80;
156 1         1 my @size;
157 1 50       34 if (open my $tty, ">", "/dev/tty") {
158             # Term::ReadKey 2.31 on macOS 10.15 has a bug in argument handling
159             # and the latest version 2.38 fails to install.
160             # This code should work on both versions.
161 0         0 @size = GetTerminalSize $tty, $tty;
162             }
163 1 50       26 $size[0] or $default;
164             }
165              
166             1;