| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Text::ANSI::Fold; |
|
2
|
|
|
|
|
|
|
|
|
3
|
12
|
|
|
12
|
|
784914
|
use v5.14; |
|
|
12
|
|
|
|
|
158
|
|
|
4
|
12
|
|
|
12
|
|
68
|
use warnings; |
|
|
12
|
|
|
|
|
25
|
|
|
|
12
|
|
|
|
|
300
|
|
|
5
|
12
|
|
|
12
|
|
1203
|
use utf8; |
|
|
12
|
|
|
|
|
48
|
|
|
|
12
|
|
|
|
|
57
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = "2.2102"; |
|
8
|
|
|
|
|
|
|
|
|
9
|
12
|
|
|
12
|
|
5333
|
use Data::Dumper; |
|
|
12
|
|
|
|
|
55178
|
|
|
|
12
|
|
|
|
|
813
|
|
|
10
|
|
|
|
|
|
|
$Data::Dumper::Sortkeys = 1; |
|
11
|
12
|
|
|
12
|
|
82
|
use Carp; |
|
|
12
|
|
|
|
|
26
|
|
|
|
12
|
|
|
|
|
754
|
|
|
12
|
12
|
|
|
12
|
|
76
|
use List::Util qw(pairmap pairgrep); |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
1223
|
|
|
13
|
12
|
|
|
12
|
|
85
|
use Scalar::Util qw(looks_like_number); |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
576
|
|
|
14
|
12
|
|
|
12
|
|
5308
|
use Text::VisualWidth::PP 'vwidth'; |
|
|
12
|
|
|
|
|
293452
|
|
|
|
12
|
|
|
|
|
1634
|
|
|
15
|
95
|
|
|
95
|
0
|
402
|
sub pwidth { vwidth $_[0] =~ s/\X\cH{1,2}//gr } |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
###################################################################### |
|
18
|
12
|
|
|
12
|
|
116
|
use Exporter 'import'; |
|
|
12
|
|
|
|
|
22
|
|
|
|
12
|
|
|
|
|
1954
|
|
|
19
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
|
20
|
|
|
|
|
|
|
constants => [ qw( |
|
21
|
|
|
|
|
|
|
&LINEBREAK_NONE |
|
22
|
|
|
|
|
|
|
&LINEBREAK_ALL |
|
23
|
|
|
|
|
|
|
&LINEBREAK_RUNIN |
|
24
|
|
|
|
|
|
|
&LINEBREAK_RUNOUT |
|
25
|
|
|
|
|
|
|
) ], |
|
26
|
|
|
|
|
|
|
regex => [ qw( |
|
27
|
|
|
|
|
|
|
$reset_re |
|
28
|
|
|
|
|
|
|
$color_re |
|
29
|
|
|
|
|
|
|
$erase_re |
|
30
|
|
|
|
|
|
|
$csi_re |
|
31
|
|
|
|
|
|
|
$osc_re |
|
32
|
|
|
|
|
|
|
) ], |
|
33
|
|
|
|
|
|
|
); |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
our @EXPORT_OK = ( qw(&ansi_fold), |
|
36
|
|
|
|
|
|
|
@{$EXPORT_TAGS{constants}}, |
|
37
|
|
|
|
|
|
|
@{$EXPORT_TAGS{regex}}, |
|
38
|
|
|
|
|
|
|
); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub ansi_fold { |
|
41
|
429
|
|
|
429
|
0
|
142888
|
my($text, $width, @option) = @_; |
|
42
|
429
|
|
|
|
|
1356
|
__PACKAGE__->fold($text, width => $width, @option); |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
###################################################################### |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
our $alphanum_re = qr{ [_\d\p{Latin}\p{Greek}\p{Cyrillic}\p{Hangul}] }x; |
|
47
|
|
|
|
|
|
|
our $nonspace_re = qr{ \p{IsPrintableLatin} }x; |
|
48
|
|
|
|
|
|
|
our $reset_re = qr{ \e \[ [0;]* m }x; |
|
49
|
|
|
|
|
|
|
our $color_re = qr{ \e \[ [\d;]* m }x; |
|
50
|
|
|
|
|
|
|
our $erase_re = qr{ \e \[ [\d;]* K }x; |
|
51
|
|
|
|
|
|
|
our $csi_re = qr{ |
|
52
|
|
|
|
|
|
|
# see ECMA-48 5.4 Control sequences |
|
53
|
|
|
|
|
|
|
(?: \e\[ | \x9b ) # csi |
|
54
|
|
|
|
|
|
|
[\x30-\x3f]* # parameter bytes |
|
55
|
|
|
|
|
|
|
[\x20-\x2f]* # intermediate bytes |
|
56
|
|
|
|
|
|
|
[\x40-\x7e] # final byte |
|
57
|
|
|
|
|
|
|
}x; |
|
58
|
|
|
|
|
|
|
our $osc_re = qr{ |
|
59
|
|
|
|
|
|
|
# see ECMA-48 8.3.89 OSC - OPERATING SYSTEM COMMAND |
|
60
|
|
|
|
|
|
|
(?: \e\] | \x9d ) # osc |
|
61
|
|
|
|
|
|
|
[\x08-\x13\x20-\x7d]*+ # command |
|
62
|
|
|
|
|
|
|
(?: \e\\ | \x9c | \a ) # st: string terminator |
|
63
|
|
|
|
|
|
|
}x; |
|
64
|
|
|
|
|
|
|
|
|
65
|
12
|
|
|
12
|
|
27595
|
use constant SGR_RESET => "\e[m"; |
|
|
12
|
|
|
|
|
27
|
|
|
|
12
|
|
|
|
|
1938
|
|
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub IsPrintableLatin { |
|
68
|
2
|
|
|
2
|
0
|
1043
|
return <<"END"; |
|
69
|
|
|
|
|
|
|
+utf8::ASCII |
|
70
|
|
|
|
|
|
|
+utf8::Latin |
|
71
|
|
|
|
|
|
|
-utf8::White_Space |
|
72
|
|
|
|
|
|
|
END |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub IsWideSpacing { |
|
76
|
5
|
|
|
5
|
0
|
746
|
return <<"END"; |
|
77
|
|
|
|
|
|
|
+utf8::East_Asian_Width=Wide |
|
78
|
|
|
|
|
|
|
+utf8::East_Asian_Width=FullWidth |
|
79
|
|
|
|
|
|
|
-utf8::Nonspacing_Mark |
|
80
|
|
|
|
|
|
|
END |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub IsWideAmbiguousSpacing { |
|
84
|
1
|
|
|
1
|
0
|
135
|
return <<"END"; |
|
85
|
|
|
|
|
|
|
+utf8::East_Asian_Width=Wide |
|
86
|
|
|
|
|
|
|
+utf8::East_Asian_Width=FullWidth |
|
87
|
|
|
|
|
|
|
+utf8::East_Asian_Width=Ambiguous |
|
88
|
|
|
|
|
|
|
-utf8::Nonspacing_Mark |
|
89
|
|
|
|
|
|
|
END |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub _startWideSpacing { |
|
93
|
|
|
|
|
|
|
# look at $_ |
|
94
|
374
|
100
|
|
374
|
|
658
|
if ($Text::VisualWidth::PP::EastAsian) { |
|
95
|
2
|
|
|
|
|
18
|
/^\p{IsWideAmbiguousSpacing}/; |
|
96
|
|
|
|
|
|
|
} else { |
|
97
|
372
|
|
|
|
|
1693
|
/^\p{IsWideSpacing}/; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
use constant { |
|
102
|
12
|
|
|
|
|
1725
|
LINEBREAK_NONE => 0, |
|
103
|
|
|
|
|
|
|
LINEBREAK_RUNIN => 1, |
|
104
|
|
|
|
|
|
|
LINEBREAK_RUNOUT => 2, |
|
105
|
|
|
|
|
|
|
LINEBREAK_ALL => 3, |
|
106
|
12
|
|
|
12
|
|
2876
|
}; |
|
|
12
|
|
|
|
|
28
|
|
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
our $DEFAULT_LINEBREAK = LINEBREAK_NONE; |
|
109
|
|
|
|
|
|
|
our $DEFAULT_RUNIN_WIDTH = 2; |
|
110
|
|
|
|
|
|
|
our $DEFAULT_RUNOUT_WIDTH = 2; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
BEGIN { |
|
113
|
12
|
50
|
|
12
|
|
1056
|
if ($] < 5.016) { |
|
114
|
0
|
|
|
|
|
0
|
require charnames; |
|
115
|
0
|
|
|
|
|
0
|
charnames->import(':full'); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
our %TABSTYLE = ( |
|
120
|
|
|
|
|
|
|
pairmap { |
|
121
|
|
|
|
|
|
|
( $a =~ s/_/-/gr => ref $b ? $b : [ $b, $b ] ); |
|
122
|
|
|
|
|
|
|
} |
|
123
|
12
|
|
|
12
|
|
6399
|
symbol => [ "\N{SYMBOL FOR HORIZONTAL TABULATION}", # ␉ |
|
|
12
|
|
|
|
|
101383
|
|
|
|
12
|
|
|
|
|
80
|
|
|
124
|
|
|
|
|
|
|
"\N{SYMBOL FOR SPACE}" ], # ␠ |
|
125
|
|
|
|
|
|
|
shade => [ "\N{MEDIUM SHADE}", # ▒ |
|
126
|
|
|
|
|
|
|
"\N{LIGHT SHADE}" ], # ░ |
|
127
|
|
|
|
|
|
|
block => [ "\N{LOWER ONE QUARTER BLOCK}", # ▂ |
|
128
|
|
|
|
|
|
|
"\N{LOWER ONE EIGHTH BLOCK}" ], # ▁ |
|
129
|
|
|
|
|
|
|
bar => [ "\N{BOX DRAWINGS HEAVY RIGHT}", # ╺ |
|
130
|
|
|
|
|
|
|
"\N{BOX DRAWINGS LIGHT HORIZONTAL}" ], # ─ |
|
131
|
|
|
|
|
|
|
dash => [ "\N{BOX DRAWINGS HEAVY RIGHT}", # ╺ |
|
132
|
|
|
|
|
|
|
"\N{BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL}" ], # ╌ |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
dot => '.', |
|
135
|
|
|
|
|
|
|
space => ' ', |
|
136
|
|
|
|
|
|
|
emspace => "\N{EM SPACE}", # |
|
137
|
|
|
|
|
|
|
middle_dot => "\N{MIDDLE DOT}", # · |
|
138
|
|
|
|
|
|
|
arrow => "\N{RIGHTWARDS ARROW}", # → |
|
139
|
|
|
|
|
|
|
double_arrow => "\N{RIGHTWARDS DOUBLE ARROW}", # ⇒ |
|
140
|
|
|
|
|
|
|
triple_arrow => "\N{RIGHTWARDS TRIPLE ARROW}", # ⇛ |
|
141
|
|
|
|
|
|
|
white_arrow => "\N{RIGHTWARDS WHITE ARROW}", # ⇨ |
|
142
|
|
|
|
|
|
|
wave_arrow => "\N{RIGHTWARDS WAVE ARROW}", # ↝ |
|
143
|
|
|
|
|
|
|
circle_arrow => "\N{CIRCLED HEAVY WHITE RIGHTWARDS ARROW}", # ➲ |
|
144
|
|
|
|
|
|
|
curved_arrow => "\N{HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW}",# ➥ |
|
145
|
|
|
|
|
|
|
shadow_arrow => "\N{HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW}",# ➮ |
|
146
|
|
|
|
|
|
|
squat_arrow => "\N{SQUAT BLACK RIGHTWARDS ARROW}", # ➧ |
|
147
|
|
|
|
|
|
|
squiggle => "\N{RIGHTWARDS SQUIGGLE ARROW}", # ⇝ |
|
148
|
|
|
|
|
|
|
harpoon => "\N{RIGHTWARDS HARPOON WITH BARB UPWARDS}", # ⇀ |
|
149
|
|
|
|
|
|
|
cuneiform => "\N{CUNEIFORM SIGN TAB}", # 𒋰 |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
); |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
my @default = ( |
|
154
|
|
|
|
|
|
|
text => '', |
|
155
|
|
|
|
|
|
|
width => undef, |
|
156
|
|
|
|
|
|
|
padding => 0, |
|
157
|
|
|
|
|
|
|
boundary => '', |
|
158
|
|
|
|
|
|
|
padchar => ' ', |
|
159
|
|
|
|
|
|
|
prefix => '', |
|
160
|
|
|
|
|
|
|
ambiguous => 'narrow', |
|
161
|
|
|
|
|
|
|
margin => 0, |
|
162
|
|
|
|
|
|
|
linebreak => $DEFAULT_LINEBREAK, |
|
163
|
|
|
|
|
|
|
runin => $DEFAULT_RUNIN_WIDTH, |
|
164
|
|
|
|
|
|
|
runout => $DEFAULT_RUNOUT_WIDTH, |
|
165
|
|
|
|
|
|
|
expand => 0, |
|
166
|
|
|
|
|
|
|
tabstop => 8, |
|
167
|
|
|
|
|
|
|
tabhead => ' ', |
|
168
|
|
|
|
|
|
|
tabspace => ' ', |
|
169
|
|
|
|
|
|
|
discard => {}, |
|
170
|
|
|
|
|
|
|
); |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub new { |
|
173
|
13
|
|
|
13
|
0
|
1823
|
my $class = shift; |
|
174
|
13
|
|
|
|
|
290
|
my $obj = bless { @default }, $class; |
|
175
|
13
|
100
|
|
|
|
73
|
$obj->configure(@_) if @_; |
|
176
|
13
|
|
|
|
|
47
|
$obj; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
INTERNAL_METHODS: { |
|
180
|
|
|
|
|
|
|
sub spawn { |
|
181
|
626
|
|
|
626
|
0
|
921
|
my $obj = shift; |
|
182
|
626
|
|
|
|
|
986
|
my $class = ref $obj; |
|
183
|
626
|
|
|
672
|
|
5400
|
my %new = ( %$obj, pairgrep { defined $b } @_ ); |
|
|
672
|
|
|
|
|
5392
|
|
|
184
|
626
|
|
|
|
|
3030
|
bless \%new, $class; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
626
|
100
|
|
626
|
0
|
1861
|
sub do_runin { $_[0]->{linebreak} & LINEBREAK_RUNIN && $_[0]->{runin} > 0 } |
|
187
|
530
|
100
|
|
530
|
0
|
2408
|
sub do_runout { $_[0]->{linebreak} & LINEBREAK_RUNOUT && $_[0]->{runout} > 0 } |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
12
|
|
|
12
|
|
225402
|
use Text::ANSI::Fold::Japanese::W3C qw(%prohibition); |
|
|
12
|
|
|
|
|
37
|
|
|
|
12
|
|
|
|
|
11107
|
|
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub chars_to_regex { |
|
193
|
24
|
|
|
24
|
0
|
7029
|
my $chars = join '', @_; |
|
194
|
24
|
|
|
|
|
53
|
my($c, @s); |
|
195
|
24
|
|
|
|
|
1150
|
for ($chars =~ /\X/g) { |
|
196
|
1860
|
100
|
|
|
|
3249
|
if (length == 1) { |
|
197
|
1848
|
|
|
|
|
2512
|
$c .= $_; |
|
198
|
|
|
|
|
|
|
} else { |
|
199
|
12
|
|
|
|
|
50
|
push @s, $_; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
} |
|
202
|
24
|
100
|
|
|
|
245
|
if (@s) { |
|
203
|
12
|
|
|
|
|
34
|
local $" = '|'; |
|
204
|
12
|
|
|
|
|
905
|
qr/(?:[\Q$c\E]|@s)/; |
|
205
|
|
|
|
|
|
|
} else { |
|
206
|
12
|
|
|
|
|
341
|
qr/[\Q$c\E]/; |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my %prohibition_re = do { |
|
211
|
|
|
|
|
|
|
head => do { |
|
212
|
|
|
|
|
|
|
my $re = chars_to_regex @prohibition{qw(head postfix)}; |
|
213
|
|
|
|
|
|
|
qr/(?: $re | \p{Space_Separator} )/x; |
|
214
|
|
|
|
|
|
|
}, |
|
215
|
|
|
|
|
|
|
end => chars_to_regex @prohibition{qw(end prefix)}, |
|
216
|
|
|
|
|
|
|
}; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub configure { |
|
219
|
47
|
|
|
47
|
0
|
13856
|
my $obj = shift; |
|
220
|
47
|
100
|
|
|
|
155
|
if (not ref $obj) { |
|
221
|
12
|
|
|
|
|
38
|
$obj = state $private = __PACKAGE__->new; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
47
|
50
|
|
|
|
156
|
croak "invalid parameter" if @_ % 2; |
|
224
|
47
|
|
|
|
|
151
|
while (@_ >= 2) { |
|
225
|
71
|
|
|
|
|
187
|
my($a, $b) = splice @_, 0, 2; |
|
226
|
|
|
|
|
|
|
|
|
227
|
71
|
100
|
|
|
|
153
|
if ($a eq 'tabstyle') { |
|
228
|
1
|
|
50
|
|
|
4
|
$b // next; |
|
229
|
1
|
50
|
|
|
|
20
|
my($h, $s) = $b =~ /([-\w]+)/g or croak "$b: invalid tabstyle"; |
|
230
|
1
|
|
33
|
|
|
8
|
$s ||= $h; |
|
231
|
|
|
|
|
|
|
my %style = ( |
|
232
|
|
|
|
|
|
|
h => ($TABSTYLE{$h} or croak "$h: invalid tabstyle"), |
|
233
|
1
|
|
33
|
|
|
16
|
s => ($TABSTYLE{$s} or croak "$s: invalid tabstyle"), |
|
|
|
|
33
|
|
|
|
|
|
234
|
|
|
|
|
|
|
); |
|
235
|
|
|
|
|
|
|
unshift @_, |
|
236
|
|
|
|
|
|
|
tabhead => $style{h}->[0], |
|
237
|
1
|
|
|
|
|
7
|
tabspace => $style{s}->[1]; |
|
238
|
1
|
|
|
|
|
5
|
next; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
|
|
241
|
70
|
50
|
|
|
|
196
|
croak "$a: invalid parameter" if not exists $obj->{$a}; |
|
242
|
70
|
|
|
|
|
206
|
$obj->{$a} = $b; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
47
|
50
|
|
|
|
181
|
if (ref $obj->{discard} eq 'ARRAY') { |
|
245
|
0
|
|
|
|
|
0
|
$obj->{discard} = { map { uc $_ => 1 } @{$obj->{discard}} }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
246
|
|
|
|
|
|
|
} |
|
247
|
47
|
|
|
|
|
99
|
$obj; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
my @color_stack; |
|
251
|
|
|
|
|
|
|
my @bg_stack; |
|
252
|
|
|
|
|
|
|
my @reset; |
|
253
|
138
|
|
|
138
|
0
|
441
|
sub put_reset { @reset = shift }; |
|
254
|
|
|
|
|
|
|
sub pop_reset { |
|
255
|
169
|
100
|
|
169
|
0
|
393
|
@reset ? do { @color_stack = (); pop @reset } : ''; |
|
|
138
|
|
|
|
|
231
|
|
|
|
138
|
|
|
|
|
278
|
|
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
12
|
|
|
12
|
|
106
|
use constant MAX_INT => ~0 >> 1; |
|
|
12
|
|
|
|
|
27
|
|
|
|
12
|
|
|
|
|
10092
|
|
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub fold { |
|
261
|
626
|
|
|
626
|
0
|
65319
|
my $obj = shift; |
|
262
|
626
|
|
50
|
|
|
1552
|
local $_ = shift // ''; |
|
263
|
|
|
|
|
|
|
|
|
264
|
626
|
100
|
|
|
|
1368
|
if (not ref $obj) { |
|
265
|
429
|
|
|
|
|
742
|
$obj = state $private = configure(); |
|
266
|
|
|
|
|
|
|
} |
|
267
|
626
|
|
|
|
|
1957
|
my $opt = $obj->spawn(splice @_); |
|
268
|
|
|
|
|
|
|
|
|
269
|
626
|
|
|
|
|
1111
|
my $width = $opt->{width}; |
|
270
|
626
|
50
|
|
|
|
1807
|
croak "invalid width" if not looks_like_number $width; |
|
271
|
626
|
100
|
|
|
|
1268
|
$width = MAX_INT if $width < 0; |
|
272
|
626
|
50
|
|
|
|
1345
|
($width -= $opt->{margin}) > 0 or croak "margin too big"; |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
my $word_char_re = |
|
275
|
|
|
|
|
|
|
{ word => $alphanum_re, space => $nonspace_re } |
|
276
|
626
|
|
50
|
|
|
2222
|
->{$opt->{boundary} // ''}; |
|
277
|
|
|
|
|
|
|
|
|
278
|
626
|
|
|
|
|
1596
|
$Text::VisualWidth::PP::EastAsian = $opt->{ambiguous} eq 'wide'; |
|
279
|
|
|
|
|
|
|
|
|
280
|
626
|
|
|
|
|
939
|
my $folded = ''; |
|
281
|
626
|
|
|
|
|
842
|
my $eol = ''; |
|
282
|
626
|
|
|
|
|
829
|
my $room = $width; |
|
283
|
626
|
|
|
|
|
1069
|
@bg_stack = @color_stack = @reset = (); |
|
284
|
626
|
100
|
|
|
|
2281
|
my $yield_re = $opt->{expand} ? qr/[^\e\n\f\r\t]/ : qr/[^\e\n\f\r]/; |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
FOLD: |
|
287
|
626
|
|
|
|
|
1560
|
while (length) { |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# newline |
|
290
|
1788
|
50
|
|
|
|
4372
|
if (s/\A(\r*\n)//) { |
|
291
|
0
|
|
|
|
|
0
|
$eol = $1; |
|
292
|
0
|
|
|
|
|
0
|
last; |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
# formfeed / carriage return |
|
295
|
1788
|
50
|
|
|
|
4786
|
if (s/\A([\f\r]+)//) { |
|
296
|
0
|
0
|
|
|
|
0
|
last if length == 0; |
|
297
|
0
|
|
|
|
|
0
|
$folded .= $1; |
|
298
|
0
|
|
|
|
|
0
|
$room = $width; |
|
299
|
0
|
|
|
|
|
0
|
next; |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
# ECMA-48 OPERATING SYSTEM COMMAND |
|
302
|
1788
|
50
|
|
|
|
7826
|
if (s/\A($osc_re)//) { |
|
303
|
0
|
0
|
|
|
|
0
|
$folded .= $1 unless $obj->{discard}->{OSC}; |
|
304
|
0
|
|
|
|
|
0
|
next; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
# erase line (assume 0) |
|
307
|
1788
|
100
|
|
|
|
5594
|
if (s/\A($erase_re)//) { |
|
308
|
1
|
50
|
|
|
|
6
|
$folded .= $1 unless $obj->{discard}->{EL}; |
|
309
|
1
|
|
|
|
|
4
|
@bg_stack = @color_stack; |
|
310
|
1
|
|
|
|
|
2
|
next; |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
# reset |
|
313
|
1787
|
100
|
|
|
|
6038
|
if (s/\A($reset_re+($erase_re*))//) { |
|
314
|
138
|
|
|
|
|
380
|
put_reset($1); |
|
315
|
138
|
50
|
|
|
|
315
|
@bg_stack = () if $2; |
|
316
|
138
|
|
|
|
|
405
|
next; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
|
|
319
|
1649
|
100
|
|
|
|
3401
|
last if $room < 1; |
|
320
|
1136
|
100
|
100
|
|
|
2478
|
last if $room != $width and &_startWideSpacing and $room < 2; |
|
|
|
|
100
|
|
|
|
|
|
321
|
|
|
|
|
|
|
|
|
322
|
1126
|
100
|
|
|
|
5265
|
if (@reset) { |
|
323
|
97
|
|
|
|
|
182
|
$folded .= pop_reset(); |
|
324
|
|
|
|
|
|
|
} |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# ANSI color sequence |
|
327
|
1126
|
100
|
|
|
|
3993
|
if (s/\A($color_re)//) { |
|
328
|
182
|
|
|
|
|
461
|
$folded .= $1; |
|
329
|
182
|
|
|
|
|
456
|
push @color_stack, $1; |
|
330
|
182
|
|
|
|
|
578
|
next; |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# tab |
|
334
|
944
|
100
|
100
|
|
|
3008
|
if ($opt->{expand} and s/\A\t//) { |
|
335
|
112
|
|
|
|
|
266
|
my $space = $opt->{tabstop} - ($width - $room) % $opt->{tabstop}; |
|
336
|
112
|
|
|
|
|
322
|
$_ = $opt->{tabhead} . $opt->{tabspace} x ($space - 1) . $_; |
|
337
|
112
|
|
|
|
|
331
|
next; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# backspace |
|
341
|
832
|
|
|
|
|
1170
|
my $bs = 0; |
|
342
|
832
|
|
|
|
|
2204
|
while (s/\A(?:\X\cH+)++(?\X|\z)//p) { |
|
343
|
12
|
|
|
12
|
|
5449
|
my $w = vwidth($+{c}); |
|
|
12
|
|
|
|
|
5686
|
|
|
|
12
|
|
|
|
|
21766
|
|
|
|
839
|
|
|
|
|
2533
|
|
|
344
|
839
|
100
|
|
|
|
30128
|
if ($w > $room) { |
|
345
|
7
|
100
|
|
|
|
17
|
if ($folded eq '') { |
|
346
|
4
|
|
|
|
|
9
|
$folded .= ${^MATCH}; |
|
347
|
4
|
|
|
|
|
6
|
$room -= $w; |
|
348
|
|
|
|
|
|
|
} else { |
|
349
|
3
|
|
|
|
|
8
|
$_ = ${^MATCH} . $_; |
|
350
|
|
|
|
|
|
|
} |
|
351
|
7
|
|
|
|
|
23
|
last FOLD; |
|
352
|
|
|
|
|
|
|
} |
|
353
|
832
|
|
|
|
|
1491
|
$folded .= ${^MATCH}; |
|
354
|
832
|
|
|
|
|
1071
|
$room -= $w; |
|
355
|
832
|
|
|
|
|
980
|
$bs++; |
|
356
|
832
|
100
|
|
|
|
4447
|
last if $room < 1; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
825
|
100
|
|
|
|
1516
|
next if $bs; |
|
359
|
|
|
|
|
|
|
|
|
360
|
769
|
50
|
|
|
|
5270
|
if (s/\A(\e+|(?:${yield_re}(?!\cH))+)//) { |
|
361
|
769
|
|
|
|
|
1891
|
my $s = $1; |
|
362
|
769
|
100
|
|
|
|
1957
|
if ((my $w = vwidth($s)) <= $room) { |
|
363
|
330
|
|
|
|
|
41121
|
$folded .= $s; |
|
364
|
330
|
|
|
|
|
479
|
$room -= $w; |
|
365
|
330
|
|
|
|
|
1044
|
next; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
439
|
|
|
|
|
117490
|
my($a, $b, $w) = simple_fold($s, $room); |
|
368
|
439
|
50
|
66
|
|
|
1225
|
if ($w > $room and $room < $width) { |
|
369
|
0
|
|
|
|
|
0
|
$_ = $s . $_; |
|
370
|
0
|
|
|
|
|
0
|
last; |
|
371
|
|
|
|
|
|
|
} |
|
372
|
439
|
|
|
|
|
1213
|
($folded, $_) = ($folded . $a, $b . $_); |
|
373
|
439
|
|
|
|
|
1431
|
$room -= $w; |
|
374
|
|
|
|
|
|
|
} else { |
|
375
|
0
|
|
|
|
|
0
|
die "panic ($_)"; |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
} |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
## |
|
380
|
|
|
|
|
|
|
## --boundary=word |
|
381
|
|
|
|
|
|
|
## |
|
382
|
626
|
100
|
100
|
|
|
5400
|
if ($word_char_re |
|
|
|
|
100
|
|
|
|
|
|
383
|
|
|
|
|
|
|
and my($w2) = /\A( (?: ${word_char_re} \cH ? ) + )/x |
|
384
|
|
|
|
|
|
|
and my($lead, $w1) = $folded =~ m{ |
|
385
|
|
|
|
|
|
|
\A ## avoid CSI final char making a word |
|
386
|
|
|
|
|
|
|
( (?: [^\e]* ${csi_re}++ ) *+ .*? ) |
|
387
|
|
|
|
|
|
|
( (?: ${word_char_re} \cH ? ) + ) |
|
388
|
|
|
|
|
|
|
\z }x |
|
389
|
|
|
|
|
|
|
) { |
|
390
|
|
|
|
|
|
|
## Break line before word only when enough space will be |
|
391
|
|
|
|
|
|
|
## provided for the word in the next turn. |
|
392
|
36
|
|
|
|
|
3861
|
my $l = pwidth($w1); |
|
393
|
|
|
|
|
|
|
## prefix length |
|
394
|
36
|
100
|
|
|
|
607
|
my $p = $opt->{prefix} eq '' ? 0 : vwidth($opt->{prefix}); |
|
395
|
36
|
100
|
66
|
|
|
210
|
if ($room + $l < $width - $p and $l + pwidth($w2) <= $width - $p) { |
|
396
|
31
|
|
|
|
|
527
|
$folded = $lead; |
|
397
|
31
|
|
|
|
|
74
|
$_ = $w1 . pop_reset() . $_; |
|
398
|
31
|
|
|
|
|
57
|
$room += $l; |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
} |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
## |
|
403
|
|
|
|
|
|
|
## RUN-OUT |
|
404
|
|
|
|
|
|
|
## |
|
405
|
626
|
100
|
100
|
|
|
2232
|
if ($_ ne '' and $opt->do_runout) { |
|
406
|
83
|
100
|
66
|
|
|
1795
|
if ($folded =~ m{ (? (?! ${reset_re}) ${color_re}*+ ) |
|
|
|
|
100
|
|
|
|
|
|
407
|
|
|
|
|
|
|
(? |
|
408
|
|
|
|
|
|
|
(?: ($prohibition_re{end}) (?: \cH{1,2} \g{-1})* )+ |
|
409
|
|
|
|
|
|
|
) \z |
|
410
|
|
|
|
|
|
|
}xp |
|
411
|
|
|
|
|
|
|
and ${^PREMATCH} ne '' |
|
412
|
|
|
|
|
|
|
and (my $w = pwidth $+{runout}) <= $opt->{runout}) { |
|
413
|
|
|
|
|
|
|
|
|
414
|
18
|
|
|
|
|
314
|
$folded = ${^PREMATCH}; |
|
415
|
18
|
|
|
|
|
77
|
$_ = join '', ${^MATCH}, @reset, $_; |
|
416
|
18
|
100
|
|
|
|
104
|
pop_reset() if $+{color}; |
|
417
|
18
|
|
|
|
|
49
|
$room += $w; |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
|
|
421
|
626
|
100
|
|
|
|
1499
|
$folded .= pop_reset() if @reset; |
|
422
|
|
|
|
|
|
|
|
|
423
|
626
|
|
|
|
|
1057
|
$room += $opt->{margin}; |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
## |
|
426
|
|
|
|
|
|
|
## RUN-IN |
|
427
|
|
|
|
|
|
|
## |
|
428
|
626
|
100
|
|
|
|
1356
|
if ($opt->do_runin) { |
|
429
|
87
|
|
|
|
|
125
|
my @runin; |
|
430
|
87
|
|
|
|
|
134
|
my $m = $opt->{runin}; |
|
431
|
87
|
|
100
|
|
|
1176
|
while ($m > 0 and |
|
432
|
|
|
|
|
|
|
m{\A (? ${color_re}*+) |
|
433
|
|
|
|
|
|
|
(? $prohibition_re{head} ) |
|
434
|
|
|
|
|
|
|
( \cH{1,2} \g{runin} )* # multiple strike |
|
435
|
|
|
|
|
|
|
(? (?: $erase_re* $reset_re+ $erase_re* )? ) |
|
436
|
|
|
|
|
|
|
}xp) { |
|
437
|
28
|
|
|
|
|
129
|
my $w = vwidth $+{runin}; |
|
438
|
28
|
50
|
|
|
|
583
|
last if ($m -= $w) < 0; |
|
439
|
28
|
100
|
|
|
|
123
|
$+{color} and do { push @color_stack, $+{color} }; |
|
|
2
|
|
|
|
|
8
|
|
|
440
|
28
|
100
|
|
|
|
115
|
$+{reset} and do { @color_stack = () }; |
|
|
2
|
|
|
|
|
5
|
|
|
441
|
28
|
|
|
|
|
51
|
$room -= $w; |
|
442
|
28
|
|
|
|
|
65
|
push @runin, ${^MATCH}; |
|
443
|
28
|
|
|
|
|
155
|
$_ = ${^POSTMATCH}; |
|
444
|
|
|
|
|
|
|
} |
|
445
|
87
|
100
|
|
|
|
840
|
$folded .= join '', @runin if @runin; |
|
446
|
|
|
|
|
|
|
} |
|
447
|
|
|
|
|
|
|
|
|
448
|
626
|
100
|
|
|
|
1284
|
if (@color_stack) { |
|
449
|
44
|
|
|
|
|
96
|
$folded .= SGR_RESET; |
|
450
|
44
|
50
|
|
|
|
149
|
$_ = join '', @color_stack, $_ if $_ ne ''; |
|
451
|
|
|
|
|
|
|
} |
|
452
|
|
|
|
|
|
|
|
|
453
|
626
|
100
|
100
|
|
|
1444
|
if ($opt->{padding} and $room > 0) { |
|
454
|
12
|
|
|
|
|
47
|
my $padding = $opt->{padchar} x $room; |
|
455
|
12
|
100
|
|
|
|
37
|
if (@bg_stack) { |
|
456
|
1
|
|
|
|
|
5
|
$padding = join '', @bg_stack, $padding, SGR_RESET; |
|
457
|
|
|
|
|
|
|
} |
|
458
|
12
|
|
|
|
|
29
|
$folded .= $padding; |
|
459
|
|
|
|
|
|
|
} |
|
460
|
|
|
|
|
|
|
|
|
461
|
626
|
100
|
100
|
|
|
2204
|
if (length and my $p = $opt->{prefix}) { |
|
462
|
19
|
100
|
|
|
|
46
|
my $s = ref $p eq 'CODE' ? &$p : $p; |
|
463
|
19
|
|
|
|
|
57
|
$_ = $s . $_; |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
|
|
466
|
626
|
|
|
|
|
5923
|
($folded . $eol, $_, $width - $room); |
|
467
|
|
|
|
|
|
|
} |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
## |
|
470
|
|
|
|
|
|
|
## Trim off one or more *logical* characters from the top. |
|
471
|
|
|
|
|
|
|
## |
|
472
|
|
|
|
|
|
|
sub simple_fold { |
|
473
|
439
|
|
|
439
|
0
|
711
|
my $orig = shift; |
|
474
|
439
|
|
|
|
|
696
|
my $width = shift; |
|
475
|
439
|
50
|
|
|
|
872
|
$width <= 0 and croak "parameter error"; |
|
476
|
|
|
|
|
|
|
|
|
477
|
439
|
50
|
|
|
|
7147
|
my($left, $right) = $orig =~ m/^(\X{0,$width}+)(.*)/ or die; |
|
478
|
|
|
|
|
|
|
|
|
479
|
439
|
|
|
|
|
1319
|
my $w = vwidth($left); |
|
480
|
439
|
|
|
|
|
6730
|
while ($w > $width) { |
|
481
|
86
|
|
|
|
|
199
|
my $trim = do { |
|
482
|
|
|
|
|
|
|
# use POSIX qw(ceil); |
|
483
|
|
|
|
|
|
|
# ceil(($w - $width) / 2) || 1; |
|
484
|
86
|
50
|
|
|
|
314
|
int(($w - $width) / 2 + 0.5) || 1; |
|
485
|
|
|
|
|
|
|
}; |
|
486
|
86
|
100
|
|
|
|
2232
|
$left =~ s/\X \K ( \X{$trim} ) \z//x or last; |
|
487
|
83
|
|
|
|
|
285
|
$right = $1 . $right; |
|
488
|
83
|
|
|
|
|
203
|
$w -= vwidth($1); |
|
489
|
|
|
|
|
|
|
} |
|
490
|
|
|
|
|
|
|
|
|
491
|
439
|
|
|
|
|
2739
|
($left, $right, $w); |
|
492
|
|
|
|
|
|
|
} |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
###################################################################### |
|
495
|
|
|
|
|
|
|
# EXTERNAL METHODS |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub text :lvalue { |
|
498
|
7
|
|
|
7
|
0
|
592
|
my $obj = shift; |
|
499
|
7
|
100
|
|
|
|
55
|
if (@_ == 0) { |
|
500
|
6
|
|
|
|
|
46
|
$obj->{text}; |
|
501
|
|
|
|
|
|
|
} else { |
|
502
|
1
|
50
|
|
|
|
5
|
croak "Invalid argument" if @_ > 1; |
|
503
|
1
|
|
|
|
|
3
|
$obj->{text} = shift; |
|
504
|
1
|
|
|
|
|
2
|
$obj; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
} |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
sub retrieve { |
|
509
|
65
|
|
|
65
|
0
|
125
|
my $obj = shift; |
|
510
|
65
|
|
|
|
|
148
|
local *_ = \$obj->{text}; |
|
511
|
65
|
100
|
|
|
|
147
|
return '' if not defined $_; |
|
512
|
56
|
|
|
|
|
141
|
(my $folded, $_) = $obj->fold($_, @_); |
|
513
|
56
|
100
|
|
|
|
125
|
$_ = undef if length == 0; |
|
514
|
56
|
|
|
|
|
183
|
$folded; |
|
515
|
|
|
|
|
|
|
} |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
sub chops { |
|
518
|
15
|
|
|
15
|
0
|
35
|
my $obj = shift; |
|
519
|
15
|
|
|
|
|
30
|
my %opt = @_; |
|
520
|
15
|
|
66
|
|
|
61
|
my $width = $opt{width} // $obj->{width}; |
|
521
|
|
|
|
|
|
|
|
|
522
|
15
|
|
|
|
|
24
|
my @chops; |
|
523
|
|
|
|
|
|
|
|
|
524
|
15
|
100
|
|
|
|
38
|
if (ref $width eq 'ARRAY') { |
|
525
|
8
|
|
|
|
|
13
|
for my $w (@{$width}) { |
|
|
8
|
|
|
|
|
18
|
|
|
526
|
40
|
100
|
|
|
|
114
|
if ($w == 0) { |
|
|
|
100
|
|
|
|
|
|
|
527
|
2
|
|
|
|
|
4
|
push @chops, ''; |
|
528
|
|
|
|
|
|
|
} |
|
529
|
|
|
|
|
|
|
elsif ((my $chop = $obj->retrieve(width => $w)) ne '') { |
|
530
|
35
|
|
|
|
|
85
|
push @chops, $chop; |
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
else { |
|
533
|
3
|
|
|
|
|
6
|
last; |
|
534
|
|
|
|
|
|
|
} |
|
535
|
|
|
|
|
|
|
} |
|
536
|
|
|
|
|
|
|
} |
|
537
|
|
|
|
|
|
|
else { |
|
538
|
7
|
|
|
|
|
17
|
while ((my $chop = $obj->retrieve(width => $width)) ne '') { |
|
539
|
19
|
|
|
|
|
52
|
push @chops, $chop; |
|
540
|
|
|
|
|
|
|
} |
|
541
|
|
|
|
|
|
|
} |
|
542
|
|
|
|
|
|
|
|
|
543
|
15
|
|
|
|
|
139
|
@chops; |
|
544
|
|
|
|
|
|
|
} |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
1; |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
__END__ |