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

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: 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