reline 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: beb24e6d3114b6debe540928f1299fd10d420ff447f90401c9a8249b12804b7d
4
- data.tar.gz: 046dfcfa706a95f62acb152238cae3680f918f9af2c9a52eee4fa4e5771ebdbc
3
+ metadata.gz: a9a8719e2dd161d4d3493907d730981e19b685854247d1da4e8a107a9af88f98
4
+ data.tar.gz: 57c468696aecaa1752bf0ebacafbb9595ec8810c0dd406beb9bd95f31b8e2d05
5
5
  SHA512:
6
- metadata.gz: a9a1abfe4febd8da98052386b0cca9a4b3c9f333c0a53c439d5980cad64c3b2f9f75c35d2498e42beadd4cea2f6a7d90c005d0112317b8ea90f89fd45b0f8632
7
- data.tar.gz: 6f482d37f4c85ab5f0a5df08e069f81c5289b7bedbcea105a0601a7174bd3ca314c0a04750e2bba91cb31ad7bdc7f56afa4f3b8398bf2bd80e635e356be12615
6
+ metadata.gz: 47f940b15f36eb7e410bf9951916258c268375fffadb661766fca64a421cc4e7aeb701a919c0b47dd03ea9b4aa1110c7c5b870328bad704c40f8e6d945a90ba2
7
+ data.tar.gz: 271926159d49eaa2b6572cc5d3640c81d82cfbc42d03a7320b0731fec276575a96c7491ab192023125a02e44d0a1cf38ee3ffa5045ac29e93f18e83ab9478071
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.com/ruby/reline.svg?branch=master)](https://travis-ci.com/ruby/reline)
2
+
1
3
  # Reline
2
4
 
3
5
  Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and Editline by pure Ruby implementation.
@@ -1,5 +1,6 @@
1
1
  require 'io/console'
2
2
  require 'timeout'
3
+ require 'forwardable'
3
4
  require 'reline/version'
4
5
  require 'reline/config'
5
6
  require 'reline/key_actor'
@@ -8,406 +9,400 @@ require 'reline/line_editor'
8
9
  require 'reline/history'
9
10
 
10
11
  module Reline
11
- Key = Struct.new('Key', :char, :combined_char, :with_meta)
12
-
13
- extend self
14
12
  FILENAME_COMPLETION_PROC = nil
15
13
  USERNAME_COMPLETION_PROC = nil
16
14
 
17
- if RUBY_PLATFORM =~ /mswin|mingw/
18
- IS_WINDOWS = true
19
- else
20
- IS_WINDOWS = false
21
- end
22
-
15
+ Key = Struct.new('Key', :char, :combined_char, :with_meta)
23
16
  CursorPos = Struct.new(:x, :y)
24
17
 
25
- @@config = Reline::Config.new
26
- @@key_stroke = Reline::KeyStroke.new(@@config)
27
- @@line_editor = Reline::LineEditor.new(@@config)
28
- @@ambiguous_width = nil
29
-
30
- HISTORY = History.new(@@config)
31
-
32
- @@completion_append_character = nil
33
- def self.completion_append_character
34
- @@completion_append_character
35
- end
36
- def self.completion_append_character=(val)
37
- if val.nil?
38
- @@completion_append_character = nil
39
- elsif val.size == 1
40
- @@completion_append_character = val.encode(Encoding::default_external)
41
- elsif val.size > 1
42
- @@completion_append_character = val[0].encode(Encoding::default_external)
43
- else
44
- @@completion_append_character = nil
18
+ class Core
19
+ ATTR_READER_NAMES = %i(
20
+ completion_append_character
21
+ basic_word_break_characters
22
+ completer_word_break_characters
23
+ basic_quote_characters
24
+ completer_quote_characters
25
+ filename_quote_characters
26
+ special_prefixes
27
+ completion_proc
28
+ output_modifier_proc
29
+ prompt_proc
30
+ auto_indent_proc
31
+ pre_input_hook
32
+ dig_perfect_match_proc
33
+ ).each(&method(:attr_reader))
34
+
35
+ ATTR_ACCESSOR_NAMES = %i(
36
+ completion_case_fold
37
+ ).each(&method(:attr_accessor))
38
+
39
+ attr_accessor :config
40
+ attr_accessor :key_stroke
41
+ attr_accessor :line_editor
42
+ attr_accessor :ambiguous_width
43
+ attr_reader :output
44
+
45
+ def initialize
46
+ self.output = STDOUT
47
+ yield self
45
48
  end
46
- end
47
49
 
48
- @@basic_word_break_characters = " \t\n`><=;|&{("
49
- def self.basic_word_break_characters
50
- @@basic_word_break_characters
51
- end
52
- def self.basic_word_break_characters=(v)
53
- @@basic_word_break_characters = v.encode(Encoding::default_external)
54
- end
55
-
56
- @@completer_word_break_characters = @@basic_word_break_characters.dup
57
- def self.completer_word_break_characters
58
- @@completer_word_break_characters
59
- end
60
- def self.completer_word_break_characters=(v)
61
- @@completer_word_break_characters = v.encode(Encoding::default_external)
62
- end
63
-
64
- @@basic_quote_characters = '"\''
65
- def self.basic_quote_characters
66
- @@basic_quote_characters
67
- end
68
- def self.basic_quote_characters=(v)
69
- @@basic_quote_characters = v.encode(Encoding::default_external)
70
- end
71
-
72
- @@completer_quote_characters = '"\''
73
- def self.completer_quote_characters
74
- @@completer_quote_characters
75
- end
76
- def self.completer_quote_characters=(v)
77
- @@completer_quote_characters = v.encode(Encoding::default_external)
78
- end
79
-
80
- @@filename_quote_characters = ''
81
- def self.filename_quote_characters
82
- @@filename_quote_characters
83
- end
84
- def self.filename_quote_characters=(v)
85
- @@filename_quote_characters = v.encode(Encoding::default_external)
86
- end
87
-
88
- @@special_prefixes = ''
89
- def self.special_prefixes
90
- @@special_prefixes
91
- end
92
- def self.special_prefixes=(v)
93
- @@special_prefixes = v.encode(Encoding::default_external)
94
- end
95
-
96
- @@completion_case_fold = nil
97
- def self.completion_case_fold
98
- @@completion_case_fold
99
- end
100
- def self.completion_case_fold=(v)
101
- @@completion_case_fold = v
102
- end
103
-
104
- @@completion_proc = nil
105
- def self.completion_proc
106
- @@completion_proc
107
- end
108
- def self.completion_proc=(p)
109
- raise ArgumentError unless p.is_a?(Proc)
110
- @@completion_proc = p
111
- end
50
+ def completion_append_character=(val)
51
+ if val.nil?
52
+ @completion_append_character = nil
53
+ elsif val.size == 1
54
+ @completion_append_character = val.encode(Encoding::default_external)
55
+ elsif val.size > 1
56
+ @completion_append_character = val[0].encode(Encoding::default_external)
57
+ else
58
+ @completion_append_character = nil
59
+ end
60
+ end
112
61
 
113
- @@output_modifier_proc = nil
114
- def self.output_modifier_proc
115
- @@output_modifier_proc
116
- end
117
- def self.output_modifier_proc=(p)
118
- raise ArgumentError unless p.is_a?(Proc)
119
- @@output_modifier_proc = p
120
- end
62
+ def basic_word_break_characters=(v)
63
+ @basic_word_break_characters = v.encode(Encoding::default_external)
64
+ end
121
65
 
122
- @@prompt_proc = nil
123
- def self.prompt_proc
124
- @@prompt_proc
125
- end
126
- def self.prompt_proc=(p)
127
- raise ArgumentError unless p.is_a?(Proc)
128
- @@prompt_proc = p
129
- end
66
+ def completer_word_break_characters=(v)
67
+ @completer_word_break_characters = v.encode(Encoding::default_external)
68
+ end
130
69
 
131
- @@auto_indent_proc = nil
132
- def self.auto_indent_proc
133
- @@auto_indent_proc
134
- end
135
- def self.auto_indent_proc=(p)
136
- raise ArgumentError unless p.is_a?(Proc)
137
- @@auto_indent_proc = p
138
- end
70
+ def basic_quote_characters=(v)
71
+ @basic_quote_characters = v.encode(Encoding::default_external)
72
+ end
139
73
 
140
- @@pre_input_hook = nil
141
- def self.pre_input_hook
142
- @@pre_input_hook
143
- end
144
- def self.pre_input_hook=(p)
145
- @@pre_input_hook = p
146
- end
74
+ def completer_quote_characters=(v)
75
+ @completer_quote_characters = v.encode(Encoding::default_external)
76
+ end
147
77
 
148
- @@dig_perfect_match_proc = nil
149
- def self.dig_perfect_match_proc
150
- @@dig_perfect_match_proc
151
- end
152
- def self.dig_perfect_match_proc=(p)
153
- raise ArgumentError unless p.is_a?(Proc)
154
- @@dig_perfect_match_proc = p
155
- end
78
+ def filename_quote_characters=(v)
79
+ @filename_quote_characters = v.encode(Encoding::default_external)
80
+ end
156
81
 
157
- def self.insert_text(text)
158
- @@line_editor&.insert_text(text)
159
- self
160
- end
82
+ def special_prefixes=(v)
83
+ @special_prefixes = v.encode(Encoding::default_external)
84
+ end
161
85
 
162
- def self.redisplay
163
- @@line_editor&.rerender
164
- end
86
+ def completion_proc=(p)
87
+ raise ArgumentError unless p.respond_to?(:call)
88
+ @completion_proc = p
89
+ end
165
90
 
166
- def self.line_buffer
167
- @@line_editor&.line
168
- end
91
+ def output_modifier_proc=(p)
92
+ raise ArgumentError unless p.respond_to?(:call)
93
+ @output_modifier_proc = p
94
+ end
169
95
 
170
- def self.point
171
- @@line_editor ? @@line_editor.byte_pointer : 0
172
- end
96
+ def prompt_proc=(p)
97
+ raise ArgumentError unless p.respond_to?(:call)
98
+ @prompt_proc = p
99
+ end
173
100
 
174
- def self.point=(val)
175
- @@line_editor.byte_pointer = val
176
- end
101
+ def auto_indent_proc=(p)
102
+ raise ArgumentError unless p.respond_to?(:call)
103
+ @auto_indent_proc = p
104
+ end
177
105
 
178
- def self.delete_text(start = nil, length = nil)
179
- @@line_editor&.delete_text(start, length)
180
- end
106
+ def pre_input_hook=(p)
107
+ @pre_input_hook = p
108
+ end
181
109
 
182
- private_class_method def self.test_mode
183
- remove_const('IOGate') if const_defined?('IOGate')
184
- const_set('IOGate', Reline::GeneralIO)
185
- @@config.instance_variable_set(:@test_mode, true)
186
- @@config.reset
187
- end
110
+ def dig_perfect_match_proc=(p)
111
+ raise ArgumentError unless p.respond_to?(:call)
112
+ @dig_perfect_match_proc = p
113
+ end
188
114
 
189
- def self.input=(val)
190
- raise TypeError unless val.respond_to?(:getc) or val.nil?
191
- if val.respond_to?(:getc)
192
- if defined?(Reline::ANSI) and IOGate == Reline::ANSI
193
- Reline::ANSI.input = val
194
- elsif IOGate == Reline::GeneralIO
195
- Reline::GeneralIO.input = val
115
+ def input=(val)
116
+ raise TypeError unless val.respond_to?(:getc) or val.nil?
117
+ if val.respond_to?(:getc)
118
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
119
+ Reline::ANSI.input = val
120
+ elsif Reline::IOGate == Reline::GeneralIO
121
+ Reline::GeneralIO.input = val
122
+ end
196
123
  end
197
124
  end
198
- end
199
125
 
200
- @@output = STDOUT
201
- def self.output=(val)
202
- raise TypeError unless val.respond_to?(:write) or val.nil?
203
- @@output = val
204
- if defined?(Reline::ANSI) and IOGate == Reline::ANSI
205
- Reline::ANSI.output = val
126
+ def output=(val)
127
+ raise TypeError unless val.respond_to?(:write) or val.nil?
128
+ @output = val
129
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
130
+ Reline::ANSI.output = val
131
+ end
206
132
  end
207
- end
208
133
 
209
- def self.vi_editing_mode
210
- @@config.editing_mode = :vi_insert
211
- nil
212
- end
213
-
214
- def self.emacs_editing_mode
215
- @@config.editing_mode = :emacs
216
- nil
217
- end
218
-
219
- def self.vi_editing_mode?
220
- @@config.editing_mode_is?(:vi_insert, :vi_command)
221
- end
222
-
223
- def self.emacs_editing_mode?
224
- @@config.editing_mode_is?(:emacs)
225
- end
134
+ def vi_editing_mode
135
+ config.editing_mode = :vi_insert
136
+ nil
137
+ end
226
138
 
227
- def self.get_screen_size
228
- Reline::IOGate.get_screen_size
229
- end
139
+ def emacs_editing_mode
140
+ config.editing_mode = :emacs
141
+ nil
142
+ end
230
143
 
231
- def eof?
232
- @@line_editor.eof?
233
- end
144
+ def vi_editing_mode?
145
+ config.editing_mode_is?(:vi_insert, :vi_command)
146
+ end
234
147
 
235
- def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
236
- unless confirm_multiline_termination
237
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
148
+ def emacs_editing_mode?
149
+ config.editing_mode_is?(:emacs)
238
150
  end
239
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
240
151
 
241
- whole_buffer = @@line_editor.whole_buffer.dup
242
- whole_buffer.taint
243
- if add_hist and whole_buffer and whole_buffer.chomp.size > 0
244
- Reline::HISTORY << whole_buffer
152
+ def get_screen_size
153
+ Reline::IOGate.get_screen_size
245
154
  end
246
155
 
247
- @@line_editor.reset_line if @@line_editor.whole_buffer.nil?
248
- whole_buffer
249
- end
156
+ def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
157
+ unless confirm_multiline_termination
158
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
159
+ end
160
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
250
161
 
251
- def readline(prompt = '', add_hist = false)
252
- inner_readline(prompt, add_hist, false)
162
+ whole_buffer = line_editor.whole_buffer.dup
163
+ whole_buffer.taint if RUBY_VERSION < '2.7'
164
+ if add_hist and whole_buffer and whole_buffer.chomp.size > 0
165
+ Reline::HISTORY << whole_buffer
166
+ end
253
167
 
254
- line = @@line_editor.line.dup
255
- line.taint
256
- if add_hist and line and line.chomp.size > 0
257
- Reline::HISTORY << line.chomp
168
+ line_editor.reset_line if line_editor.whole_buffer.nil?
169
+ whole_buffer
258
170
  end
259
171
 
260
- @@line_editor.reset_line if @@line_editor.line.nil?
261
- line
262
- end
172
+ def readline(prompt = '', add_hist = false)
173
+ inner_readline(prompt, add_hist, false)
263
174
 
264
- def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
265
- if ENV['RELINE_STDERR_TTY']
266
- $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
267
- $stderr.sync = true
268
- $stderr.puts "Reline is used by #{Process.pid}"
269
- end
270
- otio = Reline::IOGate.prep
271
-
272
- may_req_ambiguous_char_width
273
- @@line_editor.reset(prompt)
274
- if multiline
275
- @@line_editor.multiline_on
276
- if block_given?
277
- @@line_editor.confirm_multiline_termination_proc = confirm_multiline_termination
175
+ line = line_editor.line.dup
176
+ line.taint if RUBY_VERSION < '2.7'
177
+ if add_hist and line and line.chomp.size > 0
178
+ Reline::HISTORY << line.chomp
278
179
  end
279
- else
280
- @@line_editor.multiline_off
180
+
181
+ line_editor.reset_line if line_editor.line.nil?
182
+ line
281
183
  end
282
- @@line_editor.output = @@output
283
- @@line_editor.completion_proc = @@completion_proc
284
- @@line_editor.output_modifier_proc = @@output_modifier_proc
285
- @@line_editor.prompt_proc = @@prompt_proc
286
- @@line_editor.auto_indent_proc = @@auto_indent_proc
287
- @@line_editor.dig_perfect_match_proc = @@dig_perfect_match_proc
288
- @@line_editor.pre_input_hook = @@pre_input_hook
289
- @@line_editor.rerender
290
-
291
- unless @@config.test_mode
292
- @@config.read
293
- @@config.reset_default_key_bindings
294
- Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
295
- @@config.add_default_key_binding(key, func)
184
+
185
+ private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
186
+ if ENV['RELINE_STDERR_TTY']
187
+ $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
188
+ $stderr.sync = true
189
+ $stderr.puts "Reline is used by #{Process.pid}"
190
+ end
191
+ otio = Reline::IOGate.prep
192
+
193
+ may_req_ambiguous_char_width
194
+ line_editor.reset(prompt)
195
+ if multiline
196
+ line_editor.multiline_on
197
+ if block_given?
198
+ line_editor.confirm_multiline_termination_proc = confirm_multiline_termination
199
+ end
200
+ else
201
+ line_editor.multiline_off
202
+ end
203
+ line_editor.output = output
204
+ line_editor.completion_proc = completion_proc
205
+ line_editor.output_modifier_proc = output_modifier_proc
206
+ line_editor.prompt_proc = prompt_proc
207
+ line_editor.auto_indent_proc = auto_indent_proc
208
+ line_editor.dig_perfect_match_proc = dig_perfect_match_proc
209
+ line_editor.pre_input_hook = pre_input_hook
210
+ line_editor.rerender
211
+
212
+ unless config.test_mode
213
+ config.read
214
+ config.reset_default_key_bindings
215
+ Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
216
+ config.add_default_key_binding(key, func)
217
+ end
296
218
  end
297
- end
298
219
 
299
- begin
300
- loop do
301
- read_io(@@config.keyseq_timeout) { |inputs|
302
- inputs.each { |c|
303
- @@line_editor.input_key(c)
304
- @@line_editor.rerender
220
+ begin
221
+ loop do
222
+ read_io(config.keyseq_timeout) { |inputs|
223
+ inputs.each { |c|
224
+ line_editor.input_key(c)
225
+ line_editor.rerender
226
+ }
305
227
  }
306
- }
307
- break if @@line_editor.finished?
228
+ break if line_editor.finished?
229
+ end
230
+ Reline::IOGate.move_cursor_column(0)
231
+ rescue StandardError => e
232
+ line_editor.finalize
233
+ Reline::IOGate.deprep(otio)
234
+ raise e
308
235
  end
309
- Reline::IOGate.move_cursor_column(0)
310
- rescue StandardError => e
311
- @@line_editor.finalize
236
+
237
+ line_editor.finalize
312
238
  Reline::IOGate.deprep(otio)
313
- raise e
314
239
  end
315
240
 
316
- @@line_editor.finalize
317
- Reline::IOGate.deprep(otio)
318
- end
319
-
320
- # Keystrokes of GNU Readline will timeout it with the specification of
321
- # "keyseq-timeout" when waiting for the 2nd character after the 1st one.
322
- # If the 2nd character comes after 1st ESC without timeout it has a
323
- # meta-property of meta-key to discriminate modified key with meta-key
324
- # from multibyte characters that come with 8th bit on.
325
- #
326
- # GNU Readline will wait for the 2nd character with "keyseq-timeout"
327
- # milli-seconds but wait forever after 3rd characters.
328
- def read_io(keyseq_timeout, &block)
329
- buffer = []
330
- loop do
331
- c = Reline::IOGate.getc
332
- buffer << c
333
- result = @@key_stroke.match_status(buffer)
334
- case result
335
- when :matched
336
- block.(@@key_stroke.expand(buffer).map{ |c| Reline::Key.new(c, c, false) })
337
- break
338
- when :matching
339
- if buffer.size == 1
340
- begin
341
- succ_c = nil
342
- Timeout.timeout(keyseq_timeout / 1000.0) {
343
- succ_c = Reline::IOGate.getc
344
- }
345
- rescue Timeout::Error # cancel matching only when first byte
346
- block.([Reline::Key.new(c, c, false)])
347
- break
348
- else
349
- if @@key_stroke.match_status(buffer.dup.push(succ_c)) == :unmatched
350
- if c == "\e".ord
351
- block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
352
- else
353
- block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
354
- end
241
+ # Keystrokes of GNU Readline will timeout it with the specification of
242
+ # "keyseq-timeout" when waiting for the 2nd character after the 1st one.
243
+ # If the 2nd character comes after 1st ESC without timeout it has a
244
+ # meta-property of meta-key to discriminate modified key with meta-key
245
+ # from multibyte characters that come with 8th bit on.
246
+ #
247
+ # GNU Readline will wait for the 2nd character with "keyseq-timeout"
248
+ # milli-seconds but wait forever after 3rd characters.
249
+ private def read_io(keyseq_timeout, &block)
250
+ buffer = []
251
+ loop do
252
+ c = Reline::IOGate.getc
253
+ buffer << c
254
+ result = key_stroke.match_status(buffer)
255
+ case result
256
+ when :matched
257
+ expanded = key_stroke.expand(buffer).map{ |expanded_c|
258
+ Reline::Key.new(expanded_c, expanded_c, false)
259
+ }
260
+ block.(expanded)
261
+ break
262
+ when :matching
263
+ if buffer.size == 1
264
+ begin
265
+ succ_c = nil
266
+ Timeout.timeout(keyseq_timeout / 1000.0) {
267
+ succ_c = Reline::IOGate.getc
268
+ }
269
+ rescue Timeout::Error # cancel matching only when first byte
270
+ block.([Reline::Key.new(c, c, false)])
355
271
  break
356
272
  else
357
- Reline::IOGate.ungetc(succ_c)
273
+ if key_stroke.match_status(buffer.dup.push(succ_c)) == :unmatched
274
+ if c == "\e".ord
275
+ block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
276
+ else
277
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
278
+ end
279
+ break
280
+ else
281
+ Reline::IOGate.ungetc(succ_c)
282
+ end
358
283
  end
359
284
  end
285
+ when :unmatched
286
+ if buffer.size == 1 and c == "\e".ord
287
+ read_escaped_key(keyseq_timeout, c, block)
288
+ else
289
+ expanded = buffer.map{ |expanded_c|
290
+ Reline::Key.new(expanded_c, expanded_c, false)
291
+ }
292
+ block.(expanded)
293
+ end
294
+ break
360
295
  end
361
- when :unmatched
362
- if buffer.size == 1 and c == "\e".ord
363
- read_escaped_key(keyseq_timeout, buffer, block)
364
- else
365
- block.(buffer.map{ |c| Reline::Key.new(c, c, false) })
366
- end
367
- break
368
296
  end
369
297
  end
370
- end
371
298
 
372
- def read_escaped_key(keyseq_timeout, buffer, block)
373
- begin
374
- escaped_c = nil
375
- Timeout.timeout(keyseq_timeout / 1000.0) {
376
- escaped_c = Reline::IOGate.getc
377
- }
378
- rescue Timeout::Error # independent ESC
379
- block.([Reline::Key.new(c, c, false)])
380
- else
381
- if escaped_c.nil?
299
+ private def read_escaped_key(keyseq_timeout, c, block)
300
+ begin
301
+ escaped_c = nil
302
+ Timeout.timeout(keyseq_timeout / 1000.0) {
303
+ escaped_c = Reline::IOGate.getc
304
+ }
305
+ rescue Timeout::Error # independent ESC
382
306
  block.([Reline::Key.new(c, c, false)])
383
- elsif escaped_c >= 128 # maybe, first byte of multi byte
384
- block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
385
- elsif escaped_c == "\e".ord # escape twice
386
- block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
387
307
  else
388
- block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
308
+ if escaped_c.nil?
309
+ block.([Reline::Key.new(c, c, false)])
310
+ elsif escaped_c >= 128 # maybe, first byte of multi byte
311
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
312
+ elsif escaped_c == "\e".ord # escape twice
313
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
314
+ else
315
+ block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
316
+ end
389
317
  end
390
318
  end
319
+
320
+ private def may_req_ambiguous_char_width
321
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
322
+ return if ambiguous_width
323
+ Reline::IOGate.move_cursor_column(0)
324
+ print "\u{25bd}"
325
+ @ambiguous_width = Reline::IOGate.cursor_pos.x
326
+ Reline::IOGate.move_cursor_column(0)
327
+ Reline::IOGate.erase_after_cursor
328
+ end
391
329
  end
392
330
 
393
- def may_req_ambiguous_char_width
394
- @@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
395
- return if @@ambiguous_width
396
- Reline::IOGate.move_cursor_column(0)
397
- print "\u{25bd}"
398
- @@ambiguous_width = Reline::IOGate.cursor_pos.x
399
- Reline::IOGate.move_cursor_column(0)
400
- Reline::IOGate.erase_after_cursor
331
+ extend Forwardable
332
+ extend SingleForwardable
333
+
334
+ #--------------------------------------------------------
335
+ # Documented API
336
+ #--------------------------------------------------------
337
+
338
+ (Core::ATTR_READER_NAMES + Core::ATTR_ACCESSOR_NAMES).each { |name|
339
+ def_single_delegators :core, "#{name}", "#{name}="
340
+ }
341
+ def_single_delegators :core, :input=, :output=
342
+ def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
343
+ def_single_delegators :core, :readline
344
+ def_instance_delegators self, :readline
345
+ private :readline
346
+
347
+
348
+ #--------------------------------------------------------
349
+ # Undocumented API
350
+ #--------------------------------------------------------
351
+
352
+ # Testable in original
353
+ def_single_delegators :core, :get_screen_size
354
+ def_single_delegators :line_editor, :eof?
355
+ def_instance_delegators self, :eof?
356
+ def_single_delegators :line_editor, :delete_text
357
+ def_single_delegator :line_editor, :line, :line_buffer
358
+ def_single_delegator :line_editor, :byte_pointer, :point
359
+ def_single_delegator :line_editor, :byte_pointer=, :point=
360
+
361
+ def self.insert_text(*args, &block)
362
+ line_editor.insert_text(*args, &block)
363
+ self
401
364
  end
402
365
 
403
- def self.ambiguous_width
404
- @@ambiguous_width
366
+ # Untestable in original
367
+ def_single_delegator :line_editor, :rerender, :redisplay
368
+ def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
369
+ def_single_delegators :core, :ambiguous_width
370
+
371
+ def_single_delegators :core, :readmultiline
372
+ def_instance_delegators self, :readmultiline
373
+ private :readmultiline
374
+
375
+ def self.core
376
+ @core ||= Core.new { |core|
377
+ core.config = Reline::Config.new
378
+ core.key_stroke = Reline::KeyStroke.new(core.config)
379
+ core.line_editor = Reline::LineEditor.new(core.config)
380
+
381
+ core.basic_word_break_characters = " \t\n`><=;|&{("
382
+ core.completer_word_break_characters = " \t\n`><=;|&{("
383
+ core.basic_quote_characters = '"\''
384
+ core.completer_quote_characters = '"\''
385
+ core.filename_quote_characters = ""
386
+ core.special_prefixes = ""
387
+ }
388
+ end
389
+
390
+ def self.line_editor
391
+ core.line_editor
405
392
  end
393
+
394
+ HISTORY = History.new(core.config)
406
395
  end
407
396
 
408
- if Reline::IS_WINDOWS
397
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
409
398
  require 'reline/windows'
410
- Reline::IOGate = Reline::Windows
399
+ if Reline::Windows.get_screen_size == [0, 0]
400
+ # Maybe Mintty on Cygwin
401
+ require 'reline/ansi'
402
+ Reline::IOGate = Reline::ANSI
403
+ else
404
+ Reline::IOGate = Reline::Windows
405
+ end
411
406
  else
412
407
  require 'reline/ansi'
413
408
  Reline::IOGate = Reline::ANSI