reline 0.3.9 → 0.6.1
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 +8 -1
- data/lib/reline/config.rb +95 -123
- data/lib/reline/face.rb +199 -0
- data/lib/reline/history.rb +4 -4
- data/lib/reline/io/ansi.rb +318 -0
- data/lib/reline/io/dumb.rb +120 -0
- data/lib/reline/{windows.rb → io/windows.rb} +182 -153
- data/lib/reline/io.rb +55 -0
- data/lib/reline/key_actor/base.rb +27 -9
- data/lib/reline/key_actor/composite.rb +17 -0
- data/lib/reline/key_actor/emacs.rb +103 -103
- data/lib/reline/key_actor/vi_command.rb +188 -188
- data/lib/reline/key_actor/vi_insert.rb +144 -144
- data/lib/reline/key_actor.rb +1 -0
- data/lib/reline/key_stroke.rb +75 -104
- data/lib/reline/kill_ring.rb +2 -2
- data/lib/reline/line_editor.rb +1175 -2121
- data/lib/reline/unicode/east_asian_width.rb +1289 -1192
- data/lib/reline/unicode.rb +218 -445
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +143 -224
- metadata +13 -11
- data/lib/reline/ansi.rb +0 -363
- data/lib/reline/general_io.rb +0 -116
- data/lib/reline/terminfo.rb +0 -160
data/lib/reline/ansi.rb
DELETED
@@ -1,363 +0,0 @@
|
|
1
|
-
require 'io/console'
|
2
|
-
require 'io/wait'
|
3
|
-
require_relative 'terminfo'
|
4
|
-
|
5
|
-
class Reline::ANSI
|
6
|
-
CAPNAME_KEY_BINDINGS = {
|
7
|
-
'khome' => :ed_move_to_beg,
|
8
|
-
'kend' => :ed_move_to_end,
|
9
|
-
'kdch1' => :key_delete,
|
10
|
-
'kpp' => :ed_search_prev_history,
|
11
|
-
'knp' => :ed_search_next_history,
|
12
|
-
'kcuu1' => :ed_prev_history,
|
13
|
-
'kcud1' => :ed_next_history,
|
14
|
-
'kcuf1' => :ed_next_char,
|
15
|
-
'kcub1' => :ed_prev_char,
|
16
|
-
}
|
17
|
-
|
18
|
-
ANSI_CURSOR_KEY_BINDINGS = {
|
19
|
-
# Up
|
20
|
-
'A' => [:ed_prev_history, {}],
|
21
|
-
# Down
|
22
|
-
'B' => [:ed_next_history, {}],
|
23
|
-
# Right
|
24
|
-
'C' => [:ed_next_char, { ctrl: :em_next_word, meta: :em_next_word }],
|
25
|
-
# Left
|
26
|
-
'D' => [:ed_prev_char, { ctrl: :ed_prev_word, meta: :ed_prev_word }],
|
27
|
-
# End
|
28
|
-
'F' => [:ed_move_to_end, {}],
|
29
|
-
# Home
|
30
|
-
'H' => [:ed_move_to_beg, {}],
|
31
|
-
}
|
32
|
-
|
33
|
-
if Reline::Terminfo.enabled?
|
34
|
-
Reline::Terminfo.setupterm(0, 2)
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.encoding
|
38
|
-
Encoding.default_external
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.win?
|
42
|
-
false
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.set_default_key_bindings(config, allow_terminfo: true)
|
46
|
-
set_default_key_bindings_ansi_cursor(config)
|
47
|
-
if allow_terminfo && Reline::Terminfo.enabled?
|
48
|
-
set_default_key_bindings_terminfo(config)
|
49
|
-
else
|
50
|
-
set_default_key_bindings_comprehensive_list(config)
|
51
|
-
end
|
52
|
-
{
|
53
|
-
[27, 91, 90] => :completion_journey_up, # S-Tab
|
54
|
-
}.each_pair do |key, func|
|
55
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
56
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
57
|
-
end
|
58
|
-
{
|
59
|
-
# default bindings
|
60
|
-
[27, 32] => :em_set_mark, # M-<space>
|
61
|
-
[24, 24] => :em_exchange_mark, # C-x C-x
|
62
|
-
}.each_pair do |key, func|
|
63
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.set_default_key_bindings_ansi_cursor(config)
|
68
|
-
ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
|
69
|
-
bindings = [["\e[#{char}", default_func]] # CSI + char
|
70
|
-
if modifiers[:ctrl]
|
71
|
-
# CSI + ctrl_key_modifier + char
|
72
|
-
bindings << ["\e[1;5#{char}", modifiers[:ctrl]]
|
73
|
-
end
|
74
|
-
if modifiers[:meta]
|
75
|
-
# CSI + meta_key_modifier + char
|
76
|
-
bindings << ["\e[1;3#{char}", modifiers[:meta]]
|
77
|
-
# Meta(ESC) + CSI + char
|
78
|
-
bindings << ["\e\e[#{char}", modifiers[:meta]]
|
79
|
-
end
|
80
|
-
bindings.each do |sequence, func|
|
81
|
-
key = sequence.bytes
|
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
|
-
end
|
88
|
-
|
89
|
-
def self.set_default_key_bindings_terminfo(config)
|
90
|
-
key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
|
91
|
-
begin
|
92
|
-
key_code = Reline::Terminfo.tigetstr(capname)
|
93
|
-
[ key_code.bytes, key_binding ]
|
94
|
-
rescue Reline::Terminfo::TerminfoError
|
95
|
-
# capname is undefined
|
96
|
-
end
|
97
|
-
end.compact.to_h
|
98
|
-
|
99
|
-
key_bindings.each_pair do |key, func|
|
100
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
101
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
102
|
-
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.set_default_key_bindings_comprehensive_list(config)
|
107
|
-
{
|
108
|
-
# Console (80x25)
|
109
|
-
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
110
|
-
[27, 91, 52, 126] => :ed_move_to_end, # End
|
111
|
-
[27, 91, 51, 126] => :key_delete, # Del
|
112
|
-
|
113
|
-
# KDE
|
114
|
-
# Del is 0x08
|
115
|
-
[27, 71, 65] => :ed_prev_history, # ↑
|
116
|
-
[27, 71, 66] => :ed_next_history, # ↓
|
117
|
-
[27, 71, 67] => :ed_next_char, # →
|
118
|
-
[27, 71, 68] => :ed_prev_char, # ←
|
119
|
-
|
120
|
-
# urxvt / exoterm
|
121
|
-
[27, 91, 55, 126] => :ed_move_to_beg, # Home
|
122
|
-
[27, 91, 56, 126] => :ed_move_to_end, # End
|
123
|
-
|
124
|
-
# GNOME
|
125
|
-
[27, 79, 72] => :ed_move_to_beg, # Home
|
126
|
-
[27, 79, 70] => :ed_move_to_end, # End
|
127
|
-
# Del is 0x08
|
128
|
-
# Arrow keys are the same of KDE
|
129
|
-
|
130
|
-
[27, 79, 65] => :ed_prev_history, # ↑
|
131
|
-
[27, 79, 66] => :ed_next_history, # ↓
|
132
|
-
[27, 79, 67] => :ed_next_char, # →
|
133
|
-
[27, 79, 68] => :ed_prev_char, # ←
|
134
|
-
}.each_pair do |key, func|
|
135
|
-
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
136
|
-
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
137
|
-
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
@@input = STDIN
|
142
|
-
def self.input=(val)
|
143
|
-
@@input = val
|
144
|
-
end
|
145
|
-
|
146
|
-
@@output = STDOUT
|
147
|
-
def self.output=(val)
|
148
|
-
@@output = val
|
149
|
-
end
|
150
|
-
|
151
|
-
def self.with_raw_input
|
152
|
-
@@input.raw { yield }
|
153
|
-
end
|
154
|
-
|
155
|
-
@@buf = []
|
156
|
-
def self.inner_getc(timeout_second)
|
157
|
-
unless @@buf.empty?
|
158
|
-
return @@buf.shift
|
159
|
-
end
|
160
|
-
until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
|
161
|
-
timeout_second -= 0.1
|
162
|
-
return nil if timeout_second <= 0
|
163
|
-
Reline.core.line_editor.resize
|
164
|
-
end
|
165
|
-
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
|
166
|
-
rescue Errno::EIO
|
167
|
-
# Maybe the I/O has been closed.
|
168
|
-
nil
|
169
|
-
rescue Errno::ENOTTY
|
170
|
-
nil
|
171
|
-
end
|
172
|
-
|
173
|
-
@@in_bracketed_paste_mode = false
|
174
|
-
START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
|
175
|
-
END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
|
176
|
-
def self.getc_with_bracketed_paste(timeout_second)
|
177
|
-
buffer = String.new(encoding: Encoding::ASCII_8BIT)
|
178
|
-
buffer << inner_getc(timeout_second)
|
179
|
-
while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
|
180
|
-
if START_BRACKETED_PASTE == buffer
|
181
|
-
@@in_bracketed_paste_mode = true
|
182
|
-
return inner_getc(timeout_second)
|
183
|
-
elsif END_BRACKETED_PASTE == buffer
|
184
|
-
@@in_bracketed_paste_mode = false
|
185
|
-
ungetc(-1)
|
186
|
-
return inner_getc(timeout_second)
|
187
|
-
end
|
188
|
-
succ_c = inner_getc(Reline.core.config.keyseq_timeout)
|
189
|
-
|
190
|
-
if succ_c
|
191
|
-
buffer << succ_c
|
192
|
-
else
|
193
|
-
break
|
194
|
-
end
|
195
|
-
end
|
196
|
-
buffer.bytes.reverse_each do |ch|
|
197
|
-
ungetc ch
|
198
|
-
end
|
199
|
-
inner_getc(timeout_second)
|
200
|
-
end
|
201
|
-
|
202
|
-
# if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
|
203
|
-
def self.getc(timeout_second)
|
204
|
-
if Reline.core.config.enable_bracketed_paste
|
205
|
-
getc_with_bracketed_paste(timeout_second)
|
206
|
-
else
|
207
|
-
inner_getc(timeout_second)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def self.in_pasting?
|
212
|
-
@@in_bracketed_paste_mode or (not empty_buffer?)
|
213
|
-
end
|
214
|
-
|
215
|
-
def self.empty_buffer?
|
216
|
-
unless @@buf.empty?
|
217
|
-
return false
|
218
|
-
end
|
219
|
-
!@@input.wait_readable(0)
|
220
|
-
end
|
221
|
-
|
222
|
-
def self.ungetc(c)
|
223
|
-
@@buf.unshift(c)
|
224
|
-
end
|
225
|
-
|
226
|
-
def self.retrieve_keybuffer
|
227
|
-
begin
|
228
|
-
return unless @@input.wait_readable(0.001)
|
229
|
-
str = @@input.read_nonblock(1024)
|
230
|
-
str.bytes.each do |c|
|
231
|
-
@@buf.push(c)
|
232
|
-
end
|
233
|
-
rescue EOFError
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
def self.get_screen_size
|
238
|
-
s = @@input.winsize
|
239
|
-
return s if s[0] > 0 && s[1] > 0
|
240
|
-
s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
|
241
|
-
return s if s[0] > 0 && s[1] > 0
|
242
|
-
[24, 80]
|
243
|
-
rescue Errno::ENOTTY
|
244
|
-
[24, 80]
|
245
|
-
end
|
246
|
-
|
247
|
-
def self.set_screen_size(rows, columns)
|
248
|
-
@@input.winsize = [rows, columns]
|
249
|
-
self
|
250
|
-
rescue Errno::ENOTTY
|
251
|
-
self
|
252
|
-
end
|
253
|
-
|
254
|
-
def self.cursor_pos
|
255
|
-
begin
|
256
|
-
res = +''
|
257
|
-
m = nil
|
258
|
-
@@input.raw do |stdin|
|
259
|
-
@@output << "\e[6n"
|
260
|
-
@@output.flush
|
261
|
-
loop do
|
262
|
-
c = stdin.getc
|
263
|
-
next if c.nil?
|
264
|
-
res << c
|
265
|
-
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
|
266
|
-
break if m
|
267
|
-
end
|
268
|
-
(m.pre_match + m.post_match).chars.reverse_each do |ch|
|
269
|
-
stdin.ungetc ch
|
270
|
-
end
|
271
|
-
end
|
272
|
-
column = m[:column].to_i - 1
|
273
|
-
row = m[:row].to_i - 1
|
274
|
-
rescue Errno::ENOTTY
|
275
|
-
begin
|
276
|
-
buf = @@output.pread(@@output.pos, 0)
|
277
|
-
row = buf.count("\n")
|
278
|
-
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
279
|
-
rescue Errno::ESPIPE
|
280
|
-
# Just returns column 1 for ambiguous width because this I/O is not
|
281
|
-
# tty and can't seek.
|
282
|
-
row = 0
|
283
|
-
column = 1
|
284
|
-
end
|
285
|
-
end
|
286
|
-
Reline::CursorPos.new(column, row)
|
287
|
-
end
|
288
|
-
|
289
|
-
def self.move_cursor_column(x)
|
290
|
-
@@output.write "\e[#{x + 1}G"
|
291
|
-
end
|
292
|
-
|
293
|
-
def self.move_cursor_up(x)
|
294
|
-
if x > 0
|
295
|
-
@@output.write "\e[#{x}A"
|
296
|
-
elsif x < 0
|
297
|
-
move_cursor_down(-x)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def self.move_cursor_down(x)
|
302
|
-
if x > 0
|
303
|
-
@@output.write "\e[#{x}B"
|
304
|
-
elsif x < 0
|
305
|
-
move_cursor_up(-x)
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def self.hide_cursor
|
310
|
-
if Reline::Terminfo.enabled?
|
311
|
-
begin
|
312
|
-
@@output.write Reline::Terminfo.tigetstr('civis')
|
313
|
-
rescue Reline::Terminfo::TerminfoError
|
314
|
-
# civis is undefined
|
315
|
-
end
|
316
|
-
else
|
317
|
-
# ignored
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
def self.show_cursor
|
322
|
-
if Reline::Terminfo.enabled?
|
323
|
-
begin
|
324
|
-
@@output.write Reline::Terminfo.tigetstr('cnorm')
|
325
|
-
rescue Reline::Terminfo::TerminfoError
|
326
|
-
# cnorm is undefined
|
327
|
-
end
|
328
|
-
else
|
329
|
-
# ignored
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
def self.erase_after_cursor
|
334
|
-
@@output.write "\e[K"
|
335
|
-
end
|
336
|
-
|
337
|
-
# This only works when the cursor is at the bottom of the scroll range
|
338
|
-
# For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
|
339
|
-
def self.scroll_down(x)
|
340
|
-
return if x.zero?
|
341
|
-
# We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
|
342
|
-
@@output.write "\n" * x
|
343
|
-
end
|
344
|
-
|
345
|
-
def self.clear_screen
|
346
|
-
@@output.write "\e[2J"
|
347
|
-
@@output.write "\e[1;1H"
|
348
|
-
end
|
349
|
-
|
350
|
-
@@old_winch_handler = nil
|
351
|
-
def self.set_winch_handler(&handler)
|
352
|
-
@@old_winch_handler = Signal.trap('WINCH', &handler)
|
353
|
-
end
|
354
|
-
|
355
|
-
def self.prep
|
356
|
-
retrieve_keybuffer
|
357
|
-
nil
|
358
|
-
end
|
359
|
-
|
360
|
-
def self.deprep(otio)
|
361
|
-
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
362
|
-
end
|
363
|
-
end
|
data/lib/reline/general_io.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'io/wait'
|
2
|
-
|
3
|
-
class Reline::GeneralIO
|
4
|
-
def self.reset(encoding: nil)
|
5
|
-
@@pasting = false
|
6
|
-
if encoding
|
7
|
-
@@encoding = encoding
|
8
|
-
elsif defined?(@@encoding)
|
9
|
-
remove_class_variable(:@@encoding)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.encoding
|
14
|
-
if defined?(@@encoding)
|
15
|
-
@@encoding
|
16
|
-
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
17
|
-
Encoding::UTF_8
|
18
|
-
else
|
19
|
-
Encoding::default_external
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.win?
|
24
|
-
false
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.set_default_key_bindings(_)
|
28
|
-
end
|
29
|
-
|
30
|
-
@@buf = []
|
31
|
-
@@input = STDIN
|
32
|
-
|
33
|
-
def self.input=(val)
|
34
|
-
@@input = val
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.with_raw_input
|
38
|
-
yield
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.getc(_timeout_second)
|
42
|
-
unless @@buf.empty?
|
43
|
-
return @@buf.shift
|
44
|
-
end
|
45
|
-
c = nil
|
46
|
-
loop do
|
47
|
-
result = @@input.wait_readable(0.1)
|
48
|
-
next if result.nil?
|
49
|
-
c = @@input.read(1)
|
50
|
-
break
|
51
|
-
end
|
52
|
-
c&.ord
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.ungetc(c)
|
56
|
-
@@buf.unshift(c)
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.get_screen_size
|
60
|
-
[1, 1]
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.cursor_pos
|
64
|
-
Reline::CursorPos.new(1, 1)
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.hide_cursor
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.show_cursor
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.move_cursor_column(val)
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.move_cursor_up(val)
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.move_cursor_down(val)
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.erase_after_cursor
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.scroll_down(val)
|
86
|
-
end
|
87
|
-
|
88
|
-
def self.clear_screen
|
89
|
-
end
|
90
|
-
|
91
|
-
def self.set_screen_size(rows, columns)
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.set_winch_handler(&handler)
|
95
|
-
end
|
96
|
-
|
97
|
-
@@pasting = false
|
98
|
-
|
99
|
-
def self.in_pasting?
|
100
|
-
@@pasting
|
101
|
-
end
|
102
|
-
|
103
|
-
def self.start_pasting
|
104
|
-
@@pasting = true
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.finish_pasting
|
108
|
-
@@pasting = false
|
109
|
-
end
|
110
|
-
|
111
|
-
def self.prep
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.deprep(otio)
|
115
|
-
end
|
116
|
-
end
|
data/lib/reline/terminfo.rb
DELETED
@@ -1,160 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'fiddle'
|
3
|
-
require 'fiddle/import'
|
4
|
-
rescue LoadError
|
5
|
-
module Reline::Terminfo
|
6
|
-
def self.curses_dl
|
7
|
-
false
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module Reline::Terminfo
|
13
|
-
extend Fiddle::Importer
|
14
|
-
|
15
|
-
class TerminfoError < StandardError; end
|
16
|
-
|
17
|
-
def self.curses_dl_files
|
18
|
-
case RUBY_PLATFORM
|
19
|
-
when /mingw/, /mswin/
|
20
|
-
# aren't supported
|
21
|
-
[]
|
22
|
-
when /cygwin/
|
23
|
-
%w[cygncursesw-10.dll cygncurses-10.dll]
|
24
|
-
when /darwin/
|
25
|
-
%w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
|
26
|
-
else
|
27
|
-
%w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
@curses_dl = false
|
32
|
-
def self.curses_dl
|
33
|
-
return @curses_dl unless @curses_dl == false
|
34
|
-
if Fiddle.const_defined?(:TYPE_VARIADIC)
|
35
|
-
curses_dl_files.each do |curses_name|
|
36
|
-
result = Fiddle::Handle.new(curses_name)
|
37
|
-
rescue Fiddle::DLError
|
38
|
-
next
|
39
|
-
else
|
40
|
-
@curses_dl = result
|
41
|
-
break
|
42
|
-
end
|
43
|
-
end
|
44
|
-
@curses_dl = nil if @curses_dl == false
|
45
|
-
@curses_dl
|
46
|
-
end
|
47
|
-
end if not Reline.const_defined?(:Terminfo) or not Reline::Terminfo.respond_to?(:curses_dl)
|
48
|
-
|
49
|
-
module Reline::Terminfo
|
50
|
-
dlload curses_dl
|
51
|
-
#extern 'int setupterm(char *term, int fildes, int *errret)'
|
52
|
-
@setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
53
|
-
#extern 'char *tigetstr(char *capname)'
|
54
|
-
@tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
|
55
|
-
begin
|
56
|
-
#extern 'char *tiparm(const char *str, ...)'
|
57
|
-
@tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
58
|
-
rescue Fiddle::DLError
|
59
|
-
# OpenBSD lacks tiparm
|
60
|
-
#extern 'char *tparm(const char *str, ...)'
|
61
|
-
@tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
62
|
-
end
|
63
|
-
begin
|
64
|
-
#extern 'int tigetflag(char *str)'
|
65
|
-
@tigetflag = Fiddle::Function.new(curses_dl['tigetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
66
|
-
rescue Fiddle::DLError
|
67
|
-
# OpenBSD lacks tigetflag
|
68
|
-
#extern 'int tgetflag(char *str)'
|
69
|
-
@tigetflag = Fiddle::Function.new(curses_dl['tgetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
70
|
-
end
|
71
|
-
begin
|
72
|
-
#extern 'int tigetnum(char *str)'
|
73
|
-
@tigetnum = Fiddle::Function.new(curses_dl['tigetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
74
|
-
rescue Fiddle::DLError
|
75
|
-
# OpenBSD lacks tigetnum
|
76
|
-
#extern 'int tgetnum(char *str)'
|
77
|
-
@tigetnum = Fiddle::Function.new(curses_dl['tgetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.setupterm(term, fildes)
|
81
|
-
errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
|
82
|
-
ret = @setupterm.(term, fildes, errret_int)
|
83
|
-
errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
|
84
|
-
case ret
|
85
|
-
when 0 # OK
|
86
|
-
0
|
87
|
-
when -1 # ERR
|
88
|
-
case errret
|
89
|
-
when 1
|
90
|
-
raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
|
91
|
-
when 0
|
92
|
-
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.')
|
93
|
-
when -1
|
94
|
-
raise TerminfoError.new('The terminfo database could not be found.')
|
95
|
-
else # unknown
|
96
|
-
-1
|
97
|
-
end
|
98
|
-
else # unknown
|
99
|
-
-2
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
class StringWithTiparm < String
|
104
|
-
def tiparm(*args) # for method chain
|
105
|
-
Reline::Terminfo.tiparm(self, *args)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.tigetstr(capname)
|
110
|
-
raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
|
111
|
-
capability = @tigetstr.(capname)
|
112
|
-
case capability.to_i
|
113
|
-
when 0, -1
|
114
|
-
raise TerminfoError, "can't find capability: #{capname}"
|
115
|
-
end
|
116
|
-
StringWithTiparm.new(capability.to_s)
|
117
|
-
end
|
118
|
-
|
119
|
-
def self.tiparm(str, *args)
|
120
|
-
new_args = []
|
121
|
-
args.each do |a|
|
122
|
-
new_args << Fiddle::TYPE_INT << a
|
123
|
-
end
|
124
|
-
@tiparm.(str, *new_args).to_s
|
125
|
-
end
|
126
|
-
|
127
|
-
def self.tigetflag(capname)
|
128
|
-
raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
|
129
|
-
flag = @tigetflag.(capname).to_i
|
130
|
-
case flag
|
131
|
-
when -1
|
132
|
-
raise TerminfoError, "not boolean capability: #{capname}"
|
133
|
-
when 0
|
134
|
-
raise TerminfoError, "can't find capability: #{capname}"
|
135
|
-
end
|
136
|
-
flag
|
137
|
-
end
|
138
|
-
|
139
|
-
def self.tigetnum(capname)
|
140
|
-
raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
|
141
|
-
num = @tigetnum.(capname).to_i
|
142
|
-
case num
|
143
|
-
when -2
|
144
|
-
raise TerminfoError, "not numeric capability: #{capname}"
|
145
|
-
when -1
|
146
|
-
raise TerminfoError, "can't find capability: #{capname}"
|
147
|
-
end
|
148
|
-
num
|
149
|
-
end
|
150
|
-
|
151
|
-
def self.enabled?
|
152
|
-
true
|
153
|
-
end
|
154
|
-
end if Reline::Terminfo.curses_dl
|
155
|
-
|
156
|
-
module Reline::Terminfo
|
157
|
-
def self.enabled?
|
158
|
-
false
|
159
|
-
end
|
160
|
-
end unless Reline::Terminfo.curses_dl
|