reline 0.3.4 → 0.3.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: 3e5c7a3a92a99dc4e59ae8299c90086a1d5508a7aa7f23579ac9e69a516da22a
4
- data.tar.gz: 4779c4eba572d69bda056dafdc974f898678a9a0d40636ffc54836bbcedce2e8
3
+ metadata.gz: 3075f4003cf263e4652fc0dec716c71b55b597e6cbdc8cdb5297181b72780b57
4
+ data.tar.gz: 78eb2e13f17bc0c7ae34b425effe29bf40a30b355af7d0efd271823c2cdde521
5
5
  SHA512:
6
- metadata.gz: ec283bebd9d93cc46c0587da2d051f29a2f119c785eff4a0d554b019a6f4cc2c9503670e0f073c11ce3399b72ecd2b3cdd4d92315251022b4ef54378bb9eea35
7
- data.tar.gz: ffab61dee9ca267ff0015280a0fb0cbd5c76b271867dd86fc1861379af4821929917a467017b1a9b6cd17c92e3bbc74905c7b43865406b5053890bdb42b00007
6
+ metadata.gz: 9fd55d135c7b1aaffaff575f930bdb6365c202a1d15b5943d3dd9f678f416ba312b21c836ef8b78d11ee9942c4e0f0ac50d395633196bd649bd23a2fa6096456
7
+ data.tar.gz: 43fe692b243560a81da41a48f4cb5cdf05514f85788bbc6b54bba72aef4d5e7258e73c2a84622c80e51adf36345cd9e7595455f8301e09c1f299f7b2ec147ff2
data/README.md CHANGED
@@ -55,6 +55,29 @@ end
55
55
 
56
56
  See also: [test/reline/yamatanooroti/multiline_repl](https://github.com/ruby/reline/blob/master/test/reline/yamatanooroti/multiline_repl)
57
57
 
58
+ ## Contributing
59
+
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/reline.
61
+
62
+ ### Run tests
63
+
64
+ > **Note**
65
+ > Please make sure you have `libvterm` installed for `yamatanooroti` tests (integration tests).
66
+
67
+ If you use Homebrew, you can install it by running `brew install libvterm`.
68
+
69
+ ```bash
70
+ WITH_VTERM=1 bundle install
71
+ WITH_VTERM=1 bundle exec rake test test_yamatanooroti
72
+ ```
73
+
74
+ ## Releasing
75
+
76
+ ```bash
77
+ rake release
78
+ gh release create vX.Y.Z --generate-notes
79
+ ```
80
+
58
81
  ## License
59
82
 
60
83
  The gem is available as open source under the terms of the [Ruby License](https://www.ruby-lang.org/en/about/license.txt).
data/lib/reline/ansi.rb CHANGED
@@ -206,7 +206,7 @@ class Reline::ANSI
206
206
  end
207
207
 
208
208
  def self.in_pasting?
209
- @@in_bracketed_paste_mode or (not Reline::IOGate.empty_buffer?)
209
+ @@in_bracketed_paste_mode or (not empty_buffer?)
210
210
  end
211
211
 
212
212
  def self.empty_buffer?
@@ -1,4 +1,8 @@
1
1
  class Reline::KeyStroke
2
+ ESC_BYTE = 27
3
+ CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
4
+ CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
5
+
2
6
  def initialize(config)
3
7
  @config = config
4
8
  end
@@ -73,17 +77,26 @@ class Reline::KeyStroke
73
77
  return :matched if it.max_by(&:size)&.size&.< input.size
74
78
  return :matching if it.size > 1
75
79
  }
76
- key_mapping.keys.select { |lhs|
77
- start_with?(input, lhs)
78
- }.tap { |it|
79
- return it.size > 0 ? :matched : :unmatched
80
- }
80
+ if key_mapping.keys.any? { |lhs| start_with?(input, lhs) }
81
+ :matched
82
+ else
83
+ match_unknown_escape_sequence(input).first
84
+ end
81
85
  end
82
86
 
83
87
  def expand(input)
84
- input = compress_meta_key(input)
85
88
  lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
86
- return input unless lhs
89
+ unless lhs
90
+ status, size = match_unknown_escape_sequence(input)
91
+ case status
92
+ when :matched
93
+ return [:ed_unassigned] + expand(input.drop(size))
94
+ when :matching
95
+ return [:ed_unassigned]
96
+ else
97
+ return input
98
+ end
99
+ end
87
100
  rhs = key_mapping[lhs]
88
101
 
89
102
  case rhs
@@ -99,6 +112,36 @@ class Reline::KeyStroke
99
112
 
100
113
  private
101
114
 
115
+ # returns match status of CSI/SS3 sequence and matched length
116
+ def match_unknown_escape_sequence(input)
117
+ idx = 0
118
+ return [:unmatched, nil] unless input[idx] == ESC_BYTE
119
+ idx += 1
120
+ idx += 1 if input[idx] == ESC_BYTE
121
+
122
+ case input[idx]
123
+ when nil
124
+ return [:matching, nil]
125
+ when 91 # == '['.ord
126
+ # CSI sequence
127
+ idx += 1
128
+ idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx])
129
+ idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx])
130
+ input[idx] ? [:matched, idx + 1] : [:matching, nil]
131
+ when 79 # == 'O'.ord
132
+ # SS3 sequence
133
+ input[idx + 1] ? [:matched, idx + 2] : [:matching, nil]
134
+ else
135
+ if idx == 1
136
+ # `ESC char`, make it :unmatched so that it will be handled correctly in `read_2nd_character_of_key_sequence`
137
+ [:unmatched, nil]
138
+ else
139
+ # `ESC ESC char`
140
+ [:matched, idx + 1]
141
+ end
142
+ end
143
+ end
144
+
102
145
  def key_mapping
103
146
  @config.key_bindings
104
147
  end
@@ -48,8 +48,8 @@ class Reline::LineEditor
48
48
  PERFECT_MATCH = :perfect_match
49
49
  end
50
50
 
51
- CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
52
- MenuInfo = Struct.new('MenuInfo', :target, :list)
51
+ CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
52
+ MenuInfo = Struct.new(:target, :list)
53
53
 
54
54
  PROMPT_LIST_CACHE_TIMEOUT = 0.5
55
55
  MINIMUM_SCROLLBAR_HEIGHT = 1
@@ -60,6 +60,10 @@ class Reline::LineEditor
60
60
  reset_variables(encoding: encoding)
61
61
  end
62
62
 
63
+ def io_gate
64
+ Reline::IOGate
65
+ end
66
+
63
67
  def set_pasting_state(in_pasting)
64
68
  @in_pasting = in_pasting
65
69
  end
@@ -562,6 +566,16 @@ class Reline::LineEditor
562
566
  @line_editor.instance_variable_get(:@screen_size).last
563
567
  end
564
568
 
569
+ def screen_height
570
+ @line_editor.instance_variable_get(:@screen_size).first
571
+ end
572
+
573
+ def preferred_dialog_height
574
+ rest_height = @line_editor.instance_variable_get(:@rest_height)
575
+ scroll_partial_screen = @line_editor.instance_variable_get(:@scroll_partial_screen) || 0
576
+ [cursor_pos.y - scroll_partial_screen, rest_height, (screen_height + 6) / 5].max
577
+ end
578
+
565
579
  def completion_journey_data
566
580
  @line_editor.instance_variable_get(:@completion_journey_data)
567
581
  end
@@ -714,7 +728,7 @@ class Reline::LineEditor
714
728
  ymax = ymax.clamp(screen_y_range.begin, screen_y_range.end)
715
729
  dialog_y = @first_line_started_from + @started_from
716
730
  cursor_y = dialog_y
717
- if @highest_in_all < ymax
731
+ if @highest_in_all <= ymax
718
732
  scroll_down(ymax - cursor_y)
719
733
  move_cursor_up(ymax - cursor_y)
720
734
  end
@@ -1500,11 +1514,13 @@ class Reline::LineEditor
1500
1514
  return if key.char >= 128 # maybe, first byte of multi byte
1501
1515
  method_symbol = @config.editing_mode.get_method(key.combined_char)
1502
1516
  if key.with_meta and method_symbol == :ed_unassigned
1503
- # split ESC + key
1504
- method_symbol = @config.editing_mode.get_method("\e".ord)
1505
- process_key("\e".ord, method_symbol)
1506
- method_symbol = @config.editing_mode.get_method(key.char)
1507
- process_key(key.char, method_symbol)
1517
+ if @config.editing_mode_is?(:vi_command, :vi_insert)
1518
+ # split ESC + key in vi mode
1519
+ method_symbol = @config.editing_mode.get_method("\e".ord)
1520
+ process_key("\e".ord, method_symbol)
1521
+ method_symbol = @config.editing_mode.get_method(key.char)
1522
+ process_key(key.char, method_symbol)
1523
+ end
1508
1524
  else
1509
1525
  process_key(key.combined_char, method_symbol)
1510
1526
  end
@@ -1635,7 +1651,7 @@ class Reline::LineEditor
1635
1651
  @line = ' ' * new_indent + @line.lstrip
1636
1652
 
1637
1653
  new_indent = nil
1638
- result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
1654
+ result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[@line_index - 1].bytesize + 1), false)
1639
1655
  if result
1640
1656
  new_indent = result
1641
1657
  end
@@ -3276,4 +3292,7 @@ class Reline::LineEditor
3276
3292
  @mark_pointer = new_pointer
3277
3293
  end
3278
3294
  alias_method :exchange_point_and_mark, :em_exchange_mark
3295
+
3296
+ private def em_meta_next(key)
3297
+ end
3279
3298
  end
@@ -31,21 +31,7 @@ module Reline::Terminfo
31
31
  @curses_dl = false
32
32
  def self.curses_dl
33
33
  return @curses_dl unless @curses_dl == false
34
- if RUBY_VERSION >= '3.0.0'
35
- # Gem module isn't defined in test-all of the Ruby repository, and
36
- # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
37
- fiddle_supports_variadic = true
38
- elsif Fiddle.const_defined?(:VERSION,false) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
39
- # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
40
- fiddle_supports_variadic = true
41
- else
42
- fiddle_supports_variadic = false
43
- end
44
- if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
45
- # If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
46
- fiddle_supports_variadic = false
47
- end
48
- if fiddle_supports_variadic
34
+ if Fiddle.const_defined?(:TYPE_VARIADIC)
49
35
  curses_dl_files.each do |curses_name|
50
36
  result = Fiddle::Handle.new(curses_name)
51
37
  rescue Fiddle::DLError
@@ -41,26 +41,6 @@ class Reline::Unicode
41
41
  OSC_REGEXP = /\e\]\d+(?:;[^;\a\e]+)*(?:\a|\e\\)/
42
42
  WIDTH_SCANNER = /\G(?:(#{NON_PRINTING_START})|(#{NON_PRINTING_END})|(#{CSI_REGEXP})|(#{OSC_REGEXP})|(\X))/o
43
43
 
44
- def self.get_mbchar_byte_size_by_first_char(c)
45
- # Checks UTF-8 character byte size
46
- case c.ord
47
- # 0b0xxxxxxx
48
- when ->(code) { (code ^ 0b10000000).allbits?(0b10000000) } then 1
49
- # 0b110xxxxx
50
- when ->(code) { (code ^ 0b00100000).allbits?(0b11100000) } then 2
51
- # 0b1110xxxx
52
- when ->(code) { (code ^ 0b00010000).allbits?(0b11110000) } then 3
53
- # 0b11110xxx
54
- when ->(code) { (code ^ 0b00001000).allbits?(0b11111000) } then 4
55
- # 0b111110xx
56
- when ->(code) { (code ^ 0b00000100).allbits?(0b11111100) } then 5
57
- # 0b1111110x
58
- when ->(code) { (code ^ 0b00000010).allbits?(0b11111110) } then 6
59
- # successor of mbchar
60
- else 0
61
- end
62
- end
63
-
64
44
  def self.escape_for_print(str)
65
45
  str.chars.map! { |gr|
66
46
  escaped = EscapedPairs[gr.ord]
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.3.4'
2
+ VERSION = '0.3.6'
3
3
  end
data/lib/reline.rb CHANGED
@@ -17,7 +17,7 @@ module Reline
17
17
 
18
18
  class ConfigEncodingConversionError < StandardError; end
19
19
 
20
- Key = Struct.new('Key', :char, :combined_char, :with_meta) do
20
+ Key = Struct.new(:char, :combined_char, :with_meta) do
21
21
  def match?(other)
22
22
  case other
23
23
  when Reline::Key
@@ -83,44 +83,48 @@ module Reline
83
83
  @bracketed_paste_finished = false
84
84
  end
85
85
 
86
+ def io_gate
87
+ Reline::IOGate
88
+ end
89
+
86
90
  def encoding
87
- Reline::IOGate.encoding
91
+ io_gate.encoding
88
92
  end
89
93
 
90
94
  def completion_append_character=(val)
91
95
  if val.nil?
92
96
  @completion_append_character = nil
93
97
  elsif val.size == 1
94
- @completion_append_character = val.encode(Reline::IOGate.encoding)
98
+ @completion_append_character = val.encode(encoding)
95
99
  elsif val.size > 1
96
- @completion_append_character = val[0].encode(Reline::IOGate.encoding)
100
+ @completion_append_character = val[0].encode(encoding)
97
101
  else
98
102
  @completion_append_character = nil
99
103
  end
100
104
  end
101
105
 
102
106
  def basic_word_break_characters=(v)
103
- @basic_word_break_characters = v.encode(Reline::IOGate.encoding)
107
+ @basic_word_break_characters = v.encode(encoding)
104
108
  end
105
109
 
106
110
  def completer_word_break_characters=(v)
107
- @completer_word_break_characters = v.encode(Reline::IOGate.encoding)
111
+ @completer_word_break_characters = v.encode(encoding)
108
112
  end
109
113
 
110
114
  def basic_quote_characters=(v)
111
- @basic_quote_characters = v.encode(Reline::IOGate.encoding)
115
+ @basic_quote_characters = v.encode(encoding)
112
116
  end
113
117
 
114
118
  def completer_quote_characters=(v)
115
- @completer_quote_characters = v.encode(Reline::IOGate.encoding)
119
+ @completer_quote_characters = v.encode(encoding)
116
120
  end
117
121
 
118
122
  def filename_quote_characters=(v)
119
- @filename_quote_characters = v.encode(Reline::IOGate.encoding)
123
+ @filename_quote_characters = v.encode(encoding)
120
124
  end
121
125
 
122
126
  def special_prefixes=(v)
123
- @special_prefixes = v.encode(Reline::IOGate.encoding)
127
+ @special_prefixes = v.encode(encoding)
124
128
  end
125
129
 
126
130
  def completion_case_fold=(v)
@@ -181,20 +185,16 @@ module Reline
181
185
 
182
186
  def input=(val)
183
187
  raise TypeError unless val.respond_to?(:getc) or val.nil?
184
- if val.respond_to?(:getc)
185
- if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
186
- Reline::ANSI.input = val
187
- elsif Reline::IOGate == Reline::GeneralIO
188
- Reline::GeneralIO.input = val
189
- end
188
+ if val.respond_to?(:getc) && io_gate.respond_to?(:input=)
189
+ io_gate.input = val
190
190
  end
191
191
  end
192
192
 
193
193
  def output=(val)
194
194
  raise TypeError unless val.respond_to?(:write) or val.nil?
195
195
  @output = val
196
- if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
197
- Reline::ANSI.output = val
196
+ if io_gate.respond_to?(:output=)
197
+ io_gate.output = val
198
198
  end
199
199
  end
200
200
 
@@ -217,7 +217,7 @@ module Reline
217
217
  end
218
218
 
219
219
  def get_screen_size
220
- Reline::IOGate.get_screen_size
220
+ io_gate.get_screen_size
221
221
  end
222
222
 
223
223
  Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
@@ -260,7 +260,7 @@ module Reline
260
260
  pos: cursor_pos_to_render,
261
261
  contents: result,
262
262
  scrollbar: true,
263
- height: 15,
263
+ height: [15, preferred_dialog_height].min,
264
264
  bg_color: 46,
265
265
  pointer_bg_color: 45,
266
266
  fg_color: 37,
@@ -270,7 +270,8 @@ module Reline
270
270
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
271
271
 
272
272
  def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
273
- Reline::IOGate.with_raw_input do
273
+ Reline.update_iogate
274
+ io_gate.with_raw_input do
274
275
  unless confirm_multiline_termination
275
276
  raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
276
277
  end
@@ -288,6 +289,7 @@ module Reline
288
289
  end
289
290
 
290
291
  def readline(prompt = '', add_hist = false)
292
+ Reline.update_iogate
291
293
  inner_readline(prompt, add_hist, false)
292
294
 
293
295
  line = line_editor.line.dup
@@ -302,7 +304,7 @@ module Reline
302
304
 
303
305
  private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
304
306
  if ENV['RELINE_STDERR_TTY']
305
- if Reline::IOGate.win?
307
+ if io_gate.win?
306
308
  $stderr = File.open(ENV['RELINE_STDERR_TTY'], 'a')
307
309
  else
308
310
  $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
@@ -310,10 +312,10 @@ module Reline
310
312
  $stderr.sync = true
311
313
  $stderr.puts "Reline is used by #{Process.pid}"
312
314
  end
313
- otio = Reline::IOGate.prep
315
+ otio = io_gate.prep
314
316
 
315
317
  may_req_ambiguous_char_width
316
- line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
318
+ line_editor.reset(prompt, encoding: encoding)
317
319
  if multiline
318
320
  line_editor.multiline_on
319
321
  if block_given?
@@ -337,7 +339,7 @@ module Reline
337
339
  unless config.test_mode
338
340
  config.read
339
341
  config.reset_default_key_bindings
340
- Reline::IOGate.set_default_key_bindings(config)
342
+ io_gate.set_default_key_bindings(config)
341
343
  end
342
344
 
343
345
  line_editor.rerender
@@ -346,9 +348,9 @@ module Reline
346
348
  line_editor.set_signal_handlers
347
349
  prev_pasting_state = false
348
350
  loop do
349
- prev_pasting_state = Reline::IOGate.in_pasting?
351
+ prev_pasting_state = io_gate.in_pasting?
350
352
  read_io(config.keyseq_timeout) { |inputs|
351
- line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
353
+ line_editor.set_pasting_state(io_gate.in_pasting?)
352
354
  inputs.each { |c|
353
355
  line_editor.input_key(c)
354
356
  line_editor.rerender
@@ -358,29 +360,29 @@ module Reline
358
360
  @bracketed_paste_finished = false
359
361
  end
360
362
  }
361
- if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
363
+ if prev_pasting_state == true and not io_gate.in_pasting? and not line_editor.finished?
362
364
  line_editor.set_pasting_state(false)
363
365
  prev_pasting_state = false
364
366
  line_editor.rerender_all
365
367
  end
366
368
  break if line_editor.finished?
367
369
  end
368
- Reline::IOGate.move_cursor_column(0)
370
+ io_gate.move_cursor_column(0)
369
371
  rescue Errno::EIO
370
372
  # Maybe the I/O has been closed.
371
373
  rescue StandardError => e
372
374
  line_editor.finalize
373
- Reline::IOGate.deprep(otio)
375
+ io_gate.deprep(otio)
374
376
  raise e
375
377
  rescue Exception
376
378
  # Including Interrupt
377
379
  line_editor.finalize
378
- Reline::IOGate.deprep(otio)
380
+ io_gate.deprep(otio)
379
381
  raise
380
382
  end
381
383
 
382
384
  line_editor.finalize
383
- Reline::IOGate.deprep(otio)
385
+ io_gate.deprep(otio)
384
386
  end
385
387
 
386
388
  # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
@@ -395,7 +397,7 @@ module Reline
395
397
  private def read_io(keyseq_timeout, &block)
396
398
  buffer = []
397
399
  loop do
398
- c = Reline::IOGate.getc
400
+ c = io_gate.getc
399
401
  if c == -1
400
402
  result = :unmatched
401
403
  @bracketed_paste_finished = true
@@ -435,7 +437,7 @@ module Reline
435
437
  begin
436
438
  succ_c = nil
437
439
  Timeout.timeout(keyseq_timeout / 1000.0) {
438
- succ_c = Reline::IOGate.getc
440
+ succ_c = io_gate.getc
439
441
  }
440
442
  rescue Timeout::Error # cancel matching only when first byte
441
443
  block.([Reline::Key.new(c, c, false)])
@@ -450,7 +452,7 @@ module Reline
450
452
  end
451
453
  return :break
452
454
  when :matching
453
- Reline::IOGate.ungetc(succ_c)
455
+ io_gate.ungetc(succ_c)
454
456
  return :next
455
457
  when :matched
456
458
  buffer << succ_c
@@ -467,7 +469,7 @@ module Reline
467
469
  begin
468
470
  escaped_c = nil
469
471
  Timeout.timeout(keyseq_timeout / 1000.0) {
470
- escaped_c = Reline::IOGate.getc
472
+ escaped_c = io_gate.getc
471
473
  }
472
474
  rescue Timeout::Error # independent ESC
473
475
  block.([Reline::Key.new(c, c, false)])
@@ -490,19 +492,19 @@ module Reline
490
492
  end
491
493
 
492
494
  private def may_req_ambiguous_char_width
493
- @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or !STDOUT.tty?
495
+ @ambiguous_width = 2 if io_gate == Reline::GeneralIO or !STDOUT.tty?
494
496
  return if defined? @ambiguous_width
495
- Reline::IOGate.move_cursor_column(0)
497
+ io_gate.move_cursor_column(0)
496
498
  begin
497
499
  output.write "\u{25bd}"
498
500
  rescue Encoding::UndefinedConversionError
499
501
  # LANG=C
500
502
  @ambiguous_width = 1
501
503
  else
502
- @ambiguous_width = Reline::IOGate.cursor_pos.x
504
+ @ambiguous_width = io_gate.cursor_pos.x
503
505
  end
504
- Reline::IOGate.move_cursor_column(0)
505
- Reline::IOGate.erase_after_cursor
506
+ io_gate.move_cursor_column(0)
507
+ io_gate.erase_after_cursor
506
508
  end
507
509
  end
508
510
 
@@ -565,7 +567,7 @@ module Reline
565
567
  @core ||= Core.new { |core|
566
568
  core.config = Reline::Config.new
567
569
  core.key_stroke = Reline::KeyStroke.new(core.config)
568
- core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
570
+ core.line_editor = Reline::LineEditor.new(core.config, core.encoding)
569
571
 
570
572
  core.basic_word_break_characters = " \t\n`><=;|&{("
571
573
  core.completer_word_break_characters = " \t\n`><=;|&{("
@@ -578,12 +580,24 @@ module Reline
578
580
  end
579
581
 
580
582
  def self.ungetc(c)
581
- Reline::IOGate.ungetc(c)
583
+ core.io_gate.ungetc(c)
582
584
  end
583
585
 
584
586
  def self.line_editor
585
587
  core.line_editor
586
588
  end
589
+
590
+ def self.update_iogate
591
+ return if core.config.test_mode
592
+
593
+ # Need to change IOGate when `$stdout.tty?` change from false to true by `$stdout.reopen`
594
+ # Example: rails/spring boot the application in non-tty, then run console in tty.
595
+ if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
596
+ require 'reline/ansi'
597
+ remove_const(:IOGate)
598
+ const_set(:IOGate, Reline::ANSI)
599
+ end
600
+ end
587
601
  end
588
602
 
589
603
  require 'reline/general_io'
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.3.4
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-20 00:00:00.000000000 Z
11
+ date: 2023-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console