reline 0.5.7 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
data/lib/reline.rb CHANGED
@@ -7,6 +7,7 @@ require 'reline/key_stroke'
7
7
  require 'reline/line_editor'
8
8
  require 'reline/history'
9
9
  require 'reline/terminfo'
10
+ require 'reline/io'
10
11
  require 'reline/face'
11
12
  require 'rbconfig'
12
13
 
@@ -18,20 +19,10 @@ module Reline
18
19
  class ConfigEncodingConversionError < StandardError; end
19
20
 
20
21
  Key = Struct.new(:char, :combined_char, :with_meta) do
21
- def match?(other)
22
- case other
23
- when Reline::Key
24
- (other.char.nil? or char.nil? or char == other.char) and
25
- (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
26
- (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
27
- when Integer, Symbol
28
- (combined_char and combined_char == other) or
29
- (combined_char.nil? and char and char == other)
30
- else
31
- false
32
- end
22
+ # For dialog_proc `key.match?(dialog.name)`
23
+ def match?(sym)
24
+ combined_char.is_a?(Symbol) && combined_char == sym
33
25
  end
34
- alias_method :==, :match?
35
26
  end
36
27
  CursorPos = Struct.new(:x, :y)
37
28
  DialogRenderInfo = Struct.new(
@@ -263,7 +254,6 @@ module Reline
263
254
  raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
264
255
  end
265
256
 
266
- Reline.update_iogate
267
257
  io_gate.with_raw_input do
268
258
  inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
269
259
  end
@@ -286,7 +276,6 @@ module Reline
286
276
 
287
277
  def readline(prompt = '', add_hist = false)
288
278
  @mutex.synchronize do
289
- Reline.update_iogate
290
279
  io_gate.with_raw_input do
291
280
  inner_readline(prompt, add_hist, false)
292
281
  end
@@ -336,7 +325,7 @@ module Reline
336
325
  line_editor.auto_indent_proc = auto_indent_proc
337
326
  line_editor.dig_perfect_match_proc = dig_perfect_match_proc
338
327
  pre_input_hook&.call
339
- unless Reline::IOGate == Reline::GeneralIO
328
+ unless Reline::IOGate.dumb?
340
329
  @dialog_proc_list.each_pair do |name_sym, d|
341
330
  line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
342
331
  end
@@ -378,92 +367,39 @@ module Reline
378
367
  end
379
368
  end
380
369
 
381
- # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
382
- # is followed by a character, and times out and treats it as a standalone
383
- # ESC if the second character does not arrive. If the second character
384
- # comes before timed out, it is treated as a modifier key with the
385
- # meta-property of meta-key, so that it can be distinguished from
386
- # multibyte characters with the 8th bit turned on.
387
- #
388
- # GNU Readline will wait for the 2nd character with "keyseq-timeout"
389
- # milli-seconds but wait forever after 3rd characters.
370
+ # GNU Readline watis for "keyseq-timeout" milliseconds when the input is
371
+ # ambiguous whether it is matching or matched.
372
+ # If the next character does not arrive within the specified timeout, input
373
+ # is considered as matched.
374
+ # `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
375
+ # `ESC char` or part of CSI sequence (matching).
390
376
  private def read_io(keyseq_timeout, &block)
391
377
  buffer = []
378
+ status = KeyStroke::MATCHING
392
379
  loop do
393
- c = io_gate.getc(Float::INFINITY)
394
- if c == -1
395
- result = :unmatched
396
- else
397
- buffer << c
398
- result = key_stroke.match_status(buffer)
399
- end
400
- case result
401
- when :matched
402
- expanded = key_stroke.expand(buffer).map{ |expanded_c|
403
- Reline::Key.new(expanded_c, expanded_c, false)
404
- }
405
- block.(expanded)
406
- break
407
- when :matching
408
- if buffer.size == 1
409
- case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
410
- when :break then break
411
- when :next then next
412
- end
413
- end
414
- when :unmatched
415
- if buffer.size == 1 and c == "\e".ord
416
- read_escaped_key(keyseq_timeout, c, block)
380
+ timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
381
+ c = io_gate.getc(timeout)
382
+ if c.nil? || c == -1
383
+ if status == KeyStroke::MATCHING_MATCHED
384
+ status = KeyStroke::MATCHED
385
+ elsif buffer.empty?
386
+ # io_gate is closed and reached EOF
387
+ block.call([Key.new(nil, nil, false)])
388
+ return
417
389
  else
418
- expanded = buffer.map{ |expanded_c|
419
- Reline::Key.new(expanded_c, expanded_c, false)
420
- }
421
- block.(expanded)
390
+ status = KeyStroke::UNMATCHED
422
391
  end
423
- break
392
+ else
393
+ buffer << c
394
+ status = key_stroke.match_status(buffer)
424
395
  end
425
- end
426
- end
427
396
 
428
- private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
429
- succ_c = io_gate.getc(keyseq_timeout.fdiv(1000))
430
- if succ_c
431
- case key_stroke.match_status(buffer.dup.push(succ_c))
432
- when :unmatched
433
- if c == "\e".ord
434
- block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
435
- else
436
- block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
437
- end
438
- return :break
439
- when :matching
440
- io_gate.ungetc(succ_c)
441
- return :next
442
- when :matched
443
- buffer << succ_c
444
- expanded = key_stroke.expand(buffer).map{ |expanded_c|
445
- Reline::Key.new(expanded_c, expanded_c, false)
446
- }
447
- block.(expanded)
448
- return :break
397
+ if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
398
+ expanded, rest_bytes = key_stroke.expand(buffer)
399
+ rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
400
+ block.call(expanded)
401
+ return
449
402
  end
450
- else
451
- block.([Reline::Key.new(c, c, false)])
452
- return :break
453
- end
454
- end
455
-
456
- private def read_escaped_key(keyseq_timeout, c, block)
457
- escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000))
458
-
459
- if escaped_c.nil?
460
- block.([Reline::Key.new(c, c, false)])
461
- elsif escaped_c >= 128 # maybe, first byte of multi byte
462
- block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
463
- elsif escaped_c == "\e".ord # escape twice
464
- block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
465
- else
466
- block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
467
403
  end
468
404
  end
469
405
 
@@ -473,7 +409,7 @@ module Reline
473
409
  end
474
410
 
475
411
  private def may_req_ambiguous_char_width
476
- @ambiguous_width = 2 if io_gate == Reline::GeneralIO or !STDOUT.tty?
412
+ @ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
477
413
  return if defined? @ambiguous_width
478
414
  io_gate.move_cursor_column(0)
479
415
  begin
@@ -567,37 +503,13 @@ module Reline
567
503
  def self.line_editor
568
504
  core.line_editor
569
505
  end
506
+ end
570
507
 
571
- def self.update_iogate
572
- return if core.config.test_mode
573
508
 
574
- # Need to change IOGate when `$stdout.tty?` change from false to true by `$stdout.reopen`
575
- # Example: rails/spring boot the application in non-tty, then run console in tty.
576
- if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
577
- require 'reline/ansi'
578
- remove_const(:IOGate)
579
- const_set(:IOGate, Reline::ANSI)
580
- end
581
- end
582
- end
509
+ Reline::IOGate = Reline::IO.decide_io_gate
583
510
 
584
- require 'reline/general_io'
585
- io = Reline::GeneralIO
586
- unless ENV['TERM'] == 'dumb'
587
- case RbConfig::CONFIG['host_os']
588
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
589
- require 'reline/windows'
590
- tty = (io = Reline::Windows).msys_tty?
591
- else
592
- tty = $stdout.tty?
593
- end
594
- end
595
- Reline::IOGate = if tty
596
- require 'reline/ansi'
597
- Reline::ANSI
598
- else
599
- io
600
- end
511
+ # Deprecated
512
+ Reline::GeneralIO = Reline::Dumb.new
601
513
 
602
514
  Reline::Face.load_initial_configs
603
515
 
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.5.7
4
+ version: 0.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-14 00:00:00.000000000 Z
11
+ date: 2024-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -35,13 +35,16 @@ files:
35
35
  - COPYING
36
36
  - README.md
37
37
  - lib/reline.rb
38
- - lib/reline/ansi.rb
39
38
  - lib/reline/config.rb
40
39
  - lib/reline/face.rb
41
- - lib/reline/general_io.rb
42
40
  - lib/reline/history.rb
41
+ - lib/reline/io.rb
42
+ - lib/reline/io/ansi.rb
43
+ - lib/reline/io/dumb.rb
44
+ - lib/reline/io/windows.rb
43
45
  - lib/reline/key_actor.rb
44
46
  - lib/reline/key_actor/base.rb
47
+ - lib/reline/key_actor/composite.rb
45
48
  - lib/reline/key_actor/emacs.rb
46
49
  - lib/reline/key_actor/vi_command.rb
47
50
  - lib/reline/key_actor/vi_insert.rb
@@ -52,7 +55,6 @@ files:
52
55
  - lib/reline/unicode.rb
53
56
  - lib/reline/unicode/east_asian_width.rb
54
57
  - lib/reline/version.rb
55
- - lib/reline/windows.rb
56
58
  - license_of_rb-readline
57
59
  homepage: https://github.com/ruby/reline
58
60
  licenses:
@@ -1,111 +0,0 @@
1
- require 'io/wait'
2
-
3
- class Reline::GeneralIO
4
- RESET_COLOR = '' # Do not send color reset sequence
5
-
6
- def self.reset(encoding: nil)
7
- @@pasting = false
8
- if encoding
9
- @@encoding = encoding
10
- elsif defined?(@@encoding)
11
- remove_class_variable(:@@encoding)
12
- end
13
- end
14
-
15
- def self.encoding
16
- if defined?(@@encoding)
17
- @@encoding
18
- elsif RUBY_PLATFORM =~ /mswin|mingw/
19
- Encoding::UTF_8
20
- else
21
- Encoding::default_external
22
- end
23
- end
24
-
25
- def self.win?
26
- false
27
- end
28
-
29
- def self.set_default_key_bindings(_)
30
- end
31
-
32
- @@buf = []
33
- @@input = STDIN
34
-
35
- def self.input=(val)
36
- @@input = val
37
- end
38
-
39
- def self.with_raw_input
40
- yield
41
- end
42
-
43
- def self.getc(_timeout_second)
44
- unless @@buf.empty?
45
- return @@buf.shift
46
- end
47
- c = nil
48
- loop do
49
- Reline.core.line_editor.handle_signal
50
- result = @@input.wait_readable(0.1)
51
- next if result.nil?
52
- c = @@input.read(1)
53
- break
54
- end
55
- c&.ord
56
- end
57
-
58
- def self.ungetc(c)
59
- @@buf.unshift(c)
60
- end
61
-
62
- def self.get_screen_size
63
- [24, 80]
64
- end
65
-
66
- def self.cursor_pos
67
- Reline::CursorPos.new(1, 1)
68
- end
69
-
70
- def self.hide_cursor
71
- end
72
-
73
- def self.show_cursor
74
- end
75
-
76
- def self.move_cursor_column(val)
77
- end
78
-
79
- def self.move_cursor_up(val)
80
- end
81
-
82
- def self.move_cursor_down(val)
83
- end
84
-
85
- def self.erase_after_cursor
86
- end
87
-
88
- def self.scroll_down(val)
89
- end
90
-
91
- def self.clear_screen
92
- end
93
-
94
- def self.set_screen_size(rows, columns)
95
- end
96
-
97
- def self.set_winch_handler(&handler)
98
- end
99
-
100
- @@pasting = false
101
-
102
- def self.in_pasting?
103
- @@pasting
104
- end
105
-
106
- def self.prep
107
- end
108
-
109
- def self.deprep(otio)
110
- end
111
- end