reline 0.3.2 → 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/README.md +33 -2
- data/lib/reline/config.rb +58 -77
- data/lib/reline/face.rb +199 -0
- data/lib/reline/history.rb +1 -1
- data/lib/reline/io/ansi.rb +364 -0
- data/lib/reline/io/dumb.rb +106 -0
- data/lib/reline/{windows.rb → io/windows.rb} +108 -102
- data/lib/reline/io.rb +41 -0
- data/lib/reline/key_actor/base.rb +20 -8
- data/lib/reline/key_actor/composite.rb +17 -0
- data/lib/reline/key_actor/emacs.rb +15 -15
- data/lib/reline/key_actor/vi_command.rb +25 -25
- data/lib/reline/key_actor/vi_insert.rb +7 -7
- data/lib/reline/key_actor.rb +1 -0
- data/lib/reline/key_stroke.rb +88 -84
- data/lib/reline/kill_ring.rb +2 -2
- data/lib/reline/line_editor.rb +1095 -1895
- data/lib/reline/terminfo.rb +13 -29
- data/lib/reline/unicode/east_asian_width.rb +91 -59
- data/lib/reline/unicode.rb +95 -64
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +156 -240
- metadata +13 -7
- data/lib/reline/ansi.rb +0 -350
- data/lib/reline/general_io.rb +0 -109
data/lib/reline/ansi.rb
DELETED
@@ -1,350 +0,0 @@
|
|
1
|
-
require 'io/console'
|
2
|
-
require 'io/wait'
|
3
|
-
require 'timeout'
|
4
|
-
require_relative 'terminfo'
|
5
|
-
|
6
|
-
class Reline::ANSI
|
7
|
-
CAPNAME_KEY_BINDINGS = {
|
8
|
-
'khome' => :ed_move_to_beg,
|
9
|
-
'kend' => :ed_move_to_end,
|
10
|
-
'kcuu1' => :ed_prev_history,
|
11
|
-
'kcud1' => :ed_next_history,
|
12
|
-
'kcuf1' => :ed_next_char,
|
13
|
-
'kcub1' => :ed_prev_char,
|
14
|
-
'cuu' => :ed_prev_history,
|
15
|
-
'cud' => :ed_next_history,
|
16
|
-
'cuf' => :ed_next_char,
|
17
|
-
'cub' => :ed_prev_char,
|
18
|
-
}
|
19
|
-
|
20
|
-
if Reline::Terminfo.enabled?
|
21
|
-
Reline::Terminfo.setupterm(0, 2)
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.encoding
|
25
|
-
Encoding.default_external
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.win?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.set_default_key_bindings(config)
|
33
|
-
if Reline::Terminfo.enabled?
|
34
|
-
set_default_key_bindings_terminfo(config)
|
35
|
-
else
|
36
|
-
set_default_key_bindings_comprehensive_list(config)
|
37
|
-
end
|
38
|
-
{
|
39
|
-
# extended entries of terminfo
|
40
|
-
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
|
41
|
-
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
|
42
|
-
[27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
|
43
|
-
[27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
|
44
|
-
}.each_pair do |key, func|
|
45
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
46
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
47
|
-
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
48
|
-
end
|
49
|
-
{
|
50
|
-
[27, 91, 90] => :completion_journey_up, # S-Tab
|
51
|
-
}.each_pair do |key, func|
|
52
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
53
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
54
|
-
end
|
55
|
-
{
|
56
|
-
# default bindings
|
57
|
-
[27, 32] => :em_set_mark, # M-<space>
|
58
|
-
[24, 24] => :em_exchange_mark, # C-x C-x
|
59
|
-
}.each_pair do |key, func|
|
60
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.set_default_key_bindings_terminfo(config)
|
65
|
-
key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
|
66
|
-
begin
|
67
|
-
key_code = Reline::Terminfo.tigetstr(capname)
|
68
|
-
case capname
|
69
|
-
# Escape sequences that omit the move distance and are set to defaults
|
70
|
-
# value 1 may be sometimes sent by pressing the arrow-key.
|
71
|
-
when 'cuu', 'cud', 'cuf', 'cub'
|
72
|
-
[ key_code.sub(/%p1%d/, '').bytes, key_binding ]
|
73
|
-
else
|
74
|
-
[ key_code.bytes, key_binding ]
|
75
|
-
end
|
76
|
-
rescue Reline::Terminfo::TerminfoError
|
77
|
-
# capname is undefined
|
78
|
-
end
|
79
|
-
end.compact.to_h
|
80
|
-
|
81
|
-
key_bindings.each_pair do |key, func|
|
82
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
83
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
84
|
-
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def self.set_default_key_bindings_comprehensive_list(config)
|
89
|
-
{
|
90
|
-
# Console (80x25)
|
91
|
-
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
92
|
-
[27, 91, 52, 126] => :ed_move_to_end, # End
|
93
|
-
[27, 91, 51, 126] => :key_delete, # Del
|
94
|
-
[27, 91, 65] => :ed_prev_history, # ↑
|
95
|
-
[27, 91, 66] => :ed_next_history, # ↓
|
96
|
-
[27, 91, 67] => :ed_next_char, # →
|
97
|
-
[27, 91, 68] => :ed_prev_char, # ←
|
98
|
-
|
99
|
-
# KDE
|
100
|
-
[27, 91, 72] => :ed_move_to_beg, # Home
|
101
|
-
[27, 91, 70] => :ed_move_to_end, # End
|
102
|
-
# Del is 0x08
|
103
|
-
[27, 71, 65] => :ed_prev_history, # ↑
|
104
|
-
[27, 71, 66] => :ed_next_history, # ↓
|
105
|
-
[27, 71, 67] => :ed_next_char, # →
|
106
|
-
[27, 71, 68] => :ed_prev_char, # ←
|
107
|
-
|
108
|
-
# urxvt / exoterm
|
109
|
-
[27, 91, 55, 126] => :ed_move_to_beg, # Home
|
110
|
-
[27, 91, 56, 126] => :ed_move_to_end, # End
|
111
|
-
|
112
|
-
# GNOME
|
113
|
-
[27, 79, 72] => :ed_move_to_beg, # Home
|
114
|
-
[27, 79, 70] => :ed_move_to_end, # End
|
115
|
-
# Del is 0x08
|
116
|
-
# Arrow keys are the same of KDE
|
117
|
-
|
118
|
-
# iTerm2
|
119
|
-
[27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
|
120
|
-
[27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
|
121
|
-
[195, 166] => :em_next_word, # Option+f
|
122
|
-
[195, 162] => :ed_prev_word, # Option+b
|
123
|
-
|
124
|
-
[27, 79, 65] => :ed_prev_history, # ↑
|
125
|
-
[27, 79, 66] => :ed_next_history, # ↓
|
126
|
-
[27, 79, 67] => :ed_next_char, # →
|
127
|
-
[27, 79, 68] => :ed_prev_char, # ←
|
128
|
-
}.each_pair do |key, func|
|
129
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
130
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
131
|
-
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
@@input = STDIN
|
136
|
-
def self.input=(val)
|
137
|
-
@@input = val
|
138
|
-
end
|
139
|
-
|
140
|
-
@@output = STDOUT
|
141
|
-
def self.output=(val)
|
142
|
-
@@output = val
|
143
|
-
end
|
144
|
-
|
145
|
-
@@buf = []
|
146
|
-
def self.inner_getc
|
147
|
-
unless @@buf.empty?
|
148
|
-
return @@buf.shift
|
149
|
-
end
|
150
|
-
until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
|
151
|
-
Reline.core.line_editor.resize
|
152
|
-
end
|
153
|
-
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
|
154
|
-
rescue Errno::EIO
|
155
|
-
# Maybe the I/O has been closed.
|
156
|
-
nil
|
157
|
-
rescue Errno::ENOTTY
|
158
|
-
nil
|
159
|
-
end
|
160
|
-
|
161
|
-
@@in_bracketed_paste_mode = false
|
162
|
-
START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
|
163
|
-
END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
|
164
|
-
def self.getc_with_bracketed_paste
|
165
|
-
buffer = String.new(encoding: Encoding::ASCII_8BIT)
|
166
|
-
buffer << inner_getc
|
167
|
-
while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
|
168
|
-
if START_BRACKETED_PASTE == buffer
|
169
|
-
@@in_bracketed_paste_mode = true
|
170
|
-
return inner_getc
|
171
|
-
elsif END_BRACKETED_PASTE == buffer
|
172
|
-
@@in_bracketed_paste_mode = false
|
173
|
-
ungetc(-1)
|
174
|
-
return inner_getc
|
175
|
-
end
|
176
|
-
begin
|
177
|
-
succ_c = nil
|
178
|
-
Timeout.timeout(Reline.core.config.keyseq_timeout * 100) {
|
179
|
-
succ_c = inner_getc
|
180
|
-
}
|
181
|
-
rescue Timeout::Error
|
182
|
-
break
|
183
|
-
else
|
184
|
-
buffer << succ_c
|
185
|
-
end
|
186
|
-
end
|
187
|
-
buffer.bytes.reverse_each do |ch|
|
188
|
-
ungetc ch
|
189
|
-
end
|
190
|
-
inner_getc
|
191
|
-
end
|
192
|
-
|
193
|
-
def self.getc
|
194
|
-
if Reline.core.config.enable_bracketed_paste
|
195
|
-
getc_with_bracketed_paste
|
196
|
-
else
|
197
|
-
inner_getc
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def self.in_pasting?
|
202
|
-
@@in_bracketed_paste_mode or (not Reline::IOGate.empty_buffer?)
|
203
|
-
end
|
204
|
-
|
205
|
-
def self.empty_buffer?
|
206
|
-
unless @@buf.empty?
|
207
|
-
return false
|
208
|
-
end
|
209
|
-
!@@input.wait_readable(0)
|
210
|
-
end
|
211
|
-
|
212
|
-
def self.ungetc(c)
|
213
|
-
@@buf.unshift(c)
|
214
|
-
end
|
215
|
-
|
216
|
-
def self.retrieve_keybuffer
|
217
|
-
begin
|
218
|
-
return unless @@input.wait_readable(0.001)
|
219
|
-
str = @@input.read_nonblock(1024)
|
220
|
-
str.bytes.each do |c|
|
221
|
-
@@buf.push(c)
|
222
|
-
end
|
223
|
-
rescue EOFError
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def self.get_screen_size
|
228
|
-
s = @@input.winsize
|
229
|
-
return s if s[0] > 0 && s[1] > 0
|
230
|
-
s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
|
231
|
-
return s if s[0] > 0 && s[1] > 0
|
232
|
-
[24, 80]
|
233
|
-
rescue Errno::ENOTTY
|
234
|
-
[24, 80]
|
235
|
-
end
|
236
|
-
|
237
|
-
def self.set_screen_size(rows, columns)
|
238
|
-
@@input.winsize = [rows, columns]
|
239
|
-
self
|
240
|
-
rescue Errno::ENOTTY
|
241
|
-
self
|
242
|
-
end
|
243
|
-
|
244
|
-
def self.cursor_pos
|
245
|
-
begin
|
246
|
-
res = +''
|
247
|
-
m = nil
|
248
|
-
@@input.raw do |stdin|
|
249
|
-
@@output << "\e[6n"
|
250
|
-
@@output.flush
|
251
|
-
loop do
|
252
|
-
c = stdin.getc
|
253
|
-
next if c.nil?
|
254
|
-
res << c
|
255
|
-
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
|
256
|
-
break if m
|
257
|
-
end
|
258
|
-
(m.pre_match + m.post_match).chars.reverse_each do |ch|
|
259
|
-
stdin.ungetc ch
|
260
|
-
end
|
261
|
-
end
|
262
|
-
column = m[:column].to_i - 1
|
263
|
-
row = m[:row].to_i - 1
|
264
|
-
rescue Errno::ENOTTY
|
265
|
-
begin
|
266
|
-
buf = @@output.pread(@@output.pos, 0)
|
267
|
-
row = buf.count("\n")
|
268
|
-
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
269
|
-
rescue Errno::ESPIPE
|
270
|
-
# Just returns column 1 for ambiguous width because this I/O is not
|
271
|
-
# tty and can't seek.
|
272
|
-
row = 0
|
273
|
-
column = 1
|
274
|
-
end
|
275
|
-
end
|
276
|
-
Reline::CursorPos.new(column, row)
|
277
|
-
end
|
278
|
-
|
279
|
-
def self.move_cursor_column(x)
|
280
|
-
@@output.write "\e[#{x + 1}G"
|
281
|
-
end
|
282
|
-
|
283
|
-
def self.move_cursor_up(x)
|
284
|
-
if x > 0
|
285
|
-
@@output.write "\e[#{x}A"
|
286
|
-
elsif x < 0
|
287
|
-
move_cursor_down(-x)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
def self.move_cursor_down(x)
|
292
|
-
if x > 0
|
293
|
-
@@output.write "\e[#{x}B"
|
294
|
-
elsif x < 0
|
295
|
-
move_cursor_up(-x)
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def self.hide_cursor
|
300
|
-
if Reline::Terminfo.enabled?
|
301
|
-
begin
|
302
|
-
@@output.write Reline::Terminfo.tigetstr('civis')
|
303
|
-
rescue Reline::Terminfo::TerminfoError
|
304
|
-
# civis is undefined
|
305
|
-
end
|
306
|
-
else
|
307
|
-
# ignored
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
def self.show_cursor
|
312
|
-
if Reline::Terminfo.enabled?
|
313
|
-
begin
|
314
|
-
@@output.write Reline::Terminfo.tigetstr('cnorm')
|
315
|
-
rescue Reline::Terminfo::TerminfoError
|
316
|
-
# cnorm is undefined
|
317
|
-
end
|
318
|
-
else
|
319
|
-
# ignored
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
def self.erase_after_cursor
|
324
|
-
@@output.write "\e[K"
|
325
|
-
end
|
326
|
-
|
327
|
-
def self.scroll_down(x)
|
328
|
-
return if x.zero?
|
329
|
-
@@output.write "\e[#{x}S"
|
330
|
-
end
|
331
|
-
|
332
|
-
def self.clear_screen
|
333
|
-
@@output.write "\e[2J"
|
334
|
-
@@output.write "\e[1;1H"
|
335
|
-
end
|
336
|
-
|
337
|
-
@@old_winch_handler = nil
|
338
|
-
def self.set_winch_handler(&handler)
|
339
|
-
@@old_winch_handler = Signal.trap('WINCH', &handler)
|
340
|
-
end
|
341
|
-
|
342
|
-
def self.prep
|
343
|
-
retrieve_keybuffer
|
344
|
-
nil
|
345
|
-
end
|
346
|
-
|
347
|
-
def self.deprep(otio)
|
348
|
-
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
349
|
-
end
|
350
|
-
end
|
data/lib/reline/general_io.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
require 'timeout'
|
2
|
-
require 'io/wait'
|
3
|
-
|
4
|
-
class Reline::GeneralIO
|
5
|
-
def self.reset(encoding: nil)
|
6
|
-
@@pasting = false
|
7
|
-
@@encoding = encoding
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.encoding
|
11
|
-
if defined?(@@encoding)
|
12
|
-
@@encoding
|
13
|
-
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
14
|
-
Encoding::UTF_8
|
15
|
-
else
|
16
|
-
Encoding::default_external
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.win?
|
21
|
-
false
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.set_default_key_bindings(_)
|
25
|
-
end
|
26
|
-
|
27
|
-
@@buf = []
|
28
|
-
@@input = STDIN
|
29
|
-
|
30
|
-
def self.input=(val)
|
31
|
-
@@input = val
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.getc
|
35
|
-
unless @@buf.empty?
|
36
|
-
return @@buf.shift
|
37
|
-
end
|
38
|
-
c = nil
|
39
|
-
loop do
|
40
|
-
result = @@input.wait_readable(0.1)
|
41
|
-
next if result.nil?
|
42
|
-
c = @@input.read(1)
|
43
|
-
break
|
44
|
-
end
|
45
|
-
c&.ord
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.ungetc(c)
|
49
|
-
@@buf.unshift(c)
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.get_screen_size
|
53
|
-
[1, 1]
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.cursor_pos
|
57
|
-
Reline::CursorPos.new(1, 1)
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.hide_cursor
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.show_cursor
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.move_cursor_column(val)
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.move_cursor_up(val)
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.move_cursor_down(val)
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.erase_after_cursor
|
76
|
-
end
|
77
|
-
|
78
|
-
def self.scroll_down(val)
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.clear_screen
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.set_screen_size(rows, columns)
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.set_winch_handler(&handler)
|
88
|
-
end
|
89
|
-
|
90
|
-
@@pasting = false
|
91
|
-
|
92
|
-
def self.in_pasting?
|
93
|
-
@@pasting
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.start_pasting
|
97
|
-
@@pasting = true
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.finish_pasting
|
101
|
-
@@pasting = false
|
102
|
-
end
|
103
|
-
|
104
|
-
def self.prep
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.deprep(otio)
|
108
|
-
end
|
109
|
-
end
|