reline 0.1.3 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
[](https://travis-ci.com/ruby/reline)
|
2
2
|
|
3
|
+
This is a screen capture of *IRB improved by Reline*.
|
4
|
+
|
5
|
+

|
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
|