reline 0.2.8.pre.2 → 0.2.8.pre.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: 45220c00c821168746654f6c7f5ad3cc88ff8b4e3d3b6e5aefccc83b34392041
4
- data.tar.gz: a3bbf71304ce777dbae4d5b1cc91f5a2b297b811194947e5e8e8a27b229667a2
3
+ metadata.gz: 161818586702ae2834bf5e6490adf5dcec415256925ffd83339ffe6ef3c13012
4
+ data.tar.gz: 3ab65900ed4022e1baa2213d560938339711264e3188597c4eb98bc1891c81a8
5
5
  SHA512:
6
- metadata.gz: a9d8e4a15c1eff337dc476b8b4f2d603b64d35faf255a9984f119b2f14a76bcd93f145d01d1e0698e2cb0a3d80c28c8b3baa343866e3cb7b8b28ab4642e77ebf
7
- data.tar.gz: fcc70f912f7472acb0d7eeee8f221a60d06e3f08cd079b37a988392eca35723753e3b02638a4bcbb41876dc59cfcb46349b16bfff88e336ecea9bd2a4cf93231
6
+ metadata.gz: 610c5367d68b627fb7e0a7bef7919d147b5a19539725f9a2d184bbed69b0988c613acf1f001d2f05857fce2490e7309e666a4327f1f15cd0541e3bb7db5089ec
7
+ data.tar.gz: b567f8283fe5637161e21536f500f6824d9a92aadf940e10386d27cf4df29940d3e3d6cb95a7a4fff6e711ac33c73f870ee419b45d44274184160b37354d9d77
@@ -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
@@ -499,6 +499,14 @@ class Reline::LineEditor
499
499
  @line_editor.call_completion_proc_with_checking_args(pre, target, post)
500
500
  end
501
501
 
502
+ def set_dialog(dialog)
503
+ @dialog = dialog
504
+ end
505
+
506
+ def dialog
507
+ @dialog
508
+ end
509
+
502
510
  def set_cursor_pos(col, row)
503
511
  @cursor_pos.x = col
504
512
  @cursor_pos.y = row
@@ -530,19 +538,33 @@ class Reline::LineEditor
530
538
  end
531
539
 
532
540
  class Dialog
533
- attr_reader :name
534
- attr_accessor :column, :vertical_offset, :contents, :lines_backup
541
+ attr_reader :name, :contents, :width
542
+ attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup
535
543
 
536
544
  def initialize(name, proc_scope)
537
545
  @name = name
538
546
  @proc_scope = proc_scope
547
+ @width = nil
548
+ @scroll_top = 0
539
549
  end
540
550
 
541
551
  def set_cursor_pos(col, row)
542
552
  @proc_scope.set_cursor_pos(col, row)
543
553
  end
544
554
 
555
+ def width=(v)
556
+ @width = v
557
+ end
558
+
559
+ def contents=(contents)
560
+ @contents = contents
561
+ if contents and @width.nil?
562
+ @width = contents.map{ |line| Reline::Unicode.calculate_width(line, true) }.max
563
+ end
564
+ end
565
+
545
566
  def call
567
+ @proc_scope.set_dialog(self)
546
568
  @proc_scope.call
547
569
  end
548
570
  end
@@ -553,27 +575,24 @@ class Reline::LineEditor
553
575
  end
554
576
 
555
577
  DIALOG_HEIGHT = 20
556
- DIALOG_WIDTH = 40
557
578
  private def render_dialog(cursor_column)
558
579
  @dialogs.each do |dialog|
559
580
  render_each_dialog(dialog, cursor_column)
560
581
  end
561
582
  end
562
583
 
584
+ private def padding_space_with_escape_sequences(str, width)
585
+ str + (' ' * (width - calculate_width(str, true)))
586
+ end
587
+
563
588
  private def render_each_dialog(dialog, cursor_column)
564
589
  if @in_pasting
565
590
  dialog.contents = nil
566
591
  return
567
592
  end
568
593
  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
594
+ dialog_render_info = dialog.call
595
+ if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
577
596
  dialog.lines_backup = {
578
597
  lines: modify_lines(whole_lines),
579
598
  line_index: @line_index,
@@ -585,39 +604,59 @@ class Reline::LineEditor
585
604
  dialog.contents = nil
586
605
  return
587
606
  end
607
+ old_dialog = dialog.clone
608
+ dialog.width = dialog_render_info.width if dialog_render_info.width
609
+ height = dialog_render_info.height || DIALOG_HEIGHT
610
+ pointer = dialog_render_info.pointer
611
+ dialog.contents = dialog_render_info.contents
612
+ height = dialog.contents.size if dialog.contents.size < height
613
+ if dialog.contents.size > height
614
+ if dialog_render_info.pointer
615
+ if dialog_render_info.pointer < 0
616
+ dialog.scroll_top = 0
617
+ elsif (dialog_render_info.pointer - dialog.scroll_top) >= (height - 1)
618
+ dialog.scroll_top = dialog_render_info.pointer - (height - 1)
619
+ elsif (dialog_render_info.pointer - dialog.scroll_top) < 0
620
+ dialog.scroll_top = dialog_render_info.pointer
621
+ end
622
+ pointer = dialog_render_info.pointer - dialog.scroll_top
623
+ end
624
+ dialog.contents = dialog.contents[dialog.scroll_top, height]
625
+ end
588
626
  upper_space = @first_line_started_from - @started_from
589
627
  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)
628
+ dialog.column = dialog_render_info.pos.x
629
+ diff = (dialog.column + dialog.width) - (@screen_size.last - 1)
592
630
  if diff > 0
593
631
  dialog.column -= diff
594
632
  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)
633
+ if (lower_space + @rest_height - dialog_render_info.pos.y) >= height
634
+ dialog.vertical_offset = dialog_render_info.pos.y + 1
635
+ elsif upper_space >= height
636
+ dialog.vertical_offset = dialog_render_info.pos.y - height
599
637
  else
600
- if (lower_space + @rest_height) < DIALOG_HEIGHT
601
- scroll_down(DIALOG_HEIGHT)
602
- move_cursor_up(DIALOG_HEIGHT)
638
+ if (lower_space + @rest_height - dialog_render_info.pos.y) < height
639
+ scroll_down(height + dialog_render_info.pos.y)
640
+ move_cursor_up(height + dialog_render_info.pos.y)
603
641
  end
604
- dialog.vertical_offset = pos.y + 1
642
+ dialog.vertical_offset = dialog_render_info.pos.y + 1
605
643
  end
606
644
  Reline::IOGate.hide_cursor
607
- reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
645
+ reset_dialog(dialog, old_dialog)
608
646
  move_cursor_down(dialog.vertical_offset)
609
647
  Reline::IOGate.move_cursor_column(dialog.column)
610
648
  dialog.contents.each_with_index do |item, i|
611
649
  if i == pointer
612
650
  bg_color = '45'
613
651
  else
614
- if bg
615
- bg_color = bg
652
+ if dialog_render_info.bg_color
653
+ bg_color = dialog_render_info.bg_color
616
654
  else
617
655
  bg_color = '46'
618
656
  end
619
657
  end
620
- @output.write "\e[#{bg_color}m%-#{DIALOG_WIDTH}s\e[49m" % item.slice(0, DIALOG_WIDTH)
658
+ str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, dialog.width), dialog.width)
659
+ @output.write "\e[#{bg_color}m#{str}\e[49m"
621
660
  Reline::IOGate.move_cursor_column(dialog.column)
622
661
  move_cursor_down(1) if i < (dialog.contents.size - 1)
623
662
  end
@@ -633,8 +672,8 @@ class Reline::LineEditor
633
672
  }
634
673
  end
635
674
 
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?
675
+ private def reset_dialog(dialog, old_dialog)
676
+ return if dialog.lines_backup.nil? or old_dialog.contents.nil?
638
677
  prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
639
678
  visual_lines = []
640
679
  visual_start = nil
@@ -650,76 +689,80 @@ class Reline::LineEditor
650
689
  old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
651
690
  y = @first_line_started_from + @started_from
652
691
  y_diff = y - old_y
653
- if (old_y + old_dialog_vertical_offset) < (y + dialog.vertical_offset)
692
+ if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
654
693
  # 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
694
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
695
+ start = visual_start + old_dialog.vertical_offset
696
+ line_num = dialog.vertical_offset - old_dialog.vertical_offset
658
697
  line_num.times do |i|
659
- Reline::IOGate.move_cursor_column(old_dialog_column)
698
+ Reline::IOGate.move_cursor_column(old_dialog.column)
660
699
  if visual_lines[start + i].nil?
661
- s = ' ' * DIALOG_WIDTH
700
+ s = ' ' * dialog.width
662
701
  else
663
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, DIALOG_WIDTH)
702
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, dialog.width)
703
+ s = padding_space_with_escape_sequences(s, dialog.width)
664
704
  end
665
- @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % s
705
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
666
706
  move_cursor_down(1) if i < (line_num - 1)
667
707
  end
668
- move_cursor_up(old_dialog_vertical_offset + line_num - 1 - y_diff)
708
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
669
709
  end
670
- if (old_y + old_dialog_vertical_offset + old_dialog_contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
710
+ if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
671
711
  # rerender bottom
672
712
  move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
673
713
  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)
714
+ line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
675
715
  line_num.times do |i|
676
- Reline::IOGate.move_cursor_column(old_dialog_column)
716
+ Reline::IOGate.move_cursor_column(old_dialog.column)
677
717
  if visual_lines[start + i].nil?
678
- s = ' ' * DIALOG_WIDTH
718
+ s = ' ' * dialog.width
679
719
  else
680
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, DIALOG_WIDTH)
720
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, dialog.width)
721
+ s = padding_space_with_escape_sequences(s, dialog.width)
681
722
  end
682
- @output.write "\e[39m\e[49m%-#{DIALOG_WIDTH}s\e[39m\e[49m" % s
723
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
683
724
  move_cursor_down(1) if i < (line_num - 1)
684
725
  end
685
726
  move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
686
727
  end
687
- if old_dialog_column < dialog.column
728
+ if old_dialog.column < dialog.column
688
729
  # 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
730
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
731
+ width = dialog.column - old_dialog.column
732
+ start = visual_start + old_dialog.vertical_offset
733
+ line_num = old_dialog.contents.size
693
734
  line_num.times do |i|
694
- Reline::IOGate.move_cursor_column(old_dialog_column)
735
+ Reline::IOGate.move_cursor_column(old_dialog.column)
695
736
  if visual_lines[start + i].nil?
696
737
  s = ' ' * width
697
738
  else
698
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column, width)
739
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
740
+ s = padding_space_with_escape_sequences(s, dialog.width)
699
741
  end
700
- @output.write "\e[39m\e[49m%-#{width}s\e[39m\e[49m" % s
742
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
701
743
  move_cursor_down(1) if i < (line_num - 1)
702
744
  end
703
- move_cursor_up(old_dialog_vertical_offset + line_num - 1 - y_diff)
745
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
704
746
  end
705
- if (old_dialog_column + DIALOG_WIDTH) > (dialog.column + DIALOG_WIDTH)
747
+ if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
706
748
  # 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
749
+ move_cursor_down(old_dialog.vertical_offset + y_diff)
750
+ width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
751
+ start = visual_start + old_dialog.vertical_offset
752
+ line_num = old_dialog.contents.size
711
753
  line_num.times do |i|
712
- Reline::IOGate.move_cursor_column(old_dialog_column + DIALOG_WIDTH)
754
+ Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
713
755
  if visual_lines[start + i].nil?
714
756
  s = ' ' * width
715
757
  else
716
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog_column + DIALOG_WIDTH, width)
758
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
759
+ s = padding_space_with_escape_sequences(s, dialog.width)
717
760
  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
761
+ Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
762
+ @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
720
763
  move_cursor_down(1) if i < (line_num - 1)
721
764
  end
722
- move_cursor_up(old_dialog_vertical_offset + line_num - 1 + y_diff)
765
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
723
766
  end
724
767
  Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
725
768
  end
@@ -752,13 +795,14 @@ class Reline::LineEditor
752
795
  dialog_vertical_size = dialog.contents.size
753
796
  dialog_vertical_size.times do |i|
754
797
  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]
798
+ Reline::IOGate.move_cursor_column(dialog.column)
799
+ str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
800
+ str = padding_space_with_escape_sequences(str, dialog.width)
801
+ @output.write "\e[39m\e[49m#{str}\e[39m\e[49m"
757
802
  else
758
803
  Reline::IOGate.move_cursor_column(dialog.column)
759
- @output.write "\e[39m\e[49m#{' ' * DIALOG_WIDTH}\e[39m\e[49m"
804
+ @output.write "\e[39m\e[49m#{' ' * dialog.width}\e[39m\e[49m"
760
805
  end
761
- Reline::IOGate.erase_after_cursor
762
806
  move_cursor_down(1) if i < (dialog_vertical_size - 1)
763
807
  end
764
808
  move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
@@ -1252,8 +1296,10 @@ class Reline::LineEditor
1252
1296
  end
1253
1297
  end
1254
1298
  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
1299
+ new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
1300
+ @line = new_line.nil? ? String.new(encoding: @encoding) : new_line
1301
+ line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
1302
+ line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
1257
1303
  @cursor_max = calculate_width(@line)
1258
1304
  @cursor = calculate_width(line_to_pointer)
1259
1305
  @byte_pointer = line_to_pointer.bytesize
@@ -186,9 +186,9 @@ class Reline::Unicode
186
186
  end
187
187
 
188
188
  # Take a chunk of a String with escape sequences.
189
- def self.take_range(str, col, length, encoding = str.encoding)
189
+ def self.take_range(str, start_col, max_width, encoding = str.encoding)
190
190
  chunk = String.new(encoding: encoding)
191
- width = 0
191
+ total_width = 0
192
192
  rest = str.encode(Encoding::UTF_8)
193
193
  in_zero_width = false
194
194
  rest.scan(WIDTH_SCANNER) do |gc|
@@ -206,9 +206,10 @@ class Reline::Unicode
206
206
  if in_zero_width
207
207
  chunk << gc
208
208
  else
209
- width = get_mbchar_width(gc)
210
- break if (width + length) <= col
211
- chunk << gc if col <= width
209
+ mbchar_width = get_mbchar_width(gc)
210
+ total_width += mbchar_width
211
+ break if (start_col + max_width) < total_width
212
+ chunk << gc if start_col < total_width
212
213
  end
213
214
  end
214
215
  end
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.2.8.pre.2'
2
+ VERSION = '0.2.8.pre.6'
3
3
  end
data/lib/reline.rb CHANGED
@@ -18,6 +18,7 @@ module Reline
18
18
 
19
19
  Key = Struct.new('Key', :char, :combined_char, :with_meta)
20
20
  CursorPos = Struct.new(:x, :y)
21
+ DialogRenderInfo = Struct.new(:pos, :contents, :pointer, :bg_color, :width, :height, keyword_init: true)
21
22
 
22
23
  class Core
23
24
  ATTR_READER_NAMES = %i(
@@ -193,7 +194,7 @@ module Reline
193
194
  # Auto complete starts only when edited
194
195
  return nil
195
196
  end
196
- pre, target, post= retrieve_completion_block(true)
197
+ pre, target, post = retrieve_completion_block(true)
197
198
  if target.nil? or target.empty?# or target.size <= 3
198
199
  return nil
199
200
  end
@@ -219,9 +220,9 @@ module Reline
219
220
  cursor_pos_to_render = Reline::CursorPos.new(x, y)
220
221
  if context and context.is_a?(Array)
221
222
  context.clear
222
- context.push(cursor_pos_to_render, result, pointer)
223
+ context.push(cursor_pos_to_render, result, pointer, dialog)
223
224
  end
224
- [cursor_pos_to_render, result, pointer, nil]
225
+ DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, pointer: pointer, height: 15)
225
226
  }
226
227
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
227
228
 
@@ -483,6 +484,7 @@ module Reline
483
484
  def_single_delegators :core, :last_incremental_search
484
485
  def_single_delegators :core, :last_incremental_search=
485
486
  def_single_delegators :core, :add_dialog_proc
487
+ def_single_delegators :core, :autocompletion, :autocompletion=
486
488
 
487
489
  def_single_delegators :core, :readmultiline
488
490
  def_instance_delegators self, :readmultiline
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.8.pre.2
4
+ version: 0.2.8.pre.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-29 00:00:00.000000000 Z
11
+ date: 2021-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console