reline 0.0.1 → 0.0.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 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