reline 0.2.3 → 0.2.7
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 +46 -0
- data/lib/reline.rb +27 -13
- data/lib/reline/ansi.rb +103 -54
- data/lib/reline/config.rb +30 -13
- data/lib/reline/general_io.rb +11 -3
- data/lib/reline/key_actor/base.rb +12 -0
- data/lib/reline/line_editor.rb +101 -24
- data/lib/reline/terminfo.rb +126 -0
- data/lib/reline/unicode.rb +1 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +171 -80
- metadata +4 -60
- data/lib/reline/line_editor.rb.orig +0 -2696
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bb2255429504a1beb1a5a9f863f7cba5c4c65781b7cd8b2aa843b0df639fb26
|
4
|
+
data.tar.gz: c9372db87ad831e06d0e99d20981cb14a08e8b15ca3011f4b6df2a05aaeef7b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63e8b6f4a9de8a69a8f22c979b6fee92026143be658b9e928da43dddb868fb6b641b5f140de436c1dd5ed1f3cdbc3c42c7c41084fcc1d811cd713c684aedda8e
|
7
|
+
data.tar.gz: 7a459412f528f43d5e65f4c7c6a5c74055e2c5334f21a65411bc4f187b55b649c15fd612ed27f2dc0032f7fdc5973c7fa57b674b0a323ac2d9537b23fff19664
|
data/README.md
CHANGED
@@ -8,6 +8,52 @@ This is a screen capture of *IRB improved by Reline*.
|
|
8
8
|
|
9
9
|
Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and Editline by pure Ruby implementation.
|
10
10
|
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
### Single line editing mode
|
14
|
+
|
15
|
+
It's compatible with the readline standard library.
|
16
|
+
|
17
|
+
See [the document of readline stdlib](https://ruby-doc.org/stdlib/libdoc/readline/rdoc/Readline.html) or [bin/example](https://github.com/ruby/reline/blob/master/bin/example).
|
18
|
+
|
19
|
+
### Multi-line editing mode
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require "reline"
|
23
|
+
|
24
|
+
prompt = 'prompt> '
|
25
|
+
use_history = true
|
26
|
+
|
27
|
+
begin
|
28
|
+
while true
|
29
|
+
text = Reline.readmultiline(prompt, use_history) do |multiline_input|
|
30
|
+
# Accept the input until `end` is entered
|
31
|
+
multiline_input.split.last == "end"
|
32
|
+
end
|
33
|
+
|
34
|
+
puts 'You entered:'
|
35
|
+
puts text
|
36
|
+
end
|
37
|
+
# If you want to exit, type Ctrl-C
|
38
|
+
rescue Interrupt
|
39
|
+
puts '^C'
|
40
|
+
exit 0
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
```bash
|
45
|
+
$ ruby example.rb
|
46
|
+
prompt> aaa
|
47
|
+
prompt> bbb
|
48
|
+
prompt> end
|
49
|
+
You entered:
|
50
|
+
aaa
|
51
|
+
bbb
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
See also: [test/reline/yamatanooroti/multiline_repl](https://github.com/ruby/reline/blob/master/test/reline/yamatanooroti/multiline_repl)
|
56
|
+
|
11
57
|
## License
|
12
58
|
|
13
59
|
The gem is available as open source under the terms of the [Ruby License](https://www.ruby-lang.org/en/about/license.txt).
|
data/lib/reline.rb
CHANGED
@@ -7,12 +7,15 @@ require 'reline/key_actor'
|
|
7
7
|
require 'reline/key_stroke'
|
8
8
|
require 'reline/line_editor'
|
9
9
|
require 'reline/history'
|
10
|
+
require 'reline/terminfo'
|
10
11
|
require 'rbconfig'
|
11
12
|
|
12
13
|
module Reline
|
13
14
|
FILENAME_COMPLETION_PROC = nil
|
14
15
|
USERNAME_COMPLETION_PROC = nil
|
15
16
|
|
17
|
+
class ConfigEncodingConversionError < StandardError; end
|
18
|
+
|
16
19
|
Key = Struct.new('Key', :char, :combined_char, :with_meta)
|
17
20
|
CursorPos = Struct.new(:x, :y)
|
18
21
|
|
@@ -231,9 +234,7 @@ module Reline
|
|
231
234
|
unless config.test_mode
|
232
235
|
config.read
|
233
236
|
config.reset_default_key_bindings
|
234
|
-
Reline::IOGate
|
235
|
-
config.add_default_key_binding(key, func)
|
236
|
-
end
|
237
|
+
Reline::IOGate.set_default_key_bindings(config)
|
237
238
|
end
|
238
239
|
|
239
240
|
line_editor.rerender
|
@@ -273,11 +274,12 @@ module Reline
|
|
273
274
|
Reline::IOGate.deprep(otio)
|
274
275
|
end
|
275
276
|
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
280
|
-
#
|
277
|
+
# GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
|
278
|
+
# is followed by a character, and times out and treats it as a standalone
|
279
|
+
# ESC if the second character does not arrive. If the second character
|
280
|
+
# comes before timed out, it is treated as a modifier key with the
|
281
|
+
# meta-property of meta-key, so that it can be distinguished from
|
282
|
+
# multibyte characters with the 8th bit turned on.
|
281
283
|
#
|
282
284
|
# GNU Readline will wait for the 2nd character with "keyseq-timeout"
|
283
285
|
# milli-seconds but wait forever after 3rd characters.
|
@@ -446,22 +448,34 @@ module Reline
|
|
446
448
|
}
|
447
449
|
end
|
448
450
|
|
451
|
+
def self.ungetc(c)
|
452
|
+
Reline::IOGate.ungetc(c)
|
453
|
+
end
|
454
|
+
|
449
455
|
def self.line_editor
|
450
456
|
core.line_editor
|
451
457
|
end
|
452
458
|
end
|
453
459
|
|
460
|
+
require 'reline/general_io'
|
454
461
|
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
455
462
|
require 'reline/windows'
|
456
463
|
if Reline::Windows.msys_tty?
|
457
|
-
|
458
|
-
|
464
|
+
Reline::IOGate = if ENV['TERM'] == 'dumb'
|
465
|
+
Reline::GeneralIO
|
466
|
+
else
|
467
|
+
require 'reline/ansi'
|
468
|
+
Reline::ANSI
|
469
|
+
end
|
459
470
|
else
|
460
471
|
Reline::IOGate = Reline::Windows
|
461
472
|
end
|
462
473
|
else
|
463
|
-
|
464
|
-
|
474
|
+
Reline::IOGate = if $stdout.isatty
|
475
|
+
require 'reline/ansi'
|
476
|
+
Reline::ANSI
|
477
|
+
else
|
478
|
+
Reline::GeneralIO
|
479
|
+
end
|
465
480
|
end
|
466
481
|
Reline::HISTORY = Reline::History.new(Reline.core.config)
|
467
|
-
require 'reline/general_io'
|
data/lib/reline/ansi.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
require 'io/console'
|
2
|
+
require 'io/wait'
|
2
3
|
require 'timeout'
|
4
|
+
require_relative 'terminfo'
|
3
5
|
|
4
6
|
class Reline::ANSI
|
7
|
+
if Reline::Terminfo.enabled?
|
8
|
+
Reline::Terminfo.setupterm(0, 2)
|
9
|
+
end
|
10
|
+
|
5
11
|
def self.encoding
|
6
12
|
Encoding.default_external
|
7
13
|
end
|
@@ -10,52 +16,99 @@ class Reline::ANSI
|
|
10
16
|
false
|
11
17
|
end
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
19
|
+
def self.set_default_key_bindings(config)
|
20
|
+
if Reline::Terminfo.enabled?
|
21
|
+
set_default_key_bindings_terminfo(config)
|
22
|
+
else
|
23
|
+
set_default_key_bindings_comprehensive_list(config)
|
24
|
+
end
|
25
|
+
{
|
26
|
+
# extended entries of terminfo
|
27
|
+
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
|
28
|
+
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
|
29
|
+
[27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
|
30
|
+
[27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
|
31
|
+
}.each_pair do |key, func|
|
32
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
33
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
34
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
35
|
+
end
|
36
|
+
{
|
37
|
+
# default bindings
|
38
|
+
[27, 32] => :em_set_mark, # M-<space>
|
39
|
+
[24, 24] => :em_exchange_mark, # C-x C-x
|
40
|
+
}.each_pair do |key, func|
|
41
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.set_default_key_bindings_terminfo(config)
|
46
|
+
{
|
47
|
+
Reline::Terminfo.tigetstr('khome').bytes => :ed_move_to_beg,
|
48
|
+
Reline::Terminfo.tigetstr('kend').bytes => :ed_move_to_end,
|
49
|
+
Reline::Terminfo.tigetstr('kcuu1').bytes => :ed_prev_history,
|
50
|
+
Reline::Terminfo.tigetstr('kcud1').bytes => :ed_next_history,
|
51
|
+
Reline::Terminfo.tigetstr('kcuf1').bytes => :ed_next_char,
|
52
|
+
Reline::Terminfo.tigetstr('kcub1').bytes => :ed_prev_char,
|
53
|
+
# Escape sequences that omit the move distance and are set to defaults
|
54
|
+
# value 1 may be sometimes sent by pressing the arrow-key.
|
55
|
+
Reline::Terminfo.tigetstr('cuu').sub(/%p1%d/, '').bytes => :ed_prev_history,
|
56
|
+
Reline::Terminfo.tigetstr('cud').sub(/%p1%d/, '').bytes => :ed_next_history,
|
57
|
+
Reline::Terminfo.tigetstr('cuf').sub(/%p1%d/, '').bytes => :ed_next_char,
|
58
|
+
Reline::Terminfo.tigetstr('cub').sub(/%p1%d/, '').bytes => :ed_prev_char,
|
59
|
+
}.each_pair do |key, func|
|
60
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
61
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
62
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.set_default_key_bindings_comprehensive_list(config)
|
67
|
+
{
|
68
|
+
# Console (80x25)
|
69
|
+
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
70
|
+
[27, 91, 52, 126] => :ed_move_to_end, # End
|
71
|
+
[27, 91, 51, 126] => :key_delete, # Del
|
72
|
+
[27, 91, 65] => :ed_prev_history, # ↑
|
73
|
+
[27, 91, 66] => :ed_next_history, # ↓
|
74
|
+
[27, 91, 67] => :ed_next_char, # →
|
75
|
+
[27, 91, 68] => :ed_prev_char, # ←
|
76
|
+
|
77
|
+
# KDE
|
78
|
+
[27, 91, 72] => :ed_move_to_beg, # Home
|
79
|
+
[27, 91, 70] => :ed_move_to_end, # End
|
80
|
+
# Del is 0x08
|
81
|
+
[27, 71, 65] => :ed_prev_history, # ↑
|
82
|
+
[27, 71, 66] => :ed_next_history, # ↓
|
83
|
+
[27, 71, 67] => :ed_next_char, # →
|
84
|
+
[27, 71, 68] => :ed_prev_char, # ←
|
85
|
+
|
86
|
+
# urxvt / exoterm
|
87
|
+
[27, 91, 55, 126] => :ed_move_to_beg, # Home
|
88
|
+
[27, 91, 56, 126] => :ed_move_to_end, # End
|
89
|
+
|
90
|
+
# GNOME
|
91
|
+
[27, 79, 72] => :ed_move_to_beg, # Home
|
92
|
+
[27, 79, 70] => :ed_move_to_end, # End
|
93
|
+
# Del is 0x08
|
94
|
+
# Arrow keys are the same of KDE
|
95
|
+
|
96
|
+
# iTerm2
|
97
|
+
[27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
|
98
|
+
[27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
|
99
|
+
[195, 166] => :em_next_word, # Option+f
|
100
|
+
[195, 162] => :ed_prev_word, # Option+b
|
101
|
+
|
102
|
+
[27, 79, 65] => :ed_prev_history, # ↑
|
103
|
+
[27, 79, 66] => :ed_next_history, # ↓
|
104
|
+
[27, 79, 67] => :ed_next_char, # →
|
105
|
+
[27, 79, 68] => :ed_prev_char, # ←
|
106
|
+
}.each_pair do |key, func|
|
107
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
108
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
109
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
110
|
+
end
|
111
|
+
end
|
59
112
|
|
60
113
|
@@input = STDIN
|
61
114
|
def self.input=(val)
|
@@ -79,6 +132,8 @@ class Reline::ANSI
|
|
79
132
|
rescue Errno::EIO
|
80
133
|
# Maybe the I/O has been closed.
|
81
134
|
nil
|
135
|
+
rescue Errno::ENOTTY
|
136
|
+
nil
|
82
137
|
end
|
83
138
|
|
84
139
|
@@in_bracketed_paste_mode = false
|
@@ -129,12 +184,7 @@ class Reline::ANSI
|
|
129
184
|
unless @@buf.empty?
|
130
185
|
return false
|
131
186
|
end
|
132
|
-
|
133
|
-
if rs and rs[0]
|
134
|
-
false
|
135
|
-
else
|
136
|
-
true
|
137
|
-
end
|
187
|
+
!@@input.wait_readable(0)
|
138
188
|
end
|
139
189
|
|
140
190
|
def self.ungetc(c)
|
@@ -143,8 +193,7 @@ class Reline::ANSI
|
|
143
193
|
|
144
194
|
def self.retrieve_keybuffer
|
145
195
|
begin
|
146
|
-
|
147
|
-
return if result.nil?
|
196
|
+
return unless @@input.wait_readable(0.001)
|
148
197
|
str = @@input.read_nonblock(1024)
|
149
198
|
str.bytes.each do |c|
|
150
199
|
@@buf.push(c)
|
data/lib/reline/config.rb
CHANGED
@@ -47,7 +47,9 @@ class Reline::Config
|
|
47
47
|
|
48
48
|
def initialize
|
49
49
|
@additional_key_bindings = {} # from inputrc
|
50
|
-
@
|
50
|
+
@additional_key_bindings[:emacs] = {}
|
51
|
+
@additional_key_bindings[:vi_insert] = {}
|
52
|
+
@additional_key_bindings[:vi_command] = {}
|
51
53
|
@skip_section = nil
|
52
54
|
@if_stack = nil
|
53
55
|
@editing_mode_label = :emacs
|
@@ -69,8 +71,10 @@ class Reline::Config
|
|
69
71
|
if editing_mode_is?(:vi_command)
|
70
72
|
@editing_mode_label = :vi_insert
|
71
73
|
end
|
72
|
-
@additional_key_bindings
|
73
|
-
|
74
|
+
@additional_key_bindings.keys.each do |key|
|
75
|
+
@additional_key_bindings[key].clear
|
76
|
+
end
|
77
|
+
reset_default_key_bindings
|
74
78
|
end
|
75
79
|
|
76
80
|
def editing_mode
|
@@ -135,19 +139,35 @@ class Reline::Config
|
|
135
139
|
end
|
136
140
|
|
137
141
|
def key_bindings
|
138
|
-
# override @default_key_bindings with @additional_key_bindings
|
139
|
-
@default_key_bindings.merge(@additional_key_bindings)
|
142
|
+
# override @key_actors[@editing_mode_label].default_key_bindings with @additional_key_bindings[@editing_mode_label]
|
143
|
+
@key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label])
|
144
|
+
end
|
145
|
+
|
146
|
+
def add_default_key_binding_by_keymap(keymap, keystroke, target)
|
147
|
+
@key_actors[keymap].default_key_bindings[keystroke] = target
|
140
148
|
end
|
141
149
|
|
142
150
|
def add_default_key_binding(keystroke, target)
|
143
|
-
@default_key_bindings[keystroke] = target
|
151
|
+
@key_actors[@keymap_label].default_key_bindings[keystroke] = target
|
144
152
|
end
|
145
153
|
|
146
154
|
def reset_default_key_bindings
|
147
|
-
@
|
155
|
+
@key_actors.values.each do |ka|
|
156
|
+
ka.reset_default_key_bindings
|
157
|
+
end
|
148
158
|
end
|
149
159
|
|
150
160
|
def read_lines(lines, file = nil)
|
161
|
+
if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
|
162
|
+
begin
|
163
|
+
lines = lines.map do |l|
|
164
|
+
l.encode(Reline.encoding_system_needs)
|
165
|
+
rescue Encoding::UndefinedConversionError
|
166
|
+
mes = "The inputrc encoded in #{lines.first.encoding.name} can't be converted to the locale #{Reline.encoding_system_needs.name}."
|
167
|
+
raise Reline::ConfigEncodingConversionError.new(mes)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
151
171
|
conditions = [@skip_section, @if_stack]
|
152
172
|
@skip_section = nil
|
153
173
|
@if_stack = []
|
@@ -174,7 +194,7 @@ class Reline::Config
|
|
174
194
|
key, func_name = $1, $2
|
175
195
|
keystroke, func = bind_key(key, func_name)
|
176
196
|
next unless keystroke
|
177
|
-
@additional_key_bindings[keystroke] = func
|
197
|
+
@additional_key_bindings[@keymap_label][keystroke] = func
|
178
198
|
end
|
179
199
|
end
|
180
200
|
unless @if_stack.empty?
|
@@ -282,11 +302,8 @@ class Reline::Config
|
|
282
302
|
end
|
283
303
|
|
284
304
|
def retrieve_string(str)
|
285
|
-
if str =~ /\A"(.*)"\z/
|
286
|
-
|
287
|
-
else
|
288
|
-
parse_keyseq(str).map(&:chr).join
|
289
|
-
end
|
305
|
+
str = $1 if str =~ /\A"(.*)"\z/
|
306
|
+
parse_keyseq(str).map { |c| c.chr(Reline.encoding_system_needs) }.join
|
290
307
|
end
|
291
308
|
|
292
309
|
def bind_key(key, func_name)
|
data/lib/reline/general_io.rb
CHANGED
@@ -1,19 +1,27 @@
|
|
1
1
|
require 'timeout'
|
2
2
|
|
3
3
|
class Reline::GeneralIO
|
4
|
-
def self.reset
|
4
|
+
def self.reset(encoding: nil)
|
5
5
|
@@pasting = false
|
6
|
+
@@encoding = encoding
|
6
7
|
end
|
7
8
|
|
8
9
|
def self.encoding
|
9
|
-
|
10
|
+
if defined?(@@encoding)
|
11
|
+
@@encoding
|
12
|
+
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
13
|
+
Encoding::UTF_8
|
14
|
+
else
|
15
|
+
Encoding::default_external
|
16
|
+
end
|
10
17
|
end
|
11
18
|
|
12
19
|
def self.win?
|
13
20
|
false
|
14
21
|
end
|
15
22
|
|
16
|
-
|
23
|
+
def self.set_default_key_bindings(_)
|
24
|
+
end
|
17
25
|
|
18
26
|
@@buf = []
|
19
27
|
|