line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
2
|
|
|
|
|
|
|
package main; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
our $options; |
5
|
|
|
|
|
|
|
our $config; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
package ChordPro::Output::Markdown; |
8
|
|
|
|
|
|
|
# Author: Johannes Rumpf / 2022 |
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
12
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
35
|
|
11
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
30
|
|
12
|
1
|
|
|
1
|
|
8
|
use ChordPro::Output::Common; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
87
|
|
13
|
1
|
|
|
1
|
|
514
|
use Text::Layout::Markdown; |
|
1
|
|
|
|
|
13548
|
|
|
1
|
|
|
|
|
3224
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $single_space = 0; # suppress chords line when empty |
16
|
|
|
|
|
|
|
my $lyrics_only = 0; # suppress all chords lines |
17
|
|
|
|
|
|
|
my $chords_under = 0; # chords under lyrics |
18
|
|
|
|
|
|
|
my $text_layout = Text::Layout::Markdown->new; # Text::Layout::Text->new; |
19
|
|
|
|
|
|
|
my %line_routines = (); |
20
|
|
|
|
|
|
|
my $tidy; |
21
|
|
|
|
|
|
|
my $rechorus; # not implemented @todo |
22
|
|
|
|
|
|
|
my $act_song; |
23
|
|
|
|
|
|
|
my $cp = "\t"; # Chord-Prefix // Verbatim / Code line in Markdown |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub upd_config { |
26
|
10
|
|
|
10
|
0
|
35
|
$lyrics_only = $config->{settings}->{'lyrics-only'}; |
27
|
10
|
|
|
|
|
34
|
$chords_under = $config->{settings}->{'chords-under'}; |
28
|
10
|
|
|
|
|
42
|
$rechorus = $config->{text}->{chorus}->{recall}; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub generate_songbook { |
32
|
10
|
|
|
10
|
0
|
37
|
my ( $self, $sb ) = @_; |
33
|
10
|
|
|
|
|
22
|
my @book; |
34
|
|
|
|
|
|
|
# push(@book, "[TOC]"); # maybe https://metacpan.org/release/IMAGO/Markdown-TOC-0.01 to create a TOC? |
35
|
|
|
|
|
|
|
|
36
|
10
|
|
|
|
|
29
|
foreach my $song ( @{$sb->{songs}} ) { |
|
10
|
|
|
|
|
41
|
|
37
|
10
|
50
|
|
|
|
39
|
if ( @book ) { |
38
|
0
|
0
|
|
|
|
0
|
push(@book, "") if $options->{'backend-option'}->{tidy}; |
39
|
|
|
|
|
|
|
} |
40
|
10
|
|
|
|
|
28
|
push(@book, @{generate_song($song)}); |
|
10
|
|
|
|
|
40
|
|
41
|
10
|
|
|
|
|
50
|
push(@book, "--------------- \n"); #Horizontal line between each song |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
10
|
|
|
|
|
41
|
push( @book, ""); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# remove all double empty lines |
47
|
10
|
|
|
|
|
19
|
my @new; |
48
|
10
|
|
|
|
|
18
|
my $count = 0; |
49
|
10
|
|
|
|
|
32
|
foreach (@book){ |
50
|
268
|
100
|
|
|
|
541
|
if ($_ =~ /.{1,}/ ){ |
51
|
173
|
|
|
|
|
286
|
push(@new, $_); |
52
|
173
|
|
|
|
|
260
|
$count = 0 |
53
|
|
|
|
|
|
|
} else { |
54
|
95
|
100
|
|
|
|
250
|
push(@new, $_) if $count == 0; |
55
|
95
|
|
|
|
|
136
|
$count++; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
} |
58
|
10
|
|
|
|
|
69
|
\@new; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub generate_song { |
62
|
10
|
|
|
10
|
0
|
29
|
my ( $s ) = @_; |
63
|
10
|
|
|
|
|
5444
|
$act_song = $s; |
64
|
10
|
|
|
|
|
69
|
$tidy = $options->{'backend-option'}->{tidy}; |
65
|
10
|
|
|
|
|
36
|
$single_space = $options->{'single-space'}; |
66
|
|
|
|
|
|
|
|
67
|
10
|
|
|
|
|
50
|
upd_config(); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# asume songline a verse when no context is applied. # check https://github.com/ChordPro/chordpro/pull/211 |
70
|
10
|
|
|
|
|
20
|
foreach my $item ( @{ $s->{body} } ) { |
|
10
|
|
|
|
|
39
|
|
71
|
155
|
100
|
100
|
|
|
494
|
if ( $item->{type} eq "songline" && $item->{context} eq '' ){ |
72
|
55
|
|
|
|
|
117
|
$item->{context} = 'verse'; |
73
|
|
|
|
|
|
|
}} # end of pull -- |
74
|
|
|
|
|
|
|
|
75
|
10
|
|
|
|
|
145
|
$s->structurize; |
76
|
10
|
|
|
|
|
23
|
my @s; |
77
|
10
|
50
|
|
|
|
86
|
push(@s, "# " . $s->{title}) if defined $s->{title}; |
78
|
10
|
100
|
|
|
|
37
|
if ( defined $s->{subtitle} ) { |
79
|
3
|
|
|
|
|
7
|
push(@s, map { +"## $_" } @{$s->{subtitle}}); |
|
3
|
|
|
|
|
14
|
|
|
3
|
|
|
|
|
9
|
|
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
10
|
50
|
|
|
|
63
|
if ( $lyrics_only eq 0 ){ |
83
|
10
|
|
|
|
|
238
|
my $all_chords = ""; |
84
|
|
|
|
|
|
|
# https://chordgenerator.net/D.png?p=xx0212&s=2 # reuse of other projects (https://github.com/einaregilsson/ChordImageGenerator)? |
85
|
|
|
|
|
|
|
# generate png-out of this project? // fingers also possible - but not set in basics. |
86
|
10
|
|
|
|
|
22
|
foreach my $mchord (@{$s->{chords}->{chords}}){ |
|
10
|
|
|
|
|
34
|
|
87
|
|
|
|
|
|
|
# replace -1 with 'x' - alternative '-' |
88
|
32
|
100
|
|
|
|
49
|
my $frets = join("", map { if($_ eq '-1'){ $_ = 'x'; } +"$_"} @{$s->{chordsinfo}->{$mchord}->{frets}}); |
|
192
|
|
|
|
|
369
|
|
|
30
|
|
|
|
|
52
|
|
|
192
|
|
|
|
|
323
|
|
|
32
|
|
|
|
|
83
|
|
89
|
32
|
|
|
|
|
193
|
$all_chords .= " "; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
} |
92
|
10
|
|
|
|
|
47
|
push(@s, $all_chords); |
93
|
10
|
|
|
|
|
30
|
push(@s, ""); |
94
|
|
|
|
|
|
|
} |
95
|
10
|
|
|
|
|
64
|
push(@s, elt_handler($s->{body})); |
96
|
10
|
|
|
|
|
98
|
return \@s; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub line_default { |
100
|
20
|
|
|
20
|
0
|
47
|
my ( $lineobject, $ref_lineobjects ) = @_; |
101
|
20
|
|
|
|
|
45
|
return ""; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
$line_routines{line_default} = \&line_default; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub chord { |
106
|
102
|
|
|
102
|
0
|
209
|
my ( $c ) = @_; |
107
|
102
|
100
|
|
|
|
323
|
return "" unless length($c); |
108
|
77
|
100
|
|
|
|
250
|
return $c->key if $c->info->is_annotation; |
109
|
76
|
|
|
|
|
216
|
$text_layout->set_markup($c->chord_display); |
110
|
76
|
|
|
|
|
5149
|
return $text_layout->render; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub md_textline{ |
114
|
32
|
|
|
32
|
0
|
58
|
my ( $songline ) = @_; |
115
|
32
|
|
|
|
|
85
|
my $empty = $songline; |
116
|
32
|
|
|
|
|
39
|
my $textline = $songline; |
117
|
32
|
|
|
|
|
46
|
my $nbsp = "\x{00A0}"; #unicode for nbsp sign |
118
|
32
|
100
|
|
|
|
136
|
if($empty =~ /^\s+/){ # starts with spaces |
119
|
14
|
|
|
|
|
79
|
$empty =~ s/^(\s+).*$/$1/; # not the elegant solution - but working - replace all spaces in the beginning of a line |
120
|
14
|
|
|
|
|
34
|
my $replaces = $empty; #with a nbsp symbol as the intend tend to be intentional |
121
|
14
|
|
|
|
|
66
|
$replaces =~ s/\s/$nbsp/g; |
122
|
14
|
|
|
|
|
85
|
$textline =~ s/$empty/$replaces/; |
123
|
|
|
|
|
|
|
} |
124
|
32
|
|
|
|
|
95
|
$textline = $textline." "; # append two spaces to force linebreak in Markdown |
125
|
32
|
|
|
|
|
129
|
return $textline; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub line_songline { |
129
|
67
|
|
|
67
|
0
|
134
|
my ( $elt ) = @_; |
130
|
67
|
|
|
|
|
111
|
my $t_line = ""; |
131
|
134
|
|
|
|
|
2244
|
my @phrases = map { $text_layout->set_markup($_); $text_layout->render } |
|
134
|
|
|
|
|
6421
|
|
132
|
67
|
|
|
|
|
104
|
@{ $elt->{phrases} }; |
|
67
|
|
|
|
|
151
|
|
133
|
|
|
|
|
|
|
|
134
|
67
|
50
|
0
|
|
|
2042
|
if ( $lyrics_only or |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
135
|
|
|
|
|
|
|
$single_space && ! ( $elt->{chords} && join( "", map { $_->raw } @{ $elt->{chords} } ) =~ /\S/ ) |
136
|
|
|
|
|
|
|
) { |
137
|
0
|
|
|
|
|
0
|
$t_line = join( "", @phrases ); |
138
|
0
|
|
|
|
|
0
|
return md_textline($cp.$t_line); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
67
|
100
|
|
|
|
760
|
unless ( $elt->{chords} ) { # i guess we have a line with no chords now... |
142
|
32
|
|
|
|
|
108
|
return ($cp. md_textline( join( " ", @phrases )) ); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
35
|
50
|
|
|
|
119
|
if ( my $f = $::config->{settings}->{'inline-chords'} ) { |
146
|
0
|
0
|
|
|
|
0
|
$f = '[%s]' unless $f =~ /^[^%]*\%s[^%]*$/; |
147
|
0
|
|
|
|
|
0
|
$f .= '%s'; |
148
|
0
|
|
|
|
|
0
|
foreach ( 0..$#{$elt->{chords}} ) { |
|
0
|
|
|
|
|
0
|
|
149
|
|
|
|
|
|
|
$t_line .= sprintf( $f, |
150
|
0
|
|
|
|
|
0
|
chord( $elt->{chords}->[$_]->raw ), |
151
|
|
|
|
|
|
|
$phrases[$_] ); |
152
|
|
|
|
|
|
|
} |
153
|
0
|
|
|
|
|
0
|
return ( md_textline($cp.$t_line) ); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
35
|
|
|
|
|
287
|
my $c_line = ""; |
157
|
35
|
|
|
|
|
62
|
foreach ( 0..$#{$elt->{chords}} ) { |
|
35
|
|
|
|
|
158
|
|
158
|
102
|
|
|
|
|
254
|
$c_line .= chord( $elt->{chords}->[$_] ) . " "; |
159
|
102
|
|
|
|
|
2530
|
$t_line .= $phrases[$_]; |
160
|
102
|
|
|
|
|
275
|
my $d = length($c_line) - length($t_line); |
161
|
102
|
100
|
|
|
|
263
|
$t_line .= "-" x $d if $d > 0; |
162
|
102
|
100
|
|
|
|
406
|
$c_line .= " " x -$d if $d < 0; |
163
|
|
|
|
|
|
|
} # this looks like setting the chords above the words. |
164
|
|
|
|
|
|
|
|
165
|
35
|
|
|
|
|
348
|
s/\s+$// for ( $t_line, $c_line ); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# main problem in markdown - a fixed position is only available in "Code escapes" so weather to set |
168
|
|
|
|
|
|
|
# a tab or a double backticks (``) - i tend to the tab - so all lines with tabs are "together" |
169
|
35
|
50
|
|
|
|
106
|
if ($c_line ne ""){ # Block-lines are not replacing initial spaces - as the are "code" |
170
|
35
|
|
|
|
|
105
|
$t_line = $cp.$t_line." "; |
171
|
35
|
|
|
|
|
87
|
$c_line = $cp.$c_line." "; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
else{ |
174
|
0
|
|
|
|
|
0
|
$t_line = md_textline($cp.$t_line); |
175
|
|
|
|
|
|
|
} |
176
|
35
|
50
|
|
|
|
120
|
return $chords_under |
177
|
|
|
|
|
|
|
? ( $t_line, $c_line ) |
178
|
|
|
|
|
|
|
: ( $c_line, $t_line ); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
$line_routines{line_songline} = \&line_songline; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub line_newpage { |
183
|
3
|
|
|
3
|
0
|
10
|
return "--------------- \n"; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
$line_routines{line_newpage} = \&line_newpage; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub line_empty { |
188
|
0
|
|
|
0
|
0
|
0
|
return "$cp"; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
$line_routines{line_empty} = \&line_empty; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub line_comment { |
193
|
19
|
|
|
19
|
0
|
45
|
my ( $elt ) = @_; # Template for comment? |
194
|
19
|
|
|
|
|
30
|
my @s; |
195
|
19
|
|
|
|
|
42
|
my $text = $elt->{text}; |
196
|
19
|
50
|
|
|
|
55
|
if ( $elt->{chords} ) { |
197
|
0
|
|
|
|
|
0
|
$text = ""; |
198
|
0
|
|
|
|
|
0
|
for ( 0..$#{ $elt->{chords} } ) { |
|
0
|
|
|
|
|
0
|
|
199
|
|
|
|
|
|
|
$text .= "[" . $elt->{chords}->[$_]->raw . "]" |
200
|
0
|
0
|
|
|
|
0
|
if $elt->{chords}->[$_] ne ""; |
201
|
0
|
|
|
|
|
0
|
$text .= $elt->{phrases}->[$_]; |
202
|
|
|
|
|
|
|
}} |
203
|
19
|
50
|
|
|
|
66
|
if ($elt->{type} =~ /italic$/) { |
204
|
0
|
|
|
|
|
0
|
$text = "*" . $text . "* "; |
205
|
|
|
|
|
|
|
} |
206
|
19
|
|
|
|
|
73
|
push(@s, "> $text "); |
207
|
19
|
|
|
|
|
51
|
return @s; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
$line_routines{line_comment} = \&line_comment; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub line_comment_italic { |
212
|
3
|
|
|
3
|
0
|
22
|
my ( $lineobject ) = @_; # Template for comment? |
213
|
3
|
|
|
|
|
19
|
return "> *". $lineobject->{text} ."*";; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
$line_routines{line_comment_italic} = \&line_comment_italic; |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub line_image { |
219
|
0
|
|
|
0
|
0
|
0
|
my ( $elt ) = @_; |
220
|
0
|
|
|
|
|
0
|
return ""; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
$line_routines{line_image} = \&line_image; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub line_colb { |
225
|
3
|
|
|
3
|
0
|
12
|
return "\n\n\n"; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
$line_routines{line_colb} = \&line_colb; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub body_has_chords{ |
230
|
26
|
|
|
26
|
0
|
55
|
my ( $elts ) = @_; # reference to array |
231
|
26
|
|
|
|
|
38
|
my $has_chord = 0; # default false has no chords |
232
|
26
|
|
|
|
|
38
|
foreach my $elt (@{ $elts }) { |
|
26
|
|
|
|
|
55
|
|
233
|
51
|
100
|
|
|
|
133
|
if ($elt->{type} eq 'songline'){ |
234
|
50
|
100
|
66
|
|
|
124
|
if ((defined $elt->{chords}) && (scalar @{$elt->{chords}} > 0 )){ |
|
18
|
|
|
|
|
57
|
|
235
|
18
|
|
|
|
|
39
|
$has_chord = 1; |
236
|
18
|
|
|
|
|
76
|
return $has_chord; |
237
|
|
|
|
|
|
|
}} |
238
|
|
|
|
|
|
|
} |
239
|
8
|
|
|
|
|
37
|
return $has_chord; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
sub line_chorus { |
242
|
3
|
|
|
3
|
0
|
9
|
my ( $lineobject ) = @_; # |
243
|
3
|
|
|
|
|
7
|
my @s; |
244
|
3
|
100
|
|
|
|
13
|
$cp = (body_has_chords($lineobject->{body})) ? "\t" : ""; # Verbatim on Verse/Chorus because Chords are present |
245
|
3
|
|
|
|
|
10
|
push(@s, "**Chorus**"); |
246
|
3
|
|
|
|
|
7
|
push(@s, ""); |
247
|
3
|
|
|
|
|
14
|
push(@s, elt_handler($lineobject->{body})); |
248
|
|
|
|
|
|
|
# push(@s, "\x{00A0} "); # nbsp |
249
|
3
|
|
|
|
|
11
|
push(@s, "--------------- \n"); |
250
|
3
|
|
|
|
|
15
|
return @s; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
$line_routines{line_chorus} = \&line_chorus; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub line_verse { |
255
|
23
|
|
|
23
|
0
|
61
|
my ( $lineobject ) = @_; # |
256
|
23
|
|
|
|
|
34
|
my @s; |
257
|
23
|
100
|
|
|
|
69
|
$cp = (body_has_chords($lineobject->{body})) ? "\t" : ""; # Verbatim on Verse/Chorus because Chords are present |
258
|
23
|
|
|
|
|
66
|
push(@s, elt_handler($lineobject->{body})); |
259
|
23
|
|
|
|
|
57
|
push(@s, ""); |
260
|
|
|
|
|
|
|
# push(@s, "\x{00A0} "); # nbsp |
261
|
23
|
|
|
|
|
84
|
return @s; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
$line_routines{line_verse} = \&line_verse; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub line_set { # potential comments in fe. Chorus or verse or .... complicated handling - potential contextsensitiv. |
266
|
11
|
|
|
11
|
0
|
37
|
my ( $elt ) = @_; |
267
|
11
|
50
|
|
|
|
66
|
if ( $elt->{name} eq "lyrics-only" ) { |
|
|
50
|
|
|
|
|
|
268
|
|
|
|
|
|
|
$lyrics_only = $elt->{value} |
269
|
0
|
0
|
|
|
|
0
|
unless $lyrics_only > 1; |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
# Arbitrary config values. |
272
|
|
|
|
|
|
|
elsif ( $elt->{name} =~ /^(text\..+)/ ) { |
273
|
0
|
|
|
|
|
0
|
my @k = split( /[.]/, $1 ); |
274
|
0
|
|
|
|
|
0
|
my $cc = {}; |
275
|
0
|
|
|
|
|
0
|
my $c = \$cc; |
276
|
0
|
|
|
|
|
0
|
foreach ( @k ) { |
277
|
0
|
|
|
|
|
0
|
$c = \($$c->{$_}); |
278
|
|
|
|
|
|
|
} |
279
|
0
|
|
|
|
|
0
|
$$c = $elt->{value}; |
280
|
0
|
|
|
|
|
0
|
$config->augment($cc); |
281
|
0
|
|
|
|
|
0
|
upd_config(); |
282
|
|
|
|
|
|
|
} |
283
|
11
|
|
|
|
|
26
|
return ""; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
$line_routines{line_set} = \&line_set; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub line_tabline { |
288
|
0
|
|
|
0
|
0
|
0
|
my ( $lineobject ) = @_; |
289
|
0
|
|
|
|
|
0
|
return "\t".$lineobject->{text}; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
$line_routines{line_tabline} = \&line_tabline; |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub line_tab { |
294
|
0
|
|
|
0
|
0
|
0
|
my ( $lineobject ) = @_; |
295
|
0
|
|
|
|
|
0
|
my @s; |
296
|
0
|
|
|
|
|
0
|
push(@s, "**Tabulatur** "); #@todo |
297
|
0
|
|
|
|
|
0
|
push(@s, ""); |
298
|
0
|
|
|
|
|
0
|
push(@s, map { "\t".$_ } elt_handler($lineobject->{body}) ); #maybe this need to go for code markup as well´? |
|
0
|
|
|
|
|
0
|
|
299
|
0
|
|
|
|
|
0
|
return @s; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
$line_routines{line_tab} = \&line_tab; |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
sub line_grid { |
304
|
2
|
|
|
2
|
0
|
8
|
my ( $lineobject ) = @_; |
305
|
2
|
|
|
|
|
6
|
my @s; |
306
|
2
|
|
|
|
|
6
|
push(@s, "**Grid** "); |
307
|
2
|
|
|
|
|
4
|
push(@s, ""); |
308
|
2
|
|
|
|
|
10
|
push(@s, elt_handler($lineobject->{body})); |
309
|
|
|
|
|
|
|
# push(@s, "\x{00A0} "); |
310
|
2
|
|
|
|
|
5
|
push(@s, ""); |
311
|
2
|
|
|
|
|
9
|
return @s; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
$line_routines{line_grid} = \&line_grid; |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub line_gridline { |
316
|
6
|
|
|
6
|
0
|
16
|
my ( $elt ) = @_; |
317
|
6
|
|
|
|
|
10
|
my @a = @{ $elt->{tokens} }; |
|
6
|
|
|
|
|
22
|
|
318
|
6
|
|
|
|
|
15
|
@a = map { $_->{class} eq 'chord' |
319
|
|
|
|
|
|
|
? $_->{chord}->raw |
320
|
78
|
100
|
|
|
|
198
|
: $_->{symbol} } @a; |
321
|
6
|
|
|
|
|
37
|
return "\t".join("", @a); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
$line_routines{line_gridline} = \&line_gridline; |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub elt_handler { |
326
|
38
|
|
|
38
|
0
|
76
|
my ( $elts ) = @_; # reference to array |
327
|
38
|
|
|
|
|
78
|
my $cref; #command reference to subroutine |
328
|
38
|
|
|
|
|
60
|
my $init_context = 1; |
329
|
38
|
|
|
|
|
67
|
my $ctx = ""; |
330
|
|
|
|
|
|
|
|
331
|
38
|
|
|
|
|
56
|
my @lines; |
332
|
38
|
|
|
|
|
83
|
my $last_type=''; |
333
|
38
|
|
|
|
|
60
|
foreach my $elt (@{ $elts }) { |
|
38
|
|
|
|
|
71
|
|
334
|
160
|
100
|
100
|
|
|
506
|
if (($elt->{type} eq 'verse') && ($last_type =~ /comment/)){ |
335
|
10
|
|
|
|
|
24
|
push(@lines, ""); |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
# Gang of Four-Style - sort of command pattern |
338
|
160
|
|
|
|
|
334
|
my $sub_type = "line_".$elt->{type}; # build command "line_" |
339
|
160
|
100
|
|
|
|
404
|
if (defined $line_routines{$sub_type}) { |
340
|
140
|
|
|
|
|
271
|
$cref = $line_routines{$sub_type}; #\&$sub_type; # due to use strict - we need to get an reference to the command |
341
|
140
|
|
|
|
|
390
|
push(@lines, &$cref($elt)); # call line with actual line-object |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
else { |
344
|
20
|
|
|
|
|
63
|
push(@lines, line_default($elt)); # default = empty line |
345
|
|
|
|
|
|
|
} |
346
|
160
|
|
|
|
|
707
|
$last_type = $elt->{type}; |
347
|
|
|
|
|
|
|
} |
348
|
38
|
|
|
|
|
233
|
return @lines; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
################# |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# package Text::Layout::Text; |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# use parent 'Text::Layout'; |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# # Eliminate warning when HTML backend is loaded together with Text backend. |
358
|
|
|
|
|
|
|
# no warnings 'redefine'; |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# sub new { |
361
|
|
|
|
|
|
|
# my ( $pkg, @data ) = @_; |
362
|
|
|
|
|
|
|
# my $self = $pkg->SUPER::new; |
363
|
|
|
|
|
|
|
# $self; |
364
|
|
|
|
|
|
|
# } |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# sub render { |
367
|
|
|
|
|
|
|
# my ( $self ) = @_; |
368
|
|
|
|
|
|
|
# my $res = ""; |
369
|
|
|
|
|
|
|
# foreach my $fragment ( @{ $self->{_content} } ) { |
370
|
|
|
|
|
|
|
# next unless length($fragment->{text}); |
371
|
|
|
|
|
|
|
# $res .= $fragment->{text}; |
372
|
|
|
|
|
|
|
# } |
373
|
|
|
|
|
|
|
# $res; |
374
|
|
|
|
|
|
|
# } |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
1; |
378
|
|
|
|
|
|
|
# @todo |
379
|
|
|
|
|
|
|
# sub line_rechorus { |
380
|
|
|
|
|
|
|
# my ( $lineobject ) = @_; |
381
|
|
|
|
|
|
|
# if ( $rechorus->{quote} ) { |
382
|
|
|
|
|
|
|
# unshift( @elts, @{ $elt->{chorus} } ); |
383
|
|
|
|
|
|
|
# } |
384
|
|
|
|
|
|
|
# elsif ( $rechorus->{type} && $rechorus->{tag} ) { |
385
|
|
|
|
|
|
|
# push( @s, "{".$rechorus->{type}.": ".$rechorus->{tag}."}" ); |
386
|
|
|
|
|
|
|
# } |
387
|
|
|
|
|
|
|
# else { |
388
|
|
|
|
|
|
|
# push( @s, "{chorus}" ); |
389
|
|
|
|
|
|
|
# } |
390
|
|
|
|
|
|
|
# } |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
# sub line_control { |
393
|
|
|
|
|
|
|
# my ( $lineobject ) = @_; |
394
|
|
|
|
|
|
|
# } |