reline 0.2.8.pre.9 → 0.2.8.pre.10

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: b41b69340a1422f198eda02baddc77ce7ff82ed3ba1f61a8101d179e7700da23
4
- data.tar.gz: a396bceef149a9436aba896305172bb68925e2302cb7a2b1074d3c2a0ebb300a
3
+ metadata.gz: cdcb3b1edc046520bc5be9cbddb21a4ba498fd1111319c90b05f76b066155eaa
4
+ data.tar.gz: f5a5af7fb221dc0fb21aac67baa20af7c159f22ee792b5f9264badb1ff8b6ba4
5
5
  SHA512:
6
- metadata.gz: 2f83780bb2f061a88fd2d50c613efff97e56e346f484230f502ef34793bfffaa9bd374647ebdb297c80796323ab1646bd578ee59d807b665efdf24d95810267f
7
- data.tar.gz: b5312082646ee37cd04bc2b1aa71115632c92727f56428bfb908a549bfae841d179e426041a94e3595443e218466fead012cd91dce4ebc984de5f16dc0d25d1a
6
+ metadata.gz: a40a42eb7fe33b39dbf8d56eae76708caee116462bbe35b537e36b39e0edb8263cd5854f48b8c7ef440b686c5dabb7e34c72ec844c2ab79661797c23a28a9f0f
7
+ data.tar.gz: 9937033c4b7509a3ef39522bc82e574cd6049cfa6204463625bf89ad427ff7c21e36ca3e0a94b11e3b36dfb1cacb2b3a357a3a115e80b13e94eb9512697aea1e
data/lib/reline/ansi.rb CHANGED
@@ -33,11 +33,16 @@ class Reline::ANSI
33
33
  config.add_default_key_binding_by_keymap(:vi_insert, key, func)
34
34
  config.add_default_key_binding_by_keymap(:vi_command, key, func)
35
35
  end
36
+ {
37
+ [27, 91, 90] => :completion_journey_up, # S-Tab
38
+ }.each_pair do |key, func|
39
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
40
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
41
+ end
36
42
  {
37
43
  # default bindings
38
44
  [27, 32] => :em_set_mark, # M-<space>
39
45
  [24, 24] => :em_exchange_mark, # C-x C-x
40
- [27, 91, 90] => :completion_journey_up, # S-Tab
41
46
  }.each_pair do |key, func|
42
47
  config.add_default_key_binding_by_keymap(:emacs, key, func)
43
48
  end
@@ -126,8 +131,8 @@ class Reline::ANSI
126
131
  unless @@buf.empty?
127
132
  return @@buf.shift
128
133
  end
129
- until c = @@input.raw(intr: true, &:getbyte)
130
- sleep 0.1
134
+ until c = @@input.raw(intr: true) { select([@@input], [], [], 0.1) && @@input.getbyte }
135
+ Reline.core.line_editor.resize
131
136
  end
132
137
  (c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
133
138
  rescue Errno::EIO
@@ -43,7 +43,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
43
43
  # 20 ^T
44
44
  :ed_transpose_chars,
45
45
  # 21 ^U
46
- :em_kill_line,
46
+ :ed_kill_line,
47
47
  # 22 ^V
48
48
  :ed_quoted_insert,
49
49
  # 23 ^W
@@ -1,90 +1,87 @@
1
1
  class Reline::KeyStroke
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
2
+ def initialize(config)
3
+ @config = config
4
+ end
5
+
6
+ def compress_meta_key(ary)
7
+ ary.inject([]) { |result, key|
8
+ if result.size > 0 and result.last == "\e".ord
9
+ result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
10
+ else
11
+ result << key
12
+ end
13
+ result
14
+ }
15
+ end
16
+
17
+ def start_with?(me, other)
18
+ compressed_me = compress_meta_key(me)
19
+ compressed_other = compress_meta_key(other)
20
+ i = 0
21
+ loop do
22
+ my_c = compressed_me[i]
23
+ other_c = compressed_other[i]
24
+ other_is_last = (i + 1) == compressed_other.size
25
+ me_is_last = (i + 1) == compressed_me.size
26
+ if my_c != other_c
27
+ if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
28
+ return true
11
29
  else
12
- super
30
+ return false
13
31
  end
32
+ elsif other_is_last
33
+ return true
34
+ elsif me_is_last
35
+ return false
14
36
  end
37
+ i += 1
15
38
  end
39
+ end
16
40
 
17
- refine Array do
18
- def start_with?(other)
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
41
+ def equal?(me, other)
42
+ case me
43
+ when Array
44
+ compressed_me = compress_meta_key(me)
45
+ compressed_other = compress_meta_key(other)
46
+ compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| equal?(i[0], i[1]) }
47
+ when Integer
48
+ if other.is_a?(Reline::Key)
49
+ if other.combined_char == "\e".ord
50
+ false
51
+ else
52
+ other.combined_char == me
39
53
  end
54
+ else
55
+ me == other
40
56
  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
- }
57
- end
58
-
59
- def bytes
60
- self
57
+ when Reline::Key
58
+ if other.is_a?(Integer)
59
+ me.combined_char == other
60
+ else
61
+ me == other
61
62
  end
62
63
  end
63
- }
64
-
65
- def initialize(config)
66
- @config = config
67
64
  end
68
65
 
69
66
  def match_status(input)
70
67
  key_mapping.keys.select { |lhs|
71
- lhs.start_with? input
68
+ start_with?(lhs, input)
72
69
  }.tap { |it|
73
- return :matched if it.size == 1 && (it[0] == input)
74
- return :matching if it.size == 1 && (it[0] != input)
70
+ return :matched if it.size == 1 && equal?(it[0], input)
71
+ return :matching if it.size == 1 && !equal?(it[0], input)
75
72
  return :matched if it.max_by(&:size)&.size&.< input.size
76
73
  return :matching if it.size > 1
77
74
  }
78
75
  key_mapping.keys.select { |lhs|
79
- input.start_with? lhs
76
+ start_with?(input, lhs)
80
77
  }.tap { |it|
81
78
  return it.size > 0 ? :matched : :unmatched
82
79
  }
83
80
  end
84
81
 
85
82
  def expand(input)
86
- input = input.compress_meta_key
87
- lhs = key_mapping.keys.select { |item| input.start_with? item }.sort_by(&:size).last
83
+ input = compress_meta_key(input)
84
+ lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
88
85
  return input unless lhs
89
86
  rhs = key_mapping[lhs]
90
87
 
@@ -5,6 +5,7 @@ require 'tempfile'
5
5
 
6
6
  class Reline::LineEditor
7
7
  # TODO: undo
8
+ # TODO: Use "private alias_method" idiom after drop Ruby 2.5.
8
9
  attr_reader :line
9
10
  attr_reader :byte_pointer
10
11
  attr_accessor :confirm_multiline_termination_proc
@@ -178,43 +179,49 @@ class Reline::LineEditor
178
179
  rescue ArgumentError
179
180
  end
180
181
  Reline::IOGate.set_winch_handler do
181
- @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
182
- old_screen_size = @screen_size
183
- @screen_size = Reline::IOGate.get_screen_size
184
- @screen_height = @screen_size.first
185
- if old_screen_size.last < @screen_size.last # columns increase
186
- @rerender_all = true
187
- rerender
188
- else
189
- back = 0
190
- new_buffer = whole_lines
191
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
192
- new_buffer.each_with_index do |line, index|
193
- prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
194
- width = prompt_width + calculate_width(line)
195
- height = calculate_height_by_width(width)
196
- back += height
197
- end
198
- @highest_in_all = back
199
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
200
- @first_line_started_from =
201
- if @line_index.zero?
202
- 0
203
- else
204
- calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
205
- end
206
- if @prompt_proc
207
- prompt = prompt_list[@line_index]
208
- prompt_width = calculate_width(prompt, true)
182
+ @resized = true
183
+ end
184
+ @block_elem_width = Reline::Unicode.calculate_width('█')
185
+ end
186
+
187
+ def resize
188
+ return unless @resized
189
+ @resized = false
190
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
191
+ old_screen_size = @screen_size
192
+ @screen_size = Reline::IOGate.get_screen_size
193
+ @screen_height = @screen_size.first
194
+ if old_screen_size.last < @screen_size.last # columns increase
195
+ @rerender_all = true
196
+ rerender
197
+ else
198
+ back = 0
199
+ new_buffer = whole_lines
200
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
201
+ new_buffer.each_with_index do |line, index|
202
+ prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
203
+ width = prompt_width + calculate_width(line)
204
+ height = calculate_height_by_width(width)
205
+ back += height
206
+ end
207
+ @highest_in_all = back
208
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
209
+ @first_line_started_from =
210
+ if @line_index.zero?
211
+ 0
212
+ else
213
+ calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
209
214
  end
210
- calculate_nearest_cursor
211
- @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
212
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
213
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
214
- @rerender_all = true
215
+ if @prompt_proc
216
+ prompt = prompt_list[@line_index]
217
+ prompt_width = calculate_width(prompt, true)
215
218
  end
219
+ calculate_nearest_cursor
220
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
221
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
222
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
223
+ @rerender_all = true
216
224
  end
217
- @block_elem_width = Reline::Unicode.calculate_width('█')
218
225
  end
219
226
 
220
227
  def finalize
@@ -264,6 +271,7 @@ class Reline::LineEditor
264
271
  @auto_indent_proc = nil
265
272
  @dialogs = []
266
273
  @last_key = nil
274
+ @resized = false
267
275
  reset_line
268
276
  end
269
277
 
@@ -560,7 +568,7 @@ class Reline::LineEditor
560
568
 
561
569
  class Dialog
562
570
  attr_reader :name, :contents, :width
563
- attr_accessor :scroll_top, :scrollbar_pos, :column, :vertical_offset, :lines_backup, :trap_key
571
+ attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
564
572
 
565
573
  def initialize(name, config, proc_scope)
566
574
  @name = name
@@ -568,6 +576,7 @@ class Reline::LineEditor
568
576
  @proc_scope = proc_scope
569
577
  @width = nil
570
578
  @scroll_top = 0
579
+ @trap_key = nil
571
580
  end
572
581
 
573
582
  def set_cursor_pos(col, row)
@@ -643,7 +652,7 @@ class Reline::LineEditor
643
652
  end
644
653
  old_dialog = dialog.clone
645
654
  dialog.contents = dialog_render_info.contents
646
- pointer = dialog_render_info.pointer
655
+ pointer = dialog.pointer
647
656
  if dialog_render_info.width
648
657
  dialog.width = dialog_render_info.width
649
658
  else
@@ -652,15 +661,15 @@ class Reline::LineEditor
652
661
  height = dialog_render_info.height || DIALOG_HEIGHT
653
662
  height = dialog.contents.size if dialog.contents.size < height
654
663
  if dialog.contents.size > height
655
- if dialog_render_info.pointer
656
- if dialog_render_info.pointer < 0
664
+ if dialog.pointer
665
+ if dialog.pointer < 0
657
666
  dialog.scroll_top = 0
658
- elsif (dialog_render_info.pointer - dialog.scroll_top) >= (height - 1)
659
- dialog.scroll_top = dialog_render_info.pointer - (height - 1)
660
- elsif (dialog_render_info.pointer - dialog.scroll_top) < 0
661
- dialog.scroll_top = dialog_render_info.pointer
667
+ elsif (dialog.pointer - dialog.scroll_top) >= (height - 1)
668
+ dialog.scroll_top = dialog.pointer - (height - 1)
669
+ elsif (dialog.pointer - dialog.scroll_top) < 0
670
+ dialog.scroll_top = dialog.pointer
662
671
  end
663
- pointer = dialog_render_info.pointer - dialog.scroll_top
672
+ pointer = dialog.pointer - dialog.scroll_top
664
673
  end
665
674
  dialog.contents = dialog.contents[dialog.scroll_top, height]
666
675
  end
@@ -711,19 +720,18 @@ class Reline::LineEditor
711
720
  @output.write "\e[#{bg_color}m#{str}"
712
721
  if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
713
722
  @output.write "\e[37m"
714
- if dialog.scrollbar_pos <= (i * 2) and (i * 2 + @block_elem_width) < (dialog.scrollbar_pos + bar_height)
723
+ if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
715
724
  @output.write '█'
716
725
  elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
717
726
  @output.write '▀'
718
727
  str += ''
719
- elsif dialog.scrollbar_pos <= (i * 2 + @block_elem_width) and (i * 2) < (dialog.scrollbar_pos + bar_height)
728
+ elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
720
729
  @output.write '▄'
721
730
  else
722
731
  @output.write ' ' * @block_elem_width
723
732
  end
724
- @output.write "\e[39m"
725
733
  end
726
- @output.write "\e[49m"
734
+ @output.write "\e[0m"
727
735
  Reline::IOGate.move_cursor_column(dialog.column)
728
736
  move_cursor_down(1) if i < (dialog.contents.size - 1)
729
737
  end
@@ -769,7 +777,7 @@ class Reline::LineEditor
769
777
  s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
770
778
  s = padding_space_with_escape_sequences(s, old_dialog.width)
771
779
  end
772
- @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
780
+ @output.write "\e[0m#{s}\e[0m"
773
781
  move_cursor_down(1) if i < (line_num - 1)
774
782
  end
775
783
  move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
@@ -787,7 +795,7 @@ class Reline::LineEditor
787
795
  s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
788
796
  s = padding_space_with_escape_sequences(s, old_dialog.width)
789
797
  end
790
- @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
798
+ @output.write "\e[0m#{s}\e[0m"
791
799
  move_cursor_down(1) if i < (line_num - 1)
792
800
  end
793
801
  move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
@@ -806,7 +814,7 @@ class Reline::LineEditor
806
814
  s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
807
815
  s = padding_space_with_escape_sequences(s, dialog.width)
808
816
  end
809
- @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
817
+ @output.write "\e[0m#{s}\e[0m"
810
818
  move_cursor_down(1) if i < (line_num - 1)
811
819
  end
812
820
  move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
@@ -826,7 +834,7 @@ class Reline::LineEditor
826
834
  s = padding_space_with_escape_sequences(s, dialog.width)
827
835
  end
828
836
  Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
829
- @output.write "\e[39m\e[49m#{s}\e[39m\e[49m"
837
+ @output.write "\e[0m#{s}\e[0m"
830
838
  move_cursor_down(1) if i < (line_num - 1)
831
839
  end
832
840
  move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
@@ -866,10 +874,10 @@ class Reline::LineEditor
866
874
  Reline::IOGate.move_cursor_column(dialog.column)
867
875
  str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
868
876
  str = padding_space_with_escape_sequences(str, dialog.width)
869
- @output.write "\e[39m\e[49m#{str}\e[39m\e[49m"
877
+ @output.write "\e[0m#{str}\e[0m"
870
878
  else
871
879
  Reline::IOGate.move_cursor_column(dialog.column)
872
- @output.write "\e[39m\e[49m#{' ' * dialog.width}\e[39m\e[49m"
880
+ @output.write "\e[0m#{' ' * dialog.width}\e[0m"
873
881
  end
874
882
  move_cursor_down(1) if i < (dialog_vertical_size - 1)
875
883
  end
@@ -1402,7 +1410,10 @@ class Reline::LineEditor
1402
1410
  end
1403
1411
  @waiting_operator_proc = nil
1404
1412
  @waiting_operator_vi_arg = nil
1405
- @vi_arg = nil
1413
+ if @vi_arg
1414
+ @rerender_all = true
1415
+ @vi_arg = nil
1416
+ end
1406
1417
  else
1407
1418
  block.(false)
1408
1419
  end
@@ -1453,7 +1464,10 @@ class Reline::LineEditor
1453
1464
  wrap_method_call(method_symbol, method_obj, key) if method_obj
1454
1465
  end
1455
1466
  @kill_ring.process
1456
- @vi_arg = nil
1467
+ if @vi_arg
1468
+ @rerender_al = true
1469
+ @vi_arg = nil
1470
+ end
1457
1471
  elsif @vi_arg
1458
1472
  if key.chr =~ /[0-9]/
1459
1473
  ed_argument_digit(key)
@@ -1470,7 +1484,10 @@ class Reline::LineEditor
1470
1484
  ed_insert(key) unless @config.editing_mode_is?(:vi_command)
1471
1485
  end
1472
1486
  @kill_ring.process
1473
- @vi_arg = nil
1487
+ if @vi_arg
1488
+ @rerender_all = true
1489
+ @vi_arg = nil
1490
+ end
1474
1491
  end
1475
1492
  elsif @waiting_proc
1476
1493
  @waiting_proc.(key)
@@ -1909,6 +1926,8 @@ class Reline::LineEditor
1909
1926
  end
1910
1927
  end
1911
1928
 
1929
+ # Editline:: +ed-unassigned+ This editor command always results in an error.
1930
+ # GNU Readline:: There is no corresponding macro.
1912
1931
  private def ed_unassigned(key) end # do nothing
1913
1932
 
1914
1933
  private def process_insert(force: false)
@@ -1926,6 +1945,19 @@ class Reline::LineEditor
1926
1945
  @continuous_insertion_buffer.clear
1927
1946
  end
1928
1947
 
1948
+ # Editline:: +ed-insert+ (vi input: almost all; emacs: printable characters)
1949
+ # In insert mode, insert the input character left of the cursor
1950
+ # position. In replace mode, overwrite the character at the
1951
+ # cursor and move the cursor to the right by one character
1952
+ # position. Accept an argument to do this repeatedly. It is an
1953
+ # error if the input character is the NUL character (+Ctrl-@+).
1954
+ # Failure to enlarge the edit buffer also results in an error.
1955
+ # Editline:: +ed-digit+ (emacs: 0 to 9) If in argument input mode, append
1956
+ # the input digit to the argument being read. Otherwise, call
1957
+ # +ed-insert+. It is an error if the input character is not a
1958
+ # digit or if the existing argument is already greater than a
1959
+ # million.
1960
+ # GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
1929
1961
  private def ed_insert(key)
1930
1962
  str = nil
1931
1963
  width = nil
@@ -1976,6 +2008,8 @@ class Reline::LineEditor
1976
2008
  arg.times do
1977
2009
  if key == "\C-j".ord or key == "\C-m".ord
1978
2010
  key_newline(key)
2011
+ elsif key == 0
2012
+ # Ignore NUL.
1979
2013
  else
1980
2014
  ed_insert(key)
1981
2015
  end
@@ -2410,6 +2444,7 @@ class Reline::LineEditor
2410
2444
  arg -= 1
2411
2445
  ed_prev_history(key, arg: arg) if arg > 0
2412
2446
  end
2447
+ alias_method :previous_history, :ed_prev_history
2413
2448
 
2414
2449
  private def ed_next_history(key, arg: 1)
2415
2450
  if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
@@ -2457,6 +2492,7 @@ class Reline::LineEditor
2457
2492
  arg -= 1
2458
2493
  ed_next_history(key, arg: arg) if arg > 0
2459
2494
  end
2495
+ alias_method :next_history, :ed_next_history
2460
2496
 
2461
2497
  private def ed_newline(key)
2462
2498
  process_insert(force: true)
@@ -2491,7 +2527,7 @@ class Reline::LineEditor
2491
2527
  end
2492
2528
  end
2493
2529
 
2494
- private def em_delete_prev_char(key)
2530
+ private def em_delete_prev_char(key, arg: 1)
2495
2531
  if @is_multiline and @cursor == 0 and @line_index > 0
2496
2532
  @buffer_of_lines[@line_index] = @line
2497
2533
  @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
@@ -2509,9 +2545,16 @@ class Reline::LineEditor
2509
2545
  @cursor -= width
2510
2546
  @cursor_max -= width
2511
2547
  end
2548
+ arg -= 1
2549
+ em_delete_prev_char(key, arg: arg) if arg > 0
2512
2550
  end
2513
2551
  alias_method :backward_delete_char, :em_delete_prev_char
2514
2552
 
2553
+ # Editline:: +ed-kill-line+ (vi command: +D+, +Ctrl-K+; emacs: +Ctrl-K+,
2554
+ # +Ctrl-U+) + Kill from the cursor to the end of the line.
2555
+ # GNU Readline:: +kill-line+ (+C-k+) Kill the text from point to the end of
2556
+ # the line. With a negative numeric argument, kill backward
2557
+ # from the cursor to the beginning of the current line.
2515
2558
  private def ed_kill_line(key)
2516
2559
  if @line.bytesize > @byte_pointer
2517
2560
  @line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
@@ -2528,8 +2571,14 @@ class Reline::LineEditor
2528
2571
  @rest_height += 1
2529
2572
  end
2530
2573
  end
2574
+ alias_method :kill_line, :ed_kill_line
2531
2575
 
2532
- private def em_kill_line(key)
2576
+ # Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
2577
+ # beginning of the edit buffer to the cursor and save it to the
2578
+ # cut buffer.
2579
+ # GNU Readline:: +unix-line-discard+ (+C-u+) Kill backward from the cursor
2580
+ # to the beginning of the current line.
2581
+ private def vi_kill_line_prev(key)
2533
2582
  if @byte_pointer > 0
2534
2583
  @line, deleted = byteslice!(@line, 0, @byte_pointer)
2535
2584
  @byte_pointer = 0
@@ -2538,7 +2587,22 @@ class Reline::LineEditor
2538
2587
  @cursor = 0
2539
2588
  end
2540
2589
  end
2541
- alias_method :kill_line, :em_kill_line
2590
+ alias_method :unix_line_discard, :vi_kill_line_prev
2591
+
2592
+ # Editline:: +em-kill-line+ (not bound) Delete the entire contents of the
2593
+ # edit buffer and save it to the cut buffer. +vi-kill-line-prev+
2594
+ # GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
2595
+ # current line, no matter where point is.
2596
+ private def em_kill_line(key)
2597
+ if @line.size > 0
2598
+ @kill_ring.append(@line.dup, true)
2599
+ @line.clear
2600
+ @byte_pointer = 0
2601
+ @cursor_max = 0
2602
+ @cursor = 0
2603
+ end
2604
+ end
2605
+ alias_method :kill_whole_line, :em_kill_line
2542
2606
 
2543
2607
  private def em_delete(key)
2544
2608
  if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
@@ -3043,7 +3107,14 @@ class Reline::LineEditor
3043
3107
 
3044
3108
  private def ed_argument_digit(key)
3045
3109
  if @vi_arg.nil?
3046
- unless key.chr.to_i.zero?
3110
+ if key.chr.to_i.zero?
3111
+ if key.anybits?(0b10000000)
3112
+ unescaped_key = key ^ 0b10000000
3113
+ unless unescaped_key.chr.to_i.zero?
3114
+ @vi_arg = unescaped_key.chr.to_i
3115
+ end
3116
+ end
3117
+ else
3047
3118
  @vi_arg = key.chr.to_i
3048
3119
  end
3049
3120
  else
@@ -71,7 +71,7 @@ module Reline::Terminfo
71
71
  def self.setupterm(term, fildes)
72
72
  errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
73
73
  ret = @setupterm.(term, fildes, errret_int)
74
- errret = errret_int.unpack('i')[0]
74
+ errret = errret_int.unpack1('i')
75
75
  case ret
76
76
  when 0 # OK
77
77
  0
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.2.8.pre.9'
2
+ VERSION = '0.2.8.pre.10'
3
3
  end
@@ -184,7 +184,7 @@ class Reline::Windows
184
184
  # DWORD FileNameLength;
185
185
  # WCHAR FileName[1];
186
186
  # } FILE_NAME_INFO
187
- len = p_buffer[0, 4].unpack("L")[0]
187
+ len = p_buffer[0, 4].unpack1("L")
188
188
  name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
189
189
 
190
190
  # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
@@ -234,22 +234,23 @@ class Reline::Windows
234
234
  def self.check_input_event
235
235
  num_of_events = 0.chr * 8
236
236
  while @@output_buf.empty? #or true
237
+ Reline.core.line_editor.resize
237
238
  next if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
238
- next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack('L').first == 0
239
+ next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
239
240
  input_record = 0.chr * 18
240
241
  read_event = 0.chr * 4
241
242
  if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_record, 1, read_event) != 0
242
- event = input_record[0, 2].unpack('s*').first
243
+ event = input_record[0, 2].unpack1('s*')
243
244
  case event
244
245
  when WINDOW_BUFFER_SIZE_EVENT
245
246
  @@winch_handler.()
246
247
  when KEY_EVENT
247
- key_down = input_record[4, 4].unpack('l*').first
248
- repeat_count = input_record[8, 2].unpack('s*').first
249
- virtual_key_code = input_record[10, 2].unpack('s*').first
250
- virtual_scan_code = input_record[12, 2].unpack('s*').first
251
- char_code = input_record[14, 2].unpack('S*').first
252
- control_key_state = input_record[16, 2].unpack('S*').first
248
+ key_down = input_record[4, 4].unpack1('l*')
249
+ repeat_count = input_record[8, 2].unpack1('s*')
250
+ virtual_key_code = input_record[10, 2].unpack1('s*')
251
+ virtual_scan_code = input_record[12, 2].unpack1('s*')
252
+ char_code = input_record[14, 2].unpack1('S*')
253
+ control_key_state = input_record[16, 2].unpack1('S*')
253
254
  is_key_down = key_down.zero? ? false : true
254
255
  if is_key_down
255
256
  process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
@@ -291,8 +292,8 @@ class Reline::Windows
291
292
  def self.cursor_pos
292
293
  csbi = 0.chr * 22
293
294
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
294
- x = csbi[4, 2].unpack('s*').first
295
- y = csbi[6, 2].unpack('s*').first
295
+ x = csbi[4, 2].unpack1('s*')
296
+ y = csbi[6, 2].unpack1('s*')
296
297
  Reline::CursorPos.new(x, y)
297
298
  end
298
299
 
@@ -324,7 +325,7 @@ class Reline::Windows
324
325
  def self.erase_after_cursor
325
326
  csbi = 0.chr * 24
326
327
  @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
327
- cursor = csbi[4, 4].unpack('L').first
328
+ cursor = csbi[4, 4].unpack1('L')
328
329
  written = 0.chr * 4
329
330
  @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
330
331
  @@FillConsoleOutputAttribute.call(@@hConsoleHandle, 0, get_screen_size.last - cursor_pos.x, cursor, written)
@@ -343,8 +344,8 @@ class Reline::Windows
343
344
  def self.clear_screen
344
345
  csbi = 0.chr * 22
345
346
  return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
346
- buffer_width = csbi[0, 2].unpack('S').first
347
- attributes = csbi[8, 2].unpack('S').first
347
+ buffer_width = csbi[0, 2].unpack1('S')
348
+ attributes = csbi[8, 2].unpack1('S')
348
349
  _window_left, window_top, _window_right, window_bottom = *csbi[10,8].unpack('S*')
349
350
  fill_length = buffer_width * (window_bottom - window_top + 1)
350
351
  screen_topleft = window_top * 65536
data/lib/reline.rb CHANGED
@@ -17,19 +17,15 @@ module Reline
17
17
  class ConfigEncodingConversionError < StandardError; end
18
18
 
19
19
  Key = Struct.new('Key', :char, :combined_char, :with_meta) do
20
- def match?(key)
21
- if key.instance_of?(Reline::Key)
22
- (key.char.nil? or char.nil? or char == key.char) and
23
- (key.combined_char.nil? or combined_char.nil? or combined_char == key.combined_char) and
24
- (key.with_meta.nil? or with_meta.nil? or with_meta == key.with_meta)
25
- elsif key.is_a?(Integer) or key.is_a?(Symbol)
26
- if not combined_char.nil? and combined_char == key
27
- true
28
- elsif combined_char.nil? and not char.nil? and char == key
29
- true
30
- else
31
- false
32
- end
20
+ def match?(other)
21
+ case other
22
+ when Reline::Key
23
+ (other.char.nil? or char.nil? or char == other.char) and
24
+ (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
25
+ (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
26
+ when Integer, Symbol
27
+ (combined_char and combined_char == other) or
28
+ (combined_char.nil? and char and char == other)
33
29
  else
34
30
  false
35
31
  end
@@ -37,7 +33,7 @@ module Reline
37
33
  alias_method :==, :match?
38
34
  end
39
35
  CursorPos = Struct.new(:x, :y)
40
- DialogRenderInfo = Struct.new(:pos, :contents, :pointer, :bg_color, :width, :height, :scrollbar, keyword_init: true)
36
+ DialogRenderInfo = Struct.new(:pos, :contents, :bg_color, :width, :height, :scrollbar, keyword_init: true)
41
37
 
42
38
  class Core
43
39
  ATTR_READER_NAMES = %i(
@@ -241,7 +237,8 @@ module Reline
241
237
  context.clear
242
238
  context.push(cursor_pos_to_render, result, pointer, dialog)
243
239
  end
244
- DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, pointer: pointer, scrollbar: true, height: 15)
240
+ dialog.pointer = pointer
241
+ DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, scrollbar: true, height: 15)
245
242
  }
246
243
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
247
244
 
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.9
4
+ version: 0.2.8.pre.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-10 00:00:00.000000000 Z
11
+ date: 2021-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console