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.
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
@@ -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
@@ -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