reline 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +46 -0
- data/lib/reline.rb +20 -13
- data/lib/reline/ansi.rb +100 -46
- data/lib/reline/config.rb +22 -13
- data/lib/reline/general_io.rb +11 -3
- data/lib/reline/key_actor/base.rb +12 -0
- data/lib/reline/line_editor.rb +0 -2
- data/lib/reline/terminfo.rb +84 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +113 -78
- metadata +4 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc0f6fb7c331a37907554b292249a75b218646aa14298586790cc09d6c174894
|
4
|
+
data.tar.gz: 79fd7b502a7ab601f6642964bb0987dae5d0a62bc8cfda016d8806c8b76bb723
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b4300db4d7bef4ab3ddc8f45db07e20e37b371d89e7a21f343dd3c7096209d0c19028def435d584c7bc1f0a9f18d0d6c783b47d28967eb3d34e4d0eaa613490
|
7
|
+
data.tar.gz: '081a683b1980b9c8d27822e62dcdc776024cc408e3f93b0c999f8da2c6b2fef92c4eded142f7bee8f95fcd7a18fc8431a87f2cd19d1c1064fa677f7de606dcf0'
|
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
@@ -231,9 +231,7 @@ module Reline
|
|
231
231
|
unless config.test_mode
|
232
232
|
config.read
|
233
233
|
config.reset_default_key_bindings
|
234
|
-
Reline::IOGate
|
235
|
-
config.add_default_key_binding(key, func)
|
236
|
-
end
|
234
|
+
Reline::IOGate.set_default_key_bindings(config)
|
237
235
|
end
|
238
236
|
|
239
237
|
line_editor.rerender
|
@@ -273,11 +271,12 @@ module Reline
|
|
273
271
|
Reline::IOGate.deprep(otio)
|
274
272
|
end
|
275
273
|
|
276
|
-
#
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
280
|
-
#
|
274
|
+
# GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
|
275
|
+
# is followed by a character, and times out and treats it as a standalone
|
276
|
+
# ESC if the second character does not arrive. If the second character
|
277
|
+
# comes before timed out, it is treated as a modifier key with the
|
278
|
+
# meta-property of meta-key, so that it can be distinguished from
|
279
|
+
# multibyte characters with the 8th bit turned on.
|
281
280
|
#
|
282
281
|
# GNU Readline will wait for the 2nd character with "keyseq-timeout"
|
283
282
|
# milli-seconds but wait forever after 3rd characters.
|
@@ -455,17 +454,25 @@ module Reline
|
|
455
454
|
end
|
456
455
|
end
|
457
456
|
|
457
|
+
require 'reline/general_io'
|
458
458
|
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
459
459
|
require 'reline/windows'
|
460
460
|
if Reline::Windows.msys_tty?
|
461
|
-
|
462
|
-
|
461
|
+
Reline::IOGate = if ENV['TERM'] == 'dumb'
|
462
|
+
Reline::GeneralIO
|
463
|
+
else
|
464
|
+
require 'reline/ansi'
|
465
|
+
Reline::ANSI
|
466
|
+
end
|
463
467
|
else
|
464
468
|
Reline::IOGate = Reline::Windows
|
465
469
|
end
|
466
470
|
else
|
467
|
-
|
468
|
-
|
471
|
+
Reline::IOGate = if $stdout.isatty
|
472
|
+
require 'reline/ansi'
|
473
|
+
Reline::ANSI
|
474
|
+
else
|
475
|
+
Reline::GeneralIO
|
476
|
+
end
|
469
477
|
end
|
470
478
|
Reline::HISTORY = Reline::History.new(Reline.core.config)
|
471
|
-
require 'reline/general_io'
|
data/lib/reline/ansi.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
require 'io/console'
|
2
2
|
require 'timeout'
|
3
|
+
require_relative 'terminfo'
|
3
4
|
|
4
5
|
class Reline::ANSI
|
6
|
+
if Reline::Terminfo.enabled?
|
7
|
+
Reline::Terminfo.setupterm(0, 2)
|
8
|
+
end
|
9
|
+
|
5
10
|
def self.encoding
|
6
11
|
Encoding.default_external
|
7
12
|
end
|
@@ -10,52 +15,99 @@ class Reline::ANSI
|
|
10
15
|
false
|
11
16
|
end
|
12
17
|
|
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
|
-
|
18
|
+
def self.set_default_key_bindings(config)
|
19
|
+
if Reline::Terminfo.enabled?
|
20
|
+
set_default_key_bindings_terminfo(config)
|
21
|
+
else
|
22
|
+
set_default_key_bindings_comprehensive_list(config)
|
23
|
+
end
|
24
|
+
{
|
25
|
+
# extended entries of terminfo
|
26
|
+
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
|
27
|
+
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
|
28
|
+
[27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
|
29
|
+
[27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
|
30
|
+
}.each_pair do |key, func|
|
31
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
32
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
33
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
34
|
+
end
|
35
|
+
{
|
36
|
+
# default bindings
|
37
|
+
[27, 32] => :em_set_mark, # M-<space>
|
38
|
+
[24, 24] => :em_exchange_mark, # C-x C-x
|
39
|
+
}.each_pair do |key, func|
|
40
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.set_default_key_bindings_terminfo(config)
|
45
|
+
{
|
46
|
+
Reline::Terminfo.tigetstr('khome').bytes => :ed_move_to_beg,
|
47
|
+
Reline::Terminfo.tigetstr('kend').bytes => :ed_move_to_end,
|
48
|
+
Reline::Terminfo.tigetstr('kcuu1').bytes => :ed_prev_history,
|
49
|
+
Reline::Terminfo.tigetstr('kcud1').bytes => :ed_next_history,
|
50
|
+
Reline::Terminfo.tigetstr('kcuf1').bytes => :ed_next_char,
|
51
|
+
Reline::Terminfo.tigetstr('kcub1').bytes => :ed_prev_char,
|
52
|
+
# Escape sequences that omit the move distance and are set to defaults
|
53
|
+
# value 1 may be sometimes sent by pressing the arrow-key.
|
54
|
+
Reline::Terminfo.tigetstr('cuu').sub(/%p1%d/, '').bytes => :ed_prev_history,
|
55
|
+
Reline::Terminfo.tigetstr('cud').sub(/%p1%d/, '').bytes => :ed_next_history,
|
56
|
+
Reline::Terminfo.tigetstr('cuf').sub(/%p1%d/, '').bytes => :ed_next_char,
|
57
|
+
Reline::Terminfo.tigetstr('cub').sub(/%p1%d/, '').bytes => :ed_prev_char,
|
58
|
+
}.each_pair do |key, func|
|
59
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
60
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
61
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.set_default_key_bindings_comprehensive_list(config)
|
66
|
+
{
|
67
|
+
# Console (80x25)
|
68
|
+
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
69
|
+
[27, 91, 52, 126] => :ed_move_to_end, # End
|
70
|
+
[27, 91, 51, 126] => :key_delete, # Del
|
71
|
+
[27, 91, 65] => :ed_prev_history, # ↑
|
72
|
+
[27, 91, 66] => :ed_next_history, # ↓
|
73
|
+
[27, 91, 67] => :ed_next_char, # →
|
74
|
+
[27, 91, 68] => :ed_prev_char, # ←
|
75
|
+
|
76
|
+
# KDE
|
77
|
+
[27, 91, 72] => :ed_move_to_beg, # Home
|
78
|
+
[27, 91, 70] => :ed_move_to_end, # End
|
79
|
+
# Del is 0x08
|
80
|
+
[27, 71, 65] => :ed_prev_history, # ↑
|
81
|
+
[27, 71, 66] => :ed_next_history, # ↓
|
82
|
+
[27, 71, 67] => :ed_next_char, # →
|
83
|
+
[27, 71, 68] => :ed_prev_char, # ←
|
84
|
+
|
85
|
+
# urxvt / exoterm
|
86
|
+
[27, 91, 55, 126] => :ed_move_to_beg, # Home
|
87
|
+
[27, 91, 56, 126] => :ed_move_to_end, # End
|
88
|
+
|
89
|
+
# GNOME
|
90
|
+
[27, 79, 72] => :ed_move_to_beg, # Home
|
91
|
+
[27, 79, 70] => :ed_move_to_end, # End
|
92
|
+
# Del is 0x08
|
93
|
+
# Arrow keys are the same of KDE
|
94
|
+
|
95
|
+
# iTerm2
|
96
|
+
[27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
|
97
|
+
[27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
|
98
|
+
[195, 166] => :em_next_word, # Option+f
|
99
|
+
[195, 162] => :ed_prev_word, # Option+b
|
100
|
+
|
101
|
+
[27, 79, 65] => :ed_prev_history, # ↑
|
102
|
+
[27, 79, 66] => :ed_next_history, # ↓
|
103
|
+
[27, 79, 67] => :ed_next_char, # →
|
104
|
+
[27, 79, 68] => :ed_prev_char, # ←
|
105
|
+
}.each_pair do |key, func|
|
106
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
107
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
108
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
109
|
+
end
|
110
|
+
end
|
59
111
|
|
60
112
|
@@input = STDIN
|
61
113
|
def self.input=(val)
|
@@ -79,6 +131,8 @@ class Reline::ANSI
|
|
79
131
|
rescue Errno::EIO
|
80
132
|
# Maybe the I/O has been closed.
|
81
133
|
nil
|
134
|
+
rescue Errno::ENOTTY
|
135
|
+
nil
|
82
136
|
end
|
83
137
|
|
84
138
|
@@in_bracketed_paste_mode = false
|
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,9 @@ 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
|
74
77
|
end
|
75
78
|
|
76
79
|
def editing_mode
|
@@ -135,19 +138,28 @@ class Reline::Config
|
|
135
138
|
end
|
136
139
|
|
137
140
|
def key_bindings
|
138
|
-
# override @default_key_bindings with @additional_key_bindings
|
139
|
-
@default_key_bindings.merge(@additional_key_bindings)
|
141
|
+
# override @key_actors[@editing_mode_label].default_key_bindings with @additional_key_bindings[@editing_mode_label]
|
142
|
+
@key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label])
|
143
|
+
end
|
144
|
+
|
145
|
+
def add_default_key_binding_by_keymap(keymap, keystroke, target)
|
146
|
+
@key_actors[keymap].default_key_bindings[keystroke] = target
|
140
147
|
end
|
141
148
|
|
142
149
|
def add_default_key_binding(keystroke, target)
|
143
|
-
@default_key_bindings[keystroke] = target
|
150
|
+
@key_actors[@keymap_label].default_key_bindings[keystroke] = target
|
144
151
|
end
|
145
152
|
|
146
153
|
def reset_default_key_bindings
|
147
|
-
@
|
154
|
+
@key_actors.values.each do |ka|
|
155
|
+
ka.reset_default_key_bindings
|
156
|
+
end
|
148
157
|
end
|
149
158
|
|
150
159
|
def read_lines(lines, file = nil)
|
160
|
+
if lines.first.encoding != Reline.encoding_system_needs
|
161
|
+
lines = lines.map { |l| l.encode(Reline.encoding_system_needs) }
|
162
|
+
end
|
151
163
|
conditions = [@skip_section, @if_stack]
|
152
164
|
@skip_section = nil
|
153
165
|
@if_stack = []
|
@@ -174,7 +186,7 @@ class Reline::Config
|
|
174
186
|
key, func_name = $1, $2
|
175
187
|
keystroke, func = bind_key(key, func_name)
|
176
188
|
next unless keystroke
|
177
|
-
@additional_key_bindings[keystroke] = func
|
189
|
+
@additional_key_bindings[@keymap_label][keystroke] = func
|
178
190
|
end
|
179
191
|
end
|
180
192
|
unless @if_stack.empty?
|
@@ -282,11 +294,8 @@ class Reline::Config
|
|
282
294
|
end
|
283
295
|
|
284
296
|
def retrieve_string(str)
|
285
|
-
if str =~ /\A"(.*)"\z/
|
286
|
-
|
287
|
-
else
|
288
|
-
parse_keyseq(str).map(&:chr).join
|
289
|
-
end
|
297
|
+
str = $1 if str =~ /\A"(.*)"\z/
|
298
|
+
parse_keyseq(str).map { |c| c.chr(Reline.encoding_system_needs) }.join
|
290
299
|
end
|
291
300
|
|
292
301
|
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
|
|
@@ -4,4 +4,16 @@ class Reline::KeyActor::Base
|
|
4
4
|
def get_method(key)
|
5
5
|
self.class::MAPPING[key]
|
6
6
|
end
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@default_key_bindings = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_key_bindings
|
13
|
+
@default_key_bindings
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset_default_key_bindings
|
17
|
+
@default_key_bindings.clear
|
18
|
+
end
|
7
19
|
end
|
data/lib/reline/line_editor.rb
CHANGED
@@ -409,7 +409,6 @@ class Reline::LineEditor
|
|
409
409
|
return
|
410
410
|
end
|
411
411
|
new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
|
412
|
-
# FIXME: end of logical line sometimes breaks
|
413
412
|
rendered = false
|
414
413
|
if @add_newline_to_end_of_buffer
|
415
414
|
rerender_added_newline(prompt, prompt_width)
|
@@ -678,7 +677,6 @@ class Reline::LineEditor
|
|
678
677
|
private def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true)
|
679
678
|
visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
|
680
679
|
cursor_up_from_last_line = 0
|
681
|
-
# TODO: This logic would be sometimes buggy if this logical line isn't the current @line_index.
|
682
680
|
if @scroll_partial_screen
|
683
681
|
last_visual_line = this_started_from + (height - 1)
|
684
682
|
last_screen_line = @scroll_partial_screen + (@screen_height - 1)
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'fiddle'
|
2
|
+
require 'fiddle/import'
|
3
|
+
|
4
|
+
module Reline::Terminfo
|
5
|
+
extend Fiddle::Importer
|
6
|
+
|
7
|
+
class TerminfoError < StandardError; end
|
8
|
+
|
9
|
+
@curses_dl = nil
|
10
|
+
def self.curses_dl
|
11
|
+
return @curses_dl if @curses_dl
|
12
|
+
if Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
|
13
|
+
# Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
|
14
|
+
%w[libncursesw.so libcursesw.so libncurses.so libcurses.so].each do |curses_name|
|
15
|
+
result = Fiddle::Handle.new(curses_name)
|
16
|
+
rescue Fiddle::DLError
|
17
|
+
next
|
18
|
+
else
|
19
|
+
@curses_dl = result
|
20
|
+
break
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@curses_dl
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Reline::Terminfo
|
28
|
+
dlload curses_dl
|
29
|
+
#extern 'int setupterm(char *term, int fildes, int *errret)'
|
30
|
+
@setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
31
|
+
#extern 'char *tigetstr(char *capname)'
|
32
|
+
@tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
|
33
|
+
#extern 'char *tiparm(const char *str, ...)'
|
34
|
+
@tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
35
|
+
|
36
|
+
def self.setupterm(term, fildes)
|
37
|
+
errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
|
38
|
+
ret = @setupterm.(term, fildes, errret_int)
|
39
|
+
errret = errret_int.unpack('i')[0]
|
40
|
+
case ret
|
41
|
+
when 0 # OK
|
42
|
+
0
|
43
|
+
when -1 # ERR
|
44
|
+
case errret
|
45
|
+
when 1
|
46
|
+
raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
|
47
|
+
when 0
|
48
|
+
raise TerminfoError.new('The terminal could not be found, or that it is a generic type, having too little information for curses applications to run.')
|
49
|
+
when -1
|
50
|
+
raise TerminfoError.new('The terminfo database could not be found.')
|
51
|
+
else # unknown
|
52
|
+
-1
|
53
|
+
end
|
54
|
+
else # unknown
|
55
|
+
-2
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.tigetstr(capname)
|
60
|
+
result = @tigetstr.(capname).to_s
|
61
|
+
def result.tiparm(*args) # for method chain
|
62
|
+
Reline::Terminfo.tiparm(self, *args)
|
63
|
+
end
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.tiparm(str, *args)
|
68
|
+
new_args = []
|
69
|
+
args.each do |a|
|
70
|
+
new_args << Fiddle::TYPE_INT << a
|
71
|
+
end
|
72
|
+
@tiparm.(str, *new_args).to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.enabled?
|
76
|
+
true
|
77
|
+
end
|
78
|
+
end if Reline::Terminfo.curses_dl
|
79
|
+
|
80
|
+
module Reline::Terminfo
|
81
|
+
def self.enabled?
|
82
|
+
false
|
83
|
+
end
|
84
|
+
end unless Reline::Terminfo.curses_dl
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -13,23 +13,36 @@ class Reline::Windows
|
|
13
13
|
@@legacy_console
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
16
|
+
def self.set_default_key_bindings(config)
|
17
|
+
{
|
18
|
+
[224, 72] => :ed_prev_history, # ↑
|
19
|
+
[224, 80] => :ed_next_history, # ↓
|
20
|
+
[224, 77] => :ed_next_char, # →
|
21
|
+
[224, 75] => :ed_prev_char, # ←
|
22
|
+
[224, 83] => :key_delete, # Del
|
23
|
+
[224, 71] => :ed_move_to_beg, # Home
|
24
|
+
[224, 79] => :ed_move_to_end, # End
|
25
|
+
[ 0, 41] => :ed_unassigned, # input method on/off
|
26
|
+
[ 0, 72] => :ed_prev_history, # ↑
|
27
|
+
[ 0, 80] => :ed_next_history, # ↓
|
28
|
+
[ 0, 77] => :ed_next_char, # →
|
29
|
+
[ 0, 75] => :ed_prev_char, # ←
|
30
|
+
[ 0, 83] => :key_delete, # Del
|
31
|
+
[ 0, 71] => :ed_move_to_beg, # Home
|
32
|
+
[ 0, 79] => :ed_move_to_end # End
|
33
|
+
}.each_pair do |key, func|
|
34
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
35
|
+
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
36
|
+
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
37
|
+
end
|
38
|
+
|
39
|
+
{
|
40
|
+
[27, 32] => :em_set_mark, # M-<space>
|
41
|
+
[24, 24] => :em_exchange_mark, # C-x C-x
|
42
|
+
}.each_pair do |key, func|
|
43
|
+
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
44
|
+
end
|
45
|
+
end
|
33
46
|
|
34
47
|
if defined? JRUBY_VERSION
|
35
48
|
require 'win32api'
|
@@ -73,13 +86,35 @@ class Reline::Windows
|
|
73
86
|
end
|
74
87
|
end
|
75
88
|
|
89
|
+
VK_RETURN = 0x0D
|
76
90
|
VK_MENU = 0x12
|
77
91
|
VK_LMENU = 0xA4
|
78
92
|
VK_CONTROL = 0x11
|
79
93
|
VK_SHIFT = 0x10
|
94
|
+
|
95
|
+
KEY_EVENT = 0x01
|
96
|
+
WINDOW_BUFFER_SIZE_EVENT = 0x04
|
97
|
+
|
98
|
+
CAPSLOCK_ON = 0x0080
|
99
|
+
ENHANCED_KEY = 0x0100
|
100
|
+
LEFT_ALT_PRESSED = 0x0002
|
101
|
+
LEFT_CTRL_PRESSED = 0x0008
|
102
|
+
NUMLOCK_ON = 0x0020
|
103
|
+
RIGHT_ALT_PRESSED = 0x0001
|
104
|
+
RIGHT_CTRL_PRESSED = 0x0004
|
105
|
+
SCROLLLOCK_ON = 0x0040
|
106
|
+
SHIFT_PRESSED = 0x0010
|
107
|
+
|
108
|
+
VK_END = 0x23
|
109
|
+
VK_HOME = 0x24
|
110
|
+
VK_LEFT = 0x25
|
111
|
+
VK_UP = 0x26
|
112
|
+
VK_RIGHT = 0x27
|
113
|
+
VK_DOWN = 0x28
|
114
|
+
VK_DELETE = 0x2E
|
115
|
+
|
80
116
|
STD_INPUT_HANDLE = -10
|
81
117
|
STD_OUTPUT_HANDLE = -11
|
82
|
-
WINDOW_BUFFER_SIZE_EVENT = 0x04
|
83
118
|
FILE_TYPE_PIPE = 0x0003
|
84
119
|
FILE_NAME_INFO = 2
|
85
120
|
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
@@ -93,7 +128,7 @@ class Reline::Windows
|
|
93
128
|
@@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
|
94
129
|
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
95
130
|
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
96
|
-
@@
|
131
|
+
@@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
|
97
132
|
@@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
98
133
|
@@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
99
134
|
@@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
@@ -145,78 +180,78 @@ class Reline::Windows
|
|
145
180
|
name =~ /(msys-|cygwin-).*-pty/ ? true : false
|
146
181
|
end
|
147
182
|
|
148
|
-
def self.
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
183
|
+
def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
184
|
+
char = char_code.chr(Encoding::UTF_8)
|
185
|
+
if char_code == 0x0D and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED | SHIFT_PRESSED)
|
186
|
+
# It's treated as Meta+Enter on Windows.
|
187
|
+
@@output_buf.push("\e".ord)
|
188
|
+
@@output_buf.push(char_code)
|
189
|
+
elsif char_code == 0x20 and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
|
190
|
+
# It's treated as Meta+Space on Windows.
|
191
|
+
@@output_buf.push("\e".ord)
|
192
|
+
@@output_buf.push(char_code)
|
193
|
+
elsif control_key_state.anybits?(LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
|
194
|
+
@@output_buf.push("\e".ord)
|
195
|
+
@@output_buf.concat(char.bytes)
|
196
|
+
elsif control_key_state.anybits?(ENHANCED_KEY)
|
197
|
+
case virtual_key_code # Emulate getwch() key sequences.
|
198
|
+
when VK_END
|
199
|
+
@@output_buf.push(0, 79)
|
200
|
+
when VK_HOME
|
201
|
+
@@output_buf.push(0, 71)
|
202
|
+
when VK_LEFT
|
203
|
+
@@output_buf.push(0, 75)
|
204
|
+
when VK_UP
|
205
|
+
@@output_buf.push(0, 72)
|
206
|
+
when VK_RIGHT
|
207
|
+
@@output_buf.push(0, 77)
|
208
|
+
when VK_DOWN
|
209
|
+
@@output_buf.push(0, 80)
|
210
|
+
when VK_DELETE
|
211
|
+
@@output_buf.push(0, 83)
|
162
212
|
end
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
@@
|
213
|
+
elsif char_code == 0 and control_key_state != 0
|
214
|
+
# unknown
|
215
|
+
else
|
216
|
+
case virtual_key_code
|
217
|
+
when VK_RETURN
|
218
|
+
@@output_buf.push("\n".ord)
|
219
|
+
else
|
220
|
+
@@output_buf.concat(char.bytes)
|
169
221
|
end
|
170
222
|
end
|
171
|
-
@@input_buf.shift
|
172
223
|
end
|
173
224
|
|
174
|
-
def self.
|
225
|
+
def self.check_input_event
|
175
226
|
num_of_events = 0.chr * 8
|
176
|
-
while @@
|
227
|
+
while @@output_buf.empty? #or true
|
228
|
+
next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack('L').first == 0
|
177
229
|
input_record = 0.chr * 18
|
178
230
|
read_event = 0.chr * 4
|
179
|
-
if @@
|
231
|
+
if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_record, 1, read_event) != 0
|
180
232
|
event = input_record[0, 2].unpack('s*').first
|
181
|
-
|
233
|
+
case event
|
234
|
+
when WINDOW_BUFFER_SIZE_EVENT
|
182
235
|
@@winch_handler.()
|
236
|
+
when KEY_EVENT
|
237
|
+
key_down = input_record[4, 4].unpack('l*').first
|
238
|
+
repeat_count = input_record[8, 2].unpack('s*').first
|
239
|
+
virtual_key_code = input_record[10, 2].unpack('s*').first
|
240
|
+
virtual_scan_code = input_record[12, 2].unpack('s*').first
|
241
|
+
char_code = input_record[14, 2].unpack('S*').first
|
242
|
+
control_key_state = input_record[16, 2].unpack('S*').first
|
243
|
+
is_key_down = key_down.zero? ? false : true
|
244
|
+
if is_key_down
|
245
|
+
process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
246
|
+
end
|
183
247
|
end
|
184
248
|
end
|
185
249
|
end
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
control = (@@GetKeyState.call(VK_CONTROL) & 0x80) != 0
|
192
|
-
shift = (@@GetKeyState.call(VK_SHIFT) & 0x80) != 0
|
193
|
-
force_enter = !input.instance_of?(Array) && (control or shift) && input == 0x0D
|
194
|
-
if force_enter
|
195
|
-
# It's treated as Meta+Enter on Windows
|
196
|
-
@@output_buf.push("\e".ord)
|
197
|
-
@@output_buf.push(input)
|
198
|
-
else
|
199
|
-
case input
|
200
|
-
when 0x00
|
201
|
-
meta = false
|
202
|
-
@@output_buf.push(input)
|
203
|
-
input = getwch
|
204
|
-
@@output_buf.push(*input)
|
205
|
-
when 0xE0
|
206
|
-
@@output_buf.push(input)
|
207
|
-
input = getwch
|
208
|
-
@@output_buf.push(*input)
|
209
|
-
when 0x03
|
210
|
-
@@output_buf.push(input)
|
211
|
-
else
|
212
|
-
@@output_buf.push(input)
|
213
|
-
end
|
214
|
-
end
|
215
|
-
if meta
|
216
|
-
"\e".ord
|
217
|
-
else
|
218
|
-
@@output_buf.shift
|
219
|
-
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def self.getc
|
253
|
+
check_input_event
|
254
|
+
@@output_buf.shift
|
220
255
|
end
|
221
256
|
|
222
257
|
def self.ungetc(c)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|
@@ -24,62 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.5'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: test-unit
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: yamatanooroti
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 0.0.6
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 0.0.6
|
83
27
|
description: Alternative GNU Readline or Editline implementation by pure Ruby.
|
84
28
|
email:
|
85
29
|
- aycabta@gmail.com
|
@@ -104,6 +48,7 @@ files:
|
|
104
48
|
- lib/reline/kill_ring.rb
|
105
49
|
- lib/reline/line_editor.rb
|
106
50
|
- lib/reline/sibori.rb
|
51
|
+
- lib/reline/terminfo.rb
|
107
52
|
- lib/reline/unicode.rb
|
108
53
|
- lib/reline/unicode/east_asian_width.rb
|
109
54
|
- lib/reline/version.rb
|
@@ -128,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
128
73
|
- !ruby/object:Gem::Version
|
129
74
|
version: '0'
|
130
75
|
requirements: []
|
131
|
-
rubygems_version: 3.2.
|
76
|
+
rubygems_version: 3.2.17
|
132
77
|
signing_key:
|
133
78
|
specification_version: 4
|
134
79
|
summary: Alternative GNU Readline or Editline implementation by pure Ruby.
|