File Coverage

blib/lib/App/sdview/Style.pm
Criterion Covered Total %
statement 52 64 81.2
branch 9 24 37.5
condition 1 3 33.3
subroutine 10 10 100.0
pod 0 3 0.0
total 72 104 69.2


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2023 -- leonerd@leonerd.org.uk
5              
6 3     3   228197 use v5.26;
  3         16  
7 3     3   35 use warnings;
  3         6  
  3         94  
8 3     3   494 use experimental 'signatures';
  3         3510  
  3         20  
9              
10             package App::sdview::Style 0.13;
11              
12 3     3   1927 use Convert::Color;
  3         105045  
  3         151  
13 3     3   1444 use Convert::Color::XTerm 0.06;
  3         9840  
  3         3791  
14              
15             =head1 NAME
16              
17             C - store formatting style information for C
18              
19             =head1 DESCRIPTION
20              
21             This module stores formatting style information for L text output
22             formatters, such a L or
23             L.
24              
25             =head2 Config File
26              
27             Style information can be overridden by the user, supplying a
28             L-style file at F<$HOME/.sdviewrc>. Formatting for each kind of
29             paragraph is provided in a section called C, and each individual
30             key gives formatting values.
31              
32             [Para head1]
33             bold = 0|1
34             italic = 0|1
35             monospace = 0|1
36             blank_after = 0|1
37             under = NUM
38             margin = NUM
39              
40             [Para head2]
41             ...
42              
43             The value for keys that set colours should be a string suitable for
44             L<< Convert::Color->new >>:
45              
46             [Para head1]
47             fg = vga:red
48             bg = xterm:184
49              
50             Formatting for each kind of inline format is provided in a section called
51             C, using the same key names as paragraphs.
52              
53             [Inline monospace]
54             fg = xterm:rgb(5,2,0)
55              
56             Note that the C<[Inline monospace]> style is automatically inherited by
57             C<[Para verbatim]>.
58              
59             =cut
60              
61             my %FORMATSTYLES = (
62             bold => { bold => 1 },
63             italic => { italic => 1 },
64             monospace => { monospace => 1, bg => Convert::Color->new( "xterm:235" ) },
65             underline => { under => 1 },
66             strikethrough => { strike => 1 },
67              
68             file => { italic => 1, under => 1 },
69             link => { under => 1, fg => Convert::Color->new( "xterm:rgb(3,3,5)" ) }, # light blue
70             );
71              
72 34         50 sub convert_str ( $pkg, $s )
73 34     34 0 40 {
  34         45  
  34         39  
74             return $s->clone(
75             convert_tags => {
76 34     7   97 ( map { $_ => do { my $k = $_; sub { $FORMATSTYLES{$k}->%* } } } keys %FORMATSTYLES ),
  238         284  
  238         285  
  238         694  
  7         585  
77             },
78             );
79             }
80              
81             my %PARASTYLES = (
82             head1 => { fg => Convert::Color->new( "vga:yellow" ), bold => 1 },
83             head2 => { fg => Convert::Color->new( "vga:cyan" ), bold => 1, margin => 2 },
84             head3 => { fg => Convert::Color->new( "vga:green" ), bold => 1, margin => 4 },
85             head4 => { fg => Convert::Color->new( "xterm:217" ), under => 1, margin => 5 },
86             plain => { margin => 6, blank_after => 1 },
87             verbatim => { margin => 8, blank_after => 1, inherit => "monospace" },
88             list => { margin => 6 },
89             item => { blank_after => 1 },
90             leader => { bold => 1 },
91             table => { margin => 8 },
92             "table-heading" => { bold => 1 },
93             );
94              
95 1         2 sub _convert_val ( $stylekey, $val )
96 1     1   2 {
  1         2  
  1         2  
97 1 50       6 if( $stylekey =~ m/^(fg|bg)$/ ) {
    0          
    0          
98 1         6 return Convert::Color->new( $val );
99             }
100             elsif( $stylekey =~ m/^(bold|italic|monospace|blank_after)$/ ) {
101 0         0 return !!$val;
102             }
103             elsif( $stylekey =~ m/^(under|margin)$/ ) {
104 0         0 return 0+$val;
105             }
106             else {
107 0         0 return undef;
108             }
109             }
110              
111 1         2 sub load_config ( $pkg, $path )
112 1     1 0 7757 {
  1         3  
  1         2  
113 1         537 require Config::Tiny;
114              
115             # For unit testing, also accept a globref
116 1 50       1173 my $config = ( ref $path ) ? Config::Tiny->read_string( do { local $/; <$path> } )
  1         5  
  1         39  
117             : Config::Tiny->read( $path );
118              
119 1         75 foreach my $section ( sort keys %$config ) {
120 1 50       12 if( $section =~ m/^Inline (.*)$/ ) {
    50          
121 0         0 my $format = $1;
122              
123 0 0       0 unless( $FORMATSTYLES{$format} ) {
124 0         0 warn "Unrecognised $section format in $path\n";
125 0         0 next;
126             }
127              
128 0         0 foreach my $stylekey ( sort keys $config->{$section}->%* ) {
129 0 0       0 defined( $FORMATSTYLES{$format}{$stylekey} = _convert_val( $stylekey, $config->{$section}{$stylekey} ) )
130             or warn "Unrecognised $section key $stylekey in $path\n";
131             }
132             }
133             elsif( $section =~ m/^Para (.*)$/ ) {
134 1         11 my $para = $1;
135              
136 1 50       6 unless( $PARASTYLES{$para} ) {
137 0         0 warn "Unrecognised $section style in $path\n";
138 0         0 next;
139             }
140              
141 1         6 foreach my $stylekey ( sort keys $config->{$section}->%* ) {
142 1 50       5 defined( $PARASTYLES{$para}{$stylekey} = _convert_val( $stylekey, $config->{$section}{$stylekey} ) )
143             or warn "Unrecognised $section key $stylekey in $path\n";
144             }
145             }
146             else {
147 0         0 warn "Unrecognised section $section in $path\n";
148             }
149             }
150             }
151              
152 44         68 sub para_style ( $pkg, $type )
153 44     44 0 264 {
  44         61  
  44         388  
154 44 50       104 $PARASTYLES{$type} or
155             die "Unrecognised paragraph style for $type";
156              
157 44         145 my %style = $PARASTYLES{$type}->%*;
158 44 100       115 %style = ( %style, $FORMATSTYLES{delete $style{inherit}}->%* ) if defined $style{inherit};
159 44   33     164 defined $style{$_} or delete $style{$_} for keys %style;
160              
161 44         162 return \%style;
162             }
163              
164             =head1 AUTHOR
165              
166             Paul Evans
167              
168             =cut
169              
170             0x55AA;