File Coverage

blib/lib/App/ansicolumn/Border.pm
Criterion Covered Total %
statement 20 53 37.7
branch 1 16 6.2
condition 0 15 0.0
subroutine 7 12 58.3
pod 0 7 0.0
total 28 103 27.1


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 1     1   13 use v5.14;
  1         4  
29 1     1   7 use warnings;
  1         3  
  1         28  
30 1     1   5 use utf8;
  1         3  
  1         6  
31 1     1   22 use Data::Dumper;
  1         2  
  1         1496  
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             frame => {
189             top => "─",
190             bottom => "─",
191             left => [ "┌─" ,
192             "│ " ,
193             "└─" ],
194             center => [ "┬─" ,
195             "│ " ,
196             "┴─" ],
197             right => [ "┐" ,
198             "│" ,
199             "┘" ],
200             },
201             dash_frame => {
202             top => "╴",
203             left => [ "╷╴" ,
204             "╷ " ,
205             "╶╶" ],
206             center => [ "╴╴" ,
207             "╵ " ,
208             "└╶" ],
209             right => [ "╴" ,
210             "╵" ,
211             "╵" ],
212             bottom => "╶",
213             },
214             page_frame => {
215             top => "─",
216             left => [ "┌─" ,
217             "│ " ,
218             "└─" ],
219             center => [ "──" ,
220             " " ,
221             "──" ],
222             right => [ "┐" ,
223             "│" ,
224             "┘" ],
225             bottom => "─",
226             },
227             thin_shadow => {
228             top => "",
229             left => [ " " ,
230             " " ,
231             "▝" ],
232             center => [ " ▖ " ,
233             " ▌ " ,
234             "▀▘▝" ],
235             right => [ " ▖" ,
236             " ▌" ,
237             "▀▘" ],
238             bottom => "▀",
239             },
240             shadow => {
241             top => "",
242             left => [ " " ,
243             " " ,
244             " " ],
245             center => [ " ▄ " ,
246             " █ " ,
247             "▀▀ " ],
248             right => [ " ▄" ,
249             " █" ,
250             "▀▀" ],
251             bottom => "▀",
252             },
253             thin_shadow_box => {
254             top => "─",
255             left => [ "┌─" ,
256             "│ " ,
257             "└▄" ],
258             center => [ "─┐ ┌─" ,
259             " ▐ │ " ,
260             "▄▟ └▄" ],
261             right => [ "─┐" ,
262             " ▐" ,
263             "▄▟" ],
264             bottom => "▄",
265             },
266             shadow_box => {
267             top => "─",
268             left => [ "┌─" ,
269             "│ " ,
270             "└▄" ],
271             center => [ "─┐ ┌─" ,
272             " ▐▌│ " ,
273             "▄▟▌└▄" ],
274             right => [ "─┐ " ,
275             " ▐▌" ,
276             "▄▟▌" ],
277             bottom => "▄",
278             },
279             fat_box => {
280             top => "▀",
281             left => [ "█▀" ,
282             "█ " ,
283             "█▄" ],
284             center => [ "▀█ █▀" ,
285             " █ █ " ,
286             "▄█ █▄" ],
287             right => [ "▀█" ,
288             " █" ,
289             "▄█" ],
290             bottom => "▄",
291             },
292             very_fat_box => {
293             top => "█",
294             left => [ "███" ,
295             "██ " ,
296             "███" ],
297             center => [ "███ ███" ,
298             " ██ ██ " ,
299             "███ ███" ],
300             right => [ "███" ,
301             " ██" ,
302             "███" ],
303             bottom => "█",
304             },
305             fat_frame => {
306             top => "▀",
307             left => [ "█▀" ,
308             "█ " ,
309             "█▄" ],
310             center => [ "▀█▀" ,
311             " █ " ,
312             "▄█▄" ],
313             right => [ "▀█" ,
314             " █" ,
315             "▄█" ],
316             bottom => "▄",
317             },
318             very_fat_frame => {
319             top => "█",
320             left => [ "███" ,
321             "██ " ,
322             "███" ],
323             center => [ "████" ,
324             " ██ " ,
325             "████" ],
326             right => [ "███" ,
327             " ██" ,
328             "███" ],
329             bottom => "█",
330             },
331             fat_dash_box => {
332             top => "▘",
333             left => [ "▘", "▘", "▚" ],
334             center => [ "▚ ▘", "▗ ▘", "▗ ▚" ],
335             right => [ "▚", "▗", "▗" ],
336             bottom => "▗",
337             },
338             fat_dash_frame => {
339             top => "▘",
340             left => [ "▘", "▘", "▚" ],
341             center => [ "▚ ", "▗ ", "▗ " ],
342             right => [ "▚", "▗", "▗" ],
343             bottom => "▗",
344             },
345             zebra_frame => {
346             top => "▘",
347             left => [ "▘", "▘", "▚" ],
348             center => [ "▚▘", "▗▘", "▗▚" ],
349             right => [ "▚", "▗", "▗" ],
350             bottom => "▗",
351             },
352             checker_box => {
353             top => "▘",
354             left => [ "▚▘", "▚ ", "▚▗" ],
355             center => [ "▚ ▚▘", "▚ ▚ ", "▚ ▚▗" ],
356             right => "▚",
357             bottom => "▗",
358             },
359             checker_frame => {
360             top => "▘",
361             left => [ "▚▘", "▚ ", "▚▗" ],
362             center => [ "▚▘", "▚ ", "▚▗" ],
363             right => "▚",
364             bottom => "▗",
365             },
366             comb => {
367             top => "─",
368             left => [ "┌─" ,
369             "│ " ,
370             "│ " ],
371             center => [ "┬─" ,
372             "│ " ,
373             "│ " ],
374             right => [ "┐" ,
375             "│" ,
376             "│" ],
377             },
378             rake => {
379             left => [ "│ " ,
380             "│ " ,
381             "└─" ],
382             center => [ "│ " ,
383             "│ " ,
384             "┴─" ],
385             right => [ "│" ,
386             "│" ,
387             "┘" ],
388             bottom => "─",
389             },
390             mesh => {
391             left => [ "│" ,
392             "│" ,
393             "├" ],
394             center => [ "│" ,
395             "│" ,
396             "┼" ],
397             right => [ "│" ,
398             "│" ,
399             "┤" ],
400             bottom => "─",
401             },
402             hsem => {
403             top => "─",
404             left => [ "├" ,
405             "│" ,
406             "│" ],
407             center => [ "┼" ,
408             "│" ,
409             "│" ],
410             right => [ "┤" ,
411             "│" ,
412             "│" ],
413             },
414             dumbbell => {
415             center => [ "▄ " , # "\x{2584} "
416             "│ " , # "\x{2502} "
417             "▀ " ], # "\x{2580} "
418             },
419             ribbon => {
420             center => [ "┌┐ " , # "\x{250c}\x{2510}"
421             "││ " , # "\x{2502}\x{2502}"
422             "└┘ " ], # "\x{2514}\x{2518}"
423             left => ' ',
424             },
425             round_ribbon => {
426             center => [ "╭╮ " , # "\x{256D}\x{256E}"
427             "││ " , # "\x{2502}\x{2502}"
428             "╰╯ " ], # "\x{2570}\x{256F}"
429             },
430             double_ribbon => {
431             center => [ "╔╗ " , # "\x{2554}\x{2557}"
432             "║║ " , # "\x{2551}\x{2551}"
433             "╚╝ " ], # "\x{255A}\x{255D}"
434             },
435             corner => {
436             top => " ",
437             left => [ "◲", " ", "◳" ],
438             center => [ "◱ ◲", " ", "◰ ◳" ],
439             right => [ "◱", " ", "◰" ],
440             bottom => " ",
441             },
442             );
443              
444 1     1   455 use Clone qw(clone);
  1         2510  
  1         205  
445              
446             for my $style (qw(line vbar hline bottom_line box dash_box shadow_box frame dash_frame page_frame comb rake mesh
447             dumbbell ribbon)) {
448             $template{$style} // next;
449             my $new = $template{"heavy_$style"} = clone $template{$style};
450             while (my($k, $v) = each %$new) {
451             for (ref $v ? @$v : $new->{$k}) {
452             $_ = heavy($_);
453             }
454             }
455             }
456              
457             sub heavy {
458 112     112 0 331 $_[0] =~ tr[─│┌┐└┘├┤┬┴┼╴╵╶╷][━┃┏┓┗┛┣┫┳┻╋╸╹╺╻]r;
459             }
460              
461             # handle alias styles
462             for my $style (keys %template) {
463             while (not ref (my $alias = $template{$style})) {
464             ($template{$style} = $template{$alias}) // last;
465             }
466             }
467              
468             sub new {
469 0     0 0 0 my $class = shift;
470 0 0       0 my $style = @_ ? shift : '__DEFAULT__';
471 0         0 (bless { %template }, $class)->style($style);
472             }
473              
474             sub styles {
475 0     0 0 0 my $obj = shift;
476 0         0 grep { $_ !~ /^__/ } sort keys %$obj;
  0         0  
477             }
478              
479             sub style {
480 0     0 0 0 my $obj = shift;
481 0         0 my $style = do {
482 0 0       0 if (@_) {
483 0         0 my $s = shift;
484 0 0       0 if ($s =~ /^random$/i) {
485 0         0 my @styles = $obj->styles;
486 0         0 $styles[rand @styles];
487             } else {
488 0         0 $obj->{__STYLE__} = $s =~ tr[-][_]r;
489             }
490             } else {
491 0         0 return $obj->{__STYLE__};
492             }
493             };
494 0 0       0 $obj->{$style} or return undef;
495 0   0     0 $obj->{__CURRENT__} //= {};
496             # %{$obj->{__CURRENT__}} = %{$obj->{$style}}
497 0         0 %{$obj->{__CURRENT__}} =
498 0         0 map { $_ => $obj->{$style}->{$_} } keys %{$obj->{$style}};
  0         0  
  0         0  
499 0         0 $obj;
500             }
501              
502             sub get {
503 0     0 0 0 my $obj = shift;
504 0   0     0 $obj->get_by_style('__CURRENT__', @_) // $obj->get_by_style('__DEFAULT__', @_)
      0        
505             // die;
506             }
507              
508             sub add_style {
509 1     1 0 3 my $obj = shift;
510 1 50       6 die if @_ % 2;
511 1         8 while (my($name, $style) = splice @_, 0, 2) {
512 2         28 $template{$name} = $style;
513             }
514 1         3 $obj;
515             }
516              
517             sub get_by_style ($ $$;$$) {
518 0     0 0   my $obj = shift;
519 0   0       my($style, $place, $position, $page) = (shift, shift, shift//0, shift//0);
      0        
520 0   0       my $hash = $obj->{$style} // return undef;
521 0   0       my $entry = $hash->{$place} // return undef;
522 0 0         if (not ref $entry) {
    0          
523 0           return $entry;
524             } elsif (@$entry == 0) {
525 0           return undef;
526             } else {
527 0 0         my $target = ref $entry->[0] ? $entry->[$page / @$entry] : $entry;
528 0           return $target->[$position % @$target];
529             }
530             }
531              
532             1;