reline 0.5.8 → 0.5.9
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/lib/reline/config.rb +21 -19
- data/lib/reline/{ansi.rb → io/ansi.rb} +87 -85
- data/lib/reline/io/dumb.rb +106 -0
- data/lib/reline/{windows.rb → io/windows.rb} +102 -102
- data/lib/reline/io.rb +41 -0
- data/lib/reline/key_actor/base.rb +22 -6
- data/lib/reline/key_actor/composite.rb +17 -0
- data/lib/reline/key_actor/emacs.rb +2 -2
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/key_actor.rb +1 -0
- data/lib/reline/key_stroke.rb +65 -104
- data/lib/reline/line_editor.rb +31 -28
- data/lib/reline/terminfo.rb +5 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +35 -123
- metadata +7 -5
- data/lib/reline/general_io.rb +0 -111
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28ee53a9963a33e9eb1159bea507695d94cc4f67b05ce005175808b7ec2d5175
|
4
|
+
data.tar.gz: c165de2edcc223bc4e3e149208fe29994063445ea0cf02b93658010a245df5e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af0f93e54d3a414c63dfb369746f00e8fa9cac609c646c0a48ad5f87275e7b6f5c88c47d4c30218075d3774fd41ba7978f49a0ffbfa070ee42921ba0e500c06e
|
7
|
+
data.tar.gz: 5b0a45b7ae2cfb0e23c9d3b4a863e381f4d9ba5d6298f864c261e408cb5c366031d6137d623d0d46e3729b7bbe086fc5da5c5e636163bce230ae0f297441e016
|
data/lib/reline/config.rb
CHANGED
@@ -29,18 +29,20 @@ class Reline::Config
|
|
29
29
|
attr_accessor :autocompletion
|
30
30
|
|
31
31
|
def initialize
|
32
|
-
@additional_key_bindings = {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
@additional_key_bindings = { # from inputrc
|
33
|
+
emacs: Reline::KeyActor::Base.new,
|
34
|
+
vi_insert: Reline::KeyActor::Base.new,
|
35
|
+
vi_command: Reline::KeyActor::Base.new
|
36
|
+
}
|
37
|
+
@oneshot_key_bindings = Reline::KeyActor::Base.new
|
37
38
|
@editing_mode_label = :emacs
|
38
39
|
@keymap_label = :emacs
|
39
40
|
@keymap_prefix = []
|
40
|
-
@
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
@default_key_bindings = {
|
42
|
+
emacs: Reline::KeyActor::Base.new(Reline::KeyActor::EMACS_MAPPING),
|
43
|
+
vi_insert: Reline::KeyActor::Base.new(Reline::KeyActor::VI_INSERT_MAPPING),
|
44
|
+
vi_command: Reline::KeyActor::Base.new(Reline::KeyActor::VI_COMMAND_MAPPING)
|
45
|
+
}
|
44
46
|
@vi_cmd_mode_string = '(cmd)'
|
45
47
|
@vi_ins_mode_string = '(ins)'
|
46
48
|
@emacs_mode_string = '@'
|
@@ -62,7 +64,7 @@ class Reline::Config
|
|
62
64
|
end
|
63
65
|
|
64
66
|
def editing_mode
|
65
|
-
@
|
67
|
+
@default_key_bindings[@editing_mode_label]
|
66
68
|
end
|
67
69
|
|
68
70
|
def editing_mode=(val)
|
@@ -74,7 +76,7 @@ class Reline::Config
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def keymap
|
77
|
-
@
|
79
|
+
@default_key_bindings[@keymap_label]
|
78
80
|
end
|
79
81
|
|
80
82
|
def loaded?
|
@@ -133,14 +135,14 @@ class Reline::Config
|
|
133
135
|
|
134
136
|
def key_bindings
|
135
137
|
# The key bindings for each editing mode will be overwritten by the user-defined ones.
|
136
|
-
|
137
|
-
kb.merge!(@additional_key_bindings[@editing_mode_label])
|
138
|
-
kb.merge!(@oneshot_key_bindings)
|
139
|
-
kb
|
138
|
+
Reline::KeyActor::Composite.new([@oneshot_key_bindings, @additional_key_bindings[@editing_mode_label], @default_key_bindings[@editing_mode_label]])
|
140
139
|
end
|
141
140
|
|
142
141
|
def add_oneshot_key_binding(keystroke, target)
|
143
|
-
|
142
|
+
# IRB sets invalid keystroke [Reline::Key]. We should ignore it.
|
143
|
+
return unless keystroke.all? { |c| c.is_a?(Integer) }
|
144
|
+
|
145
|
+
@oneshot_key_bindings.add(keystroke, target)
|
144
146
|
end
|
145
147
|
|
146
148
|
def reset_oneshot_key_bindings
|
@@ -148,11 +150,11 @@ class Reline::Config
|
|
148
150
|
end
|
149
151
|
|
150
152
|
def add_default_key_binding_by_keymap(keymap, keystroke, target)
|
151
|
-
@
|
153
|
+
@default_key_bindings[keymap].add(keystroke, target)
|
152
154
|
end
|
153
155
|
|
154
156
|
def add_default_key_binding(keystroke, target)
|
155
|
-
@
|
157
|
+
add_default_key_binding_by_keymap(@keymap_label, keystroke, target)
|
156
158
|
end
|
157
159
|
|
158
160
|
def read_lines(lines, file = nil)
|
@@ -192,7 +194,7 @@ class Reline::Config
|
|
192
194
|
func_name = func_name.split.first
|
193
195
|
keystroke, func = bind_key(key, func_name)
|
194
196
|
next unless keystroke
|
195
|
-
@additional_key_bindings[@keymap_label]
|
197
|
+
@additional_key_bindings[@keymap_label].add(@keymap_prefix + keystroke, func)
|
196
198
|
end
|
197
199
|
end
|
198
200
|
unless if_stack.empty?
|
@@ -1,10 +1,7 @@
|
|
1
1
|
require 'io/console'
|
2
2
|
require 'io/wait'
|
3
|
-
require_relative 'terminfo'
|
4
|
-
|
5
|
-
class Reline::ANSI
|
6
|
-
RESET_COLOR = "\e[0m"
|
7
3
|
|
4
|
+
class Reline::ANSI < Reline::IO
|
8
5
|
CAPNAME_KEY_BINDINGS = {
|
9
6
|
'khome' => :ed_move_to_beg,
|
10
7
|
'kend' => :ed_move_to_end,
|
@@ -36,15 +33,18 @@ class Reline::ANSI
|
|
36
33
|
Reline::Terminfo.setupterm(0, 2)
|
37
34
|
end
|
38
35
|
|
39
|
-
def
|
40
|
-
|
36
|
+
def initialize
|
37
|
+
@input = STDIN
|
38
|
+
@output = STDOUT
|
39
|
+
@buf = []
|
40
|
+
@old_winch_handler = nil
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
43
|
+
def encoding
|
44
|
+
Encoding.default_external
|
45
45
|
end
|
46
46
|
|
47
|
-
def
|
47
|
+
def set_default_key_bindings(config, allow_terminfo: true)
|
48
48
|
set_bracketed_paste_key_bindings(config)
|
49
49
|
set_default_key_bindings_ansi_cursor(config)
|
50
50
|
if allow_terminfo && Reline::Terminfo.enabled?
|
@@ -67,13 +67,13 @@ class Reline::ANSI
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
70
|
+
def set_bracketed_paste_key_bindings(config)
|
71
71
|
[:emacs, :vi_insert, :vi_command].each do |keymap|
|
72
72
|
config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
76
|
+
def set_default_key_bindings_ansi_cursor(config)
|
77
77
|
ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
|
78
78
|
bindings = [["\e[#{char}", default_func]] # CSI + char
|
79
79
|
if modifiers[:ctrl]
|
@@ -95,7 +95,7 @@ class Reline::ANSI
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
def
|
98
|
+
def set_default_key_bindings_terminfo(config)
|
99
99
|
key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
|
100
100
|
begin
|
101
101
|
key_code = Reline::Terminfo.tigetstr(capname)
|
@@ -112,12 +112,16 @@ class Reline::ANSI
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
|
-
def
|
115
|
+
def set_default_key_bindings_comprehensive_list(config)
|
116
116
|
{
|
117
|
+
# xterm
|
118
|
+
[27, 91, 51, 126] => :key_delete, # kdch1
|
119
|
+
[27, 91, 53, 126] => :ed_search_prev_history, # kpp
|
120
|
+
[27, 91, 54, 126] => :ed_search_next_history, # knp
|
121
|
+
|
117
122
|
# Console (80x25)
|
118
123
|
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
119
124
|
[27, 91, 52, 126] => :ed_move_to_end, # End
|
120
|
-
[27, 91, 51, 126] => :key_delete, # Del
|
121
125
|
|
122
126
|
# KDE
|
123
127
|
# Del is 0x08
|
@@ -147,47 +151,42 @@ class Reline::ANSI
|
|
147
151
|
end
|
148
152
|
end
|
149
153
|
|
150
|
-
|
151
|
-
|
152
|
-
@@input = val
|
154
|
+
def input=(val)
|
155
|
+
@input = val
|
153
156
|
end
|
154
157
|
|
155
|
-
|
156
|
-
|
157
|
-
@@output = val
|
158
|
+
def output=(val)
|
159
|
+
@output = val
|
158
160
|
end
|
159
161
|
|
160
|
-
def
|
161
|
-
if
|
162
|
-
|
162
|
+
def with_raw_input
|
163
|
+
if @input.tty?
|
164
|
+
@input.raw(intr: true) { yield }
|
163
165
|
else
|
164
166
|
yield
|
165
167
|
end
|
166
168
|
end
|
167
169
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
return @@buf.shift
|
170
|
+
def inner_getc(timeout_second)
|
171
|
+
unless @buf.empty?
|
172
|
+
return @buf.shift
|
172
173
|
end
|
173
|
-
until
|
174
|
+
until @input.wait_readable(0.01)
|
174
175
|
timeout_second -= 0.01
|
175
176
|
return nil if timeout_second <= 0
|
176
177
|
|
177
178
|
Reline.core.line_editor.handle_signal
|
178
179
|
end
|
179
|
-
c =
|
180
|
-
(c == 0x16 &&
|
180
|
+
c = @input.getbyte
|
181
|
+
(c == 0x16 && @input.tty? && @input.raw(min: 0, time: 0, &:getbyte)) || c
|
181
182
|
rescue Errno::EIO
|
182
183
|
# Maybe the I/O has been closed.
|
183
184
|
nil
|
184
|
-
rescue Errno::ENOTTY
|
185
|
-
nil
|
186
185
|
end
|
187
186
|
|
188
187
|
START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
|
189
188
|
END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
|
190
|
-
def
|
189
|
+
def read_bracketed_paste
|
191
190
|
buffer = String.new(encoding: Encoding::ASCII_8BIT)
|
192
191
|
until buffer.end_with?(END_BRACKETED_PASTE)
|
193
192
|
c = inner_getc(Float::INFINITY)
|
@@ -199,38 +198,38 @@ class Reline::ANSI
|
|
199
198
|
end
|
200
199
|
|
201
200
|
# if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
|
202
|
-
def
|
201
|
+
def getc(timeout_second)
|
203
202
|
inner_getc(timeout_second)
|
204
203
|
end
|
205
204
|
|
206
|
-
def
|
205
|
+
def in_pasting?
|
207
206
|
not empty_buffer?
|
208
207
|
end
|
209
208
|
|
210
|
-
def
|
211
|
-
unless
|
209
|
+
def empty_buffer?
|
210
|
+
unless @buf.empty?
|
212
211
|
return false
|
213
212
|
end
|
214
|
-
|
213
|
+
!@input.wait_readable(0)
|
215
214
|
end
|
216
215
|
|
217
|
-
def
|
218
|
-
|
216
|
+
def ungetc(c)
|
217
|
+
@buf.unshift(c)
|
219
218
|
end
|
220
219
|
|
221
|
-
def
|
220
|
+
def retrieve_keybuffer
|
222
221
|
begin
|
223
|
-
return unless
|
224
|
-
str =
|
222
|
+
return unless @input.wait_readable(0.001)
|
223
|
+
str = @input.read_nonblock(1024)
|
225
224
|
str.bytes.each do |c|
|
226
|
-
|
225
|
+
@buf.push(c)
|
227
226
|
end
|
228
227
|
rescue EOFError
|
229
228
|
end
|
230
229
|
end
|
231
230
|
|
232
|
-
def
|
233
|
-
s =
|
231
|
+
def get_screen_size
|
232
|
+
s = @input.winsize
|
234
233
|
return s if s[0] > 0 && s[1] > 0
|
235
234
|
s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
|
236
235
|
return s if s[0] > 0 && s[1] > 0
|
@@ -239,20 +238,20 @@ class Reline::ANSI
|
|
239
238
|
[24, 80]
|
240
239
|
end
|
241
240
|
|
242
|
-
def
|
243
|
-
|
241
|
+
def set_screen_size(rows, columns)
|
242
|
+
@input.winsize = [rows, columns]
|
244
243
|
self
|
245
|
-
rescue Errno::ENOTTY
|
244
|
+
rescue Errno::ENOTTY, Errno::ENODEV
|
246
245
|
self
|
247
246
|
end
|
248
247
|
|
249
|
-
def
|
250
|
-
|
248
|
+
def cursor_pos
|
249
|
+
if both_tty?
|
251
250
|
res = +''
|
252
251
|
m = nil
|
253
|
-
|
254
|
-
|
255
|
-
|
252
|
+
@input.raw do |stdin|
|
253
|
+
@output << "\e[6n"
|
254
|
+
@output.flush
|
256
255
|
loop do
|
257
256
|
c = stdin.getc
|
258
257
|
next if c.nil?
|
@@ -266,9 +265,9 @@ class Reline::ANSI
|
|
266
265
|
end
|
267
266
|
column = m[:column].to_i - 1
|
268
267
|
row = m[:row].to_i - 1
|
269
|
-
|
268
|
+
else
|
270
269
|
begin
|
271
|
-
buf =
|
270
|
+
buf = @output.pread(@output.pos, 0)
|
272
271
|
row = buf.count("\n")
|
273
272
|
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
274
273
|
rescue Errno::ESPIPE, IOError
|
@@ -281,82 +280,85 @@ class Reline::ANSI
|
|
281
280
|
Reline::CursorPos.new(column, row)
|
282
281
|
end
|
283
282
|
|
284
|
-
def
|
285
|
-
|
283
|
+
def both_tty?
|
284
|
+
@input.tty? && @output.tty?
|
285
|
+
end
|
286
|
+
|
287
|
+
def move_cursor_column(x)
|
288
|
+
@output.write "\e[#{x + 1}G"
|
286
289
|
end
|
287
290
|
|
288
|
-
def
|
291
|
+
def move_cursor_up(x)
|
289
292
|
if x > 0
|
290
|
-
|
293
|
+
@output.write "\e[#{x}A"
|
291
294
|
elsif x < 0
|
292
295
|
move_cursor_down(-x)
|
293
296
|
end
|
294
297
|
end
|
295
298
|
|
296
|
-
def
|
299
|
+
def move_cursor_down(x)
|
297
300
|
if x > 0
|
298
|
-
|
301
|
+
@output.write "\e[#{x}B"
|
299
302
|
elsif x < 0
|
300
303
|
move_cursor_up(-x)
|
301
304
|
end
|
302
305
|
end
|
303
306
|
|
304
|
-
def
|
307
|
+
def hide_cursor
|
308
|
+
seq = "\e[?25l"
|
305
309
|
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
|
306
310
|
begin
|
307
|
-
|
311
|
+
seq = Reline::Terminfo.tigetstr('civis')
|
308
312
|
rescue Reline::Terminfo::TerminfoError
|
309
313
|
# civis is undefined
|
310
314
|
end
|
311
|
-
else
|
312
|
-
# ignored
|
313
315
|
end
|
316
|
+
@output.write seq
|
314
317
|
end
|
315
318
|
|
316
|
-
def
|
319
|
+
def show_cursor
|
320
|
+
seq = "\e[?25h"
|
317
321
|
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
|
318
322
|
begin
|
319
|
-
|
323
|
+
seq = Reline::Terminfo.tigetstr('cnorm')
|
320
324
|
rescue Reline::Terminfo::TerminfoError
|
321
325
|
# cnorm is undefined
|
322
326
|
end
|
323
|
-
else
|
324
|
-
# ignored
|
325
327
|
end
|
328
|
+
@output.write seq
|
326
329
|
end
|
327
330
|
|
328
|
-
def
|
329
|
-
|
331
|
+
def erase_after_cursor
|
332
|
+
@output.write "\e[K"
|
330
333
|
end
|
331
334
|
|
332
335
|
# This only works when the cursor is at the bottom of the scroll range
|
333
336
|
# For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
|
334
|
-
def
|
337
|
+
def scroll_down(x)
|
335
338
|
return if x.zero?
|
336
339
|
# We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
|
337
|
-
|
340
|
+
@output.write "\n" * x
|
338
341
|
end
|
339
342
|
|
340
|
-
def
|
341
|
-
|
342
|
-
|
343
|
+
def clear_screen
|
344
|
+
@output.write "\e[2J"
|
345
|
+
@output.write "\e[1;1H"
|
343
346
|
end
|
344
347
|
|
345
|
-
|
346
|
-
|
347
|
-
@@old_winch_handler = Signal.trap('WINCH', &handler)
|
348
|
+
def set_winch_handler(&handler)
|
349
|
+
@old_winch_handler = Signal.trap('WINCH', &handler)
|
348
350
|
end
|
349
351
|
|
350
|
-
def
|
352
|
+
def prep
|
351
353
|
# Enable bracketed paste
|
352
|
-
|
354
|
+
@output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste && both_tty?
|
353
355
|
retrieve_keybuffer
|
354
356
|
nil
|
355
357
|
end
|
356
358
|
|
357
|
-
def
|
359
|
+
def deprep(otio)
|
358
360
|
# Disable bracketed paste
|
359
|
-
|
360
|
-
Signal.trap('WINCH',
|
361
|
+
@output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste && both_tty?
|
362
|
+
Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler
|
361
363
|
end
|
362
364
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'io/wait'
|
2
|
+
|
3
|
+
class Reline::Dumb < Reline::IO
|
4
|
+
RESET_COLOR = '' # Do not send color reset sequence
|
5
|
+
|
6
|
+
def initialize(encoding: nil)
|
7
|
+
@input = STDIN
|
8
|
+
@buf = []
|
9
|
+
@pasting = false
|
10
|
+
@encoding = encoding
|
11
|
+
@screen_size = [24, 80]
|
12
|
+
end
|
13
|
+
|
14
|
+
def dumb?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def encoding
|
19
|
+
if @encoding
|
20
|
+
@encoding
|
21
|
+
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
22
|
+
Encoding::UTF_8
|
23
|
+
else
|
24
|
+
Encoding::default_external
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_default_key_bindings(_)
|
29
|
+
end
|
30
|
+
|
31
|
+
def input=(val)
|
32
|
+
@input = val
|
33
|
+
end
|
34
|
+
|
35
|
+
def with_raw_input
|
36
|
+
yield
|
37
|
+
end
|
38
|
+
|
39
|
+
def getc(_timeout_second)
|
40
|
+
unless @buf.empty?
|
41
|
+
return @buf.shift
|
42
|
+
end
|
43
|
+
c = nil
|
44
|
+
loop do
|
45
|
+
Reline.core.line_editor.handle_signal
|
46
|
+
result = @input.wait_readable(0.1)
|
47
|
+
next if result.nil?
|
48
|
+
c = @input.read(1)
|
49
|
+
break
|
50
|
+
end
|
51
|
+
c&.ord
|
52
|
+
end
|
53
|
+
|
54
|
+
def ungetc(c)
|
55
|
+
@buf.unshift(c)
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_screen_size
|
59
|
+
@screen_size
|
60
|
+
end
|
61
|
+
|
62
|
+
def cursor_pos
|
63
|
+
Reline::CursorPos.new(1, 1)
|
64
|
+
end
|
65
|
+
|
66
|
+
def hide_cursor
|
67
|
+
end
|
68
|
+
|
69
|
+
def show_cursor
|
70
|
+
end
|
71
|
+
|
72
|
+
def move_cursor_column(val)
|
73
|
+
end
|
74
|
+
|
75
|
+
def move_cursor_up(val)
|
76
|
+
end
|
77
|
+
|
78
|
+
def move_cursor_down(val)
|
79
|
+
end
|
80
|
+
|
81
|
+
def erase_after_cursor
|
82
|
+
end
|
83
|
+
|
84
|
+
def scroll_down(val)
|
85
|
+
end
|
86
|
+
|
87
|
+
def clear_screen
|
88
|
+
end
|
89
|
+
|
90
|
+
def set_screen_size(rows, columns)
|
91
|
+
@screen_size = [rows, columns]
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_winch_handler(&handler)
|
95
|
+
end
|
96
|
+
|
97
|
+
def in_pasting?
|
98
|
+
@pasting
|
99
|
+
end
|
100
|
+
|
101
|
+
def prep
|
102
|
+
end
|
103
|
+
|
104
|
+
def deprep(otio)
|
105
|
+
end
|
106
|
+
end
|