reline 0.2.5 → 0.2.6
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 +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.
|