reline 0.2.8.pre.4 → 0.2.8.pre.8

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: 5e7c5785424de4deda942cdd54cab39bc7d96fd79b1451095626996b875a32d9
4
- data.tar.gz: 3afcf3fc84d2b3d4dd48481bca613a8fc08de049983619772e9fcd502caffa83
3
+ metadata.gz: 6f03d46c602265d3a197f00021df365a9686e4fd0b5d0ef2a037a9ad25143b91
4
+ data.tar.gz: e97bfb610d3c9498e651b25de97e87380e624b56ea970ab7048b25dca7be9488
5
5
  SHA512:
6
- metadata.gz: c1be959cdf8fc499ec71184bc3768964dbc1eb078085bbd8303a6d9b4b0ade3ccd25a8d90486c620316b38c4dfe7b7fb224d99912ff855bd8bc3fc64946f1d5d
7
- data.tar.gz: cfe31c94298208f8cda2c7fddeba8940e71589c60b06167fcb81e8c0d278055ffd94261713d1aa3a2d6031d6572c3dc9194412d15e57f83d0fb81e87361496c0
6
+ metadata.gz: be1a180b58930985ea7ba5d63be81b62c8ffb0b960daf33c5ad984652fa6021151519cc1fa41055c240d7675d628c6749ab69ca67c2c2bfa306a9deab8200c56
7
+ data.tar.gz: 68be299c9815a350c8afec2c5b27aa02905c8fcc04c6fbba331aded2aded1d0dc160d2e8b01be58a91f308b1ad1dd880209e237de770002422910c6014ddc51a
data/lib/reline/config.rb CHANGED
@@ -50,6 +50,7 @@ class Reline::Config
50
50
  @additional_key_bindings[:emacs] = {}
51
51
  @additional_key_bindings[:vi_insert] = {}
52
52
  @additional_key_bindings[:vi_command] = {}
53
+ @oneshot_key_bindings = {}
53
54
  @skip_section = nil
54
55
  @if_stack = nil
55
56
  @editing_mode_label = :emacs
@@ -75,6 +76,7 @@ class Reline::Config
75
76
  @additional_key_bindings.keys.each do |key|
76
77
  @additional_key_bindings[key].clear
77
78
  end
79
+ @oneshot_key_bindings.clear
78
80
  reset_default_key_bindings
79
81
  end
80
82
 
@@ -128,8 +130,12 @@ class Reline::Config
128
130
  return home_rc_path
129
131
  end
130
132
 
133
+ private def default_inputrc_path
134
+ @default_inputrc_path ||= inputrc_path
135
+ end
136
+
131
137
  def read(file = nil)
132
- file ||= inputrc_path
138
+ file ||= default_inputrc_path
133
139
  begin
134
140
  if file.respond_to?(:readlines)
135
141
  lines = file.readlines
@@ -149,7 +155,15 @@ class Reline::Config
149
155
 
150
156
  def key_bindings
151
157
  # override @key_actors[@editing_mode_label].default_key_bindings with @additional_key_bindings[@editing_mode_label]
152
- @key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label])
158
+ @key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label]).merge(@oneshot_key_bindings)
159
+ end
160
+
161
+ def add_oneshot_key_binding(keystroke, target)
162
+ @oneshot_key_bindings[keystroke] = target
163
+ end
164
+
165
+ def reset_oneshot_key_bindings
166
+ @oneshot_key_bindings.clear
153
167
  end
154
168
 
155
169
  def add_default_key_binding_by_keymap(keymap, keystroke, target)
@@ -24,6 +24,7 @@ class Reline::GeneralIO
24
24
  end
25
25
 
26
26
  @@buf = []
27
+ @@input = STDIN
27
28
 
28
29
  def self.input=(val)
29
30
  @@input = val
@@ -1,8 +1,59 @@
1
1
  class Reline::KeyStroke
2
2
  using Module.new {
3
+ refine Integer do
4
+ def ==(other)
5
+ if other.is_a?(Reline::Key)
6
+ if other.combined_char == "\e".ord
7
+ false
8
+ else
9
+ other.combined_char == self
10
+ end
11
+ else
12
+ super
13
+ end
14
+ end
15
+ end
16
+
3
17
  refine Array do
4
18
  def start_with?(other)
5
- other.size <= size && other == self.take(other.size)
19
+ compressed_me = compress_meta_key
20
+ compressed_other = other.compress_meta_key
21
+ i = 0
22
+ loop do
23
+ my_c = compressed_me[i]
24
+ other_c = compressed_other[i]
25
+ other_is_last = (i + 1) == compressed_other.size
26
+ me_is_last = (i + 1) == compressed_me.size
27
+ if my_c != other_c
28
+ if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
29
+ return true
30
+ else
31
+ return false
32
+ end
33
+ elsif other_is_last
34
+ return true
35
+ elsif me_is_last
36
+ return false
37
+ end
38
+ i += 1
39
+ end
40
+ end
41
+
42
+ def ==(other)
43
+ compressed_me = compress_meta_key
44
+ compressed_other = other.compress_meta_key
45
+ compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| i[0] == i[1] }
46
+ end
47
+
48
+ def compress_meta_key
49
+ inject([]) { |result, key|
50
+ if result.size > 0 and result.last == "\e".ord
51
+ result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
52
+ else
53
+ result << key
54
+ end
55
+ result
56
+ }
6
57
  end
7
58
 
8
59
  def bytes
@@ -19,8 +70,8 @@ class Reline::KeyStroke
19
70
  key_mapping.keys.select { |lhs|
20
71
  lhs.start_with? input
21
72
  }.tap { |it|
22
- return :matched if it.size == 1 && (it.max_by(&:size)&.size&.== input.size)
23
- return :matching if it.size == 1 && (it.max_by(&:size)&.size&.!= input.size)
73
+ return :matched if it.size == 1 && (it[0] == input)
74
+ return :matching if it.size == 1 && (it[0] != input)
24
75
  return :matched if it.max_by(&:size)&.size&.< input.size
25
76
  return :matching if it.size > 1
26
77
  }
@@ -32,7 +83,8 @@ class Reline::KeyStroke
32
83
  end
33
84
 
34
85
  def expand(input)
35
- lhs = key_mapping.keys.select { |item| input.start_with? item }.sort_by(&:size).reverse.first
86
+ input = input.compress_meta_key
87
+ lhs = key_mapping.keys.select { |item| input.start_with? item }.sort_by(&:size).last
36
88
  return input unless lhs
37
89
  rhs = key_mapping[lhs]
38
90
 
@@ -251,6 +251,7 @@ class Reline::LineEditor
251
251
  @in_pasting = false
252
252
  @auto_indent_proc = nil
253
253
  @dialogs = []
254
+ @last_key = nil
254
255
  reset_line
255
256
  end
256
257
 
@@ -512,6 +513,14 @@ class Reline::LineEditor
512
513
  @cursor_pos.y = row
513
514
  end
514
515
 
516
+ def set_key(key)
517
+ @key = key
518
+ end
519
+
520
+ def key
521
+ @key
522
+ end
523
+
515
524
  def cursor_pos
516
525
  @cursor_pos
517
526
  end
@@ -538,12 +547,14 @@ class Reline::LineEditor
538
547
  end
539
548
 
540
549
  class Dialog
541
- attr_reader :name
542
- attr_accessor :scroll_top, :column, :vertical_offset, :contents, :lines_backup
550
+ attr_reader :name, :contents, :width
551
+ attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup, :trap_key
543
552
 
544
- def initialize(name, proc_scope)
553
+ def initialize(name, config, proc_scope)
545
554
  @name = name
555
+ @config = config
546
556
  @proc_scope = proc_scope
557
+ @width = nil
547
558
  @scroll_top = 0
548
559
  end
549
560
 
@@ -551,54 +562,61 @@ class Reline::LineEditor
551
562
  @proc_scope.set_cursor_pos(col, row)
552
563
  end
553
564
 
554
- def call
565
+ def width=(v)
566
+ @width = v
567
+ end
568
+
569
+ def contents=(contents)
570
+ @contents = contents
571
+ if contents and @width.nil?
572
+ @width = contents.map{ |line| Reline::Unicode.calculate_width(line, true) }.max
573
+ end
574
+ end
575
+
576
+ def call(key)
555
577
  @proc_scope.set_dialog(self)
556
- @proc_scope.call
578
+ @proc_scope.set_key(key)
579
+ dialog_render_info = @proc_scope.call
580
+ if @trap_key
581
+ if @trap_key.any?{ |i| i.is_a?(Array) } # multiple trap
582
+ @trap_key.each do |t|
583
+ @config.add_oneshot_key_binding(t, @name)
584
+ end
585
+ elsif @trap_key.is_a?(Array)
586
+ @config.add_oneshot_key_binding(@trap_key, @name)
587
+ elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
588
+ @config.add_oneshot_key_binding([@trap_key], @name)
589
+ end
590
+ end
591
+ dialog_render_info
557
592
  end
558
593
  end
559
594
 
560
595
  def add_dialog_proc(name, p, context = nil)
561
596
  return if @dialogs.any? { |d| d.name == name }
562
- @dialogs << Dialog.new(name, DialogProcScope.new(self, @config, p, context))
597
+ @dialogs << Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context))
563
598
  end
564
599
 
565
600
  DIALOG_HEIGHT = 20
566
- DIALOG_WIDTH = 40
567
601
  private def render_dialog(cursor_column)
568
602
  @dialogs.each do |dialog|
569
603
  render_each_dialog(dialog, cursor_column)
570
604
  end
571
605
  end
572
606
 
607
+ private def padding_space_with_escape_sequences(str, width)
608
+ str + (' ' * (width - calculate_width(str, true)))
609
+ end
610
+
573
611
  private def render_each_dialog(dialog, cursor_column)
574
612
  if @in_pasting
575
613
  dialog.contents = nil
614
+ dialog.trap_key = nil
576
615
  return
577
616
  end
578
617
  dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
579
- dialog_render_info = dialog.call
580
- old_dialog_contents = dialog.contents
581
- old_dialog_column = dialog.column
582
- old_dialog_vertical_offset = dialog.vertical_offset
583
- start = 0
584
- if dialog_render_info and dialog_render_info.contents and not dialog_render_info.contents.empty?
585
- height = dialog_render_info.height || DIALOG_HEIGHT
586
- pointer = dialog_render_info.pointer
587
- dialog.contents = dialog_render_info.contents
588
- if dialog.contents.size > height
589
- if dialog_render_info.pointer
590
- if dialog_render_info.pointer < 0
591
- dialog.scroll_top = 0
592
- elsif (dialog_render_info.pointer - dialog.scroll_top) >= (height - 1)
593
- dialog.scroll_top = dialog_render_info.pointer - (height - 1)
594
- elsif (dialog_render_info.pointer - dialog.scroll_top) < 0
595
- dialog.scroll_top = dialog_render_info.pointer
596
- end
597
- pointer = dialog_render_info.pointer - dialog.scroll_top
598
- end
599
- dialog.contents = dialog.contents[dialog.scroll_top, height]
600
- end
601
- else
618
+ dialog_render_info = dialog.call(@last_key)
619
+ if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
602
620
  dialog.lines_backup = {
603
621
  lines: modify_lines(whole_lines),
604
622
  line_index: @line_index,
@@ -608,19 +626,43 @@ class Reline::LineEditor
608
626
  }
609
627
  clear_each_dialog(dialog)
610
628
  dialog.contents = nil
629
+ dialog.trap_key = nil
611
630
  return
612
631
  end
632
+ old_dialog = dialog.clone
633
+ dialog.contents = dialog_render_info.contents
634
+ pointer = dialog_render_info.pointer
635
+ if dialog_render_info.width
636
+ dialog.width = dialog_render_info.width
637
+ else
638
+ dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
639
+ end
640
+ height = dialog_render_info.height || DIALOG_HEIGHT
641
+ height = dialog.contents.size if dialog.contents.size < height
642
+ if dialog.contents.size > height
643
+ if dialog_render_info.pointer
644
+ if dialog_render_info.pointer < 0
645
+ dialog.scroll_top = 0
646
+ elsif (dialog_render_info.pointer - dialog.scroll_top) >= (height - 1)
647
+ dialog.scroll_top = dialog_render_info.pointer - (height - 1)
648
+ elsif (dialog_render_info.pointer - dialog.scroll_top) < 0
649
+ dialog.scroll_top = dialog_render_info.pointer
650
+ end
651
+ pointer = dialog_render_info.pointer - dialog.scroll_top
652
+ end
653
+ dialog.contents = dialog.contents[dialog.scroll_top, height]
654
+ end
613
655
  upper_space = @first_line_started_from - @started_from
614
656
  lower_space = @highest_in_all - @first_line_started_from - @started_from - 1
615
657
  dialog.column = dialog_render_info.pos.x
616
- diff = (dialog.column + DIALOG_WIDTH) - (@screen_size.last - 1)
658
+ diff = (dialog.column + dialog.width) - (@screen_size.last - 1)
617
659
  if diff > 0
618
660
  dialog.column -= diff
619
661
  end
620
662
  if (lower_space + @rest_height - dialog_render_info.pos.y) >= height
621
663
  dialog.vertical_offset = dialog_render_info.pos.y + 1
622
664
  elsif upper_space >= height
623
- dialog.vertical_offset = dialog_render_info.pos.y + -(height + 1)
665
+ dialog.vertical_offset = dialog_render_info.pos.y - height
624
666
  else
625
667
  if (lower_space + @rest_height - dialog_render_info.pos.y) < height
626
668
  scroll_down(height + dialog_render_info.pos.y)
@@ -629,9 +671,16 @@ class Reline::LineEditor
629
671
  dialog.vertical_offset = dialog_render_info.pos.y + 1
630
672
  end
631
673
  Reline::IOGate.hide_cursor
632
- reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
674
+ reset_dialog(dialog, old_dialog)
633
675
  move_cursor_down(dialog.vertical_offset)
634
676
  Reline::IOGate.move_cursor_column(dialog.column)
677
+ if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
678
+ bar_max_height = height * 2
679
+ moving_distance = (dialog_render_info.contents.size - height) * 2
680
+ position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
681
+ bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
682
+ position = ((bar_max_height - bar_height) * position_ratio).floor.to_i
683
+ end
635
684
  dialog.contents.each_with_index do |item, i|
636
685
  if i == pointer
637
686
  bg_color = '45'
@@ -642,10 +691,27 @@ class Reline::LineEditor
642
691
  bg_color = '46'
643
692
  end
644
693
  end
645
- @output.write "\e[#{bg_color}m%-#{DIALOG_WIDTH}s\e[49m" % item.slice(0, DIALOG_WIDTH)
694
+ str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, dialog.width), dialog.width)
695
+ @output.write "\e[#{bg_color}m#{str}"
696
+ if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
697
+ @output.write "\e[37m"
698
+ if position <= (i * 2) and (i * 2 + 1) < (position + bar_height)
699
+ @output.write '█'
700
+ elsif position <= (i * 2) and (i * 2) < (position + bar_height)
701
+ @output.write '▀'
702
+ str += ''
703
+ elsif position <= (i * 2 + 1) and (i * 2) < (position + bar_height)
704
+ @output.write '▄'
705
+ else
706
+ @output.write ' '
707
+ end
708
+ @output.write "\e[39m"
709
+ end
710
+ @output.write "\e[49m"
646
711
  Reline::IOGate.move_cursor_column(dialog.column)
647
712
  move_cursor_down(1) if i < (dialog.contents.size - 1)
648
713
  end
714
+ dialog.width += 1 if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
649
715
  Reline::IOGate.move_cursor_column(cursor_column)
650
716
  move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
651
717
  Reline::IOGate.show_cursor
@@ -658,8 +724,8 @@ class Reline::LineEditor
658
724
  }
659
725
  end
660
726
 
661
- private def reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
662
- return if dialog.lines_backup.nil? or old_dialog_contents.nil?
727
+ private def reset_dialog(dialog, old_dialog)
728
+ return if dialog.lines_backup.nil? or old_dialog.contents.nil?
663
729
  prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
664
730
  visual_lines = []
665
731
  visual_start = nil
@@ -675,76 +741,80 @@ class Reline::LineEditor
675
741
  old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
676
742
  y = @first_line_started_from + @started_from
677
743
  y_diff = y - old_y
678
- if (old_y + old_dialog_vertical_offset) < (y + dialog.vertical_offset)
744
+ if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
679
745
  # rerender top
680
- move_cursor_down(old_dialog_vertical_offset - y_diff)
681
- start = visual_start + old_dialog_vertical_offset
682
- line_num = dialog.vertical_offset - old_dialog_vertical_offset
746
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
747
+ start = visual_start + old_dialog.vertical_offset
748
+ line_num = dialog.vertical_offset - old_dialog.vertical_offset
683
749
  line_num.times do |i|
684
- Reline::IOGate.move_cursor_column(old_dialog_column)
750
+ Reline::IOGate.move_cursor_column(old_dialog.column)
685
751
  if visual_lines[start + i].nil?
686
- s = ' ' * DIALOG_WIDTH
752
+ s = ' ' * dialog.width
687
753
  else
688
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, DIALOG_WIDTH)
754
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, dialog.width)
755
+ s = padding_space_with_escape_sequences(s, dialog.width)
689
756
  end
690
- @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % s
757
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
691
758
  move_cursor_down(1) if i < (line_num - 1)
692
759
  end
693
- move_cursor_up(old_dialog_vertical_offset + line_num - 1 - y_diff)
760
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
694
761
  end
695
- if (old_y + old_dialog_vertical_offset + old_dialog_contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
762
+ if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
696
763
  # rerender bottom
697
764
  move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
698
765
  start = visual_start + dialog.vertical_offset + dialog.contents.size
699
- line_num = (old_dialog_vertical_offset + old_dialog_contents.size) - (dialog.vertical_offset + dialog.contents.size)
766
+ line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
700
767
  line_num.times do |i|
701
- Reline::IOGate.move_cursor_column(old_dialog_column)
768
+ Reline::IOGate.move_cursor_column(old_dialog.column)
702
769
  if visual_lines[start + i].nil?
703
- s = ' ' * DIALOG_WIDTH
770
+ s = ' ' * dialog.width
704
771
  else
705
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, DIALOG_WIDTH)
772
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, dialog.width)
773
+ s = padding_space_with_escape_sequences(s, dialog.width)
706
774
  end
707
- @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % s
775
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
708
776
  move_cursor_down(1) if i < (line_num - 1)
709
777
  end
710
778
  move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
711
779
  end
712
- if old_dialog_column < dialog.column
780
+ if old_dialog.column < dialog.column
713
781
  # rerender left
714
- move_cursor_down(old_dialog_vertical_offset - y_diff)
715
- width = dialog.column - old_dialog_column
716
- start = visual_start + old_dialog_vertical_offset
717
- line_num = old_dialog_contents.size
782
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
783
+ width = dialog.column - old_dialog.column
784
+ start = visual_start + old_dialog.vertical_offset
785
+ line_num = old_dialog.contents.size
718
786
  line_num.times do |i|
719
- Reline::IOGate.move_cursor_column(old_dialog_column)
787
+ Reline::IOGate.move_cursor_column(old_dialog.column)
720
788
  if visual_lines[start + i].nil?
721
789
  s = ' ' * width
722
790
  else
723
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, width)
791
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
792
+ s = padding_space_with_escape_sequences(s, dialog.width)
724
793
  end
725
- @output.write "\e[39m\e[49m%-#{width}s\e[39m\e[49m" % s
794
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
726
795
  move_cursor_down(1) if i < (line_num - 1)
727
796
  end
728
- move_cursor_up(old_dialog_vertical_offset + line_num - 1 - y_diff)
797
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
729
798
  end
730
- if (old_dialog_column + DIALOG_WIDTH) > (dialog.column + DIALOG_WIDTH)
799
+ if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
731
800
  # rerender right
732
- move_cursor_down(old_dialog_vertical_offset + y_diff)
733
- width = (old_dialog_column + DIALOG_WIDTH) - (dialog.column + DIALOG_WIDTH)
734
- start = visual_start + old_dialog_vertical_offset
735
- line_num = old_dialog_contents.size
801
+ move_cursor_down(old_dialog.vertical_offset + y_diff)
802
+ width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
803
+ start = visual_start + old_dialog.vertical_offset
804
+ line_num = old_dialog.contents.size
736
805
  line_num.times do |i|
737
- Reline::IOGate.move_cursor_column(old_dialog_column + DIALOG_WIDTH)
806
+ Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
738
807
  if visual_lines[start + i].nil?
739
808
  s = ' ' * width
740
809
  else
741
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column + DIALOG_WIDTH, width)
810
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
811
+ s = padding_space_with_escape_sequences(s, dialog.width)
742
812
  end
743
- Reline::IOGate.move_cursor_column(dialog.column + DIALOG_WIDTH)
744
- @output.write "\e[39m\e[49m%-#{width}s\e[39m\e[49m" % s
813
+ Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
814
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
745
815
  move_cursor_down(1) if i < (line_num - 1)
746
816
  end
747
- move_cursor_up(old_dialog_vertical_offset + line_num - 1 + y_diff)
817
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
748
818
  end
749
819
  Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
750
820
  end
@@ -756,6 +826,7 @@ class Reline::LineEditor
756
826
  end
757
827
 
758
828
  private def clear_each_dialog(dialog)
829
+ dialog.trap_key = nil
759
830
  return unless dialog.contents
760
831
  prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
761
832
  visual_lines = []
@@ -777,13 +848,14 @@ class Reline::LineEditor
777
848
  dialog_vertical_size = dialog.contents.size
778
849
  dialog_vertical_size.times do |i|
779
850
  if i < visual_lines_under_dialog.size
780
- Reline::IOGate.move_cursor_column(0)
781
- @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % visual_lines_under_dialog[i]
851
+ Reline::IOGate.move_cursor_column(dialog.column)
852
+ str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
853
+ str = padding_space_with_escape_sequences(str, dialog.width)
854
+ @output.write "\e[39m\e[49m#{str}\e[39m\e[49m"
782
855
  else
783
856
  Reline::IOGate.move_cursor_column(dialog.column)
784
- @output.write "\e[39m\e[49m#{' ' * DIALOG_WIDTH}\e[39m\e[49m"
857
+ @output.write "\e[39m\e[49m#{' ' * dialog.width}\e[39m\e[49m"
785
858
  end
786
- Reline::IOGate.erase_after_cursor
787
859
  move_cursor_down(1) if i < (dialog_vertical_size - 1)
788
860
  end
789
861
  move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
@@ -1277,8 +1349,10 @@ class Reline::LineEditor
1277
1349
  end
1278
1350
  end
1279
1351
  completed = @completion_journey_data.list[@completion_journey_data.pointer]
1280
- @line = @completion_journey_data.preposing + completed + @completion_journey_data.postposing
1281
- line_to_pointer = @completion_journey_data.preposing + completed
1352
+ new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
1353
+ @line = new_line.nil? ? String.new(encoding: @encoding) : new_line
1354
+ line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
1355
+ line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
1282
1356
  @cursor_max = calculate_width(@line)
1283
1357
  @cursor = calculate_width(line_to_pointer)
1284
1358
  @byte_pointer = line_to_pointer.bytesize
@@ -1439,6 +1513,13 @@ class Reline::LineEditor
1439
1513
  end
1440
1514
 
1441
1515
  def input_key(key)
1516
+ @last_key = key
1517
+ @config.reset_oneshot_key_bindings
1518
+ @dialogs.each do |dialog|
1519
+ if key.char.instance_of?(Symbol) and key.char == dialog.name
1520
+ return
1521
+ end
1522
+ end
1442
1523
  @just_cursor_moving = nil
1443
1524
  if key.char.nil?
1444
1525
  if @first_char