| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# -*- coding: utf-8 -*- |
|
2
|
|
|
|
|
|
|
# Copyright (C) 2014 Rocky Bernstein <rocky@cpan.org> |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# Part of Devel::Trepan::CmdProcessor that loads up debugger commands from |
|
5
|
|
|
|
|
|
|
# builtin and user directories. |
|
6
|
|
|
|
|
|
|
# Top-level command completion routines. |
|
7
|
12
|
|
|
12
|
|
81
|
use rlib '../../..'; |
|
|
12
|
|
|
|
|
24
|
|
|
|
12
|
|
|
|
|
70
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package Devel::Trepan::CmdProcessor; |
|
10
|
12
|
|
|
12
|
|
4122
|
use warnings; use strict; |
|
|
12
|
|
|
12
|
|
24
|
|
|
|
12
|
|
|
|
|
299
|
|
|
|
12
|
|
|
|
|
154
|
|
|
|
12
|
|
|
|
|
29
|
|
|
|
12
|
|
|
|
|
271
|
|
|
11
|
12
|
|
|
12
|
|
320
|
no warnings 'redefine'; |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
420
|
|
|
12
|
12
|
|
|
12
|
|
5104
|
use Devel::Trepan::Complete; |
|
|
12
|
|
|
|
|
31
|
|
|
|
12
|
|
|
|
|
16188
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my $_list_complete_i = -1; |
|
15
|
|
|
|
|
|
|
sub list_complete($$$) |
|
16
|
|
|
|
|
|
|
{ |
|
17
|
0
|
|
|
0
|
0
|
0
|
my($self, $text, $state) = @_; |
|
18
|
|
|
|
|
|
|
# clear counter at the first call |
|
19
|
0
|
|
|
|
|
0
|
eval { state $_list_complete_i = -1; |
|
|
0
|
|
|
|
|
0
|
|
|
20
|
0
|
|
|
|
|
0
|
$_list_complete_i++;; |
|
21
|
|
|
|
|
|
|
}; |
|
22
|
0
|
|
|
|
|
0
|
my $cw = $self->{completions}; |
|
23
|
0
|
|
|
|
|
0
|
for (; $_list_complete_i <= $#{$cw}; $_list_complete_i++) { |
|
|
0
|
|
|
|
|
0
|
|
|
24
|
0
|
0
|
0
|
|
|
0
|
return $cw->[$_list_complete_i] |
|
25
|
|
|
|
|
|
|
if defined $cw->[$_list_complete_i] and ($cw->[$_list_complete_i] =~ /^\Q$text/); |
|
26
|
|
|
|
|
|
|
} |
|
27
|
0
|
|
|
|
|
0
|
return undef; |
|
28
|
|
|
|
|
|
|
}; |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my ($_last_line, $_last_start, $_last_end, @_last_return, $_last_token); |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Handle initial completion. We draw from the commands, aliases, |
|
34
|
|
|
|
|
|
|
# and macros for completion. However we won't include aliases which |
|
35
|
|
|
|
|
|
|
# are prefixes of other commands. |
|
36
|
|
|
|
|
|
|
sub complete($$$$$) |
|
37
|
|
|
|
|
|
|
{ |
|
38
|
18
|
|
|
18
|
0
|
10852
|
my ($self, $text, $line, $start, $end) = @_; |
|
39
|
18
|
|
|
|
|
39
|
$self->{leading_str} = $line; |
|
40
|
|
|
|
|
|
|
|
|
41
|
18
|
100
|
|
|
|
50
|
$_last_line = '' unless defined $_last_line; |
|
42
|
18
|
100
|
|
|
|
37
|
$_last_start = -1 unless defined $_last_start; |
|
43
|
18
|
100
|
|
|
|
38
|
$_last_end = -1 unless defined $_last_end; |
|
44
|
18
|
100
|
|
|
|
35
|
$_last_token = '' unless defined $_last_token; |
|
45
|
18
|
100
|
66
|
|
|
111
|
$_last_token = '' unless |
|
46
|
|
|
|
|
|
|
$_last_start < length($line) && |
|
47
|
|
|
|
|
|
|
0 == index(substr($line, $_last_start), $_last_token); |
|
48
|
|
|
|
|
|
|
# print "\ntext: $text, line: $line, start: $start, end: $end\n"; |
|
49
|
|
|
|
|
|
|
# print "\nlast_line: $_last_line, last_start: $_last_start, last_end: $last_end\n"; |
|
50
|
18
|
|
|
|
|
29
|
my $stripped_line; |
|
51
|
18
|
|
|
|
|
130
|
($stripped_line = $line) =~ s/\s*$//; |
|
52
|
18
|
50
|
33
|
|
|
59
|
if ($_last_line eq $stripped_line && $stripped_line) { |
|
53
|
0
|
|
|
|
|
0
|
$self->{completions} = \@_last_return; |
|
54
|
0
|
|
|
|
|
0
|
return @_last_return; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
18
|
|
|
|
|
41
|
($_last_line, $_last_start, $_last_end) = ($line, $start, $end); |
|
57
|
|
|
|
|
|
|
|
|
58
|
18
|
|
|
|
|
27
|
my @commands = sort keys %{$self->{commands}}; |
|
|
18
|
|
|
|
|
375
|
|
|
59
|
18
|
|
|
|
|
103
|
my ($next_blank_pos, $token) = |
|
60
|
|
|
|
|
|
|
Devel::Trepan::Complete::next_token($line, 0); |
|
61
|
18
|
0
|
33
|
|
|
44
|
if (!$token && !$_last_token) { |
|
62
|
0
|
|
|
|
|
0
|
@_last_return = @commands; |
|
63
|
0
|
|
|
|
|
0
|
$_last_token = $_last_return[0]; |
|
64
|
0
|
|
|
|
|
0
|
$_last_line = $line . $_last_token; |
|
65
|
0
|
|
|
|
|
0
|
$_last_end += length($_last_token); |
|
66
|
0
|
|
|
|
|
0
|
$self->{completions} = \@_last_return; |
|
67
|
0
|
|
|
|
|
0
|
return (@commands); |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
|
|
70
|
18
|
|
33
|
|
|
37
|
$token ||= $_last_token; |
|
71
|
18
|
|
|
|
|
65
|
my @match_pairs = complete_token_with_next($self->{commands}, $token); |
|
72
|
|
|
|
|
|
|
|
|
73
|
18
|
|
|
|
|
38
|
my $match_hash = {}; |
|
74
|
18
|
|
|
|
|
41
|
for my $pair (@match_pairs) { |
|
75
|
22
|
|
|
|
|
77
|
$match_hash->{$pair->[0]} = $pair->[1]; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my @alias_pairs = complete_token_filtered_with_next($self->{aliases}, |
|
79
|
|
|
|
|
|
|
$token, $match_hash, |
|
80
|
18
|
|
|
|
|
57
|
$self->{commands}); |
|
81
|
18
|
|
|
|
|
32
|
push @match_pairs, @alias_pairs; |
|
82
|
18
|
100
|
|
|
|
50
|
if ($next_blank_pos >= length($line)) { |
|
83
|
4
|
|
|
|
|
10
|
@_last_return = sort map {$_->[0]} @match_pairs; |
|
|
9
|
|
|
|
|
26
|
|
|
84
|
4
|
|
|
|
|
10
|
$_last_token = $_last_return[0]; |
|
85
|
4
|
50
|
|
|
|
12
|
if (defined($_last_token)) { |
|
86
|
4
|
|
|
|
|
9
|
$_last_line = $line . $_last_token; |
|
87
|
4
|
|
|
|
|
9
|
$_last_end += length($_last_token); |
|
88
|
|
|
|
|
|
|
} |
|
89
|
4
|
0
|
33
|
|
|
27
|
if (scalar @_last_return == 0 && $self->{settings}{autoeval}) { |
|
90
|
0
|
|
|
|
|
0
|
return Devel::Trepan::Complete::complete_subs($stripped_line); |
|
91
|
|
|
|
|
|
|
} |
|
92
|
4
|
|
|
|
|
89
|
$self->{completions} = \@_last_return; |
|
93
|
4
|
|
|
|
|
37
|
return @_last_return; |
|
94
|
|
|
|
|
|
|
} else { |
|
95
|
14
|
|
|
|
|
29
|
for my $pair (@alias_pairs) { |
|
96
|
0
|
|
|
|
|
0
|
$match_hash->{$pair->[0]} = $pair->[1]; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
} |
|
99
|
14
|
50
|
|
|
|
34
|
if (scalar(@match_pairs) > 1) { |
|
100
|
|
|
|
|
|
|
# FIXME: figure out what to do here. |
|
101
|
|
|
|
|
|
|
# Matched multiple items in the middle of the string |
|
102
|
|
|
|
|
|
|
# We can't handle this so do nothing. |
|
103
|
0
|
|
|
|
|
0
|
return (); |
|
104
|
|
|
|
|
|
|
# return match_pairs.map do |name, cmd| |
|
105
|
|
|
|
|
|
|
# ["#{name} #{args[1..-1].join(' ')}"] |
|
106
|
|
|
|
|
|
|
# } |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
# scalar @match_pairs == 1 |
|
109
|
14
|
|
|
|
|
74
|
@_last_return = $self->next_complete($line, $next_blank_pos, |
|
110
|
|
|
|
|
|
|
$match_pairs[0]->[1], |
|
111
|
|
|
|
|
|
|
$token); |
|
112
|
|
|
|
|
|
|
|
|
113
|
14
|
|
|
|
|
31
|
$self->{completions} = \@_last_return; |
|
114
|
14
|
50
|
66
|
|
|
49
|
if (scalar @_last_return == 0 && $self->{settings}{autoeval}) { |
|
115
|
2
|
|
|
|
|
10
|
return Devel::Trepan::Complete::complete_subs($stripped_line); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
12
|
|
|
|
|
90
|
return @_last_return; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub next_complete($$$$$) |
|
122
|
|
|
|
|
|
|
{ |
|
123
|
20
|
|
|
20
|
0
|
61
|
my($self, $str, $next_blank_pos, $cmd, $last_token) = @_; |
|
124
|
|
|
|
|
|
|
|
|
125
|
20
|
|
|
|
|
29
|
my $token; |
|
126
|
20
|
|
|
|
|
51
|
($next_blank_pos, $token) = |
|
127
|
|
|
|
|
|
|
Devel::Trepan::Complete::next_token($str, $next_blank_pos); |
|
128
|
20
|
50
|
66
|
|
|
68
|
return () if !$token && !$last_token; |
|
129
|
20
|
50
|
|
|
|
42
|
return () unless defined($cmd); |
|
130
|
20
|
50
|
|
|
|
59
|
return @{$cmd} if ref($cmd) eq 'ARRAY'; |
|
|
0
|
|
|
|
|
0
|
|
|
131
|
20
|
100
|
|
|
|
40
|
return $cmd->($token) if (ref($cmd) eq 'CODE'); |
|
132
|
|
|
|
|
|
|
|
|
133
|
19
|
100
|
|
|
|
147
|
if ($cmd->can("complete_token_with_next")) { |
|
|
|
50
|
|
|
|
|
|
|
134
|
15
|
|
|
|
|
53
|
my @match_pairs = $cmd->complete_token_with_next($token); |
|
135
|
15
|
50
|
|
|
|
38
|
return () unless scalar @match_pairs; |
|
136
|
15
|
100
|
|
|
|
36
|
if ($next_blank_pos >= length($str)) { |
|
137
|
9
|
|
|
|
|
21
|
return map {$_->[0]} @match_pairs; |
|
|
37
|
|
|
|
|
84
|
|
|
138
|
|
|
|
|
|
|
} else { |
|
139
|
6
|
50
|
|
|
|
17
|
if (scalar @match_pairs == 1) { |
|
140
|
6
|
50
|
66
|
|
|
39
|
if ($next_blank_pos == length($str)-1 |
|
|
|
50
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
&& ' ' ne substr($str, length($str)-1)) { |
|
142
|
0
|
|
|
|
|
0
|
return map {$_->[0]} @match_pairs; |
|
|
0
|
|
|
|
|
0
|
|
|
143
|
|
|
|
|
|
|
} elsif ($match_pairs[0]->[0] eq $token) { |
|
144
|
6
|
|
|
|
|
38
|
return $self->next_complete($str, $next_blank_pos, |
|
145
|
|
|
|
|
|
|
$match_pairs[0]->[1], |
|
146
|
|
|
|
|
|
|
$token); |
|
147
|
|
|
|
|
|
|
} else { |
|
148
|
0
|
|
|
|
|
0
|
return (); |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
} else { |
|
151
|
|
|
|
|
|
|
# FIXME: figure out what to do here. |
|
152
|
|
|
|
|
|
|
# Matched multiple items in the middle of the string |
|
153
|
|
|
|
|
|
|
# We can't handle this so do nothing. |
|
154
|
0
|
|
|
|
|
0
|
return (); |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
} elsif ($cmd->can('complete')) { |
|
158
|
4
|
|
|
|
|
12
|
my @matches = $cmd->complete($token); |
|
159
|
4
|
50
|
|
|
|
11
|
return () unless scalar @matches; |
|
160
|
4
|
50
|
|
|
|
17
|
if (substr($str, $next_blank_pos) =~ /\s*$/ ) { |
|
161
|
4
|
100
|
100
|
|
|
23
|
if (1 == scalar(@matches) && $matches[0] eq $token) { |
|
162
|
|
|
|
|
|
|
# Nothing more to complete. |
|
163
|
2
|
|
|
|
|
8
|
return (); |
|
164
|
|
|
|
|
|
|
} else { |
|
165
|
2
|
|
|
|
|
25
|
return @matches; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
} else { |
|
168
|
|
|
|
|
|
|
# FIXME: figure out what to do here. |
|
169
|
|
|
|
|
|
|
# Matched multiple items in the middle of the string |
|
170
|
|
|
|
|
|
|
# We can't handle this so do nothing. |
|
171
|
0
|
|
|
|
|
|
return (); |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
} else { |
|
174
|
0
|
|
|
|
|
|
return (); |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub filename_complete($$) { |
|
179
|
0
|
|
|
0
|
0
|
|
my ($self, $prefix) = @_; |
|
180
|
0
|
|
|
|
|
|
$self->{interfaces}[-1]->rl_filename_list($prefix); |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
unless (caller) { |
|
184
|
|
|
|
|
|
|
require Devel::Trepan::CmdProcessor; |
|
185
|
|
|
|
|
|
|
my $cmdproc = Devel::Trepan::CmdProcessor->new; |
|
186
|
|
|
|
|
|
|
# $cmdproc->run_cmd(['list', 5]); # Invalid - nonstring arg |
|
187
|
|
|
|
|
|
|
printf "complete('s') => %s\n", join(', ', $cmdproc->complete("s", 's', 0, 1)); |
|
188
|
|
|
|
|
|
|
printf "complete('') => %s\n", join(', ', $cmdproc->complete("", '', 0, 1)); |
|
189
|
|
|
|
|
|
|
printf "complete('help se') => %s\n", join(', ', $cmdproc->complete("help se", 'help se', 0, 1)); |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
eval { |
|
192
|
|
|
|
|
|
|
sub complete_it($$) { |
|
193
|
0
|
|
|
0
|
0
|
|
my ($cmdproc, $str) = @_; |
|
194
|
0
|
|
|
|
|
|
my @c = $cmdproc->complete($str, $str, 0, length($str)); |
|
195
|
0
|
|
|
|
|
|
printf "complete('$str') => %s\n", join(', ', @c); |
|
196
|
0
|
|
|
|
|
|
return @c; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
}; |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my @c = complete_it($cmdproc, "set "); |
|
201
|
|
|
|
|
|
|
@c = complete_it($cmdproc, "help set base"); |
|
202
|
|
|
|
|
|
|
@c = complete_it($cmdproc, "set basename on "); |
|
203
|
|
|
|
|
|
|
my $str = './'; |
|
204
|
|
|
|
|
|
|
@c = $cmdproc->filename_complete($str); |
|
205
|
|
|
|
|
|
|
printf "complete('$str') => %s\n", join(', ', @c); |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
1; |