reline 0.3.1 → 0.3.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: 1009c9156a8c15c1f3c64a3cb89a0d6a1acef037185bfb76c24ed9df7e49cb2c
4
- data.tar.gz: 983ad1d570617a47d732402485a79eba8bd1acc6f3555f117ca6822cee52030d
3
+ metadata.gz: b0fe224245c6f66bdfa42b7fd6b0dc4c30f9645f0c1498fd7780ff17db642eec
4
+ data.tar.gz: af1b5a53e09f4b2c60ae20e153a4b3043ea3a19a38c58be697067c58f63feec7
5
5
  SHA512:
6
- metadata.gz: 424c026623c896ccd59fed73b5f61e7bb067dfdc8fe34a13bdb317895fb512eb666b25c76439e940915307e658e85dbbfcb8339ecfae5c5b72fa9239d1599778
7
- data.tar.gz: 93077ced9c8009d5c2f7f59eb013f8134394347c57660e7958244a2adfe60b2a09463ac2062d9ce31e5d75974b19665f7e800f2078bf9b461dfbada76c3e572e
6
+ metadata.gz: cb456e06f2cef817fe3ae8fa27e9666587f2b3175cdbc97714ab3638d5b11bf606595d772c4e100fc21d9f50ed6e55fb6b833c28bad6b4ae3c8838d2418e75f5
7
+ data.tar.gz: 6f3eb2f3feee78d7b4754c069a7d6c0d5d29af100bcb493bab2696c9b610c86de4fb3b201d624b6d00f218f1257a526d0c29bf95c79a1ed3daf117f0c95a2768
data/lib/reline/ansi.rb CHANGED
@@ -7,6 +7,9 @@ class Reline::ANSI
7
7
  CAPNAME_KEY_BINDINGS = {
8
8
  'khome' => :ed_move_to_beg,
9
9
  'kend' => :ed_move_to_end,
10
+ 'kdch1' => :key_delete,
11
+ 'kpp' => :ed_search_prev_history,
12
+ 'knp' => :ed_search_next_history,
10
13
  'kcuu1' => :ed_prev_history,
11
14
  'kcud1' => :ed_next_history,
12
15
  'kcuf1' => :ed_next_char,
@@ -29,8 +32,8 @@ class Reline::ANSI
29
32
  false
30
33
  end
31
34
 
32
- def self.set_default_key_bindings(config)
33
- if Reline::Terminfo.enabled?
35
+ def self.set_default_key_bindings(config, allow_terminfo: true)
36
+ if allow_terminfo && Reline::Terminfo.enabled?
34
37
  set_default_key_bindings_terminfo(config)
35
38
  else
36
39
  set_default_key_bindings_comprehensive_list(config)
@@ -142,6 +145,10 @@ class Reline::ANSI
142
145
  @@output = val
143
146
  end
144
147
 
148
+ def self.with_raw_input
149
+ @@input.raw { yield }
150
+ end
151
+
145
152
  @@buf = []
146
153
  def self.inner_getc
147
154
  unless @@buf.empty?
@@ -150,7 +157,7 @@ class Reline::ANSI
150
157
  until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
151
158
  Reline.core.line_editor.resize
152
159
  end
153
- (c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
160
+ (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
154
161
  rescue Errno::EIO
155
162
  # Maybe the I/O has been closed.
156
163
  nil
data/lib/reline/config.rb CHANGED
@@ -45,6 +45,8 @@ class Reline::Config
45
45
  attr_accessor v
46
46
  end
47
47
 
48
+ attr_accessor :autocompletion
49
+
48
50
  def initialize
49
51
  @additional_key_bindings = {} # from inputrc
50
52
  @additional_key_bindings[:emacs] = {}
@@ -55,6 +57,7 @@ class Reline::Config
55
57
  @if_stack = nil
56
58
  @editing_mode_label = :emacs
57
59
  @keymap_label = :emacs
60
+ @keymap_prefix = []
58
61
  @key_actors = {}
59
62
  @key_actors[:emacs] = Reline::KeyActor::Emacs.new
60
63
  @key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
@@ -90,15 +93,7 @@ class Reline::Config
90
93
  end
91
94
 
92
95
  def editing_mode_is?(*val)
93
- (val.respond_to?(:any?) ? val : [val]).any?(@editing_mode_label)
94
- end
95
-
96
- def autocompletion=(val)
97
- @autocompletion = val
98
- end
99
-
100
- def autocompletion
101
- @autocompletion
96
+ val.any?(@editing_mode_label)
102
97
  end
103
98
 
104
99
  def keymap
@@ -221,7 +216,7 @@ class Reline::Config
221
216
  key, func_name = $1, $2
222
217
  keystroke, func = bind_key(key, func_name)
223
218
  next unless keystroke
224
- @additional_key_bindings[@keymap_label][keystroke] = func
219
+ @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
225
220
  end
226
221
  end
227
222
  unless @if_stack.empty?
@@ -292,18 +287,29 @@ class Reline::Config
292
287
  when 'emacs'
293
288
  @editing_mode_label = :emacs
294
289
  @keymap_label = :emacs
290
+ @keymap_prefix = []
295
291
  when 'vi'
296
292
  @editing_mode_label = :vi_insert
297
293
  @keymap_label = :vi_insert
294
+ @keymap_prefix = []
298
295
  end
299
296
  when 'keymap'
300
297
  case value
301
- when 'emacs', 'emacs-standard', 'emacs-meta', 'emacs-ctlx'
298
+ when 'emacs', 'emacs-standard'
299
+ @keymap_label = :emacs
300
+ @keymap_prefix = []
301
+ when 'emacs-ctlx'
302
+ @keymap_label = :emacs
303
+ @keymap_prefix = [?\C-x.ord]
304
+ when 'emacs-meta'
302
305
  @keymap_label = :emacs
306
+ @keymap_prefix = [?\e.ord]
303
307
  when 'vi', 'vi-move', 'vi-command'
304
308
  @keymap_label = :vi_command
309
+ @keymap_prefix = []
305
310
  when 'vi-insert'
306
311
  @keymap_label = :vi_insert
312
+ @keymap_prefix = []
307
313
  end
308
314
  when 'keyseq-timeout'
309
315
  @keyseq_timeout = value.to_i
@@ -31,6 +31,10 @@ class Reline::GeneralIO
31
31
  @@input = val
32
32
  end
33
33
 
34
+ def self.with_raw_input
35
+ yield
36
+ end
37
+
34
38
  def self.getc
35
39
  unless @@buf.empty?
36
40
  return @@buf.shift
@@ -57,6 +61,12 @@ class Reline::GeneralIO
57
61
  Reline::CursorPos.new(1, 1)
58
62
  end
59
63
 
64
+ def self.hide_cursor
65
+ end
66
+
67
+ def self.show_cursor
68
+ end
69
+
60
70
  def self.move_cursor_column(val)
61
71
  end
62
72
 
@@ -52,6 +52,7 @@ class Reline::LineEditor
52
52
  MenuInfo = Struct.new('MenuInfo', :target, :list)
53
53
 
54
54
  PROMPT_LIST_CACHE_TIMEOUT = 0.5
55
+ MINIMUM_SCROLLBAR_HEIGHT = 1
55
56
 
56
57
  def initialize(config, encoding)
57
58
  @config = config
@@ -449,14 +450,10 @@ class Reline::LineEditor
449
450
  Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
450
451
  Reline::IOGate.move_cursor_column(0)
451
452
  @scroll_partial_screen = nil
452
- prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
453
- if @previous_line_index
454
- new_lines = whole_lines(index: @previous_line_index, line: @line)
455
- else
456
- new_lines = whole_lines
457
- end
453
+ new_lines = whole_lines
454
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
458
455
  modify_lines(new_lines).each_with_index do |line, index|
459
- @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
456
+ @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\r\n"
460
457
  Reline::IOGate.erase_after_cursor
461
458
  end
462
459
  @output.flush
@@ -466,15 +463,17 @@ class Reline::LineEditor
466
463
  new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
467
464
  rendered = false
468
465
  if @add_newline_to_end_of_buffer
469
- rerender_added_newline(prompt, prompt_width)
466
+ clear_dialog_with_content
467
+ rerender_added_newline(prompt, prompt_width, prompt_list)
470
468
  @add_newline_to_end_of_buffer = false
471
469
  else
472
470
  if @just_cursor_moving and not @rerender_all
471
+ clear_dialog_with_content
473
472
  rendered = just_move_cursor
474
- render_dialog((prompt_width + @cursor) % @screen_size.last)
475
473
  @just_cursor_moving = false
476
474
  return
477
475
  elsif @previous_line_index or new_highest_in_this != @highest_in_this
476
+ clear_dialog_with_content
478
477
  rerender_changed_current_line
479
478
  @previous_line_index = nil
480
479
  rendered = true
@@ -488,11 +487,7 @@ class Reline::LineEditor
488
487
  if @is_multiline
489
488
  if finished?
490
489
  # Always rerender on finish because output_modifier_proc may return a different output.
491
- if @previous_line_index
492
- new_lines = whole_lines(index: @previous_line_index, line: @line)
493
- else
494
- new_lines = whole_lines
495
- end
490
+ new_lines = whole_lines
496
491
  line = modify_lines(new_lines)[@line_index]
497
492
  clear_dialog
498
493
  prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
@@ -653,7 +648,10 @@ class Reline::LineEditor
653
648
  end
654
649
 
655
650
  private def padding_space_with_escape_sequences(str, width)
656
- str + (' ' * (width - calculate_width(str, true)))
651
+ padding_width = width - calculate_width(str, true)
652
+ # padding_width should be only positive value. But macOS and Alacritty returns negative value.
653
+ padding_width = 0 if padding_width < 0
654
+ str + (' ' * padding_width)
657
655
  end
658
656
 
659
657
  private def render_each_dialog(dialog, cursor_column)
@@ -666,8 +664,10 @@ class Reline::LineEditor
666
664
  dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
667
665
  dialog_render_info = dialog.call(@last_key)
668
666
  if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
667
+ lines = whole_lines
669
668
  dialog.lines_backup = {
670
- lines: modify_lines(whole_lines),
669
+ unmodified_lines: lines,
670
+ lines: modify_lines(lines),
671
671
  line_index: @line_index,
672
672
  first_line_started_from: @first_line_started_from,
673
673
  started_from: @started_from,
@@ -698,17 +698,17 @@ class Reline::LineEditor
698
698
  dialog.scroll_top = dialog.pointer
699
699
  end
700
700
  pointer = dialog.pointer - dialog.scroll_top
701
+ else
702
+ dialog.scroll_top = 0
701
703
  end
702
704
  dialog.contents = dialog.contents[dialog.scroll_top, height]
703
705
  end
704
- if dialog.contents and dialog.scroll_top >= dialog.contents.size
705
- dialog.scroll_top = dialog.contents.size - height
706
- end
707
706
  if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
708
707
  bar_max_height = height * 2
709
708
  moving_distance = (dialog_render_info.contents.size - height) * 2
710
709
  position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
711
710
  bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
711
+ bar_height = MINIMUM_SCROLLBAR_HEIGHT if bar_height < MINIMUM_SCROLLBAR_HEIGHT
712
712
  dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
713
713
  else
714
714
  dialog.scrollbar_pos = nil
@@ -741,24 +741,21 @@ class Reline::LineEditor
741
741
  Reline::IOGate.move_cursor_column(dialog.column)
742
742
  dialog.contents.each_with_index do |item, i|
743
743
  if i == pointer
744
- bg_color = '45'
744
+ fg_color = dialog_render_info.pointer_fg_color
745
+ bg_color = dialog_render_info.pointer_bg_color
745
746
  else
746
- if dialog_render_info.bg_color
747
- bg_color = dialog_render_info.bg_color
748
- else
749
- bg_color = '46'
750
- end
747
+ fg_color = dialog_render_info.fg_color
748
+ bg_color = dialog_render_info.bg_color
751
749
  end
752
750
  str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
753
751
  str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
754
- @output.write "\e[#{bg_color}m#{str}"
755
- if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
752
+ @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}"
753
+ if dialog.scrollbar_pos
756
754
  @output.write "\e[37m"
757
755
  if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
758
756
  @output.write @full_block
759
757
  elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
760
758
  @output.write @upper_half_block
761
- str += ''
762
759
  elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
763
760
  @output.write @lower_half_block
764
761
  else
@@ -772,8 +769,10 @@ class Reline::LineEditor
772
769
  Reline::IOGate.move_cursor_column(cursor_column)
773
770
  move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
774
771
  Reline::IOGate.show_cursor
772
+ lines = whole_lines
775
773
  dialog.lines_backup = {
776
- lines: modify_lines(whole_lines),
774
+ unmodified_lines: lines,
775
+ lines: modify_lines(lines),
777
776
  line_index: @line_index,
778
777
  first_line_started_from: @first_line_started_from,
779
778
  started_from: @started_from,
@@ -783,7 +782,7 @@ class Reline::LineEditor
783
782
 
784
783
  private def reset_dialog(dialog, old_dialog)
785
784
  return if dialog.lines_backup.nil? or old_dialog.contents.nil?
786
- prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
785
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:unmodified_lines])
787
786
  visual_lines = []
788
787
  visual_start = nil
789
788
  dialog.lines_backup[:lines].each_with_index { |l, i|
@@ -883,10 +882,18 @@ class Reline::LineEditor
883
882
  end
884
883
  end
885
884
 
885
+ private def clear_dialog_with_content
886
+ @dialogs.each do |dialog|
887
+ clear_each_dialog(dialog)
888
+ dialog.contents = nil
889
+ dialog.trap_key = nil
890
+ end
891
+ end
892
+
886
893
  private def clear_each_dialog(dialog)
887
894
  dialog.trap_key = nil
888
895
  return unless dialog.contents
889
- prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
896
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:unmodified_lines])
890
897
  visual_lines = []
891
898
  visual_lines_under_dialog = []
892
899
  visual_start = nil
@@ -954,11 +961,20 @@ class Reline::LineEditor
954
961
  end
955
962
  end
956
963
 
957
- private def rerender_added_newline(prompt, prompt_width)
958
- scroll_down(1)
964
+ private def rerender_added_newline(prompt, prompt_width, prompt_list)
959
965
  @buffer_of_lines[@previous_line_index] = @line
960
966
  @line = @buffer_of_lines[@line_index]
961
- unless @in_pasting
967
+ @previous_line_index = nil
968
+ if @in_pasting
969
+ scroll_down(1)
970
+ else
971
+ lines = whole_lines
972
+ prev_line_prompt = @prompt_proc ? prompt_list[@line_index - 1] : prompt
973
+ prev_line_prompt_width = @prompt_proc ? calculate_width(prev_line_prompt, true) : prompt_width
974
+ prev_line = modify_lines(lines)[@line_index - 1]
975
+ move_cursor_up(@started_from)
976
+ render_partial(prev_line_prompt, prev_line_prompt_width, prev_line, @first_line_started_from + @started_from, with_control: false)
977
+ scroll_down(1)
962
978
  render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
963
979
  end
964
980
  @cursor = @cursor_max = calculate_width(@line)
@@ -967,7 +983,6 @@ class Reline::LineEditor
967
983
  @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
968
984
  @first_line_started_from += @started_from + 1
969
985
  @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
970
- @previous_line_index = nil
971
986
  end
972
987
 
973
988
  def just_move_cursor
@@ -980,22 +995,18 @@ class Reline::LineEditor
980
995
  calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
981
996
  end
982
997
  first_line_diff = new_first_line_started_from - @first_line_started_from
983
- new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
984
- new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1
998
+ @cursor, @cursor_max, _, @byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
999
+ new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
985
1000
  calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
986
1001
  @previous_line_index = nil
1002
+ @line = @buffer_of_lines[@line_index]
987
1003
  if @rerender_all
988
- @line = @buffer_of_lines[@line_index]
989
1004
  rerender_all_lines
990
1005
  @rerender_all = false
991
1006
  true
992
1007
  else
993
- @line = @buffer_of_lines[@line_index]
994
1008
  @first_line_started_from = new_first_line_started_from
995
1009
  @started_from = new_started_from
996
- @cursor = new_cursor
997
- @cursor_max = new_cursor_max
998
- @byte_pointer = new_byte_pointer
999
1010
  move_cursor_down(first_line_diff + @started_from)
1000
1011
  Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
1001
1012
  false
@@ -1003,11 +1014,7 @@ class Reline::LineEditor
1003
1014
  end
1004
1015
 
1005
1016
  private def rerender_changed_current_line
1006
- if @previous_line_index
1007
- new_lines = whole_lines(index: @previous_line_index, line: @line)
1008
- else
1009
- new_lines = whole_lines
1010
- end
1017
+ new_lines = whole_lines
1011
1018
  prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
1012
1019
  all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
1013
1020
  diff = all_height - @highest_in_all
@@ -1361,8 +1368,8 @@ class Reline::LineEditor
1361
1368
  @completion_state = CompletionState::MENU
1362
1369
  end
1363
1370
  if not just_show_list and target < completed
1364
- @line = preposing + completed + completion_append_character.to_s + postposing
1365
- line_to_pointer = preposing + completed + completion_append_character.to_s
1371
+ @line = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
1372
+ line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
1366
1373
  @cursor_max = calculate_width(@line)
1367
1374
  @cursor = calculate_width(line_to_pointer)
1368
1375
  @byte_pointer = line_to_pointer.bytesize
@@ -1420,7 +1427,7 @@ class Reline::LineEditor
1420
1427
  if @waiting_operator_proc
1421
1428
  if VI_MOTIONS.include?(method_symbol)
1422
1429
  old_cursor, old_byte_pointer = @cursor, @byte_pointer
1423
- @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg > 1
1430
+ @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
1424
1431
  block.(true)
1425
1432
  unless @waiting_proc
1426
1433
  cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
@@ -1688,7 +1695,7 @@ class Reline::LineEditor
1688
1695
  return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
1689
1696
  if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
1690
1697
  # Fix indent of a line when a newline is inserted to the next
1691
- new_lines = whole_lines(index: @previous_line_index, line: @line)
1698
+ new_lines = whole_lines
1692
1699
  new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
1693
1700
  md = @line.match(/\A */)
1694
1701
  prev_indent = md[0].count(' ')
@@ -1703,23 +1710,20 @@ class Reline::LineEditor
1703
1710
  @line = ' ' * new_indent + @line.lstrip
1704
1711
  end
1705
1712
  end
1706
- if @previous_line_index
1707
- new_lines = whole_lines(index: @previous_line_index, line: @line)
1708
- else
1709
- new_lines = whole_lines
1710
- end
1713
+ new_lines = whole_lines
1711
1714
  new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
1712
- new_indent = @cursor_max if new_indent&.> @cursor_max
1713
1715
  if new_indent&.>= 0
1714
1716
  md = new_lines[@line_index].match(/\A */)
1715
1717
  prev_indent = md[0].count(' ')
1716
1718
  if @check_new_auto_indent
1717
- @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
1719
+ line = @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
1718
1720
  @cursor = new_indent
1721
+ @cursor_max = calculate_width(line)
1719
1722
  @byte_pointer = new_indent
1720
1723
  else
1721
1724
  @line = ' ' * new_indent + @line.lstrip
1722
1725
  @cursor += new_indent - prev_indent
1726
+ @cursor_max = calculate_width(@line)
1723
1727
  @byte_pointer += new_indent - prev_indent
1724
1728
  end
1725
1729
  end
@@ -1793,11 +1797,7 @@ class Reline::LineEditor
1793
1797
  target = before
1794
1798
  end
1795
1799
  if @is_multiline
1796
- if @previous_line_index
1797
- lines = whole_lines(index: @previous_line_index, line: @line)
1798
- else
1799
- lines = whole_lines
1800
- end
1800
+ lines = whole_lines
1801
1801
  if @line_index > 0
1802
1802
  preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
1803
1803
  end
@@ -1897,9 +1897,10 @@ class Reline::LineEditor
1897
1897
  @cursor_max = calculate_width(@line)
1898
1898
  end
1899
1899
 
1900
- def whole_lines(index: @line_index, line: @line)
1900
+ def whole_lines
1901
+ index = @previous_line_index || @line_index
1901
1902
  temp_lines = @buffer_of_lines.dup
1902
- temp_lines[index] = line
1903
+ temp_lines[index] = @line
1903
1904
  temp_lines
1904
1905
  end
1905
1906
 
@@ -1907,11 +1908,7 @@ class Reline::LineEditor
1907
1908
  if @buffer_of_lines.size == 1 and @line.nil?
1908
1909
  nil
1909
1910
  else
1910
- if @previous_line_index
1911
- whole_lines(index: @previous_line_index, line: @line).join("\n")
1912
- else
1913
- whole_lines.join("\n")
1914
- end
1911
+ whole_lines.join("\n")
1915
1912
  end
1916
1913
  end
1917
1914
 
@@ -1943,8 +1940,10 @@ class Reline::LineEditor
1943
1940
  end
1944
1941
 
1945
1942
  private def key_delete(key)
1946
- if @config.editing_mode_is?(:vi_insert, :emacs)
1943
+ if @config.editing_mode_is?(:vi_insert)
1947
1944
  ed_delete_next_char(key)
1945
+ elsif @config.editing_mode_is?(:emacs)
1946
+ em_delete(key)
1948
1947
  end
1949
1948
  end
1950
1949
 
@@ -2223,6 +2222,8 @@ class Reline::LineEditor
2223
2222
  @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
2224
2223
  @line_index = @buffer_of_lines.size - 1
2225
2224
  @line = @buffer_of_lines.last
2225
+ @byte_pointer = @line.bytesize
2226
+ @cursor = @cursor_max = calculate_width(@line)
2226
2227
  @rerender_all = true
2227
2228
  @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
2228
2229
  else
@@ -2648,7 +2649,7 @@ class Reline::LineEditor
2648
2649
  alias_method :kill_whole_line, :em_kill_line
2649
2650
 
2650
2651
  private def em_delete(key)
2651
- if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
2652
+ if @line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == "\C-d".ord
2652
2653
  @line = nil
2653
2654
  if @buffer_of_lines.size > 1
2654
2655
  scroll_down(@highest_in_all - @first_line_started_from)
@@ -35,7 +35,7 @@ module Reline::Terminfo
35
35
  # Gem module isn't defined in test-all of the Ruby repository, and
36
36
  # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
37
37
  fiddle_supports_variadic = true
38
- elsif Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
38
+ elsif Fiddle.const_defined?(:VERSION,false) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
39
39
  # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
40
40
  fiddle_supports_variadic = true
41
41
  else
@@ -92,9 +92,9 @@ module Reline::Terminfo
92
92
  end
93
93
 
94
94
  def self.setupterm(term, fildes)
95
- errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
95
+ errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
96
96
  ret = @setupterm.(term, fildes, errret_int)
97
- errret = errret_int.unpack1('i')
97
+ errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
98
98
  case ret
99
99
  when 0 # OK
100
100
  0
@@ -121,6 +121,7 @@ module Reline::Terminfo
121
121
  end
122
122
 
123
123
  def self.tigetstr(capname)
124
+ raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
124
125
  capability = @tigetstr.(capname)
125
126
  case capability.to_i
126
127
  when 0, -1
@@ -138,6 +139,7 @@ module Reline::Terminfo
138
139
  end
139
140
 
140
141
  def self.tigetflag(capname)
142
+ raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
141
143
  flag = @tigetflag.(capname).to_i
142
144
  case flag
143
145
  when -1
@@ -149,6 +151,7 @@ module Reline::Terminfo
149
151
  end
150
152
 
151
153
  def self.tigetnum(capname)
154
+ raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
152
155
  num = @tigetnum.(capname).to_i
153
156
  case num
154
157
  when -2
@@ -84,8 +84,13 @@ class Reline::Unicode::EastAsianWidth
84
84
  \u{17000}-\u{187F7}
85
85
  \u{18800}-\u{18CD5}
86
86
  \u{18D00}-\u{18D08}
87
- \u{1B000}-\u{1B11E}
87
+ \u{1AFF0}-\u{1AFF3}
88
+ \u{1AFF5}-\u{1AFFB}
89
+ \u{1AFFD}-\u{1AFFE}
90
+ \u{1B000}-\u{1B122}
91
+ \u{1B132}
88
92
  \u{1B150}-\u{1B152}
93
+ \u{1B155}
89
94
  \u{1B164}-\u{1B167}
90
95
  \u{1B170}-\u{1B2FB}
91
96
  \u{1F004}
@@ -119,21 +124,21 @@ class Reline::Unicode::EastAsianWidth
119
124
  \u{1F6CC}
120
125
  \u{1F6D0}-\u{1F6D2}
121
126
  \u{1F6D5}-\u{1F6D7}
127
+ \u{1F6DC}-\u{1F6DF}
122
128
  \u{1F6EB}-\u{1F6EC}
123
129
  \u{1F6F4}-\u{1F6FC}
124
130
  \u{1F7E0}-\u{1F7EB}
131
+ \u{1F7F0}
125
132
  \u{1F90C}-\u{1F93A}
126
133
  \u{1F93C}-\u{1F945}
127
- \u{1F947}-\u{1F978}
128
- \u{1F97A}-\u{1F9CB}
129
- \u{1F9CD}-\u{1F9FF}
130
- \u{1FA70}-\u{1FA74}
131
- \u{1FA78}-\u{1FA7A}
132
- \u{1FA80}-\u{1FA86}
133
- \u{1FA90}-\u{1FAA8}
134
- \u{1FAB0}-\u{1FAB6}
135
- \u{1FAC0}-\u{1FAC2}
136
- \u{1FAD0}-\u{1FAD6}
134
+ \u{1F947}-\u{1F9FF}
135
+ \u{1FA70}-\u{1FA7C}
136
+ \u{1FA80}-\u{1FA88}
137
+ \u{1FA90}-\u{1FABD}
138
+ \u{1FABF}-\u{1FAC5}
139
+ \u{1FACE}-\u{1FADB}
140
+ \u{1FAE0}-\u{1FAE8}
141
+ \u{1FAF0}-\u{1FAF8}
137
142
  \u{20000}-\u{2FFFD}
138
143
  \u{30000}-\u{3FFFD}
139
144
  ).join }]/
@@ -403,8 +408,7 @@ class Reline::Unicode::EastAsianWidth
403
408
  \u{0591}-\u{05C7}
404
409
  \u{05D0}-\u{05EA}
405
410
  \u{05EF}-\u{05F4}
406
- \u{0600}-\u{061C}
407
- \u{061E}-\u{070D}
411
+ \u{0600}-\u{070D}
408
412
  \u{070F}-\u{074A}
409
413
  \u{074D}-\u{07B1}
410
414
  \u{07C0}-\u{07FA}
@@ -413,9 +417,9 @@ class Reline::Unicode::EastAsianWidth
413
417
  \u{0840}-\u{085B}
414
418
  \u{085E}
415
419
  \u{0860}-\u{086A}
416
- \u{08A0}-\u{08B4}
417
- \u{08B6}-\u{08C7}
418
- \u{08D3}-\u{0983}
420
+ \u{0870}-\u{088E}
421
+ \u{0890}-\u{0891}
422
+ \u{0898}-\u{0983}
419
423
  \u{0985}-\u{098C}
420
424
  \u{098F}-\u{0990}
421
425
  \u{0993}-\u{09A8}
@@ -493,11 +497,12 @@ class Reline::Unicode::EastAsianWidth
493
497
  \u{0C0E}-\u{0C10}
494
498
  \u{0C12}-\u{0C28}
495
499
  \u{0C2A}-\u{0C39}
496
- \u{0C3D}-\u{0C44}
500
+ \u{0C3C}-\u{0C44}
497
501
  \u{0C46}-\u{0C48}
498
502
  \u{0C4A}-\u{0C4D}
499
503
  \u{0C55}-\u{0C56}
500
504
  \u{0C58}-\u{0C5A}
505
+ \u{0C5D}
501
506
  \u{0C60}-\u{0C63}
502
507
  \u{0C66}-\u{0C6F}
503
508
  \u{0C77}-\u{0C8C}
@@ -509,10 +514,10 @@ class Reline::Unicode::EastAsianWidth
509
514
  \u{0CC6}-\u{0CC8}
510
515
  \u{0CCA}-\u{0CCD}
511
516
  \u{0CD5}-\u{0CD6}
512
- \u{0CDE}
517
+ \u{0CDD}-\u{0CDE}
513
518
  \u{0CE0}-\u{0CE3}
514
519
  \u{0CE6}-\u{0CEF}
515
- \u{0CF1}-\u{0CF2}
520
+ \u{0CF1}-\u{0CF3}
516
521
  \u{0D00}-\u{0D0C}
517
522
  \u{0D0E}-\u{0D10}
518
523
  \u{0D12}-\u{0D44}
@@ -542,7 +547,7 @@ class Reline::Unicode::EastAsianWidth
542
547
  \u{0EA7}-\u{0EBD}
543
548
  \u{0EC0}-\u{0EC4}
544
549
  \u{0EC6}
545
- \u{0EC8}-\u{0ECD}
550
+ \u{0EC8}-\u{0ECE}
546
551
  \u{0ED0}-\u{0ED9}
547
552
  \u{0EDC}-\u{0EDF}
548
553
  \u{0F00}-\u{0F47}
@@ -577,9 +582,8 @@ class Reline::Unicode::EastAsianWidth
577
582
  \u{13F8}-\u{13FD}
578
583
  \u{1400}-\u{169C}
579
584
  \u{16A0}-\u{16F8}
580
- \u{1700}-\u{170C}
581
- \u{170E}-\u{1714}
582
- \u{1720}-\u{1736}
585
+ \u{1700}-\u{1715}
586
+ \u{171F}-\u{1736}
583
587
  \u{1740}-\u{1753}
584
588
  \u{1760}-\u{176C}
585
589
  \u{176E}-\u{1770}
@@ -587,8 +591,7 @@ class Reline::Unicode::EastAsianWidth
587
591
  \u{1780}-\u{17DD}
588
592
  \u{17E0}-\u{17E9}
589
593
  \u{17F0}-\u{17F9}
590
- \u{1800}-\u{180E}
591
- \u{1810}-\u{1819}
594
+ \u{1800}-\u{1819}
592
595
  \u{1820}-\u{1878}
593
596
  \u{1880}-\u{18AA}
594
597
  \u{18B0}-\u{18F5}
@@ -607,9 +610,9 @@ class Reline::Unicode::EastAsianWidth
607
610
  \u{1A7F}-\u{1A89}
608
611
  \u{1A90}-\u{1A99}
609
612
  \u{1AA0}-\u{1AAD}
610
- \u{1AB0}-\u{1AC0}
611
- \u{1B00}-\u{1B4B}
612
- \u{1B50}-\u{1B7C}
613
+ \u{1AB0}-\u{1ACE}
614
+ \u{1B00}-\u{1B4C}
615
+ \u{1B50}-\u{1B7E}
613
616
  \u{1B80}-\u{1BF3}
614
617
  \u{1BFC}-\u{1C37}
615
618
  \u{1C3B}-\u{1C49}
@@ -617,8 +620,7 @@ class Reline::Unicode::EastAsianWidth
617
620
  \u{1C90}-\u{1CBA}
618
621
  \u{1CBD}-\u{1CC7}
619
622
  \u{1CD0}-\u{1CFA}
620
- \u{1D00}-\u{1DF9}
621
- \u{1DFB}-\u{1F15}
623
+ \u{1D00}-\u{1F15}
622
624
  \u{1F18}-\u{1F1D}
623
625
  \u{1F20}-\u{1F45}
624
626
  \u{1F48}-\u{1F4D}
@@ -653,7 +655,7 @@ class Reline::Unicode::EastAsianWidth
653
655
  \u{2090}-\u{209C}
654
656
  \u{20A0}-\u{20A8}
655
657
  \u{20AA}-\u{20AB}
656
- \u{20AD}-\u{20BF}
658
+ \u{20AD}-\u{20C0}
657
659
  \u{20D0}-\u{20F0}
658
660
  \u{2100}-\u{2102}
659
661
  \u{2104}
@@ -767,9 +769,7 @@ class Reline::Unicode::EastAsianWidth
767
769
  \u{2B51}-\u{2B54}
768
770
  \u{2B5A}-\u{2B73}
769
771
  \u{2B76}-\u{2B95}
770
- \u{2B97}-\u{2C2E}
771
- \u{2C30}-\u{2C5E}
772
- \u{2C60}-\u{2CF3}
772
+ \u{2B97}-\u{2CF3}
773
773
  \u{2CF9}-\u{2D25}
774
774
  \u{2D27}
775
775
  \u{2D2D}
@@ -784,14 +784,16 @@ class Reline::Unicode::EastAsianWidth
784
784
  \u{2DC8}-\u{2DCE}
785
785
  \u{2DD0}-\u{2DD6}
786
786
  \u{2DD8}-\u{2DDE}
787
- \u{2DE0}-\u{2E52}
787
+ \u{2DE0}-\u{2E5D}
788
788
  \u{303F}
789
789
  \u{4DC0}-\u{4DFF}
790
790
  \u{A4D0}-\u{A62B}
791
791
  \u{A640}-\u{A6F7}
792
- \u{A700}-\u{A7BF}
793
- \u{A7C2}-\u{A7CA}
794
- \u{A7F5}-\u{A82C}
792
+ \u{A700}-\u{A7CA}
793
+ \u{A7D0}-\u{A7D1}
794
+ \u{A7D3}
795
+ \u{A7D5}-\u{A7D9}
796
+ \u{A7F2}-\u{A82C}
795
797
  \u{A830}-\u{A839}
796
798
  \u{A840}-\u{A877}
797
799
  \u{A880}-\u{A8C5}
@@ -823,11 +825,11 @@ class Reline::Unicode::EastAsianWidth
823
825
  \u{FB3E}
824
826
  \u{FB40}-\u{FB41}
825
827
  \u{FB43}-\u{FB44}
826
- \u{FB46}-\u{FBC1}
827
- \u{FBD3}-\u{FD3F}
828
- \u{FD50}-\u{FD8F}
828
+ \u{FB46}-\u{FBC2}
829
+ \u{FBD3}-\u{FD8F}
829
830
  \u{FD92}-\u{FDC7}
830
- \u{FDF0}-\u{FDFD}
831
+ \u{FDCF}
832
+ \u{FDF0}-\u{FDFF}
831
833
  \u{FE20}-\u{FE2F}
832
834
  \u{FE70}-\u{FE74}
833
835
  \u{FE76}-\u{FEFC}
@@ -861,10 +863,20 @@ class Reline::Unicode::EastAsianWidth
861
863
  \u{104D8}-\u{104FB}
862
864
  \u{10500}-\u{10527}
863
865
  \u{10530}-\u{10563}
864
- \u{1056F}
866
+ \u{1056F}-\u{1057A}
867
+ \u{1057C}-\u{1058A}
868
+ \u{1058C}-\u{10592}
869
+ \u{10594}-\u{10595}
870
+ \u{10597}-\u{105A1}
871
+ \u{105A3}-\u{105B1}
872
+ \u{105B3}-\u{105B9}
873
+ \u{105BB}-\u{105BC}
865
874
  \u{10600}-\u{10736}
866
875
  \u{10740}-\u{10755}
867
876
  \u{10760}-\u{10767}
877
+ \u{10780}-\u{10785}
878
+ \u{10787}-\u{107B0}
879
+ \u{107B2}-\u{107BA}
868
880
  \u{10800}-\u{10805}
869
881
  \u{10808}
870
882
  \u{1080A}-\u{10835}
@@ -906,13 +918,14 @@ class Reline::Unicode::EastAsianWidth
906
918
  \u{10E80}-\u{10EA9}
907
919
  \u{10EAB}-\u{10EAD}
908
920
  \u{10EB0}-\u{10EB1}
909
- \u{10F00}-\u{10F27}
921
+ \u{10EFD}-\u{10F27}
910
922
  \u{10F30}-\u{10F59}
923
+ \u{10F70}-\u{10F89}
911
924
  \u{10FB0}-\u{10FCB}
912
925
  \u{10FE0}-\u{10FF6}
913
926
  \u{11000}-\u{1104D}
914
- \u{11052}-\u{1106F}
915
- \u{1107F}-\u{110C1}
927
+ \u{11052}-\u{11075}
928
+ \u{1107F}-\u{110C2}
916
929
  \u{110CD}
917
930
  \u{110D0}-\u{110E8}
918
931
  \u{110F0}-\u{110F9}
@@ -922,7 +935,7 @@ class Reline::Unicode::EastAsianWidth
922
935
  \u{11180}-\u{111DF}
923
936
  \u{111E1}-\u{111F4}
924
937
  \u{11200}-\u{11211}
925
- \u{11213}-\u{1123E}
938
+ \u{11213}-\u{11241}
926
939
  \u{11280}-\u{11286}
927
940
  \u{11288}
928
941
  \u{1128A}-\u{1128D}
@@ -954,11 +967,11 @@ class Reline::Unicode::EastAsianWidth
954
967
  \u{11600}-\u{11644}
955
968
  \u{11650}-\u{11659}
956
969
  \u{11660}-\u{1166C}
957
- \u{11680}-\u{116B8}
970
+ \u{11680}-\u{116B9}
958
971
  \u{116C0}-\u{116C9}
959
972
  \u{11700}-\u{1171A}
960
973
  \u{1171D}-\u{1172B}
961
- \u{11730}-\u{1173F}
974
+ \u{11730}-\u{11746}
962
975
  \u{11800}-\u{1183B}
963
976
  \u{118A0}-\u{118F2}
964
977
  \u{118FF}-\u{11906}
@@ -974,7 +987,8 @@ class Reline::Unicode::EastAsianWidth
974
987
  \u{119DA}-\u{119E4}
975
988
  \u{11A00}-\u{11A47}
976
989
  \u{11A50}-\u{11AA2}
977
- \u{11AC0}-\u{11AF8}
990
+ \u{11AB0}-\u{11AF8}
991
+ \u{11B00}-\u{11B09}
978
992
  \u{11C00}-\u{11C08}
979
993
  \u{11C0A}-\u{11C36}
980
994
  \u{11C38}-\u{11C45}
@@ -996,19 +1010,23 @@ class Reline::Unicode::EastAsianWidth
996
1010
  \u{11D93}-\u{11D98}
997
1011
  \u{11DA0}-\u{11DA9}
998
1012
  \u{11EE0}-\u{11EF8}
1013
+ \u{11F00}-\u{11F10}
1014
+ \u{11F12}-\u{11F3A}
1015
+ \u{11F3E}-\u{11F59}
999
1016
  \u{11FB0}
1000
1017
  \u{11FC0}-\u{11FF1}
1001
1018
  \u{11FFF}-\u{12399}
1002
1019
  \u{12400}-\u{1246E}
1003
1020
  \u{12470}-\u{12474}
1004
1021
  \u{12480}-\u{12543}
1005
- \u{13000}-\u{1342E}
1006
- \u{13430}-\u{13438}
1022
+ \u{12F90}-\u{12FF2}
1023
+ \u{13000}-\u{13455}
1007
1024
  \u{14400}-\u{14646}
1008
1025
  \u{16800}-\u{16A38}
1009
1026
  \u{16A40}-\u{16A5E}
1010
1027
  \u{16A60}-\u{16A69}
1011
- \u{16A6E}-\u{16A6F}
1028
+ \u{16A6E}-\u{16ABE}
1029
+ \u{16AC0}-\u{16AC9}
1012
1030
  \u{16AD0}-\u{16AED}
1013
1031
  \u{16AF0}-\u{16AF5}
1014
1032
  \u{16B00}-\u{16B45}
@@ -1025,10 +1043,14 @@ class Reline::Unicode::EastAsianWidth
1025
1043
  \u{1BC80}-\u{1BC88}
1026
1044
  \u{1BC90}-\u{1BC99}
1027
1045
  \u{1BC9C}-\u{1BCA3}
1046
+ \u{1CF00}-\u{1CF2D}
1047
+ \u{1CF30}-\u{1CF46}
1048
+ \u{1CF50}-\u{1CFC3}
1028
1049
  \u{1D000}-\u{1D0F5}
1029
1050
  \u{1D100}-\u{1D126}
1030
- \u{1D129}-\u{1D1E8}
1051
+ \u{1D129}-\u{1D1EA}
1031
1052
  \u{1D200}-\u{1D245}
1053
+ \u{1D2C0}-\u{1D2D3}
1032
1054
  \u{1D2E0}-\u{1D2F3}
1033
1055
  \u{1D300}-\u{1D356}
1034
1056
  \u{1D360}-\u{1D378}
@@ -1055,17 +1077,27 @@ class Reline::Unicode::EastAsianWidth
1055
1077
  \u{1D7CE}-\u{1DA8B}
1056
1078
  \u{1DA9B}-\u{1DA9F}
1057
1079
  \u{1DAA1}-\u{1DAAF}
1080
+ \u{1DF00}-\u{1DF1E}
1081
+ \u{1DF25}-\u{1DF2A}
1058
1082
  \u{1E000}-\u{1E006}
1059
1083
  \u{1E008}-\u{1E018}
1060
1084
  \u{1E01B}-\u{1E021}
1061
1085
  \u{1E023}-\u{1E024}
1062
1086
  \u{1E026}-\u{1E02A}
1087
+ \u{1E030}-\u{1E06D}
1088
+ \u{1E08F}
1063
1089
  \u{1E100}-\u{1E12C}
1064
1090
  \u{1E130}-\u{1E13D}
1065
1091
  \u{1E140}-\u{1E149}
1066
1092
  \u{1E14E}-\u{1E14F}
1093
+ \u{1E290}-\u{1E2AE}
1067
1094
  \u{1E2C0}-\u{1E2F9}
1068
1095
  \u{1E2FF}
1096
+ \u{1E4D0}-\u{1E4F9}
1097
+ \u{1E7E0}-\u{1E7E6}
1098
+ \u{1E7E8}-\u{1E7EB}
1099
+ \u{1E7ED}-\u{1E7EE}
1100
+ \u{1E7F0}-\u{1E7FE}
1069
1101
  \u{1E800}-\u{1E8C4}
1070
1102
  \u{1E8C7}-\u{1E8D6}
1071
1103
  \u{1E900}-\u{1E94B}
@@ -1142,8 +1174,8 @@ class Reline::Unicode::EastAsianWidth
1142
1174
  \u{1F6D3}-\u{1F6D4}
1143
1175
  \u{1F6E0}-\u{1F6EA}
1144
1176
  \u{1F6F0}-\u{1F6F3}
1145
- \u{1F700}-\u{1F773}
1146
- \u{1F780}-\u{1F7D8}
1177
+ \u{1F700}-\u{1F776}
1178
+ \u{1F77B}-\u{1F7D9}
1147
1179
  \u{1F800}-\u{1F80B}
1148
1180
  \u{1F810}-\u{1F847}
1149
1181
  \u{1F850}-\u{1F859}
@@ -160,16 +160,21 @@ class Reline::Unicode
160
160
  width = 0
161
161
  rest = str.encode(Encoding::UTF_8)
162
162
  in_zero_width = false
163
+ seq = String.new(encoding: encoding)
163
164
  rest.scan(WIDTH_SCANNER) do |gc|
164
165
  case
165
166
  when gc[NON_PRINTING_START_INDEX]
166
167
  in_zero_width = true
168
+ lines.last << NON_PRINTING_START
167
169
  when gc[NON_PRINTING_END_INDEX]
168
170
  in_zero_width = false
171
+ lines.last << NON_PRINTING_END
169
172
  when gc[CSI_REGEXP_INDEX]
170
173
  lines.last << gc[CSI_REGEXP_INDEX]
174
+ seq << gc[CSI_REGEXP_INDEX]
171
175
  when gc[OSC_REGEXP_INDEX]
172
176
  lines.last << gc[OSC_REGEXP_INDEX]
177
+ seq << gc[OSC_REGEXP_INDEX]
173
178
  when gc[GRAPHEME_CLUSTER_INDEX]
174
179
  gc = gc[GRAPHEME_CLUSTER_INDEX]
175
180
  unless in_zero_width
@@ -177,7 +182,7 @@ class Reline::Unicode
177
182
  if (width += mbchar_width) > max_width
178
183
  width = mbchar_width
179
184
  lines << nil
180
- lines << String.new(encoding: encoding)
185
+ lines << seq.dup
181
186
  height += 1
182
187
  end
183
188
  end
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.3'
3
3
  end
@@ -95,7 +95,7 @@ class Reline::Windows
95
95
  end
96
96
 
97
97
  VK_RETURN = 0x0D
98
- VK_MENU = 0x12
98
+ VK_MENU = 0x12 # ALT key
99
99
  VK_LMENU = 0xA4
100
100
  VK_CONTROL = 0x11
101
101
  VK_SHIFT = 0x10
@@ -249,7 +249,7 @@ class Reline::Windows
249
249
  # no char, only control keys
250
250
  return if key.char_code == 0 and key.control_keys.any?
251
251
 
252
- @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT)
252
+ @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
253
253
 
254
254
  @@output_buf.concat(key.char.bytes)
255
255
  end
@@ -291,6 +291,10 @@ class Reline::Windows
291
291
  end
292
292
  end
293
293
 
294
+ def self.with_raw_input
295
+ yield
296
+ end
297
+
294
298
  def self.getc
295
299
  check_input_event
296
300
  @@output_buf.shift
data/lib/reline.rb CHANGED
@@ -11,6 +11,7 @@ require 'reline/terminfo'
11
11
  require 'rbconfig'
12
12
 
13
13
  module Reline
14
+ # NOTE: For making compatible with the rb-readline gem
14
15
  FILENAME_COMPLETION_PROC = nil
15
16
  USERNAME_COMPLETION_PROC = nil
16
17
 
@@ -33,7 +34,18 @@ module Reline
33
34
  alias_method :==, :match?
34
35
  end
35
36
  CursorPos = Struct.new(:x, :y)
36
- DialogRenderInfo = Struct.new(:pos, :contents, :bg_color, :width, :height, :scrollbar, keyword_init: true)
37
+ DialogRenderInfo = Struct.new(
38
+ :pos,
39
+ :contents,
40
+ :bg_color,
41
+ :pointer_bg_color,
42
+ :fg_color,
43
+ :pointer_fg_color,
44
+ :width,
45
+ :height,
46
+ :scrollbar,
47
+ keyword_init: true
48
+ )
37
49
 
38
50
  class Core
39
51
  ATTR_READER_NAMES = %i(
@@ -58,6 +70,11 @@ module Reline
58
70
  attr_accessor :last_incremental_search
59
71
  attr_reader :output
60
72
 
73
+ extend Forwardable
74
+ def_delegators :config,
75
+ :autocompletion,
76
+ :autocompletion=
77
+
61
78
  def initialize
62
79
  self.output = STDOUT
63
80
  @dialog_proc_list = {}
@@ -123,14 +140,6 @@ module Reline
123
140
  @completion_proc = p
124
141
  end
125
142
 
126
- def autocompletion
127
- @config.autocompletion
128
- end
129
-
130
- def autocompletion=(val)
131
- @config.autocompletion = val
132
- end
133
-
134
143
  def output_modifier_proc=(p)
135
144
  raise ArgumentError unless p.respond_to?(:call) or p.nil?
136
145
  @output_modifier_proc = p
@@ -243,24 +252,35 @@ module Reline
243
252
  context.push(cursor_pos_to_render, result, pointer, dialog)
244
253
  end
245
254
  dialog.pointer = pointer
246
- DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, scrollbar: true, height: 15)
255
+ DialogRenderInfo.new(
256
+ pos: cursor_pos_to_render,
257
+ contents: result,
258
+ scrollbar: true,
259
+ height: 15,
260
+ bg_color: 46,
261
+ pointer_bg_color: 45,
262
+ fg_color: 37,
263
+ pointer_fg_color: 37
264
+ )
247
265
  }
248
266
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
249
267
 
250
268
  def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
251
- unless confirm_multiline_termination
252
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
253
- end
254
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
269
+ Reline::IOGate.with_raw_input do
270
+ unless confirm_multiline_termination
271
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
272
+ end
273
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
255
274
 
256
- whole_buffer = line_editor.whole_buffer.dup
257
- whole_buffer.taint if RUBY_VERSION < '2.7'
258
- if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
259
- Reline::HISTORY << whole_buffer
260
- end
275
+ whole_buffer = line_editor.whole_buffer.dup
276
+ whole_buffer.taint if RUBY_VERSION < '2.7'
277
+ if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
278
+ Reline::HISTORY << whole_buffer
279
+ end
261
280
 
262
- line_editor.reset_line if line_editor.whole_buffer.nil?
263
- whole_buffer
281
+ line_editor.reset_line if line_editor.whole_buffer.nil?
282
+ whole_buffer
283
+ end
264
284
  end
265
285
 
266
286
  def readline(prompt = '', add_hist = false)
@@ -466,7 +486,7 @@ module Reline
466
486
  end
467
487
 
468
488
  private def may_req_ambiguous_char_width
469
- @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
489
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or !STDOUT.tty?
470
490
  return if defined? @ambiguous_width
471
491
  Reline::IOGate.move_cursor_column(0)
472
492
  begin
@@ -563,24 +583,21 @@ module Reline
563
583
  end
564
584
 
565
585
  require 'reline/general_io'
566
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
567
- require 'reline/windows'
568
- if Reline::Windows.msys_tty?
569
- Reline::IOGate = if ENV['TERM'] == 'dumb'
570
- Reline::GeneralIO
571
- else
572
- require 'reline/ansi'
573
- Reline::ANSI
574
- end
586
+ io = Reline::GeneralIO
587
+ unless ENV['TERM'] == 'dumb'
588
+ case RbConfig::CONFIG['host_os']
589
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
590
+ require 'reline/windows'
591
+ tty = (io = Reline::Windows).msys_tty?
575
592
  else
576
- Reline::IOGate = Reline::Windows
593
+ tty = $stdout.tty?
577
594
  end
595
+ end
596
+ Reline::IOGate = if tty
597
+ require 'reline/ansi'
598
+ Reline::ANSI
578
599
  else
579
- Reline::IOGate = if $stdout.isatty
580
- require 'reline/ansi'
581
- Reline::ANSI
582
- else
583
- Reline::GeneralIO
584
- end
600
+ io
585
601
  end
602
+
586
603
  Reline::HISTORY = Reline::History.new(Reline.core.config)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-02 00:00:00.000000000 Z
11
+ date: 2023-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -47,7 +47,6 @@ files:
47
47
  - lib/reline/key_stroke.rb
48
48
  - lib/reline/kill_ring.rb
49
49
  - lib/reline/line_editor.rb
50
- - lib/reline/sibori.rb
51
50
  - lib/reline/terminfo.rb
52
51
  - lib/reline/unicode.rb
53
52
  - lib/reline/unicode/east_asian_width.rb
@@ -66,14 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
65
  requirements:
67
66
  - - ">="
68
67
  - !ruby/object:Gem::Version
69
- version: '2.5'
68
+ version: '2.6'
70
69
  required_rubygems_version: !ruby/object:Gem::Requirement
71
70
  requirements:
72
71
  - - ">="
73
72
  - !ruby/object:Gem::Version
74
73
  version: '0'
75
74
  requirements: []
76
- rubygems_version: 3.0.3.1
75
+ rubygems_version: 3.4.8
77
76
  signing_key:
78
77
  specification_version: 4
79
78
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.
data/lib/reline/sibori.rb DELETED
@@ -1,170 +0,0 @@
1
- require 'reline/unicode'
2
-
3
- =begin
4
-
5
- \ |
6
- \ | <--- whipped cream
7
- \ |
8
- \ |
9
- \-~~|
10
- \ | <--- shibori kutigane (piping nozzle in Japanese)
11
- \Ml
12
- (\ __ __
13
- ( \--( ) )
14
- (__(__)__) <--- compressed whipped cream
15
- =end
16
-
17
- class Sibori
18
- attr_writer :output
19
-
20
- def initialize(width, height, cursor_pos)
21
- @width = width
22
- @height = height
23
- @cursor_pos = cursor_pos
24
- @screen = [String.new]
25
- @line_index = 0
26
- @byte_pointer_in_line = 0
27
- @cleared = false
28
- clone_screen
29
- end
30
-
31
- def clone_screen
32
- @prev_screen = @screen.map { |line|
33
- line.dup
34
- }
35
- @prev_cursor_pos = @cursor_pos.dup
36
- @prev_line_index = @line_index
37
- end
38
-
39
- def print(str)
40
- #$stderr.puts "print #{str.inspect}"
41
- line = @screen[@line_index]
42
- before = line.byteslice(0, @byte_pointer_in_line)
43
- str_width = Reline::Unicode.calculate_width(str, true)
44
- after_cursor = line.byteslice(@byte_pointer_in_line..-1)
45
- after_cursor_width = Reline::Unicode.calculate_width(after_cursor, true)
46
- rest = ''
47
- if after_cursor_width > str_width
48
- rest_byte_pointer = @byte_pointer_in_line + width_to_bytesize(after_cursor, str_width)
49
- rest = line.byteslice(rest_byte_pointer..-1)
50
- end
51
- @screen[@line_index] = before + str + rest
52
- @byte_pointer_in_line += str.bytesize
53
- @cursor_pos.x += Reline::Unicode.calculate_width(str, true)
54
- end
55
-
56
- def move_cursor_column(col)
57
- #$stderr.puts "move_cursor_column(#{col})"
58
- @byte_pointer_in_line = width_to_bytesize(@screen[@line_index], col)
59
- @cursor_pos.x = col
60
- end
61
-
62
- def move_cursor_up(val)
63
- #$stderr.puts "move_cursor_up(#{val})"
64
- if @line_index.positive?
65
- @line_index -= val
66
- @byte_pointer_in_line = width_to_bytesize(@screen[@line_index], @cursor_pos.x)
67
- @cursor_pos.y -= val
68
- end
69
- end
70
-
71
- def move_cursor_down(val)
72
- #$stderr.puts "move_cursor_down(#{val})"
73
- if @line_index < @height - 1
74
- #$stderr.puts "@line_index #{@line_index} @screen.size #{@screen.size} @height #{@height}"
75
- #$stderr.puts @screen.inspect
76
- @line_index += val
77
- @screen[@line_index] = String.new if @line_index == @screen.size
78
- @byte_pointer_in_line = width_to_bytesize(@screen[@line_index], @cursor_pos.x)
79
- @cursor_pos.y += val
80
- end
81
- end
82
-
83
- def scroll_down(val)
84
- #$stderr.puts "scroll_down(#{val})"
85
- if val >= @height
86
- clear_screen
87
- @line_index = @screen.size - 1
88
- return
89
- end
90
- @screen.size.times do |n|
91
- if n < @screen.size - val
92
- #$stderr.puts "A @screen[#{val} + #{n}] (#{@screen[val + n].inspect}) to @screen[#{n}]"
93
- @screen[n] = @screen[val + n]
94
- else
95
- #$stderr.puts "B String.new to @screen[#{n}]"
96
- @screen[n] = String.new
97
- end
98
- end
99
- @line_index += val
100
- end
101
-
102
- def erase_after_cursor
103
- #$stderr.puts "erase_after_cursor"
104
- @screen[@line_index] = @screen[@line_index].byteslice(0, @byte_pointer_in_line)
105
- end
106
-
107
- def clear_screen
108
- #$stderr.puts "clear_screen"
109
- @screen = [String.new]
110
- @line_index = 0
111
- @byte_pointer_in_line = 0
112
- @cursor_pos.x = @cursor_pos.y = 0
113
- @cleared = true
114
- Reline::IOGate.clear_screen
115
- end
116
-
117
- private def width_to_bytesize(str, width)
118
- lines, _ = Reline::Unicode.split_by_width(str, width)
119
- lines.first.bytesize
120
- end
121
-
122
- def render
123
- #$stderr.puts ?* * 100
124
- Reline::IOGate.move_cursor_up(@prev_line_index) if @prev_line_index.positive?
125
- #$stderr.puts "! move_cursor_up(#{@prev_line_index})" if @prev_line_index.positive?
126
- #$stderr.puts "@prev_line_index #{@prev_line_index} @line_index #{@line_index}"
127
- if @screen.size > @prev_screen.size
128
- #$stderr.puts ?a * 100
129
- down = @screen.size - @prev_screen.size
130
- #$stderr.puts "#{@prev_cursor_pos.y} #{down} #{@height}"
131
- if @prev_cursor_pos.y + down > (@height - 1)
132
- #$stderr.puts ?b * 100
133
- scroll = (@prev_cursor_pos.y + down) - (@height - 1)
134
- Reline::IOGate.scroll_down(scroll)
135
- #$stderr.puts "! scroll_down(#{scroll})"
136
- #$stderr.puts "down #{down}"
137
- Reline::IOGate.move_cursor_up(@screen.size - 1 - scroll)
138
- #$stderr.puts "! move_cursor_up(#{@screen.size - 1})"
139
- else
140
- #$stderr.puts ?c * 100
141
- end
142
- end
143
- @screen.size.times do |n|
144
- Reline::IOGate.move_cursor_column(0)
145
- #$stderr.puts "! move_cursor_column(0)"
146
- @output.write @screen[n]
147
- #$stderr.puts "! print #{@screen[n].inspect}"
148
- Reline::IOGate.erase_after_cursor
149
- #$stderr.puts "! erase_after_cursor"
150
- Reline::IOGate.move_cursor_down(1) if n != (@screen.size - 1)
151
- #$stderr.puts "! move_cursor_down(1)" if n != (@screen.size - 1)
152
- end
153
- up = @screen.size - 1 - @line_index
154
- Reline::IOGate.move_cursor_up(up) if up.positive?
155
- #$stderr.puts "! move_cursor_up(#{up})" if up.positive?
156
- column = Reline::Unicode.calculate_width(@screen[@line_index].byteslice(0, @byte_pointer_in_line), true)
157
- Reline::IOGate.move_cursor_column(column)
158
- #$stderr.puts "! move_cursor_column(#{column}) #{@byte_pointer_in_line}"
159
- clone_screen
160
- #$stderr.puts ?- * 10
161
- end
162
-
163
- def prep
164
- Reline::IOGate.prep
165
- end
166
-
167
- def deprep
168
- Reline::IOGate.deprep
169
- end
170
- end