reline 0.1.3 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/reline.rb +27 -11
- data/lib/reline/ansi.rb +48 -7
- data/lib/reline/config.rb +65 -8
- data/lib/reline/general_io.rb +18 -0
- data/lib/reline/history.rb +31 -11
- data/lib/reline/key_actor/emacs.rb +6 -6
- data/lib/reline/key_actor/vi_command.rb +4 -4
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/key_stroke.rb +2 -0
- data/lib/reline/line_editor.rb +309 -133
- data/lib/reline/sibori.rb +170 -0
- data/lib/reline/unicode.rb +93 -15
- data/lib/reline/unicode/east_asian_width.rb +1149 -1130
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +26 -3
- metadata +22 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89f055454b502262f43495a2d8de12ba033259287a4c09e7c93afeb0462c9c33
|
4
|
+
data.tar.gz: 6c6f081e14d699faed9ac7ba08001dac978318535f58458fd2c777db56b57b50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bd17793312ff9f2996ce08ebada091005c7efd9ff1d0ef007ea982ee5e74ee03a83fb0bb7c975c6da747db712a3837d14c108fd7de087094f1db37e051876aa
|
7
|
+
data.tar.gz: 148dd6767b1aae9a295d334445957b64e6f6a46b8941a10517e5d4567a29eac369fe3843c6c8c1bb5fd66d1165c82988316b030eb05080517bb7105bc5174281
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
[![Build Status](https://travis-ci.com/ruby/reline.svg?branch=master)](https://travis-ci.com/ruby/reline)
|
2
2
|
|
3
|
+
This is a screen capture of *IRB improved by Reline*.
|
4
|
+
|
5
|
+
![IRB improved by Reline](https://raw.githubusercontent.com/wiki/ruby/reline/images/irb_improved_by_reline.gif)
|
6
|
+
|
3
7
|
# Reline
|
4
8
|
|
5
9
|
Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and Editline by pure Ruby implementation.
|
data/lib/reline.rb
CHANGED
@@ -7,6 +7,7 @@ require 'reline/key_actor'
|
|
7
7
|
require 'reline/key_stroke'
|
8
8
|
require 'reline/line_editor'
|
9
9
|
require 'reline/history'
|
10
|
+
require 'rbconfig'
|
10
11
|
|
11
12
|
module Reline
|
12
13
|
FILENAME_COMPLETION_PROC = nil
|
@@ -98,22 +99,22 @@ module Reline
|
|
98
99
|
end
|
99
100
|
|
100
101
|
def completion_proc=(p)
|
101
|
-
raise ArgumentError unless p.respond_to?(:call)
|
102
|
+
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
102
103
|
@completion_proc = p
|
103
104
|
end
|
104
105
|
|
105
106
|
def output_modifier_proc=(p)
|
106
|
-
raise ArgumentError unless p.respond_to?(:call)
|
107
|
+
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
107
108
|
@output_modifier_proc = p
|
108
109
|
end
|
109
110
|
|
110
111
|
def prompt_proc=(p)
|
111
|
-
raise ArgumentError unless p.respond_to?(:call)
|
112
|
+
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
112
113
|
@prompt_proc = p
|
113
114
|
end
|
114
115
|
|
115
116
|
def auto_indent_proc=(p)
|
116
|
-
raise ArgumentError unless p.respond_to?(:call)
|
117
|
+
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
117
118
|
@auto_indent_proc = p
|
118
119
|
end
|
119
120
|
|
@@ -122,7 +123,7 @@ module Reline
|
|
122
123
|
end
|
123
124
|
|
124
125
|
def dig_perfect_match_proc=(p)
|
125
|
-
raise ArgumentError unless p.respond_to?(:call)
|
126
|
+
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
126
127
|
@dig_perfect_match_proc = p
|
127
128
|
end
|
128
129
|
|
@@ -175,7 +176,7 @@ module Reline
|
|
175
176
|
|
176
177
|
whole_buffer = line_editor.whole_buffer.dup
|
177
178
|
whole_buffer.taint if RUBY_VERSION < '2.7'
|
178
|
-
if add_hist and whole_buffer and whole_buffer.chomp.size > 0
|
179
|
+
if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
|
179
180
|
Reline::HISTORY << whole_buffer
|
180
181
|
end
|
181
182
|
|
@@ -188,8 +189,8 @@ module Reline
|
|
188
189
|
|
189
190
|
line = line_editor.line.dup
|
190
191
|
line.taint if RUBY_VERSION < '2.7'
|
191
|
-
if add_hist and line and line.chomp.size > 0
|
192
|
-
Reline::HISTORY << line.chomp
|
192
|
+
if add_hist and line and line.chomp("\n").size > 0
|
193
|
+
Reline::HISTORY << line.chomp("\n")
|
193
194
|
end
|
194
195
|
|
195
196
|
line_editor.reset_line if line_editor.line.nil?
|
@@ -222,7 +223,6 @@ module Reline
|
|
222
223
|
line_editor.auto_indent_proc = auto_indent_proc
|
223
224
|
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
|
224
225
|
line_editor.pre_input_hook = pre_input_hook
|
225
|
-
line_editor.rerender
|
226
226
|
|
227
227
|
unless config.test_mode
|
228
228
|
config.read
|
@@ -232,17 +232,27 @@ module Reline
|
|
232
232
|
end
|
233
233
|
end
|
234
234
|
|
235
|
+
line_editor.rerender
|
236
|
+
|
235
237
|
begin
|
238
|
+
prev_pasting_state = false
|
236
239
|
loop do
|
240
|
+
prev_pasting_state = Reline::IOGate.in_pasting?
|
237
241
|
read_io(config.keyseq_timeout) { |inputs|
|
238
242
|
inputs.each { |c|
|
239
243
|
line_editor.input_key(c)
|
240
244
|
line_editor.rerender
|
241
245
|
}
|
242
246
|
}
|
247
|
+
if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
|
248
|
+
prev_pasting_state = false
|
249
|
+
line_editor.rerender_all
|
250
|
+
end
|
243
251
|
break if line_editor.finished?
|
244
252
|
end
|
245
253
|
Reline::IOGate.move_cursor_column(0)
|
254
|
+
rescue Errno::EIO
|
255
|
+
# Maybe the I/O has been closed.
|
246
256
|
rescue StandardError => e
|
247
257
|
line_editor.finalize
|
248
258
|
Reline::IOGate.deprep(otio)
|
@@ -336,8 +346,14 @@ module Reline
|
|
336
346
|
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
|
337
347
|
return if ambiguous_width
|
338
348
|
Reline::IOGate.move_cursor_column(0)
|
339
|
-
|
340
|
-
|
349
|
+
begin
|
350
|
+
output.write "\u{25bd}"
|
351
|
+
rescue Encoding::UndefinedConversionError
|
352
|
+
# LANG=C
|
353
|
+
@ambiguous_width = 1
|
354
|
+
else
|
355
|
+
@ambiguous_width = Reline::IOGate.cursor_pos.x
|
356
|
+
end
|
341
357
|
Reline::IOGate.move_cursor_column(0)
|
342
358
|
Reline::IOGate.erase_after_cursor
|
343
359
|
end
|
data/lib/reline/ansi.rb
CHANGED
@@ -28,12 +28,22 @@ class Reline::ANSI
|
|
28
28
|
[27, 71, 67] => :ed_next_char, # →
|
29
29
|
[27, 71, 68] => :ed_prev_char, # ←
|
30
30
|
|
31
|
+
# urxvt / exoterm
|
32
|
+
[27, 91, 55, 126] => :ed_move_to_beg, # Home
|
33
|
+
[27, 91, 56, 126] => :ed_move_to_end, # End
|
34
|
+
|
31
35
|
# GNOME
|
32
36
|
[27, 79, 72] => :ed_move_to_beg, # Home
|
33
37
|
[27, 79, 70] => :ed_move_to_end, # End
|
34
38
|
# Del is 0x08
|
35
39
|
# Arrow keys are the same of KDE
|
36
40
|
|
41
|
+
# iTerm2
|
42
|
+
[27, 27, 91, 67] => :em_next_word, # Option+→
|
43
|
+
[27, 27, 91, 68] => :ed_prev_word, # Option+←
|
44
|
+
[195, 166] => :em_next_word, # Option+f
|
45
|
+
[195, 162] => :ed_prev_word, # Option+b
|
46
|
+
|
37
47
|
# others
|
38
48
|
[27, 32] => :em_set_mark, # M-<space>
|
39
49
|
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
@@ -61,8 +71,29 @@ class Reline::ANSI
|
|
61
71
|
unless @@buf.empty?
|
62
72
|
return @@buf.shift
|
63
73
|
end
|
64
|
-
c = @@input.raw(intr: true, &:getbyte)
|
74
|
+
until c = @@input.raw(intr: true, &:getbyte)
|
75
|
+
sleep 0.1
|
76
|
+
end
|
65
77
|
(c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
|
78
|
+
rescue Errno::EIO
|
79
|
+
# Maybe the I/O has been closed.
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.in_pasting?
|
84
|
+
not Reline::IOGate.empty_buffer?
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.empty_buffer?
|
88
|
+
unless @@buf.empty?
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
rs, = IO.select([@@input], [], [], 0.00001)
|
92
|
+
if rs and rs[0]
|
93
|
+
false
|
94
|
+
else
|
95
|
+
true
|
96
|
+
end
|
66
97
|
end
|
67
98
|
|
68
99
|
def self.ungetc(c)
|
@@ -105,10 +136,13 @@ class Reline::ANSI
|
|
105
136
|
@@input.raw do |stdin|
|
106
137
|
@@output << "\e[6n"
|
107
138
|
@@output.flush
|
108
|
-
|
109
|
-
|
139
|
+
loop do
|
140
|
+
c = stdin.getc
|
141
|
+
next if c.nil?
|
142
|
+
res << c
|
143
|
+
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
|
144
|
+
break if m
|
110
145
|
end
|
111
|
-
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)/)
|
112
146
|
(m.pre_match + m.post_match).chars.reverse_each do |ch|
|
113
147
|
stdin.ungetc ch
|
114
148
|
end
|
@@ -116,9 +150,16 @@ class Reline::ANSI
|
|
116
150
|
column = m[:column].to_i - 1
|
117
151
|
row = m[:row].to_i - 1
|
118
152
|
rescue Errno::ENOTTY
|
119
|
-
|
120
|
-
|
121
|
-
|
153
|
+
begin
|
154
|
+
buf = @@output.pread(@@output.pos, 0)
|
155
|
+
row = buf.count("\n")
|
156
|
+
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
157
|
+
rescue Errno::ESPIPE
|
158
|
+
# Just returns column 1 for ambiguous width because this I/O is not
|
159
|
+
# tty and can't seek.
|
160
|
+
row = 0
|
161
|
+
column = 1
|
162
|
+
end
|
122
163
|
end
|
123
164
|
Reline::CursorPos.new(column, row)
|
124
165
|
end
|
data/lib/reline/config.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
1
|
class Reline::Config
|
4
2
|
attr_reader :test_mode
|
5
3
|
|
6
|
-
DEFAULT_PATH = '~/.inputrc'
|
7
|
-
|
8
4
|
KEYSEQ_PATTERN = /\\(?:C|Control)-[A-Za-z_]|\\(?:M|Meta)-[0-9A-Za-z_]|\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]|\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]|\\e|\\[\\\"\'abdfnrtv]|\\\d{1,3}|\\x\h{1,2}|./
|
9
5
|
|
10
6
|
class InvalidInputrc < RuntimeError
|
@@ -37,6 +33,10 @@ class Reline::Config
|
|
37
33
|
show-all-if-ambiguous
|
38
34
|
show-all-if-unmodified
|
39
35
|
visible-stats
|
36
|
+
show-mode-in-prompt
|
37
|
+
vi-cmd-mode-icon
|
38
|
+
vi-ins-mode-icon
|
39
|
+
emacs-mode-string
|
40
40
|
}
|
41
41
|
VARIABLE_NAME_SYMBOLS = VARIABLE_NAMES.map { |v| :"#{v.tr(?-, ?_)}" }
|
42
42
|
VARIABLE_NAME_SYMBOLS.each do |v|
|
@@ -54,7 +54,11 @@ class Reline::Config
|
|
54
54
|
@key_actors[:emacs] = Reline::KeyActor::Emacs.new
|
55
55
|
@key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
|
56
56
|
@key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
|
57
|
-
@
|
57
|
+
@vi_cmd_mode_icon = '(cmd)'
|
58
|
+
@vi_ins_mode_icon = '(ins)'
|
59
|
+
@emacs_mode_string = '@'
|
60
|
+
# https://tiswww.case.edu/php/chet/readline/readline.html#IDX25
|
61
|
+
@history_size = -1 # unlimited
|
58
62
|
@keyseq_timeout = 500
|
59
63
|
@test_mode = false
|
60
64
|
end
|
@@ -83,8 +87,34 @@ class Reline::Config
|
|
83
87
|
@key_actors[@keymap_label]
|
84
88
|
end
|
85
89
|
|
90
|
+
def inputrc_path
|
91
|
+
case ENV['INPUTRC']
|
92
|
+
when nil, ''
|
93
|
+
else
|
94
|
+
return File.expand_path(ENV['INPUTRC'])
|
95
|
+
end
|
96
|
+
|
97
|
+
# In the XDG Specification, if ~/.config/readline/inputrc exists, then
|
98
|
+
# ~/.inputrc should not be read, but for compatibility with GNU Readline,
|
99
|
+
# if ~/.inputrc exists, then it is given priority.
|
100
|
+
home_rc_path = File.expand_path('~/.inputrc')
|
101
|
+
return home_rc_path if File.exist?(home_rc_path)
|
102
|
+
|
103
|
+
case path = ENV['XDG_CONFIG_HOME']
|
104
|
+
when nil, ''
|
105
|
+
else
|
106
|
+
path = File.join(path, 'readline/inputrc')
|
107
|
+
return path if File.exist?(path) and path == File.expand_path(path)
|
108
|
+
end
|
109
|
+
|
110
|
+
path = File.expand_path('~/.config/readline/inputrc')
|
111
|
+
return path if File.exist?(path)
|
112
|
+
|
113
|
+
return home_rc_path
|
114
|
+
end
|
115
|
+
|
86
116
|
def read(file = nil)
|
87
|
-
file ||=
|
117
|
+
file ||= inputrc_path
|
88
118
|
begin
|
89
119
|
if file.respond_to?(:readlines)
|
90
120
|
lines = file.readlines
|
@@ -135,7 +165,7 @@ class Reline::Config
|
|
135
165
|
|
136
166
|
case line
|
137
167
|
when /^set +([^ ]+) +([^ ]+)/i
|
138
|
-
var, value = $1.downcase, $2
|
168
|
+
var, value = $1.downcase, $2
|
139
169
|
bind_variable(var, value)
|
140
170
|
next
|
141
171
|
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
|
@@ -185,7 +215,11 @@ class Reline::Config
|
|
185
215
|
def bind_variable(name, value)
|
186
216
|
case name
|
187
217
|
when 'history-size'
|
188
|
-
|
218
|
+
begin
|
219
|
+
@history_size = Integer(value)
|
220
|
+
rescue ArgumentError
|
221
|
+
@history_size = 500
|
222
|
+
end
|
189
223
|
when 'bell-style'
|
190
224
|
@bell_style =
|
191
225
|
case value
|
@@ -224,12 +258,35 @@ class Reline::Config
|
|
224
258
|
end
|
225
259
|
when 'keyseq-timeout'
|
226
260
|
@keyseq_timeout = value.to_i
|
261
|
+
when 'show-mode-in-prompt'
|
262
|
+
case value
|
263
|
+
when 'off'
|
264
|
+
@show_mode_in_prompt = false
|
265
|
+
when 'on'
|
266
|
+
@show_mode_in_prompt = true
|
267
|
+
else
|
268
|
+
@show_mode_in_prompt = false
|
269
|
+
end
|
270
|
+
when 'vi-cmd-mode-string'
|
271
|
+
@vi_cmd_mode_icon = retrieve_string(value)
|
272
|
+
when 'vi-ins-mode-string'
|
273
|
+
@vi_ins_mode_icon = retrieve_string(value)
|
274
|
+
when 'emacs-mode-string'
|
275
|
+
@emacs_mode_string = retrieve_string(value)
|
227
276
|
when *VARIABLE_NAMES then
|
228
277
|
variable_name = :"@#{name.tr(?-, ?_)}"
|
229
278
|
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
230
279
|
end
|
231
280
|
end
|
232
281
|
|
282
|
+
def retrieve_string(str)
|
283
|
+
if str =~ /\A"(.*)"\z/
|
284
|
+
parse_keyseq($1).map(&:chr).join
|
285
|
+
else
|
286
|
+
parse_keyseq(str).map(&:chr).join
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
233
290
|
def bind_key(key, func_name)
|
234
291
|
if key =~ /\A"(.*)"\z/
|
235
292
|
keyseq = parse_keyseq($1)
|
data/lib/reline/general_io.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'timeout'
|
2
2
|
|
3
3
|
class Reline::GeneralIO
|
4
|
+
def self.reset
|
5
|
+
@@pasting = false
|
6
|
+
end
|
7
|
+
|
4
8
|
def self.encoding
|
5
9
|
RUBY_PLATFORM =~ /mswin|mingw/ ? Encoding::UTF_8 : Encoding::default_external
|
6
10
|
end
|
@@ -67,6 +71,20 @@ class Reline::GeneralIO
|
|
67
71
|
def self.set_winch_handler(&handler)
|
68
72
|
end
|
69
73
|
|
74
|
+
@@pasting = false
|
75
|
+
|
76
|
+
def self.in_pasting?
|
77
|
+
@@pasting
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.start_pasting
|
81
|
+
@@pasting = true
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.finish_pasting
|
85
|
+
@@pasting = false
|
86
|
+
end
|
87
|
+
|
70
88
|
def self.prep
|
71
89
|
end
|
72
90
|
|
data/lib/reline/history.rb
CHANGED
@@ -29,27 +29,47 @@ class Reline::History < Array
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def push(*val)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
# If history_size is zero, all histories are dropped.
|
33
|
+
return self if @config.history_size.zero?
|
34
|
+
# If history_size is negative, history size is unlimited.
|
35
|
+
if @config.history_size.positive?
|
36
|
+
diff = size + val.size - @config.history_size
|
37
|
+
if diff > 0
|
38
|
+
if diff <= size
|
39
|
+
shift(diff)
|
40
|
+
else
|
41
|
+
diff -= size
|
42
|
+
clear
|
43
|
+
val.shift(diff)
|
44
|
+
end
|
40
45
|
end
|
41
46
|
end
|
42
|
-
super(*(val.map{ |v|
|
47
|
+
super(*(val.map{ |v|
|
48
|
+
String.new(v, encoding: Reline.encoding_system_needs)
|
49
|
+
}))
|
43
50
|
end
|
44
51
|
|
45
52
|
def <<(val)
|
46
|
-
|
53
|
+
# If history_size is zero, all histories are dropped.
|
54
|
+
return self if @config.history_size.zero?
|
55
|
+
# If history_size is negative, history size is unlimited.
|
56
|
+
if @config.history_size.positive?
|
57
|
+
shift if size + 1 > @config.history_size
|
58
|
+
end
|
47
59
|
super(String.new(val, encoding: Reline.encoding_system_needs))
|
48
60
|
end
|
49
61
|
|
50
62
|
private def check_index(index)
|
51
63
|
index += size if index < 0
|
52
|
-
|
64
|
+
if index < -2147483648 or 2147483647 < index
|
65
|
+
raise RangeError.new("integer #{index} too big to convert to `int'")
|
66
|
+
end
|
67
|
+
# If history_size is negative, history size is unlimited.
|
68
|
+
if @config.history_size.positive?
|
69
|
+
if index < -@config.history_size or @config.history_size < index
|
70
|
+
raise RangeError.new("index=<#{index}>")
|
71
|
+
end
|
72
|
+
end
|
53
73
|
raise IndexError.new("index=<#{index}>") if index < 0 or size <= index
|
54
74
|
index
|
55
75
|
end
|
@@ -37,9 +37,9 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
37
37
|
# 17 ^Q
|
38
38
|
:ed_quoted_insert,
|
39
39
|
# 18 ^R
|
40
|
-
:
|
40
|
+
:vi_search_prev,
|
41
41
|
# 19 ^S
|
42
|
-
:
|
42
|
+
:vi_search_next,
|
43
43
|
# 20 ^T
|
44
44
|
:ed_transpose_chars,
|
45
45
|
# 21 ^U
|
@@ -413,11 +413,11 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
413
413
|
# 205 M-M
|
414
414
|
:ed_unassigned,
|
415
415
|
# 206 M-N
|
416
|
-
:
|
416
|
+
:vi_search_next,
|
417
417
|
# 207 M-O
|
418
418
|
:ed_sequence_lead_in,
|
419
419
|
# 208 M-P
|
420
|
-
:
|
420
|
+
:vi_search_prev,
|
421
421
|
# 209 M-Q
|
422
422
|
:ed_unassigned,
|
423
423
|
# 210 M-R
|
@@ -477,11 +477,11 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
477
477
|
# 237 M-m
|
478
478
|
:ed_unassigned,
|
479
479
|
# 238 M-n
|
480
|
-
:
|
480
|
+
:vi_search_next,
|
481
481
|
# 239 M-o
|
482
482
|
:ed_unassigned,
|
483
483
|
# 240 M-p
|
484
|
-
:
|
484
|
+
:vi_search_prev,
|
485
485
|
# 241 M-q
|
486
486
|
:ed_unassigned,
|
487
487
|
# 242 M-r
|