reline 0.2.6 → 0.2.8.pre.3

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: fc0f6fb7c331a37907554b292249a75b218646aa14298586790cc09d6c174894
4
- data.tar.gz: 79fd7b502a7ab601f6642964bb0987dae5d0a62bc8cfda016d8806c8b76bb723
3
+ metadata.gz: 92eb26edb27bc79f95c9f54a4396b86e764acb928a4d704db8b8d1016331aa67
4
+ data.tar.gz: 04b7af1f6107bc8cd302494a057e6cfd812c60ec3768b3cd475105d8e119d20c
5
5
  SHA512:
6
- metadata.gz: 2b4300db4d7bef4ab3ddc8f45db07e20e37b371d89e7a21f343dd3c7096209d0c19028def435d584c7bc1f0a9f18d0d6c783b47d28967eb3d34e4d0eaa613490
7
- data.tar.gz: '081a683b1980b9c8d27822e62dcdc776024cc408e3f93b0c999f8da2c6b2fef92c4eded142f7bee8f95fcd7a18fc8431a87f2cd19d1c1064fa677f7de606dcf0'
6
+ metadata.gz: 40503d95634408feb981bcb3448679ed6c847123465b5b965399c75c4bbc9ac0ddbb5422386d209613e45b34a85f2ecb275fac7587272da88de7a16b2feb40b0
7
+ data.tar.gz: '030383e1c77101f296344c794443439af32c6fd7f2f86f0230666287df901e5aea9f25d78242ab9ea16253ab17faa97c02fc234137e166a71edbac2de2f44f16'
data/lib/reline/ansi.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'io/console'
2
+ require 'io/wait'
2
3
  require 'timeout'
3
4
  require_relative 'terminfo'
4
5
 
@@ -36,6 +37,7 @@ class Reline::ANSI
36
37
  # default bindings
37
38
  [27, 32] => :em_set_mark, # M-<space>
38
39
  [24, 24] => :em_exchange_mark, # C-x C-x
40
+ [27, 91, 90] => :completion_journey_up, # S-Tab
39
41
  }.each_pair do |key, func|
40
42
  config.add_default_key_binding_by_keymap(:emacs, key, func)
41
43
  end
@@ -183,12 +185,7 @@ class Reline::ANSI
183
185
  unless @@buf.empty?
184
186
  return false
185
187
  end
186
- rs, = IO.select([@@input], [], [], 0.00001)
187
- if rs and rs[0]
188
- false
189
- else
190
- true
191
- end
188
+ !@@input.wait_readable(0)
192
189
  end
193
190
 
194
191
  def self.ungetc(c)
@@ -197,8 +194,7 @@ class Reline::ANSI
197
194
 
198
195
  def self.retrieve_keybuffer
199
196
  begin
200
- result = select([@@input], [], [], 0.001)
201
- return if result.nil?
197
+ return unless @@input.wait_readable(0.001)
202
198
  str = @@input.read_nonblock(1024)
203
199
  str.bytes.each do |c|
204
200
  @@buf.push(c)
@@ -279,6 +275,22 @@ class Reline::ANSI
279
275
  end
280
276
  end
281
277
 
278
+ def self.hide_cursor
279
+ if Reline::Terminfo.enabled?
280
+ @@output.write Reline::Terminfo.tigetstr('civis')
281
+ else
282
+ # ignored
283
+ end
284
+ end
285
+
286
+ def self.show_cursor
287
+ if Reline::Terminfo.enabled?
288
+ @@output.write Reline::Terminfo.tigetstr('cnorm')
289
+ else
290
+ # ignored
291
+ end
292
+ end
293
+
282
294
  def self.erase_after_cursor
283
295
  @@output.write "\e[K"
284
296
  end
@@ -300,8 +312,6 @@ class Reline::ANSI
300
312
 
301
313
  def self.prep
302
314
  retrieve_keybuffer
303
- int_handle = Signal.trap('INT', 'IGNORE')
304
- Signal.trap('INT', int_handle)
305
315
  nil
306
316
  end
307
317
 
data/lib/reline/config.rb CHANGED
@@ -65,6 +65,7 @@ class Reline::Config
65
65
  @history_size = -1 # unlimited
66
66
  @keyseq_timeout = 500
67
67
  @test_mode = false
68
+ @autocompletion = false
68
69
  end
69
70
 
70
71
  def reset
@@ -74,6 +75,7 @@ class Reline::Config
74
75
  @additional_key_bindings.keys.each do |key|
75
76
  @additional_key_bindings[key].clear
76
77
  end
78
+ reset_default_key_bindings
77
79
  end
78
80
 
79
81
  def editing_mode
@@ -88,6 +90,14 @@ class Reline::Config
88
90
  (val.respond_to?(:any?) ? val : [val]).any?(@editing_mode_label)
89
91
  end
90
92
 
93
+ def autocompletion=(val)
94
+ @autocompletion = val
95
+ end
96
+
97
+ def autocompletion
98
+ @autocompletion
99
+ end
100
+
91
101
  def keymap
92
102
  @key_actors[@keymap_label]
93
103
  end
@@ -157,8 +167,15 @@ class Reline::Config
157
167
  end
158
168
 
159
169
  def read_lines(lines, file = nil)
160
- if lines.first.encoding != Reline.encoding_system_needs
161
- lines = lines.map { |l| l.encode(Reline.encoding_system_needs) }
170
+ if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
171
+ begin
172
+ lines = lines.map do |l|
173
+ l.encode(Reline.encoding_system_needs)
174
+ rescue Encoding::UndefinedConversionError
175
+ mes = "The inputrc encoded in #{lines.first.encoding.name} can't be converted to the locale #{Reline.encoding_system_needs.name}."
176
+ raise Reline::ConfigEncodingConversionError.new(mes)
177
+ end
178
+ end
162
179
  end
163
180
  conditions = [@skip_section, @if_stack]
164
181
  @skip_section = nil
@@ -150,7 +150,8 @@ class Reline::LineEditor
150
150
  @screen_size = Reline::IOGate.get_screen_size
151
151
  @screen_height = @screen_size.first
152
152
  reset_variables(prompt, encoding: encoding)
153
- @old_trap = Signal.trap('SIGINT') {
153
+ @old_trap = Signal.trap(:INT) {
154
+ clear_dialog
154
155
  if @scroll_partial_screen
155
156
  move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
156
157
  else
@@ -158,8 +159,16 @@ class Reline::LineEditor
158
159
  end
159
160
  Reline::IOGate.move_cursor_column(0)
160
161
  scroll_down(1)
161
- @old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
162
- raise Interrupt
162
+ case @old_trap
163
+ when 'DEFAULT', 'SYSTEM_DEFAULT'
164
+ raise Interrupt
165
+ when 'IGNORE'
166
+ # Do nothing
167
+ when 'EXIT'
168
+ exit
169
+ else
170
+ @old_trap.call
171
+ end
163
172
  }
164
173
  Reline::IOGate.set_winch_handler do
165
174
  @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
@@ -241,6 +250,7 @@ class Reline::LineEditor
241
250
  @drop_terminate_spaces = false
242
251
  @in_pasting = false
243
252
  @auto_indent_proc = nil
253
+ @dialogs = []
244
254
  reset_line
245
255
  end
246
256
 
@@ -406,6 +416,7 @@ class Reline::LineEditor
406
416
  Reline::IOGate.erase_after_cursor
407
417
  end
408
418
  @output.flush
419
+ clear_dialog
409
420
  return
410
421
  end
411
422
  new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
@@ -416,6 +427,7 @@ class Reline::LineEditor
416
427
  else
417
428
  if @just_cursor_moving and not @rerender_all
418
429
  rendered = just_move_cursor
430
+ render_dialog((prompt_width + @cursor) % @screen_size.last)
419
431
  @just_cursor_moving = false
420
432
  return
421
433
  elsif @previous_line_index or new_highest_in_this != @highest_in_this
@@ -438,18 +450,20 @@ class Reline::LineEditor
438
450
  new_lines = whole_lines
439
451
  end
440
452
  line = modify_lines(new_lines)[@line_index]
453
+ clear_dialog
441
454
  prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines, prompt)
442
455
  render_partial(prompt, prompt_width, line, @first_line_started_from)
443
456
  move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
444
457
  scroll_down(1)
445
458
  Reline::IOGate.move_cursor_column(0)
446
459
  Reline::IOGate.erase_after_cursor
447
- elsif not rendered
448
- unless @in_pasting
460
+ else
461
+ if not rendered and not @in_pasting
449
462
  line = modify_lines(whole_lines)[@line_index]
450
463
  prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
451
464
  render_partial(prompt, prompt_width, line, @first_line_started_from)
452
465
  end
466
+ render_dialog((prompt_width + @cursor) % @screen_size.last)
453
467
  end
454
468
  @buffer_of_lines[@line_index] = @line
455
469
  @rest_height = 0 if @scroll_partial_screen
@@ -464,6 +478,294 @@ class Reline::LineEditor
464
478
  end
465
479
  end
466
480
 
481
+ class DialogProcScope
482
+ def initialize(line_editor, config, proc_to_exec, context)
483
+ @line_editor = line_editor
484
+ @config = config
485
+ @proc_to_exec = proc_to_exec
486
+ @context = context
487
+ @cursor_pos = Reline::CursorPos.new
488
+ end
489
+
490
+ def context
491
+ @context
492
+ end
493
+
494
+ def retrieve_completion_block(set_completion_quote_character = false)
495
+ @line_editor.retrieve_completion_block(set_completion_quote_character)
496
+ end
497
+
498
+ def call_completion_proc_with_checking_args(pre, target, post)
499
+ @line_editor.call_completion_proc_with_checking_args(pre, target, post)
500
+ end
501
+
502
+ def set_cursor_pos(col, row)
503
+ @cursor_pos.x = col
504
+ @cursor_pos.y = row
505
+ end
506
+
507
+ def cursor_pos
508
+ @cursor_pos
509
+ end
510
+
511
+ def just_cursor_moving
512
+ @line_editor.instance_variable_get(:@just_cursor_moving)
513
+ end
514
+
515
+ def screen_width
516
+ @line_editor.instance_variable_get(:@screen_size).last
517
+ end
518
+
519
+ def completion_journey_data
520
+ @line_editor.instance_variable_get(:@completion_journey_data)
521
+ end
522
+
523
+ def config
524
+ @config
525
+ end
526
+
527
+ def call
528
+ instance_exec(&@proc_to_exec)
529
+ end
530
+ end
531
+
532
+ class Dialog
533
+ attr_reader :name
534
+ attr_accessor :column, :vertical_offset, :contents, :lines_backup
535
+
536
+ def initialize(name, proc_scope)
537
+ @name = name
538
+ @proc_scope = proc_scope
539
+ end
540
+
541
+ def set_cursor_pos(col, row)
542
+ @proc_scope.set_cursor_pos(col, row)
543
+ end
544
+
545
+ def call
546
+ @proc_scope.call
547
+ end
548
+ end
549
+
550
+ def add_dialog_proc(name, p, context = nil)
551
+ return if @dialogs.any? { |d| d.name == name }
552
+ @dialogs << Dialog.new(name, DialogProcScope.new(self, @config, p, context))
553
+ end
554
+
555
+ DIALOG_HEIGHT = 20
556
+ DIALOG_WIDTH = 40
557
+ private def render_dialog(cursor_column)
558
+ @dialogs.each do |dialog|
559
+ render_each_dialog(dialog, cursor_column)
560
+ end
561
+ end
562
+
563
+ private def render_each_dialog(dialog, cursor_column)
564
+ if @in_pasting
565
+ dialog.contents = nil
566
+ return
567
+ end
568
+ dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
569
+ pos, result, pointer, bg = dialog.call
570
+ old_dialog_contents = dialog.contents
571
+ old_dialog_column = dialog.column
572
+ old_dialog_vertical_offset = dialog.vertical_offset
573
+ if result and not result.empty?
574
+ dialog.contents = result
575
+ dialog.contents = dialog.contents[0...DIALOG_HEIGHT] if dialog.contents.size > DIALOG_HEIGHT
576
+ else
577
+ dialog.lines_backup = {
578
+ lines: modify_lines(whole_lines),
579
+ line_index: @line_index,
580
+ first_line_started_from: @first_line_started_from,
581
+ started_from: @started_from,
582
+ byte_pointer: @byte_pointer
583
+ }
584
+ clear_each_dialog(dialog)
585
+ dialog.contents = nil
586
+ return
587
+ end
588
+ upper_space = @first_line_started_from - @started_from
589
+ lower_space = @highest_in_all - @first_line_started_from - @started_from - 1
590
+ dialog.column = pos.x
591
+ diff = (dialog.column + DIALOG_WIDTH) - (@screen_size.last - 1)
592
+ if diff > 0
593
+ dialog.column -= diff
594
+ end
595
+ if (lower_space + @rest_height) >= DIALOG_HEIGHT
596
+ dialog.vertical_offset = pos.y + 1
597
+ elsif upper_space >= DIALOG_HEIGHT
598
+ dialog.vertical_offset = pos.y + -(DIALOG_HEIGHT + 1)
599
+ else
600
+ if (lower_space + @rest_height) < DIALOG_HEIGHT
601
+ scroll_down(DIALOG_HEIGHT)
602
+ move_cursor_up(DIALOG_HEIGHT)
603
+ end
604
+ dialog.vertical_offset = pos.y + 1
605
+ end
606
+ Reline::IOGate.hide_cursor
607
+ reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
608
+ move_cursor_down(dialog.vertical_offset)
609
+ Reline::IOGate.move_cursor_column(dialog.column)
610
+ dialog.contents.each_with_index do |item, i|
611
+ if i == pointer
612
+ bg_color = '45'
613
+ else
614
+ if bg
615
+ bg_color = bg
616
+ else
617
+ bg_color = '46'
618
+ end
619
+ end
620
+ @output.write "\e[#{bg_color}m%-#{DIALOG_WIDTH}s\e[49m" % item.slice(0, DIALOG_WIDTH)
621
+ Reline::IOGate.move_cursor_column(dialog.column)
622
+ move_cursor_down(1) if i < (dialog.contents.size - 1)
623
+ end
624
+ Reline::IOGate.move_cursor_column(cursor_column)
625
+ move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
626
+ Reline::IOGate.show_cursor
627
+ dialog.lines_backup = {
628
+ lines: modify_lines(whole_lines),
629
+ line_index: @line_index,
630
+ first_line_started_from: @first_line_started_from,
631
+ started_from: @started_from,
632
+ byte_pointer: @byte_pointer
633
+ }
634
+ end
635
+
636
+ private def reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
637
+ return if dialog.lines_backup.nil? or old_dialog_contents.nil?
638
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
639
+ visual_lines = []
640
+ visual_start = nil
641
+ dialog.lines_backup[:lines].each_with_index { |l, i|
642
+ pr = prompt_list ? prompt_list[i] : prompt
643
+ vl, _ = split_by_width(pr + l, @screen_size.last)
644
+ vl.compact!
645
+ if i == dialog.lines_backup[:line_index]
646
+ visual_start = visual_lines.size + dialog.lines_backup[:started_from]
647
+ end
648
+ visual_lines.concat(vl)
649
+ }
650
+ old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
651
+ y = @first_line_started_from + @started_from
652
+ y_diff = y - old_y
653
+ if (old_y + old_dialog_vertical_offset) < (y + dialog.vertical_offset)
654
+ # rerender top
655
+ move_cursor_down(old_dialog_vertical_offset - y_diff)
656
+ start = visual_start + old_dialog_vertical_offset
657
+ line_num = dialog.vertical_offset - old_dialog_vertical_offset
658
+ line_num.times do |i|
659
+ Reline::IOGate.move_cursor_column(old_dialog_column)
660
+ if visual_lines[start + i].nil?
661
+ s = ' ' * DIALOG_WIDTH
662
+ else
663
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, DIALOG_WIDTH)
664
+ end
665
+ @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % s
666
+ move_cursor_down(1) if i < (line_num - 1)
667
+ end
668
+ move_cursor_up(old_dialog_vertical_offset + line_num - 1 - y_diff)
669
+ end
670
+ if (old_y + old_dialog_vertical_offset + old_dialog_contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
671
+ # rerender bottom
672
+ move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
673
+ start = visual_start + dialog.vertical_offset + dialog.contents.size
674
+ line_num = (old_dialog_vertical_offset + old_dialog_contents.size) - (dialog.vertical_offset + dialog.contents.size)
675
+ line_num.times do |i|
676
+ Reline::IOGate.move_cursor_column(old_dialog_column)
677
+ if visual_lines[start + i].nil?
678
+ s = ' ' * DIALOG_WIDTH
679
+ else
680
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, DIALOG_WIDTH)
681
+ end
682
+ @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % s
683
+ move_cursor_down(1) if i < (line_num - 1)
684
+ end
685
+ move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
686
+ end
687
+ if old_dialog_column < dialog.column
688
+ # rerender left
689
+ move_cursor_down(old_dialog_vertical_offset - y_diff)
690
+ width = dialog.column - old_dialog_column
691
+ start = visual_start + old_dialog_vertical_offset
692
+ line_num = old_dialog_contents.size
693
+ line_num.times do |i|
694
+ Reline::IOGate.move_cursor_column(old_dialog_column)
695
+ if visual_lines[start + i].nil?
696
+ s = ' ' * width
697
+ else
698
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, width)
699
+ end
700
+ @output.write "\e[39m\e[49m%-#{width}s\e[39m\e[49m" % s
701
+ move_cursor_down(1) if i < (line_num - 1)
702
+ end
703
+ move_cursor_up(old_dialog_vertical_offset + line_num - 1 - y_diff)
704
+ end
705
+ if (old_dialog_column + DIALOG_WIDTH) > (dialog.column + DIALOG_WIDTH)
706
+ # rerender right
707
+ move_cursor_down(old_dialog_vertical_offset + y_diff)
708
+ width = (old_dialog_column + DIALOG_WIDTH) - (dialog.column + DIALOG_WIDTH)
709
+ start = visual_start + old_dialog_vertical_offset
710
+ line_num = old_dialog_contents.size
711
+ line_num.times do |i|
712
+ Reline::IOGate.move_cursor_column(old_dialog_column + DIALOG_WIDTH)
713
+ if visual_lines[start + i].nil?
714
+ s = ' ' * width
715
+ else
716
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column + DIALOG_WIDTH, width)
717
+ end
718
+ Reline::IOGate.move_cursor_column(dialog.column + DIALOG_WIDTH)
719
+ @output.write "\e[39m\e[49m%-#{width}s\e[39m\e[49m" % s
720
+ move_cursor_down(1) if i < (line_num - 1)
721
+ end
722
+ move_cursor_up(old_dialog_vertical_offset + line_num - 1 + y_diff)
723
+ end
724
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
725
+ end
726
+
727
+ private def clear_dialog
728
+ @dialogs.each do |dialog|
729
+ clear_each_dialog(dialog)
730
+ end
731
+ end
732
+
733
+ private def clear_each_dialog(dialog)
734
+ return unless dialog.contents
735
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
736
+ visual_lines = []
737
+ visual_lines_under_dialog = []
738
+ visual_start = nil
739
+ dialog.lines_backup[:lines].each_with_index { |l, i|
740
+ pr = prompt_list ? prompt_list[i] : prompt
741
+ vl, _ = split_by_width(pr + l, @screen_size.last)
742
+ vl.compact!
743
+ if i == dialog.lines_backup[:line_index]
744
+ visual_start = visual_lines.size + dialog.lines_backup[:started_from] + dialog.vertical_offset
745
+ end
746
+ visual_lines.concat(vl)
747
+ }
748
+ visual_lines_under_dialog = visual_lines[visual_start, dialog.contents.size]
749
+ visual_lines_under_dialog = [] if visual_lines_under_dialog.nil?
750
+ Reline::IOGate.hide_cursor
751
+ move_cursor_down(dialog.vertical_offset)
752
+ dialog_vertical_size = dialog.contents.size
753
+ dialog_vertical_size.times do |i|
754
+ if i < visual_lines_under_dialog.size
755
+ Reline::IOGate.move_cursor_column(0)
756
+ @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % visual_lines_under_dialog[i]
757
+ else
758
+ Reline::IOGate.move_cursor_column(dialog.column)
759
+ @output.write "\e[39m\e[49m#{' ' * DIALOG_WIDTH}\e[39m\e[49m"
760
+ end
761
+ Reline::IOGate.erase_after_cursor
762
+ move_cursor_down(1) if i < (dialog_vertical_size - 1)
763
+ end
764
+ move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
765
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
766
+ Reline::IOGate.show_cursor
767
+ end
768
+
467
769
  private def calculate_scroll_partial_screen(highest_in_all, cursor_y)
468
770
  if @screen_height < highest_in_all
469
771
  old_scroll_partial_screen = @scroll_partial_screen
@@ -924,6 +1226,16 @@ class Reline::LineEditor
924
1226
  @completion_journey_data = CompletionJourneyData.new(
925
1227
  preposing, postposing,
926
1228
  [target] + list.select{ |item| item.start_with?(target) }, 0)
1229
+ if @completion_journey_data.list.size == 1
1230
+ @completion_journey_data.pointer = 0
1231
+ else
1232
+ case direction
1233
+ when :up
1234
+ @completion_journey_data.pointer = @completion_journey_data.list.size - 1
1235
+ when :down
1236
+ @completion_journey_data.pointer = 1
1237
+ end
1238
+ end
927
1239
  @completion_state = CompletionState::JOURNEY
928
1240
  else
929
1241
  case direction
@@ -938,13 +1250,13 @@ class Reline::LineEditor
938
1250
  @completion_journey_data.pointer = 0
939
1251
  end
940
1252
  end
941
- completed = @completion_journey_data.list[@completion_journey_data.pointer]
942
- @line = @completion_journey_data.preposing + completed + @completion_journey_data.postposing
943
- line_to_pointer = @completion_journey_data.preposing + completed
944
- @cursor_max = calculate_width(@line)
945
- @cursor = calculate_width(line_to_pointer)
946
- @byte_pointer = line_to_pointer.bytesize
947
1253
  end
1254
+ completed = @completion_journey_data.list[@completion_journey_data.pointer]
1255
+ @line = @completion_journey_data.preposing + completed + @completion_journey_data.postposing
1256
+ line_to_pointer = @completion_journey_data.preposing + completed
1257
+ @cursor_max = calculate_width(@line)
1258
+ @cursor = calculate_width(line_to_pointer)
1259
+ @byte_pointer = line_to_pointer.bytesize
948
1260
  end
949
1261
 
950
1262
  private def run_for_operators(key, method_symbol, &block)
@@ -1119,7 +1431,20 @@ class Reline::LineEditor
1119
1431
  if result.is_a?(Array)
1120
1432
  completion_occurs = true
1121
1433
  process_insert
1122
- complete(result)
1434
+ if @config.autocompletion
1435
+ move_completed_list(result, :down)
1436
+ else
1437
+ complete(result)
1438
+ end
1439
+ end
1440
+ end
1441
+ elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
1442
+ if not @config.disable_completion and @config.autocompletion
1443
+ result = call_completion_proc
1444
+ if result.is_a?(Array)
1445
+ completion_occurs = true
1446
+ process_insert
1447
+ move_completed_list(result, :up)
1123
1448
  end
1124
1449
  end
1125
1450
  elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
@@ -1138,6 +1463,7 @@ class Reline::LineEditor
1138
1463
  end
1139
1464
  unless completion_occurs
1140
1465
  @completion_state = CompletionState::NORMAL
1466
+ @completion_journey_data = nil
1141
1467
  end
1142
1468
  if not @in_pasting and @just_cursor_moving.nil?
1143
1469
  if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
@@ -1157,7 +1483,13 @@ class Reline::LineEditor
1157
1483
 
1158
1484
  def call_completion_proc
1159
1485
  result = retrieve_completion_block(true)
1160
- preposing, target, postposing = result
1486
+ pre, target, post = result
1487
+ result = call_completion_proc_with_checking_args(pre, target, post)
1488
+ Reline.core.instance_variable_set(:@completion_quote_character, nil)
1489
+ result
1490
+ end
1491
+
1492
+ def call_completion_proc_with_checking_args(pre, target, post)
1161
1493
  if @completion_proc and target
1162
1494
  argnum = @completion_proc.parameters.inject(0) { |result, item|
1163
1495
  case item.first
@@ -1171,12 +1503,11 @@ class Reline::LineEditor
1171
1503
  when 1
1172
1504
  result = @completion_proc.(target)
1173
1505
  when 2
1174
- result = @completion_proc.(target, preposing)
1506
+ result = @completion_proc.(target, pre)
1175
1507
  when 3..Float::INFINITY
1176
- result = @completion_proc.(target, preposing, postposing)
1508
+ result = @completion_proc.(target, pre, post)
1177
1509
  end
1178
1510
  end
1179
- Reline.core.instance_variable_set(:@completion_quote_character, nil)
1180
1511
  result
1181
1512
  end
1182
1513
 
@@ -6,12 +6,39 @@ module Reline::Terminfo
6
6
 
7
7
  class TerminfoError < StandardError; end
8
8
 
9
- @curses_dl = nil
9
+ def self.curses_dl_files
10
+ case RUBY_PLATFORM
11
+ when /mingw/, /mswin/
12
+ # aren't supported
13
+ []
14
+ when /cygwin/
15
+ %w[cygncursesw-10.dll cygncurses-10.dll]
16
+ when /darwin/
17
+ %w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
18
+ else
19
+ %w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
20
+ end
21
+ end
22
+
23
+ @curses_dl = false
10
24
  def self.curses_dl
11
- return @curses_dl if @curses_dl
12
- if Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
25
+ return @curses_dl unless @curses_dl == false
26
+ if RUBY_VERSION >= '3.0.0'
27
+ # Gem module isn't defined in test-all of the Ruby repository, and
28
+ # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
29
+ fiddle_supports_variadic = true
30
+ elsif Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
13
31
  # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
14
- %w[libncursesw.so libcursesw.so libncurses.so libcurses.so].each do |curses_name|
32
+ fiddle_supports_variadic = true
33
+ else
34
+ fiddle_supports_variadic = false
35
+ end
36
+ if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
37
+ # If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
38
+ fiddle_supports_variadic = false
39
+ end
40
+ if fiddle_supports_variadic
41
+ curses_dl_files.each do |curses_name|
15
42
  result = Fiddle::Handle.new(curses_name)
16
43
  rescue Fiddle::DLError
17
44
  next
@@ -20,6 +47,7 @@ module Reline::Terminfo
20
47
  break
21
48
  end
22
49
  end
50
+ @curses_dl = nil if @curses_dl == false
23
51
  @curses_dl
24
52
  end
25
53
  end
@@ -30,8 +58,15 @@ module Reline::Terminfo
30
58
  @setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
31
59
  #extern 'char *tigetstr(char *capname)'
32
60
  @tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
33
- #extern 'char *tiparm(const char *str, ...)'
34
- @tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
61
+ begin
62
+ #extern 'char *tiparm(const char *str, ...)'
63
+ @tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
64
+ rescue Fiddle::DLError
65
+ # OpenBSD lacks tiparm
66
+ #extern 'char *tparm(const char *str, ...)'
67
+ @tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
68
+ end
69
+ # TODO: add int tigetflag(char *capname) and int tigetnum(char *capname)
35
70
 
36
71
  def self.setupterm(term, fildes)
37
72
  errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
@@ -56,12 +91,19 @@ module Reline::Terminfo
56
91
  end
57
92
  end
58
93
 
59
- def self.tigetstr(capname)
60
- result = @tigetstr.(capname).to_s
61
- def result.tiparm(*args) # for method chain
94
+ class StringWithTiparm < String
95
+ def tiparm(*args) # for method chain
62
96
  Reline::Terminfo.tiparm(self, *args)
63
97
  end
64
- result
98
+ end
99
+
100
+ def self.tigetstr(capname)
101
+ capability = @tigetstr.(capname)
102
+ case capability.to_i
103
+ when 0, -1
104
+ raise TerminfoError, "can't find capability: #{capname}"
105
+ end
106
+ StringWithTiparm.new(capability.to_s)
65
107
  end
66
108
 
67
109
  def self.tiparm(str, *args)
@@ -185,6 +185,36 @@ class Reline::Unicode
185
185
  [lines, height]
186
186
  end
187
187
 
188
+ # Take a chunk of a String with escape sequences.
189
+ def self.take_range(str, col, length, encoding = str.encoding)
190
+ chunk = String.new(encoding: encoding)
191
+ width = 0
192
+ rest = str.encode(Encoding::UTF_8)
193
+ in_zero_width = false
194
+ rest.scan(WIDTH_SCANNER) do |gc|
195
+ case
196
+ when gc[NON_PRINTING_START_INDEX]
197
+ in_zero_width = true
198
+ when gc[NON_PRINTING_END_INDEX]
199
+ in_zero_width = false
200
+ when gc[CSI_REGEXP_INDEX]
201
+ chunk << gc[CSI_REGEXP_INDEX]
202
+ when gc[OSC_REGEXP_INDEX]
203
+ chunk << gc[OSC_REGEXP_INDEX]
204
+ when gc[GRAPHEME_CLUSTER_INDEX]
205
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
206
+ if in_zero_width
207
+ chunk << gc
208
+ else
209
+ width = get_mbchar_width(gc)
210
+ break if (width + length) <= col
211
+ chunk << gc if col <= width
212
+ end
213
+ end
214
+ end
215
+ chunk
216
+ end
217
+
188
218
  def self.get_next_mbchar_size(line, byte_pointer)
189
219
  grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
190
220
  grapheme ? grapheme.bytesize : 0
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.2.6'
2
+ VERSION = '0.2.8.pre.3'
3
3
  end
@@ -42,6 +42,14 @@ class Reline::Windows
42
42
  }.each_pair do |key, func|
43
43
  config.add_default_key_binding_by_keymap(:emacs, key, func)
44
44
  end
45
+
46
+ # Emulate ANSI key sequence.
47
+ {
48
+ [27, 91, 90] => :completion_journey_up, # S-Tab
49
+ }.each_pair do |key, func|
50
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
51
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
52
+ end
45
53
  end
46
54
 
47
55
  if defined? JRUBY_VERSION
@@ -91,6 +99,7 @@ class Reline::Windows
91
99
  VK_LMENU = 0xA4
92
100
  VK_CONTROL = 0x11
93
101
  VK_SHIFT = 0x10
102
+ VK_DIVIDE = 0x6F
94
103
 
95
104
  KEY_EVENT = 0x01
96
105
  WINDOW_BUFFER_SIZE_EVENT = 0x04
@@ -105,6 +114,7 @@ class Reline::Windows
105
114
  SCROLLLOCK_ON = 0x0040
106
115
  SHIFT_PRESSED = 0x0010
107
116
 
117
+ VK_TAB = 0x09
108
118
  VK_END = 0x23
109
119
  VK_HOME = 0x24
110
120
  VK_LEFT = 0x25
@@ -132,9 +142,11 @@ class Reline::Windows
132
142
  @@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
133
143
  @@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
134
144
  @@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
145
+ @@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
135
146
 
136
147
  @@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
137
148
  @@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
149
+ @@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
138
150
  ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
139
151
 
140
152
  private_class_method def self.getconsolemode
@@ -180,51 +192,47 @@ class Reline::Windows
180
192
  name =~ /(msys-|cygwin-).*-pty/ ? true : false
181
193
  end
182
194
 
195
+ KEY_MAP = [
196
+ # It's treated as Meta+Enter on Windows.
197
+ [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
198
+ [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
199
+
200
+ # It's treated as Meta+Space on Windows.
201
+ [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
202
+
203
+ # Emulate getwch() key sequences.
204
+ [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
205
+ [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
206
+ [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
207
+ [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
208
+ [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
209
+ [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
210
+ [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
211
+
212
+ # Emulate ANSI key sequence.
213
+ [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
214
+ ]
215
+
183
216
  def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
184
- char = char_code.chr(Encoding::UTF_8)
185
- if char_code == 0x0D and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED | SHIFT_PRESSED)
186
- # It's treated as Meta+Enter on Windows.
187
- @@output_buf.push("\e".ord)
188
- @@output_buf.push(char_code)
189
- elsif char_code == 0x20 and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
190
- # It's treated as Meta+Space on Windows.
191
- @@output_buf.push("\e".ord)
192
- @@output_buf.push(char_code)
193
- elsif control_key_state.anybits?(LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
194
- @@output_buf.push("\e".ord)
195
- @@output_buf.concat(char.bytes)
196
- elsif control_key_state.anybits?(ENHANCED_KEY)
197
- case virtual_key_code # Emulate getwch() key sequences.
198
- when VK_END
199
- @@output_buf.push(0, 79)
200
- when VK_HOME
201
- @@output_buf.push(0, 71)
202
- when VK_LEFT
203
- @@output_buf.push(0, 75)
204
- when VK_UP
205
- @@output_buf.push(0, 72)
206
- when VK_RIGHT
207
- @@output_buf.push(0, 77)
208
- when VK_DOWN
209
- @@output_buf.push(0, 80)
210
- when VK_DELETE
211
- @@output_buf.push(0, 83)
212
- end
213
- elsif char_code == 0 and control_key_state != 0
214
- # unknown
215
- else
216
- case virtual_key_code
217
- when VK_RETURN
218
- @@output_buf.push("\n".ord)
219
- else
220
- @@output_buf.concat(char.bytes)
221
- end
217
+
218
+ key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
219
+
220
+ match = KEY_MAP.find { |args,| key.matches?(**args) }
221
+ unless match.nil?
222
+ @@output_buf.concat(match.last)
223
+ return
222
224
  end
225
+
226
+ # no char, only control keys
227
+ return if key.char_code == 0 and key.control_keys.any?
228
+
229
+ @@output_buf.concat(key.char.bytes)
223
230
  end
224
231
 
225
232
  def self.check_input_event
226
233
  num_of_events = 0.chr * 8
227
234
  while @@output_buf.empty? #or true
235
+ next if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
228
236
  next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack('L').first == 0
229
237
  input_record = 0.chr * 18
230
238
  read_event = 0.chr * 4
@@ -348,6 +356,20 @@ class Reline::Windows
348
356
  raise NotImplementedError
349
357
  end
350
358
 
359
+ def self.hide_cursor
360
+ size = 100
361
+ visible = 0 # 0 means false
362
+ cursor_info = [size, visible].pack('Li')
363
+ @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
364
+ end
365
+
366
+ def self.show_cursor
367
+ size = 100
368
+ visible = 1 # 1 means true
369
+ cursor_info = [size, visible].pack('Li')
370
+ @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
371
+ end
372
+
351
373
  def self.set_winch_handler(&handler)
352
374
  @@winch_handler = handler
353
375
  end
@@ -360,4 +382,43 @@ class Reline::Windows
360
382
  def self.deprep(otio)
361
383
  # do nothing
362
384
  end
385
+
386
+ class KeyEventRecord
387
+
388
+ attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
389
+
390
+ def initialize(virtual_key_code, char_code, control_key_state)
391
+ @virtual_key_code = virtual_key_code
392
+ @char_code = char_code
393
+ @control_key_state = control_key_state
394
+ @enhanced = control_key_state & ENHANCED_KEY != 0
395
+
396
+ (@control_keys = []).tap do |control_keys|
397
+ # symbols must be sorted to make comparison is easier later on
398
+ control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
399
+ control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
400
+ control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
401
+ end.freeze
402
+ end
403
+
404
+ def char
405
+ @char_code.chr(Encoding::UTF_8)
406
+ end
407
+
408
+ def enhanced?
409
+ @enhanced
410
+ end
411
+
412
+ # Verifies if the arguments match with this key event.
413
+ # Nil arguments are ignored, but at least one must be passed as non-nil.
414
+ # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
415
+ def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
416
+ raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
417
+
418
+ (control_keys.nil? || [*control_keys].sort == @control_keys) &&
419
+ (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
420
+ (char_code.nil? || char_code == @char_code)
421
+ end
422
+
423
+ end
363
424
  end
data/lib/reline.rb CHANGED
@@ -7,12 +7,15 @@ require 'reline/key_actor'
7
7
  require 'reline/key_stroke'
8
8
  require 'reline/line_editor'
9
9
  require 'reline/history'
10
+ require 'reline/terminfo'
10
11
  require 'rbconfig'
11
12
 
12
13
  module Reline
13
14
  FILENAME_COMPLETION_PROC = nil
14
15
  USERNAME_COMPLETION_PROC = nil
15
16
 
17
+ class ConfigEncodingConversionError < StandardError; end
18
+
16
19
  Key = Struct.new('Key', :char, :combined_char, :with_meta)
17
20
  CursorPos = Struct.new(:x, :y)
18
21
 
@@ -41,6 +44,7 @@ module Reline
41
44
 
42
45
  def initialize
43
46
  self.output = STDOUT
47
+ @dialog_proc_list = []
44
48
  yield self
45
49
  @completion_quote_character = nil
46
50
  @bracketed_paste_finished = false
@@ -103,6 +107,14 @@ module Reline
103
107
  @completion_proc = p
104
108
  end
105
109
 
110
+ def autocompletion
111
+ @config.autocompletion
112
+ end
113
+
114
+ def autocompletion=(val)
115
+ @config.autocompletion = val
116
+ end
117
+
106
118
  def output_modifier_proc=(p)
107
119
  raise ArgumentError unless p.respond_to?(:call) or p.nil?
108
120
  @output_modifier_proc = p
@@ -127,6 +139,12 @@ module Reline
127
139
  @dig_perfect_match_proc = p
128
140
  end
129
141
 
142
+ def add_dialog_proc(name_sym, p, context = nil)
143
+ raise ArgumentError unless p.respond_to?(:call) or p.nil?
144
+ raise ArgumentError unless name_sym.instance_of?(Symbol)
145
+ @dialog_proc_list << [name_sym, p, context]
146
+ end
147
+
130
148
  def input=(val)
131
149
  raise TypeError unless val.respond_to?(:getc) or val.nil?
132
150
  if val.respond_to?(:getc)
@@ -168,6 +186,45 @@ module Reline
168
186
  Reline::IOGate.get_screen_size
169
187
  end
170
188
 
189
+ Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
190
+ # autocomplete
191
+ return nil unless config.autocompletion
192
+ if just_cursor_moving and completion_journey_data.nil?
193
+ # Auto complete starts only when edited
194
+ return nil
195
+ end
196
+ pre, target, post= retrieve_completion_block(true)
197
+ if target.nil? or target.empty?# or target.size <= 3
198
+ return nil
199
+ end
200
+ if completion_journey_data and completion_journey_data.list
201
+ result = completion_journey_data.list.dup
202
+ result.shift
203
+ pointer = completion_journey_data.pointer - 1
204
+ else
205
+ result = call_completion_proc_with_checking_args(pre, target, post)
206
+ pointer = nil
207
+ end
208
+ if result and result.size == 1 and result[0] == target
209
+ result = nil
210
+ end
211
+ target_width = Reline::Unicode.calculate_width(target)
212
+ x = cursor_pos.x - target_width
213
+ if x < 0
214
+ x = screen_width + x
215
+ y = -1
216
+ else
217
+ y = 0
218
+ end
219
+ cursor_pos_to_render = Reline::CursorPos.new(x, y)
220
+ if context and context.is_a?(Array)
221
+ context.clear
222
+ context.push(cursor_pos_to_render, result, pointer)
223
+ end
224
+ [cursor_pos_to_render, result, pointer, nil]
225
+ }
226
+ Reline::DEFAULT_DIALOG_CONTEXT = Array.new
227
+
171
228
  def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
172
229
  unless confirm_multiline_termination
173
230
  raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
@@ -227,6 +284,10 @@ module Reline
227
284
  line_editor.auto_indent_proc = auto_indent_proc
228
285
  line_editor.dig_perfect_match_proc = dig_perfect_match_proc
229
286
  line_editor.pre_input_hook = pre_input_hook
287
+ @dialog_proc_list.each do |d|
288
+ name_sym, dialog_proc, context = d
289
+ line_editor.add_dialog_proc(name_sym, dialog_proc, context)
290
+ end
230
291
 
231
292
  unless config.test_mode
232
293
  config.read
@@ -421,6 +482,8 @@ module Reline
421
482
  def_single_delegators :core, :ambiguous_width
422
483
  def_single_delegators :core, :last_incremental_search
423
484
  def_single_delegators :core, :last_incremental_search=
485
+ def_single_delegators :core, :add_dialog_proc
486
+ def_single_delegators :core, :autocompletion, :autocompletion=
424
487
 
425
488
  def_single_delegators :core, :readmultiline
426
489
  def_instance_delegators self, :readmultiline
@@ -442,6 +505,7 @@ module Reline
442
505
  core.completer_quote_characters = '"\''
443
506
  core.filename_quote_characters = ""
444
507
  core.special_prefixes = ""
508
+ core.add_dialog_proc(:autocomplete, Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE, Reline::DEFAULT_DIALOG_CONTEXT)
445
509
  }
446
510
  end
447
511
 
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.2.6
4
+ version: 0.2.8.pre.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-21 00:00:00.000000000 Z
11
+ date: 2021-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -69,11 +69,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
69
  version: '2.5'
70
70
  required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ">="
72
+ - - ">"
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: 1.3.1
75
75
  requirements: []
76
- rubygems_version: 3.2.17
76
+ rubygems_version: 3.2.22
77
77
  signing_key:
78
78
  specification_version: 4
79
79
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.