line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ============================================================================ |
2
|
|
|
|
|
|
|
package MooseX::App::Plugin::Term::Meta::Attribute; |
3
|
|
|
|
|
|
|
# ============================================================================ |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
1536
|
use utf8; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
6
|
1
|
|
|
1
|
|
52
|
use 5.010; |
|
1
|
|
|
|
|
3
|
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
8
|
use namespace::autoclean; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
7
|
|
9
|
1
|
|
|
1
|
|
91
|
use Moose::Role; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
6140
|
no if $] >= 5.018000, warnings => qw(experimental::smartmatch); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
11
|
|
12
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
100
|
use Term::ReadKey; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2564
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
has 'cmd_term' => ( |
16
|
|
|
|
|
|
|
is => 'ro', |
17
|
|
|
|
|
|
|
isa => 'Bool', |
18
|
|
|
|
|
|
|
default => sub {0}, |
19
|
|
|
|
|
|
|
); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has 'cmd_term_label' => ( |
22
|
|
|
|
|
|
|
is => 'ro', |
23
|
|
|
|
|
|
|
isa => 'Str', |
24
|
|
|
|
|
|
|
predicate => 'has_cmd_term_label', |
25
|
|
|
|
|
|
|
); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub cmd_term_label_full { |
28
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
29
|
|
|
|
|
|
|
|
30
|
0
|
|
|
|
|
|
my $label = $self->cmd_term_label_name; |
31
|
0
|
|
|
|
|
|
my @tags; |
32
|
0
|
0
|
|
|
|
|
if ($self->is_required) { |
33
|
0
|
|
|
|
|
|
push(@tags,'Required'); |
34
|
|
|
|
|
|
|
} else { |
35
|
0
|
|
|
|
|
|
push(@tags,'Optional'); |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
0
|
0
|
|
|
|
|
if ($self->has_type_constraint) { |
39
|
0
|
|
|
|
|
|
my $type_constraint = $self->type_constraint; |
40
|
0
|
0
|
|
|
|
|
if ($type_constraint->is_a_type_of('Bool')) { |
41
|
0
|
|
|
|
|
|
push(@tags,'Y/N'); |
42
|
|
|
|
|
|
|
} else { |
43
|
0
|
|
|
|
|
|
push(@tags,$self->cmd_type_constraint_description($type_constraint)); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
} |
46
|
0
|
0
|
|
|
|
|
if (scalar @tags) { |
47
|
0
|
|
|
|
|
|
$label .= ' ('.join(', ',@tags).')'; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
return $label; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub cmd_term_label_name { |
54
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
55
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
my $label; |
57
|
0
|
0
|
|
|
|
|
if ($self->has_cmd_term_label) { |
|
|
0
|
|
|
|
|
|
58
|
0
|
|
|
|
|
|
return $self->cmd_term_label; |
59
|
|
|
|
|
|
|
} elsif ($self->has_documentation) { |
60
|
0
|
|
|
|
|
|
return $self->documentation; |
61
|
|
|
|
|
|
|
} else { |
62
|
0
|
|
|
|
|
|
return $self->name; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub cmd_term_read { |
67
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
68
|
|
|
|
|
|
|
|
69
|
0
|
0
|
0
|
|
|
|
if ($self->has_type_constraint |
70
|
|
|
|
|
|
|
&& $self->type_constraint->is_a_type_of('Bool')) { |
71
|
0
|
|
|
|
|
|
return $self->cmd_term_read_bool(); |
72
|
|
|
|
|
|
|
} else { |
73
|
0
|
|
|
|
|
|
return $self->cmd_term_read_string(); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub cmd_term_read_string { |
78
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
79
|
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
|
my $label = $self->cmd_term_label_full; |
81
|
0
|
|
|
|
|
|
my ($return,@history,$history_disable,$allowed); |
82
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
binmode STDIN,':encoding(UTF-8)'; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Prefill history with enums |
86
|
0
|
0
|
|
|
|
|
if ($self->has_type_constraint) { |
87
|
0
|
|
|
|
|
|
my $type_constraint = $self->type_constraint; |
88
|
0
|
0
|
|
|
|
|
if ($type_constraint->isa('Moose::Meta::TypeConstraint::Enum')) { |
|
|
0
|
|
|
|
|
|
89
|
0
|
|
|
|
|
|
push(@history,@{$self->type_constraint->values}); |
|
0
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
$history_disable = 1 |
91
|
|
|
|
|
|
|
} elsif (!$type_constraint->has_coercion) { |
92
|
0
|
0
|
|
|
|
|
if ($type_constraint->is_a_type_of('Int')) { |
|
|
0
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
$allowed = qr/[0-9]/; |
94
|
|
|
|
|
|
|
} elsif ($type_constraint->is_a_type_of('Num')) { |
95
|
0
|
|
|
|
|
|
$allowed = qr/[0-9.]/; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
0
|
0
|
|
|
|
|
push(@history,"") |
101
|
|
|
|
|
|
|
unless scalar @history; |
102
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
my $history_index = 0; |
104
|
|
|
|
|
|
|
my $history_add = sub { |
105
|
0
|
|
|
0
|
|
|
my $entry = shift; |
106
|
0
|
0
|
0
|
|
|
|
if (! $history_disable |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
107
|
|
|
|
|
|
|
&& defined $entry |
108
|
|
|
|
|
|
|
&& $entry !~ m/^\s*$/ |
109
|
|
|
|
|
|
|
&& ! ($entry ~~ \@history)) { |
110
|
0
|
|
|
|
|
|
push(@history,$entry); |
111
|
|
|
|
|
|
|
} |
112
|
0
|
|
|
|
|
|
}; |
113
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
ReadMode('cbreak'); # change input mode |
115
|
|
|
|
|
|
|
TRY_STRING: |
116
|
0
|
|
|
|
|
|
while (1) { |
117
|
0
|
0
|
0
|
|
|
|
print "\n" |
118
|
|
|
|
|
|
|
if defined $return |
119
|
|
|
|
|
|
|
&& $return !~ /^\s*$/; |
120
|
0
|
|
|
|
|
|
$return = ''; |
121
|
|
|
|
|
|
|
|
122
|
0
|
0
|
|
|
|
|
if (defined $Term::ANSIColor::VERSION) { |
123
|
0
|
|
|
|
|
|
say Term::ANSIColor::color('white bold').$label.' :'.Term::ANSIColor::color('reset'); |
124
|
|
|
|
|
|
|
} else { |
125
|
0
|
|
|
|
|
|
say $label.": "; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
|
1 while defined ReadKey -1; # discard any previous input |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
my $cursor = 0; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
KEY_STRING: |
133
|
0
|
|
|
|
|
|
while (1) { |
134
|
0
|
|
|
|
|
|
my $key = ReadKey 0; # read a single character |
135
|
0
|
|
|
|
|
|
my $length = length($return); |
136
|
0
|
|
|
|
|
|
my $key_code = ord($key); |
137
|
|
|
|
|
|
|
|
138
|
0
|
0
|
|
|
|
|
if ($key_code == 10) { # Enter |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
print "\n"; |
140
|
0
|
|
|
|
|
|
my $error; |
141
|
0
|
0
|
|
|
|
|
if ($return =~ m/^\s*$/) { |
142
|
0
|
0
|
|
|
|
|
if ($self->is_required) { |
143
|
0
|
|
|
|
|
|
$error = 'Value is required'; |
144
|
|
|
|
|
|
|
} else { |
145
|
0
|
|
|
|
|
|
$return = undef; |
146
|
0
|
|
|
|
|
|
last TRY_STRING; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
} else { |
149
|
0
|
|
|
|
|
|
$error = $self->cmd_type_constraint_check($return); |
150
|
|
|
|
|
|
|
} |
151
|
0
|
0
|
|
|
|
|
if ($error) { |
152
|
0
|
0
|
|
|
|
|
if (defined $Term::ANSIColor::VERSION) { |
153
|
0
|
|
|
|
|
|
say Term::ANSIColor::color('bright_red bold').$error.Term::ANSIColor::color('reset'); |
154
|
|
|
|
|
|
|
} else { |
155
|
0
|
|
|
|
|
|
say $error; |
156
|
|
|
|
|
|
|
} |
157
|
0
|
|
|
|
|
|
$history_add->($return); |
158
|
0
|
|
|
|
|
|
next TRY_STRING; |
159
|
|
|
|
|
|
|
} else { |
160
|
0
|
|
|
|
|
|
last TRY_STRING; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
} elsif ($key_code == 27) { # Escape sequence |
163
|
0
|
|
|
|
|
|
my $escape; |
164
|
0
|
|
|
|
|
|
while (1) { # Read rest of escape sequence |
165
|
0
|
|
|
|
|
|
my $code = ReadKey -1; |
166
|
0
|
0
|
|
|
|
|
last unless defined $code; |
167
|
0
|
|
|
|
|
|
$escape .= $code; |
168
|
|
|
|
|
|
|
} |
169
|
0
|
0
|
|
|
|
|
if (defined $escape) { |
170
|
0
|
|
|
|
|
|
given ($escape) { |
171
|
0
|
|
|
|
|
|
when ('[D') { # Cursor left |
172
|
0
|
0
|
|
|
|
|
if ($cursor > 0) { |
173
|
0
|
|
|
|
|
|
print "\b"; |
174
|
0
|
|
|
|
|
|
$cursor--; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
0
|
|
|
|
|
|
when ($escape eq '[C') { # Cursor right |
178
|
0
|
0
|
|
|
|
|
if ($cursor < length($return)) { |
179
|
0
|
|
|
|
|
|
print substr $return,$cursor,1; |
180
|
0
|
|
|
|
|
|
$cursor++; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
} |
183
|
0
|
|
|
|
|
|
when ($escape eq '[A') { # Cursor up |
184
|
0
|
|
|
|
|
|
$history_add->($return); |
185
|
0
|
|
|
|
|
|
print "\b" x $cursor; |
186
|
0
|
|
|
|
|
|
print " " x length($return); |
187
|
0
|
|
|
|
|
|
print "\b" x length($return); |
188
|
|
|
|
|
|
|
|
189
|
0
|
0
|
0
|
|
|
|
$history_index ++ |
190
|
|
|
|
|
|
|
if defined $history[$history_index] |
191
|
|
|
|
|
|
|
&& $history[$history_index] eq $return; |
192
|
0
|
0
|
|
|
|
|
$history_index = 0 |
193
|
|
|
|
|
|
|
unless defined $history[$history_index]; |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$return = $history[$history_index]; |
196
|
0
|
|
|
|
|
|
$cursor = length($return); |
197
|
0
|
|
|
|
|
|
print $return; |
198
|
0
|
|
|
|
|
|
$history_index++; |
199
|
|
|
|
|
|
|
} |
200
|
0
|
|
|
|
|
|
when ($escape eq '[3~') { # Del |
201
|
0
|
0
|
|
|
|
|
if ($cursor != length($return)) { |
202
|
0
|
|
|
|
|
|
substr $return,$cursor,1,''; |
203
|
0
|
|
|
|
|
|
print substr $return,$cursor; |
204
|
0
|
|
|
|
|
|
print " ".(("\b") x (length($return) - $cursor + 1)); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
} |
207
|
0
|
|
|
|
|
|
when ($escape eq 'OH') { # Pos 1 |
208
|
0
|
|
|
|
|
|
print (("\b") x $cursor); |
209
|
0
|
|
|
|
|
|
$cursor = 0; |
210
|
|
|
|
|
|
|
} |
211
|
0
|
|
|
|
|
|
when ($escape eq 'OF') { # End |
212
|
0
|
|
|
|
|
|
print substr $return,$cursor; |
213
|
0
|
|
|
|
|
|
$cursor = length($return); |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
#default { |
216
|
|
|
|
|
|
|
# print $escape; |
217
|
|
|
|
|
|
|
#} |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} else { |
220
|
0
|
|
|
|
|
|
$history_add->($return); |
221
|
0
|
|
|
|
|
|
next TRY_STRING; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
} elsif ($key_code == 127) { # Backspace |
225
|
0
|
0
|
|
|
|
|
if ($cursor == 0) { # Ignore first |
226
|
0
|
|
|
|
|
|
next KEY_STRING; |
227
|
|
|
|
|
|
|
} |
228
|
0
|
|
|
|
|
|
$cursor--; |
229
|
0
|
|
|
|
|
|
substr $return,$cursor,1,''; # string |
230
|
0
|
|
|
|
|
|
print "\b".substr $return,$cursor; # print |
231
|
0
|
|
|
|
|
|
print " ".(("\b") x (length($return) - $cursor + 1)); # cursor |
232
|
|
|
|
|
|
|
} else { # Character |
233
|
0
|
0
|
0
|
|
|
|
if ($_ <= 31) { # ignore controll chars |
|
|
0
|
|
|
|
|
|
234
|
0
|
|
|
|
|
|
print "\a"; |
235
|
0
|
|
|
|
|
|
next KEY_STRING; |
236
|
|
|
|
|
|
|
} elsif (defined $allowed |
237
|
|
|
|
|
|
|
&& $key !~ /$allowed/) { |
238
|
0
|
|
|
|
|
|
print "\a"; |
239
|
0
|
|
|
|
|
|
next KEY_STRING; |
240
|
|
|
|
|
|
|
} |
241
|
0
|
|
|
|
|
|
substr $return,$cursor,0,$key; # string |
242
|
0
|
|
|
|
|
|
print substr $return,$cursor; # print |
243
|
0
|
|
|
|
|
|
$cursor++; |
244
|
0
|
|
|
|
|
|
print (("\b") x (length($return) - $cursor)); # cursor |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
} |
248
|
0
|
|
|
|
|
|
ReadMode 0; |
249
|
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
|
return $return; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub cmd_term_read_bool { |
254
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
255
|
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
|
my $label = $self->cmd_term_label_full; |
257
|
0
|
|
|
|
|
|
my $return; |
258
|
|
|
|
|
|
|
|
259
|
0
|
0
|
|
|
|
|
if (defined $Term::ANSIColor::VERSION) { |
260
|
0
|
|
|
|
|
|
say Term::ANSIColor::color('white bold').$label.' :'.Term::ANSIColor::color('reset'); |
261
|
|
|
|
|
|
|
} else { |
262
|
0
|
|
|
|
|
|
say $label.": "; |
263
|
|
|
|
|
|
|
} |
264
|
0
|
|
|
|
|
|
ReadMode 4; # change to raw input mode |
265
|
|
|
|
|
|
|
TRY: |
266
|
0
|
|
|
|
|
|
while (1) { |
267
|
0
|
|
|
|
|
|
1 while defined ReadKey -1; # discard any previous input |
268
|
0
|
|
|
|
|
|
my $key = ReadKey 0; # read a single character |
269
|
0
|
0
|
0
|
|
|
|
if ($key =~ /^[yn]$/i) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
say uc($key); |
271
|
0
|
0
|
|
|
|
|
$return = uc($key) eq 'Y' ? 1:0; |
272
|
0
|
|
|
|
|
|
last; |
273
|
|
|
|
|
|
|
} elsif ((ord($key) == 10 || ord($key) == 27) && ! $self->is_required) { |
274
|
0
|
|
|
|
|
|
last; |
275
|
|
|
|
|
|
|
} elsif (ord($key) == 3) { |
276
|
0
|
|
|
|
|
|
ReadMode 0; |
277
|
0
|
|
|
|
|
|
kill INT => $$; # Not sure ? |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
0
|
|
|
|
|
|
ReadMode 0; |
281
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
|
return $return; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
around 'cmd_tags_list' => sub { |
286
|
|
|
|
|
|
|
my $orig = shift; |
287
|
|
|
|
|
|
|
my ($self) = @_; |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
my @tags = $self->$orig(); |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
push(@tags,'Term') |
292
|
|
|
|
|
|
|
if $self->can('cmd_term') |
293
|
|
|
|
|
|
|
&& $self->cmd_term; |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
return @tags; |
296
|
|
|
|
|
|
|
}; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
{ |
299
|
|
|
|
|
|
|
package Moose::Meta::Attribute::Custom::Trait::AppTerm; |
300
|
|
|
|
|
|
|
|
301
|
1
|
|
|
1
|
|
15
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
37
|
|
302
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
79
|
|
303
|
|
|
|
|
|
|
|
304
|
0
|
|
|
0
|
|
|
sub register_implementation { return 'MooseX::App::Plugin::Term::Meta::Attribute' } |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
1; |