line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Term::ReadLine::Zoid::ViCommand; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
2793
|
use strict; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
168
|
|
4
|
3
|
|
|
3
|
|
15
|
use vars '$AUTOLOAD'; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
461
|
|
5
|
3
|
|
|
3
|
|
18
|
no strict 'refs'; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
93
|
|
6
|
3
|
|
|
3
|
|
1065
|
use AutoLoader; |
|
3
|
|
|
|
|
1708
|
|
|
3
|
|
|
|
|
25
|
|
7
|
3
|
|
|
3
|
|
297
|
use base 'Term::ReadLine::Zoid'; |
|
3
|
|
|
|
|
53
|
|
|
3
|
|
|
|
|
940
|
|
8
|
3
|
|
|
3
|
|
25
|
no warnings; # undef == '' down here |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
4650
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = 0.05; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub AUTOLOAD { # more intelligent inheritance |
13
|
13
|
|
|
13
|
|
27
|
my $sub = $AUTOLOAD; |
14
|
13
|
|
|
|
|
61
|
$sub =~ s/.*:://; |
15
|
13
|
50
|
|
|
|
52
|
my $m = $_[0]->can($sub) ? 'AutoLoader' : 'Term::ReadLine::Zoid'; |
16
|
13
|
|
|
|
|
19
|
${$m.'::AUTOLOAD'} = $AUTOLOAD; |
|
13
|
|
|
|
|
42
|
|
17
|
13
|
|
|
|
|
20
|
goto &{$m.'::AUTOLOAD'}; |
|
13
|
|
|
|
|
66
|
|
18
|
|
|
|
|
|
|
} |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 NAME |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Term::ReadLine::Zoid::ViCommand - a readline command mode |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
This class is used as a mode under L, |
27
|
|
|
|
|
|
|
see there for usage details. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This mode provides a "vi command mode" as specified by the posix spec for the sh(1) |
32
|
|
|
|
|
|
|
utility. It intends to include at least all key-bindings |
33
|
|
|
|
|
|
|
mentioned by the posix spec for the vi mode in sh(1). |
34
|
|
|
|
|
|
|
It also contains some extensions borrowed from vim(1) and some private extensions. |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
This mode has a "kill buffer" that stores the last killed text so it can |
37
|
|
|
|
|
|
|
be yanked again. This buffer has only one value, it isn't a "kill ring". |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 KEY MAPPING |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Since ViCommand inherits from MultiLine, which in turn inherits |
42
|
|
|
|
|
|
|
from Term::ReadLine::Zoid, key bindings are also inherited unless explicitly overloaded. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Control-d is ignored in this mode. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=over 4 |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=cut |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
our %_keymap = ( |
51
|
|
|
|
|
|
|
return => 'accept_line', |
52
|
|
|
|
|
|
|
ctrl_D => 'bell', |
53
|
|
|
|
|
|
|
ctrl_Z => 'sigtstp', |
54
|
|
|
|
|
|
|
backspace => 'backward_char', |
55
|
|
|
|
|
|
|
escape => 'vi_reset', |
56
|
|
|
|
|
|
|
ctrl_A => 'vi_increment', |
57
|
|
|
|
|
|
|
ctrl_X => 'vi_increment', |
58
|
|
|
|
|
|
|
_on_switch => 'vi_switch', |
59
|
|
|
|
|
|
|
_isa => 'multiline', # but wait .. self_insert is overloaded |
60
|
|
|
|
|
|
|
); |
61
|
|
|
|
|
|
|
|
62
|
2
|
|
|
2
|
1
|
34
|
sub keymap { return \%_keymap } |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub vi_switch { |
65
|
31
|
|
|
31
|
0
|
49
|
my $self = shift; |
66
|
31
|
50
|
|
|
|
85
|
return $$self{_loop} = undef if $$self{_vi_mini_b}; |
67
|
31
|
|
|
|
|
54
|
$$self{vi_command} = ''; |
68
|
31
|
|
100
|
|
|
84
|
$$self{vi_history} ||= []; |
69
|
31
|
100
|
66
|
|
|
230
|
$self->backward_char unless $_[1] or $$self{pos}[0] == 0; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
our @vi_motions = (' ', ',', qw/0 b F l W ^ $ ; E f T w | B e h t/); |
73
|
|
|
|
|
|
|
our %vi_subs = ( |
74
|
|
|
|
|
|
|
'#' => 'vi_comment', '=' => 'vi_complete', |
75
|
|
|
|
|
|
|
'\\' => 'vi_complete', '*' => 'vi_complete', |
76
|
|
|
|
|
|
|
'@' => 'vi_macro', '~' => 'vi_case', |
77
|
|
|
|
|
|
|
'.' => 'vi_repeat', ' ' => 'forward_char', |
78
|
|
|
|
|
|
|
'^' => 'vi_home', '$' => 'end_of_line', |
79
|
|
|
|
|
|
|
'0' => 'beginning_of_line', '|' => 'vi_cursor', |
80
|
|
|
|
|
|
|
';' => 'vi_c_repeat', ',' => 'vi_c_repeat', |
81
|
|
|
|
|
|
|
'_' => 'vi_topic', '-' => 'vi_K', |
82
|
|
|
|
|
|
|
'+' => 'vi_J', |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
'l' => 'forward_char', 'h' => 'backward_char', |
85
|
|
|
|
|
|
|
't' => 'vi_F', 'T' => 'vi_F', |
86
|
|
|
|
|
|
|
); |
87
|
|
|
|
|
|
|
our %vi_commands = ( |
88
|
|
|
|
|
|
|
'/' => 'bsearch', |
89
|
|
|
|
|
|
|
'?' => 'fsearch', |
90
|
|
|
|
|
|
|
'!' => 'shell', |
91
|
|
|
|
|
|
|
'q' => 'quit', |
92
|
|
|
|
|
|
|
); |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub self_insert { |
95
|
95
|
|
|
95
|
0
|
824
|
my ($self, $key) = @_; |
96
|
|
|
|
|
|
|
|
97
|
95
|
50
|
|
|
|
172
|
if (length($key) > 1) { # no vague chars |
98
|
0
|
|
|
|
|
0
|
$self->bell; |
99
|
0
|
|
|
|
|
0
|
$$self{vi_command} = ''; |
100
|
|
|
|
|
|
|
} |
101
|
95
|
|
|
|
|
164
|
else { $$self{vi_command} .= $key } |
102
|
|
|
|
|
|
|
|
103
|
95
|
50
|
|
|
|
510
|
if ($$self{vi_command} =~ /^[\/\?\:]/) { |
|
|
100
|
|
|
|
|
|
104
|
0
|
|
|
|
|
0
|
$self->vi_mini_buffer($key) |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
elsif ($$self{vi_command} =~ /^0|^(\d*)(\D)/) { # this is where a command gets executed |
107
|
81
|
|
100
|
|
|
446
|
my ($cnt, $cmd) = ($1||1, $2||'0'); |
|
|
|
100
|
|
|
|
|
108
|
81
|
|
66
|
|
|
293
|
my $sub = $vi_subs{$cmd} || 'vi_'.uc($cmd); |
109
|
|
|
|
|
|
|
#print STDERR "string: $$self{vi_command} cnt: $cnt sub: $sub\n"; |
110
|
81
|
|
|
|
|
77
|
my $r; |
111
|
81
|
50
|
|
|
|
284
|
if ($self->can($sub)) { |
112
|
81
|
|
|
|
|
253
|
my $s = $self->save(); |
113
|
81
|
|
|
|
|
1348
|
$r = $self->$sub($cmd, $cnt); # key, count |
114
|
38
|
|
|
|
|
80
|
push @{$$self{undostack}}, $s unless lc($cmd) eq 'u' |
|
81
|
|
|
|
|
232
|
|
115
|
81
|
100
|
66
|
|
|
275
|
or join("\n", @{$$s{lines}}) eq join("\n", @{$$self{lines}}); |
|
81
|
|
|
|
|
384
|
|
116
|
|
|
|
|
|
|
} |
117
|
0
|
|
|
|
|
0
|
else { $self->bell() } |
118
|
1480
|
|
|
|
|
2222
|
$$self{vi_last_cmd} = $$self{vi_command} |
119
|
81
|
100
|
100
|
|
|
278
|
if $$self{vi_command} && ! grep( {$_ eq $cmd} @vi_motions, '.'); # for repeat ('.') |
120
|
81
|
|
|
|
|
117
|
$$self{vi_command} = ''; |
121
|
|
|
|
|
|
|
#print STDERR "return: $r vi_last_cmd: $$self{vi_last_cmd}\n"; |
122
|
81
|
|
|
|
|
257
|
return $r; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
else { |
125
|
14
|
50
|
|
|
|
81
|
return if $$self{vi_command} =~ /^\d+$/; |
126
|
|
|
|
|
|
|
#print STDERR "string: $$self{vi_command} rejected\n"; |
127
|
0
|
|
|
|
|
0
|
$self->bell; |
128
|
0
|
|
|
|
|
0
|
$$self{vi_command} = ''; |
129
|
|
|
|
|
|
|
} |
130
|
0
|
|
|
|
|
0
|
return 0; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# ############ # |
134
|
|
|
|
|
|
|
# Key bindings # |
135
|
|
|
|
|
|
|
# ############ # |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Subs get args ($self, $key, $count) |
138
|
|
|
|
|
|
|
|
139
|
2
|
|
|
2
|
0
|
5
|
sub vi_reset { $_[0]{vi_command} = ''; return 0 } |
|
2
|
|
|
|
|
5
|
|
140
|
|
|
|
|
|
|
|
141
|
0
|
|
|
0
|
0
|
0
|
sub sigtstp { kill 20, $$ } # SIGTSTP |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item escape |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Reset the command mode. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item return |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item ^J |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Return the current edit line to the application for execution. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=item ^Z |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Send a SIGSTOP to the process of the application. Might not work when the application |
156
|
|
|
|
|
|
|
ignores those, which is something shells tend to do. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=item i |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Switch back to insert mode. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item I |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Switch back to insert mode at the begin of the edit line. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=item a |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Enter insert mode after the current cursor position. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=item A |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Enter insert mode at the end of the edit line. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=cut |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub vi_I { |
177
|
0
|
0
|
|
0
|
0
|
0
|
$_[0]{pos}[0] = 0 if $_[1] eq 'I'; |
178
|
0
|
|
|
|
|
0
|
$_[0]->switch_mode(); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub vi_A { |
182
|
0
|
0
|
|
0
|
0
|
0
|
($_[1] eq 'A') ? $_[0]->end_of_line : $_[0]->forward_char ; |
183
|
0
|
|
|
|
|
0
|
$_[0]->switch_mode(); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item m |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Switch to multiline insert mode, see L. |
189
|
|
|
|
|
|
|
(private extension) |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item M |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Switch to multiline insert mode at the end of the edit buffer. |
194
|
|
|
|
|
|
|
(private extension) |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub vi_M { |
199
|
0
|
0
|
|
0
|
0
|
0
|
if ($_[1] eq 'M') { |
200
|
0
|
|
|
|
|
0
|
$_[0]{pos}[1] = $#{$_[0]{lines}}; |
|
0
|
|
|
|
|
0
|
|
201
|
0
|
|
|
|
|
0
|
$_[0]->end_of_line; |
202
|
|
|
|
|
|
|
} |
203
|
0
|
|
|
|
|
0
|
else { $_[0]->forward_char } |
204
|
0
|
|
|
|
|
0
|
$_[0]->switch_mode('multiline') |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item R |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Enter insert mode with replace toggled on. |
210
|
|
|
|
|
|
|
(vim extension) |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=cut |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub vi_R { |
215
|
2
|
|
|
2
|
0
|
3
|
my $self = shift; |
216
|
2
|
50
|
|
|
|
42
|
return $self->vi_r(@_) if $_[0] eq 'r'; |
217
|
0
|
|
|
|
|
0
|
$self->switch_mode(); |
218
|
0
|
|
|
|
|
0
|
$$self{replace} = 1; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
## more bindings are defined in __END__ section for autosplit ## |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
__END__ |