reline 0.2.1 → 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 +26 -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 +161 -35
- data/lib/reline/terminfo.rb +84 -0
- data/lib/reline/unicode.rb +1 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +138 -78
- metadata +4 -59
@@ -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/unicode.rb
CHANGED
@@ -108,6 +108,7 @@ class Reline::Unicode
|
|
108
108
|
end
|
109
109
|
m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE)
|
110
110
|
case
|
111
|
+
when m.nil? then 1 # TODO should be U+FFFD � REPLACEMENT CHARACTER
|
111
112
|
when m[:width_2_1], m[:width_2_2] then 2
|
112
113
|
when m[:width_3] then 3
|
113
114
|
when m[:width_0] then 0
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -9,23 +9,40 @@ class Reline::Windows
|
|
9
9
|
true
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
12
|
+
def self.win_legacy_console?
|
13
|
+
@@legacy_console
|
14
|
+
end
|
15
|
+
|
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
|
29
46
|
|
30
47
|
if defined? JRUBY_VERSION
|
31
48
|
require 'win32api'
|
@@ -69,13 +86,35 @@ class Reline::Windows
|
|
69
86
|
end
|
70
87
|
end
|
71
88
|
|
89
|
+
VK_RETURN = 0x0D
|
72
90
|
VK_MENU = 0x12
|
73
91
|
VK_LMENU = 0xA4
|
74
92
|
VK_CONTROL = 0x11
|
75
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
|
+
|
76
116
|
STD_INPUT_HANDLE = -10
|
77
117
|
STD_OUTPUT_HANDLE = -11
|
78
|
-
WINDOW_BUFFER_SIZE_EVENT = 0x04
|
79
118
|
FILE_TYPE_PIPE = 0x0003
|
80
119
|
FILE_NAME_INFO = 2
|
81
120
|
@@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
|
@@ -89,11 +128,31 @@ class Reline::Windows
|
|
89
128
|
@@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
|
90
129
|
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
91
130
|
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
92
|
-
@@
|
131
|
+
@@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
|
93
132
|
@@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
|
94
133
|
@@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
|
95
134
|
@@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
|
96
135
|
|
136
|
+
@@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
|
137
|
+
@@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
|
138
|
+
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
139
|
+
|
140
|
+
private_class_method def self.getconsolemode
|
141
|
+
mode = "\000\000\000\000"
|
142
|
+
@@GetConsoleMode.call(@@hConsoleHandle, mode)
|
143
|
+
mode.unpack1('L')
|
144
|
+
end
|
145
|
+
|
146
|
+
private_class_method def self.setconsolemode(mode)
|
147
|
+
@@SetConsoleMode.call(@@hConsoleHandle, mode)
|
148
|
+
end
|
149
|
+
|
150
|
+
@@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
151
|
+
#if @@legacy_console
|
152
|
+
# setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
153
|
+
# @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
154
|
+
#end
|
155
|
+
|
97
156
|
@@input_buf = []
|
98
157
|
@@output_buf = []
|
99
158
|
|
@@ -121,78 +180,78 @@ class Reline::Windows
|
|
121
180
|
name =~ /(msys-|cygwin-).*-pty/ ? true : false
|
122
181
|
end
|
123
182
|
|
124
|
-
def self.
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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)
|
138
212
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
@@
|
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)
|
145
221
|
end
|
146
222
|
end
|
147
|
-
@@input_buf.shift
|
148
223
|
end
|
149
224
|
|
150
|
-
def self.
|
225
|
+
def self.check_input_event
|
151
226
|
num_of_events = 0.chr * 8
|
152
|
-
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
|
153
229
|
input_record = 0.chr * 18
|
154
230
|
read_event = 0.chr * 4
|
155
|
-
if @@
|
231
|
+
if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_record, 1, read_event) != 0
|
156
232
|
event = input_record[0, 2].unpack('s*').first
|
157
|
-
|
233
|
+
case event
|
234
|
+
when WINDOW_BUFFER_SIZE_EVENT
|
158
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
|
159
247
|
end
|
160
248
|
end
|
161
249
|
end
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
control = (@@GetKeyState.call(VK_CONTROL) & 0x80) != 0
|
168
|
-
shift = (@@GetKeyState.call(VK_SHIFT) & 0x80) != 0
|
169
|
-
force_enter = !input.instance_of?(Array) && (control or shift) && input == 0x0D
|
170
|
-
if force_enter
|
171
|
-
# It's treated as Meta+Enter on Windows
|
172
|
-
@@output_buf.push("\e".ord)
|
173
|
-
@@output_buf.push(input)
|
174
|
-
else
|
175
|
-
case input
|
176
|
-
when 0x00
|
177
|
-
meta = false
|
178
|
-
@@output_buf.push(input)
|
179
|
-
input = getwch
|
180
|
-
@@output_buf.push(*input)
|
181
|
-
when 0xE0
|
182
|
-
@@output_buf.push(input)
|
183
|
-
input = getwch
|
184
|
-
@@output_buf.push(*input)
|
185
|
-
when 0x03
|
186
|
-
@@output_buf.push(input)
|
187
|
-
else
|
188
|
-
@@output_buf.push(input)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
if meta
|
192
|
-
"\e".ord
|
193
|
-
else
|
194
|
-
@@output_buf.shift
|
195
|
-
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def self.getc
|
253
|
+
check_input_event
|
254
|
+
@@output_buf.shift
|
196
255
|
end
|
197
256
|
|
198
257
|
def self.ungetc(c)
|
@@ -258,6 +317,7 @@ class Reline::Windows
|
|
258
317
|
cursor = csbi[4, 4].unpack('L').first
|
259
318
|
written = 0.chr * 4
|
260
319
|
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
|
320
|
+
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, 0, get_screen_size.last - cursor_pos.x, cursor, written)
|
261
321
|
end
|
262
322
|
|
263
323
|
def self.scroll_down(val)
|
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.
|