File Coverage

blib/lib/App/ansicolumn/Border.pm
Criterion Covered Total %
statement 46 53 86.7
branch 9 16 56.2
condition 9 15 60.0
subroutine 11 12 91.6
pod 0 7 0.0
total 75 103 72.8


line stmt bran cond sub pod time code
1             package App::ansicolumn::Border;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             App::ansicolumn::Border - App::ansicolumn Border module
8              
9             =head1 DESCRIPTION
10              
11             Each item has five elements; C, C
, C, C,
12             C.
13              
14             C and C items have single string.
15              
16             C, C and C
items can hold string value or list
17             reference, and string value is equivalent to a list of single item.
18             If the list has single item, it is used on all positions. If the
19             second item exists, it is used on middle position. Third item is for
20             bottom position.
21              
22             Class method C can be used to add new border style.
23              
24             This is experimental implementation and subject to change.
25              
26             =cut
27              
28 32     32   451 use v5.14;
  32         122  
29 32     32   185 use warnings;
  32         58  
  32         1742  
30 32     32   187 use utf8;
  32         69  
  32         197  
31 32     32   1062 use Data::Dumper;
  32         173  
  32         81324  
32              
33             my %template = (
34             __DEFAULT__ => 'space',
35             space => {
36             top => '',
37             left => '',
38             center => ' ',
39             right => '',
40             bottom => '',
41             },
42             none => {
43             top => '',
44             left => '',
45             center => '',
46             right => '',
47             bottom => '',
48             },
49             side => { right => ' ' , left => ' ' },
50             left => { right => '' , left => ' ' },
51             line => {
52             center => "│ ", # "\x{2502} "
53             },
54             fat_line => {
55             center => [ "█ ", "░ " ], # "\x{2588} "
56             },
57             vbar => {
58             center => [ "╷ " , # "\x{2577} "
59             "│ " , # "\x{2502} "
60             "╵ " ], # "\x{2575} "
61             },
62             thick_vbar => {
63             center => [ "▗ " , # "\x{2597} "
64             "▐ " , # "\x{2590} "
65             "▝ " ], # "\x{259D} "
66             },
67             fat_vbar => {
68             center => [ "▄ " , # "\x{2584} "
69             "█ " , # "\x{2588} "
70             "▀ " ], # "\x{2580} "
71             },
72             hline => {
73             top => "─",
74             center => " ",
75             bottom => "─",
76             },
77             bottom_line => {
78             center => " ",
79             bottom => "─",
80             },
81             stick => {
82             center => [ "╻ " , # "\x{2577} "
83             "│ " , # "\x{2502} "
84             "╹ " ], # "\x{2575} "
85             },
86             ascii_frame => {
87             top => "-",
88             left => [ "+" , "|" ],
89             center => [ "+ +" , "| |" ],
90             right => [ "+" , "|" ],
91             bottom => "-",
92             },
93             ascii_box => {
94             top => "-",
95             left => [ "+" , "|" ],
96             center => [ "+" , "|" ],
97             right => [ "+" , "|" ],
98             bottom => "-",
99             },
100             c_box => {
101             top => '*',
102             left => [ '/**',
103             '/* ' ],
104             center => [ '**/ /**',
105             ' */ /* ' ],
106             right => [ '**/',
107             ' */' ],
108             bottom => '*',
109             },
110             c_box2 => {
111             top => '*',
112             left => [ '/**',
113             ' * ',
114             ' **' ],
115             center => [ '** /**',
116             ' * * ',
117             '**/ **' ],
118             right => [ '** ',
119             ' * ',
120             '**/' ],
121             bottom => '*',
122             },
123             box => {
124             top => "─",
125             left => [ "┌─" ,
126             "│ " ,
127             "└─" ],
128             center => [ "┐┌─" ,
129             "││ " ,
130             "┘└─" ],
131             right => [ "┐" ,
132             "│" ,
133             "┘" ],
134             bottom => "─",
135             },
136             dash_box => {
137             top => "╴",
138             left => [ "╷╴" ,
139             "╷ " ,
140             "╶╶" ],
141             center => [ "╴╷╴" ,
142             "╵╷ " ,
143             "╵╶╶" ],
144             right => [ "╴" ,
145             "╵" ,
146             "╵" ],
147             bottom => "╶",
148             },
149             round_box => {
150             top => "─",
151             left => [ "╭─" ,
152             "│ " ,
153             "╰─" ],
154             center => [ "╮╭─" ,
155             "││ " ,
156             "╯╰─" ],
157             right => [ "╮" ,
158             "│" ,
159             "╯" ],
160             bottom => "─",
161             },
162             inner_box => {
163             top => "▄",
164             left => [ "▗" ,
165             "▐" ,
166             "▝" ],
167             center => [ "▖▗" ,
168             "▌▐" ,
169             "▘▝" ],
170             right => [ "▖" ,
171             "▌" ,
172             "▘" ],
173             bottom => "▀",
174             },
175             outer_box => {
176             top => "▀",
177             left => [ "▛" ,
178             "▌" ,
179             "▙" ],
180             center => [ "▜▛" ,
181             "▐▌" ,
182             "▟▙" ],
183             right => [ "▜" ,
184             "▐" ,
185             "▟" ],
186             bottom => "▄",
187             },
188             ladder => {
189             top => "─",
190             bottom => "─",
191             left => [ "" ,
192             "" ,
193             "" ],
194             center => [ "┬─" ,
195             "│ " ,
196             "┴─" ],
197             right => [ "" ,
198             "" ,
199             "" ],
200             },
201             frame => {
202             top => "─",
203             bottom => "─",
204             left => [ "┌─" ,
205             "│ " ,
206             "└─" ],
207             center => [ "┬─" ,
208             "│ " ,
209             "┴─" ],
210             right => [ "┐" ,
211             "│" ,
212             "┘" ],
213             },
214             dash_frame => {
215             top => "╴",
216             left => [ "╷╴" ,
217             "╷ " ,
218             "╶╶" ],
219             center => [ "╴╴" ,
220             "╵ " ,
221             "└╶" ],
222             right => [ "╴" ,
223             "╵" ,
224             "╵" ],
225             bottom => "╶",
226             },
227             page_frame => {
228             top => "─",
229             left => [ "┌─" ,
230             "│ " ,
231             "└─" ],
232             center => [ "──" ,
233             " " ,
234             "──" ],
235             right => [ "┐" ,
236             "│" ,
237             "┘" ],
238             bottom => "─",
239             },
240             thin_shadow => {
241             top => "",
242             left => [ " " ,
243             " " ,
244             "▝" ],
245             center => [ " ▖ " ,
246             " ▌ " ,
247             "▀▘▝" ],
248             right => [ " ▖" ,
249             " ▌" ,
250             "▀▘" ],
251             bottom => "▀",
252             },
253             shadow => {
254             top => "",
255             left => [ " " ,
256             " " ,
257             " " ],
258             center => [ " ▄ " ,
259             " █ " ,
260             "▀▀ " ],
261             right => [ " ▄" ,
262             " █" ,
263             "▀▀" ],
264             bottom => "▀",
265             },
266             thin_shadow_box => {
267             top => "─",
268             left => [ "┌─" ,
269             "│ " ,
270             "└▄" ],
271             center => [ "─┐ ┌─" ,
272             " ▐ │ " ,
273             "▄▟ └▄" ],
274             right => [ "─┐" ,
275             " ▐" ,
276             "▄▟" ],
277             bottom => "▄",
278             },
279             shadow_box => {
280             top => "─",
281             left => [ "┌─" ,
282             "│ " ,
283             "└▄" ],
284             center => [ "─┐ ┌─" ,
285             " ▐▌│ " ,
286             "▄▟▌└▄" ],
287             right => [ "─┐ " ,
288             " ▐▌" ,
289             "▄▟▌" ],
290             bottom => "▄",
291             },
292             fat_box => {
293             top => "▀",
294             left => [ "█▀" ,
295             "█ " ,
296             "█▄" ],
297             center => [ "▀█ █▀" ,
298             " █ █ " ,
299             "▄█ █▄" ],
300             right => [ "▀█" ,
301             " █" ,
302             "▄█" ],
303             bottom => "▄",
304             },
305             very_fat_box => {
306             top => "█",
307             left => [ "███" ,
308             "██ " ,
309             "███" ],
310             center => [ "███ ███" ,
311             " ██ ██ " ,
312             "███ ███" ],
313             right => [ "███" ,
314             " ██" ,
315             "███" ],
316             bottom => "█",
317             },
318             fat_frame => {
319             top => "▀",
320             left => [ "█▀" ,
321             "█ " ,
322             "█▄" ],
323             center => [ "▀█▀" ,
324             " █ " ,
325             "▄█▄" ],
326             right => [ "▀█" ,
327             " █" ,
328             "▄█" ],
329             bottom => "▄",
330             },
331             very_fat_frame => {
332             top => "█",
333             left => [ "███" ,
334             "██ " ,
335             "███" ],
336             center => [ "████" ,
337             " ██ " ,
338             "████" ],
339             right => [ "███" ,
340             " ██" ,
341             "███" ],
342             bottom => "█",
343             },
344             fat_dash_box => {
345             top => "▘",
346             left => [ "▘", "▘", "▚" ],
347             center => [ "▚ ▘", "▗ ▘", "▗ ▚" ],
348             right => [ "▚", "▗", "▗" ],
349             bottom => "▗",
350             },
351             fat_dash_frame => {
352             top => "▘",
353             left => [ "▘", "▘", "▚" ],
354             center => [ "▚▘", "▗ ", "▗▗" ],
355             right => [ "▚", "▗", "▗" ],
356             bottom => "▗",
357             },
358             zebra_frame => {
359             top => "▘",
360             left => [ "▘", "▘", "▚" ],
361             center => [ "▚▘", "▗▘", "▗▚" ],
362             right => [ "▚", "▗", "▗" ],
363             bottom => "▗",
364             },
365             checker_box => {
366             top => "▘",
367             left => [ "▚▘", "▚ ", "▚▗" ],
368             center => [ "▚ ▚▘", "▚ ▚ ", "▚ ▚▗" ],
369             right => "▚",
370             bottom => "▗",
371             },
372             checker_frame => {
373             top => "▘",
374             left => [ "▚▘", "▚ ", "▚▗" ],
375             center => [ "▚▘", "▚ ", "▚▗" ],
376             right => "▚",
377             bottom => "▗",
378             },
379             comb => {
380             top => "─",
381             left => [ "┌─" ,
382             "│ " ,
383             "│ " ],
384             center => [ "┬─" ,
385             "│ " ,
386             "│ " ],
387             right => [ "┐" ,
388             "│" ,
389             "│" ],
390             },
391             rake => {
392             left => [ "│ " ,
393             "│ " ,
394             "└─" ],
395             center => [ "│ " ,
396             "│ " ,
397             "┴─" ],
398             right => [ "│" ,
399             "│" ,
400             "┘" ],
401             bottom => "─",
402             },
403             mesh => {
404             left => [ "│" ,
405             "│" ,
406             "├" ],
407             center => [ "│" ,
408             "│" ,
409             "┼" ],
410             right => [ "│" ,
411             "│" ,
412             "┤" ],
413             bottom => "─",
414             },
415             hsem => {
416             top => "─",
417             left => [ "├" ,
418             "│" ,
419             "│" ],
420             center => [ "┼" ,
421             "│" ,
422             "│" ],
423             right => [ "┤" ,
424             "│" ,
425             "│" ],
426             },
427             dumbbell => {
428             center => [ "▄ " , # "\x{2584} "
429             "│ " , # "\x{2502} "
430             "▀ " ], # "\x{2580} "
431             },
432             ribbon => {
433             center => [ "┌┐ " , # "\x{250c}\x{2510}"
434             "││ " , # "\x{2502}\x{2502}"
435             "└┘ " ], # "\x{2514}\x{2518}"
436             left => ' ',
437             },
438             round_ribbon => {
439             center => [ "╭╮ " , # "\x{256D}\x{256E}"
440             "││ " , # "\x{2502}\x{2502}"
441             "╰╯ " ], # "\x{2570}\x{256F}"
442             },
443             double_ribbon => {
444             center => [ "╔╗ " , # "\x{2554}\x{2557}"
445             "║║ " , # "\x{2551}\x{2551}"
446             "╚╝ " ], # "\x{255A}\x{255D}"
447             },
448             corner => {
449             top => " ",
450             left => [ "◲", " ", "◳" ],
451             center => [ "◱ ◲", " ", "◰ ◳" ],
452             right => [ "◱", " ", "◰" ],
453             bottom => " ",
454             },
455             crop => {
456             top => " ",
457             left => [ "⌏", " ", "⌍" ],
458             center => [ "⌎ ⌏", " ", "⌌ ⌍" ],
459             right => [ "⌎", " " , "⌌" ],
460             bottom => " ",
461             },
462             bracket => {
463             top => "",
464             left => [ "┌ ", "│ ", "└ " ],
465             center => [ " ┐ ┌ ", " │ │ ", " ┘ └ " ],
466             right => [ " ┐", " │" , " ┘" ],
467             bottom => "",
468             },
469             side_bracket => {
470             top => "",
471             left => [ "┌ ", "│ ", "└ " ],
472             center => [ " ╷ ", " │ ", " ╵ " ],
473             right => [ " ┐", " │" , " ┘" ],
474             bottom => "",
475             },
476             left_bracket => {
477             top => "",
478             left => [ "┌ ", "│ ", "└ " ],
479             center => [ "┌ ", "│ ", "└ " ],
480             bottom => "",
481             },
482             right_bracket => {
483             top => "",
484             center => [ " ┐ ", " │ " , " ┘ " ],
485             right => [ " ┐", " │" , " ┘ " ],
486             bottom => "",
487             },
488             paren => {
489             top => "",
490             left => [ "⎛ ", "⎜ ", "⎝ " ],
491             center => [ " ⎞ ⎛ ", " ⎟ ⎜ ", " ⎠ ⎝ " ],
492             right => [ " ⎞", " ⎟" , " ⎠" ],
493             bottom => "",
494             },
495             );
496              
497 32     32   350 use Clone qw(clone);
  32         81  
  32         37732  
498              
499             for my $style (qw(line vbar hline bottom_line box dash_box shadow_box ladder frame dash_frame page_frame comb rake mesh bracket side_bracket left_bracket right_bracket
500             dumbbell ribbon)) {
501             $template{$style} // next;
502             my $new = $template{"heavy_$style"} = clone $template{$style};
503             while (my($k, $v) = each %$new) {
504             for (ref $v ? @$v : $new->{$k}) {
505             $_ = heavy($_);
506             }
507             }
508             }
509              
510             sub heavy {
511 5152     5152 0 14075 $_[0] =~ tr[─│┌┐└┘├┤┬┴┼╴╵╶╷][━┃┏┓┗┛┣┫┳┻╋╸╹╺╻]r;
512             }
513              
514             # handle alias styles
515             for my $style (keys %template) {
516             while (not ref (my $alias = $template{$style})) {
517             ($template{$style} = $template{$alias}) // last;
518             }
519             }
520              
521             sub new {
522 17     17 0 144 my $class = shift;
523 17 50       71 my $style = @_ ? shift : '__DEFAULT__';
524 17         1170 (bless { %template }, $class)->style($style);
525             }
526              
527             sub styles {
528 0     0 0 0 my $obj = shift;
529 0         0 grep { $_ !~ /^__/ } sort keys %$obj;
  0         0  
530             }
531              
532             sub style {
533 34     34 0 170 my $obj = shift;
534 34         52 my $style = do {
535 34 50       201 if (@_) {
536 34         437 my $s = shift;
537 34 50       255 if ($s =~ /^random$/i) {
538 0         0 my @styles = $obj->styles;
539 0         0 $styles[rand @styles];
540             } else {
541 34         217 $obj->{__STYLE__} = $s =~ tr[-][_]r;
542             }
543             } else {
544 0         0 return $obj->{__STYLE__};
545             }
546             };
547 34 50       159 $obj->{$style} or return undef;
548 34   100     166 $obj->{__CURRENT__} //= {};
549             # %{$obj->{__CURRENT__}} = %{$obj->{$style}}
550 34         137 %{$obj->{__CURRENT__}} =
551 34         60 map { $_ => $obj->{$style}->{$_} } keys %{$obj->{$style}};
  170         401  
  34         179  
552 34         291 $obj;
553             }
554              
555             sub get {
556 295     295 0 403 my $obj = shift;
557 295   33     756 $obj->get_by_style('__CURRENT__', @_) // $obj->get_by_style('__DEFAULT__', @_)
      50        
558             // die;
559             }
560              
561             sub add_style {
562 32     32 0 123 my $obj = shift;
563 32 50       211 die if @_ % 2;
564 32         254 while (my($name, $style) = splice @_, 0, 2) {
565 64         402 $template{$name} = $style;
566             }
567 32         95 $obj;
568             }
569              
570             sub get_by_style ($ $$;$$) {
571 295     295 0 417 my $obj = shift;
572 295   100     1334 my($style, $place, $position, $page) = (shift, shift, shift//0, shift//0);
      50        
573 295   50     696 my $hash = $obj->{$style} // return undef;
574 295   50     725 my $entry = $hash->{$place} // return undef;
575 295 100       607 if (not ref $entry) {
    50          
576 184         993 return $entry;
577             } elsif (@$entry == 0) {
578 0         0 return undef;
579             } else {
580 111 50       211 my $target = ref $entry->[0] ? $entry->[$page / @$entry] : $entry;
581 111         690 return $target->[$position % @$target];
582             }
583             }
584              
585             1;