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   12 use v5.14;
  1         3  
29 1     1   5 use warnings;
  1         2  
  1         24  
30 1     1   5 use utf8;
  1         2  
  1         5  
31 1     1   22 use Data::Dumper;
  1         2  
  1         1473  
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             );
436              
437 1     1   454 use Clone qw(clone);
  1         2426  
  1         182  
438              
439             for my $style (qw(line vbar hline bottom_line box dash_box shadow_box frame dash_frame page_frame comb rake mesh
440             dumbbell ribbon)) {
441             $template{$style} // next;
442             my $new = $template{"heavy_$style"} = clone $template{$style};
443             while (my($k, $v) = each %$new) {
444             for (ref $v ? @$v : $new->{$k}) {
445             $_ = heavy($_);
446             }
447             }
448             }
449              
450             sub heavy {
451 112     112 0 337 $_[0] =~ tr[─│┌┐└┘├┤┬┴┼╴╵╶╷][━┃┏┓┗┛┣┫┳┻╋╸╹╺╻]r;
452             }
453              
454             # handle alias styles
455             for my $style (keys %template) {
456             while (not ref (my $alias = $template{$style})) {
457             ($template{$style} = $template{$alias}) // last;
458             }
459             }
460              
461             sub new {
462 0     0 0 0 my $class = shift;
463 0 0       0 my $style = @_ ? shift : '__DEFAULT__';
464 0         0 (bless { %template }, $class)->style($style);
465             }
466              
467             sub styles {
468 0     0 0 0 my $obj = shift;
469 0         0 grep { $_ !~ /^__/ } sort keys %$obj;
  0         0  
470             }
471              
472             sub style {
473 0     0 0 0 my $obj = shift;
474 0         0 my $style = do {
475 0 0       0 if (@_) {
476 0         0 my $s = shift;
477 0 0       0 if ($s =~ /^random$/i) {
478 0         0 my @styles = $obj->styles;
479 0         0 $styles[rand @styles];
480             } else {
481 0         0 $obj->{__STYLE__} = $s =~ tr[-][_]r;
482             }
483             } else {
484 0         0 return $obj->{__STYLE__};
485             }
486             };
487 0 0       0 $obj->{$style} or return undef;
488 0   0     0 $obj->{__CURRENT__} //= {};
489             # %{$obj->{__CURRENT__}} = %{$obj->{$style}}
490 0         0 %{$obj->{__CURRENT__}} =
491 0         0 map { $_ => $obj->{$style}->{$_} } keys %{$obj->{$style}};
  0         0  
  0         0  
492 0         0 $obj;
493             }
494              
495             sub get {
496 0     0 0 0 my $obj = shift;
497 0   0     0 $obj->get_by_style('__CURRENT__', @_) // $obj->get_by_style('__DEFAULT__', @_)
      0        
498             // die;
499             }
500              
501             sub add_style {
502 1     1 0 3 my $obj = shift;
503 1 50       4 die if @_ % 2;
504 1         5 while (my($name, $style) = splice @_, 0, 2) {
505 2         8 $template{$name} = $style;
506             }
507 1         2 $obj;
508             }
509              
510             sub get_by_style ($ $$;$$) {
511 0     0 0   my $obj = shift;
512 0   0       my($style, $place, $position, $page) = (shift, shift, shift//0, shift//0);
      0        
513 0   0       my $hash = $obj->{$style} // return undef;
514 0   0       my $entry = $hash->{$place} // return undef;
515 0 0         if (not ref $entry) {
    0          
516 0           return $entry;
517             } elsif (@$entry == 0) {
518 0           return undef;
519             } else {
520 0 0         my $target = ref $entry->[0] ? $entry->[$page / @$entry] : $entry;
521 0           return $target->[$position % @$target];
522             }
523             }
524              
525             1;