reline 0.5.11 → 0.5.12

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: d2e17ec5d6de83746c38c5e0764f7fa1ecda40f01c18b9e8cdf769e4bf2a155e
4
- data.tar.gz: 7ce06466fae4c8115bb507141998d322595b9e924dfc1ad3001871265088a680
3
+ metadata.gz: 14c0b8843530985ab335eb7dbb365d72708214a67b5a858d75d0aebe605050c3
4
+ data.tar.gz: ba60692647a18e520d1b8ed0fff6ac44b11048b3c8f2f2050a5651955db21c89
5
5
  SHA512:
6
- metadata.gz: 31e90ffea6ac235aad5c2c243fbd41163142f94e044ed9f4980860263fab97154857483755dcacd259fa9b578b1c29be5b878cd7f883f18e7b92380cb5865ef3
7
- data.tar.gz: 54b91a893c536b3e6b5c984c0fc2b053b8978ab586ae361446fb603c4eecfb0240a99c45b25e4996ff58d9ef15fa4e33bab5cef9cb4aef3dc7eab85998af3711
6
+ metadata.gz: 242efcf7910a3981d12f7238df77b20d8c0a4fffb735bc59d53f8662e8fbb149d53c8081adf03bbb2b237f576a6f942ba66f01d6b46e1de29617fb29edb89a58
7
+ data.tar.gz: 9d80fef9e52a79300e6163b9dd5141fe412fc3caa32f108f9158108d54abef6ec23b93fc018afd5efdf374c38713e0973afe06adbbe148cae457ca45dd7024b7
@@ -29,10 +29,6 @@ class Reline::ANSI < Reline::IO
29
29
  'H' => [:ed_move_to_beg, {}],
30
30
  }
31
31
 
32
- if Reline::Terminfo.enabled?
33
- Reline::Terminfo.setupterm(0, 2)
34
- end
35
-
36
32
  def initialize
37
33
  @input = STDIN
38
34
  @output = STDOUT
@@ -42,16 +38,15 @@ class Reline::ANSI < Reline::IO
42
38
 
43
39
  def encoding
44
40
  @input.external_encoding || Encoding.default_external
41
+ rescue IOError
42
+ # STDIN.external_encoding raises IOError in Ruby <= 3.0 when STDIN is closed
43
+ Encoding.default_external
45
44
  end
46
45
 
47
- def set_default_key_bindings(config, allow_terminfo: true)
46
+ def set_default_key_bindings(config)
48
47
  set_bracketed_paste_key_bindings(config)
49
48
  set_default_key_bindings_ansi_cursor(config)
50
- if allow_terminfo && Reline::Terminfo.enabled?
51
- set_default_key_bindings_terminfo(config)
52
- else
53
- set_default_key_bindings_comprehensive_list(config)
54
- end
49
+ set_default_key_bindings_comprehensive_list(config)
55
50
  {
56
51
  [27, 91, 90] => :completion_journey_up, # S-Tab
57
52
  }.each_pair do |key, func|
@@ -98,23 +93,6 @@ class Reline::ANSI < Reline::IO
98
93
  end
99
94
  end
100
95
 
101
- def set_default_key_bindings_terminfo(config)
102
- key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
103
- begin
104
- key_code = Reline::Terminfo.tigetstr(capname)
105
- [ key_code.bytes, key_binding ]
106
- rescue Reline::Terminfo::TerminfoError
107
- # capname is undefined
108
- end
109
- end.compact.to_h
110
-
111
- key_bindings.each_pair do |key, func|
112
- config.add_default_key_binding_by_keymap(:emacs, key, func)
113
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
114
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
115
- end
116
- end
117
-
118
96
  def set_default_key_bindings_comprehensive_list(config)
119
97
  {
120
98
  # xterm
@@ -281,27 +259,11 @@ class Reline::ANSI < Reline::IO
281
259
  end
282
260
 
283
261
  def hide_cursor
284
- seq = "\e[?25l"
285
- if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
286
- begin
287
- seq = Reline::Terminfo.tigetstr('civis')
288
- rescue Reline::Terminfo::TerminfoError
289
- # civis is undefined
290
- end
291
- end
292
- @output.write seq
262
+ @output.write "\e[?25l"
293
263
  end
294
264
 
295
265
  def show_cursor
296
- seq = "\e[?25h"
297
- if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
298
- begin
299
- seq = Reline::Terminfo.tigetstr('cnorm')
300
- rescue Reline::Terminfo::TerminfoError
301
- # cnorm is undefined
302
- end
303
- end
304
- @output.write seq
266
+ @output.write "\e[?25h"
305
267
  end
306
268
 
307
269
  def erase_after_cursor
@@ -21,8 +21,11 @@ class Reline::Dumb < Reline::IO
21
21
  elsif RUBY_PLATFORM =~ /mswin|mingw/
22
22
  Encoding::UTF_8
23
23
  else
24
- @input.external_encoding || Encoding::default_external
24
+ @input.external_encoding || Encoding.default_external
25
25
  end
26
+ rescue IOError
27
+ # STDIN.external_encoding raises IOError in Ruby <= 3.0 when STDIN is closed
28
+ Encoding.default_external
26
29
  end
27
30
 
28
31
  def set_default_key_bindings(_)
@@ -3,8 +3,11 @@ class Reline::KeyStroke
3
3
  CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
4
4
  CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
5
5
 
6
- def initialize(config)
6
+ attr_accessor :encoding
7
+
8
+ def initialize(config, encoding)
7
9
  @config = config
10
+ @encoding = encoding
8
11
  end
9
12
 
10
13
  # Input exactly matches to a key sequence
@@ -21,7 +24,7 @@ class Reline::KeyStroke
21
24
  matched = key_mapping.get(input)
22
25
 
23
26
  # FIXME: Workaround for single byte. remove this after MAPPING is merged into KeyActor.
24
- matched ||= input.size == 1
27
+ matched ||= input.size == 1 && input[0] < 0x80
25
28
  matching ||= input == [ESC_BYTE]
26
29
 
27
30
  if matching && matched
@@ -32,10 +35,14 @@ class Reline::KeyStroke
32
35
  MATCHED
33
36
  elsif input[0] == ESC_BYTE
34
37
  match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command))
35
- elsif input.size == 1
36
- MATCHED
37
38
  else
38
- UNMATCHED
39
+ s = input.pack('c*').force_encoding(@encoding)
40
+ if s.valid_encoding?
41
+ s.size == 1 ? MATCHED : UNMATCHED
42
+ else
43
+ # Invalid string is MATCHING (part of valid string) or MATCHED (invalid bytes to be ignored)
44
+ MATCHING_MATCHED
45
+ end
39
46
  end
40
47
  end
41
48
 
@@ -45,6 +52,7 @@ class Reline::KeyStroke
45
52
  bytes = input.take(i)
46
53
  status = match_status(bytes)
47
54
  matched_bytes = bytes if status == MATCHED || status == MATCHING_MATCHED
55
+ break if status == MATCHED || status == UNMATCHED
48
56
  end
49
57
  return [[], []] unless matched_bytes
50
58
 
@@ -53,12 +61,15 @@ class Reline::KeyStroke
53
61
  keys = func.map { |c| Reline::Key.new(c, c, false) }
54
62
  elsif func
55
63
  keys = [Reline::Key.new(func, func, false)]
56
- elsif matched_bytes.size == 1
57
- keys = [Reline::Key.new(matched_bytes.first, matched_bytes.first, false)]
58
64
  elsif matched_bytes.size == 2 && matched_bytes[0] == ESC_BYTE
59
65
  keys = [Reline::Key.new(matched_bytes[1], matched_bytes[1] | 0b10000000, true)]
60
66
  else
61
- keys = []
67
+ s = matched_bytes.pack('c*').force_encoding(@encoding)
68
+ if s.valid_encoding? && s.size == 1
69
+ keys = [Reline::Key.new(s.ord, s.ord, false)]
70
+ else
71
+ keys = []
72
+ end
62
73
  end
63
74
 
64
75
  [keys, input.drop(matched_bytes.size)]
@@ -36,7 +36,6 @@ class Reline::LineEditor
36
36
 
37
37
  module CompletionState
38
38
  NORMAL = :normal
39
- COMPLETION = :completion
40
39
  MENU = :menu
41
40
  MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
42
41
  PERFECT_MATCH = :perfect_match
@@ -266,7 +265,6 @@ class Reline::LineEditor
266
265
  @line_index = 0
267
266
  @cache.clear
268
267
  @line_backup_in_history = nil
269
- @multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
270
268
  end
271
269
 
272
270
  def multiline_on
@@ -300,8 +298,8 @@ class Reline::LineEditor
300
298
  end
301
299
  end
302
300
 
303
- private def split_by_width(str, max_width, offset: 0)
304
- Reline::Unicode.split_by_width(str, max_width, encoding, offset: offset)
301
+ private def split_line_by_width(str, max_width, offset: 0)
302
+ Reline::Unicode.split_line_by_width(str, max_width, encoding, offset: offset)
305
303
  end
306
304
 
307
305
  def current_byte_pointer_cursor
@@ -391,8 +389,8 @@ class Reline::LineEditor
391
389
  if (cached = cached_wraps[[prompt, line]])
392
390
  next cached
393
391
  end
394
- *wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
395
- wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt, true)).first.compact
392
+ *wrapped_prompts, code_line_prompt = split_line_by_width(prompt, width)
393
+ wrapped_lines = split_line_by_width(line, width, offset: calculate_width(code_line_prompt, true))
396
394
  wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
397
395
  end
398
396
  end
@@ -440,7 +438,7 @@ class Reline::LineEditor
440
438
  def wrapped_cursor_position
441
439
  prompt_width = calculate_width(prompt_list[@line_index], true)
442
440
  line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
443
- wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
441
+ wrapped_line_before_cursor = split_line_by_width(' ' * prompt_width + line_before_cursor, screen_width)
444
442
  wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
445
443
  wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
446
444
  [wrapped_cursor_x, wrapped_cursor_y]
@@ -465,7 +463,7 @@ class Reline::LineEditor
465
463
  render_differential([], 0, 0)
466
464
  lines = @buffer_of_lines.size.times.map do |i|
467
465
  line = Reline::Unicode.strip_non_printing_start_end(prompt_list[i]) + modified_lines[i]
468
- wrapped_lines, = split_by_width(line, screen_width)
466
+ wrapped_lines = split_line_by_width(line, screen_width)
469
467
  wrapped_lines.last.empty? ? "#{line} " : line
470
468
  end
471
469
  @output.puts lines.map { |l| "#{l}\r\n" }.join
@@ -579,8 +577,9 @@ class Reline::LineEditor
579
577
  @context
580
578
  end
581
579
 
582
- def retrieve_completion_block(set_completion_quote_character = false)
583
- @line_editor.retrieve_completion_block(set_completion_quote_character)
580
+ def retrieve_completion_block(_unused = false)
581
+ preposing, target, postposing, _quote = @line_editor.retrieve_completion_block
582
+ [preposing, target, postposing]
584
583
  end
585
584
 
586
585
  def call_completion_proc_with_checking_args(pre, target, post)
@@ -800,105 +799,73 @@ class Reline::LineEditor
800
799
  @config.editing_mode
801
800
  end
802
801
 
803
- private def menu(_target, list)
802
+ private def menu(list)
804
803
  @menu_info = MenuInfo.new(list)
805
804
  end
806
805
 
807
- private def complete_internal_proc(list, is_menu)
808
- preposing, target, postposing = retrieve_completion_block
809
- candidates = list.select { |i|
810
- if i and not Encoding.compatible?(target.encoding, i.encoding)
811
- raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{i.encoding.name}"
806
+ private def filter_normalize_candidates(target, list)
807
+ target = target.downcase if @config.completion_ignore_case
808
+ list.select do |item|
809
+ next unless item
810
+
811
+ unless Encoding.compatible?(target.encoding, item.encoding)
812
+ # Crash with Encoding::CompatibilityError is required by readline-ext/test/readline/test_readline.rb
813
+ # TODO: fix the test
814
+ raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{item.encoding.name}"
812
815
  end
816
+
813
817
  if @config.completion_ignore_case
814
- i&.downcase&.start_with?(target.downcase)
818
+ item.downcase.start_with?(target)
815
819
  else
816
- i&.start_with?(target)
820
+ item.start_with?(target)
817
821
  end
818
- }.uniq
819
- if is_menu
820
- menu(target, candidates)
821
- return nil
822
- end
823
- completed = candidates.inject { |memo, item|
824
- begin
825
- memo_mbchars = memo.unicode_normalize.grapheme_clusters
826
- item_mbchars = item.unicode_normalize.grapheme_clusters
827
- rescue Encoding::CompatibilityError
828
- memo_mbchars = memo.grapheme_clusters
829
- item_mbchars = item.grapheme_clusters
830
- end
831
- size = [memo_mbchars.size, item_mbchars.size].min
832
- result = +''
833
- size.times do |i|
834
- if @config.completion_ignore_case
835
- if memo_mbchars[i].casecmp?(item_mbchars[i])
836
- result << memo_mbchars[i]
837
- else
838
- break
839
- end
840
- else
841
- if memo_mbchars[i] == item_mbchars[i]
842
- result << memo_mbchars[i]
843
- else
844
- break
845
- end
846
- end
847
- end
848
- result
849
- }
850
-
851
- [target, preposing, completed, postposing, candidates]
822
+ end.map do |item|
823
+ item.unicode_normalize
824
+ rescue Encoding::CompatibilityError
825
+ item
826
+ end.uniq
852
827
  end
853
828
 
854
- private def perform_completion(list, just_show_list)
829
+ private def perform_completion(preposing, target, postposing, quote, list)
830
+ candidates = filter_normalize_candidates(target, list)
831
+
855
832
  case @completion_state
856
- when CompletionState::NORMAL
857
- @completion_state = CompletionState::COMPLETION
858
833
  when CompletionState::PERFECT_MATCH
859
834
  if @dig_perfect_match_proc
860
- @dig_perfect_match_proc.(@perfect_matched)
861
- else
862
- @completion_state = CompletionState::COMPLETION
835
+ @dig_perfect_match_proc.call(@perfect_matched)
836
+ return
863
837
  end
864
- end
865
- if just_show_list
866
- is_menu = true
867
- elsif @completion_state == CompletionState::MENU
868
- is_menu = true
869
- elsif @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
870
- is_menu = true
871
- else
872
- is_menu = false
873
- end
874
- result = complete_internal_proc(list, is_menu)
875
- if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
838
+ when CompletionState::MENU
839
+ menu(candidates)
840
+ return
841
+ when CompletionState::MENU_WITH_PERFECT_MATCH
842
+ menu(candidates)
876
843
  @completion_state = CompletionState::PERFECT_MATCH
844
+ return
877
845
  end
878
- return if result.nil?
879
- target, preposing, completed, postposing, candidates = result
880
- return if completed.nil?
881
- if target <= completed and (@completion_state == CompletionState::COMPLETION)
882
- append_character = ''
883
- if candidates.include?(completed)
884
- if candidates.one?
885
- append_character = completion_append_character.to_s
886
- @completion_state = CompletionState::PERFECT_MATCH
887
- else
888
- @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
889
- perform_completion(candidates, true) if @config.show_all_if_ambiguous
890
- end
891
- @perfect_matched = completed
846
+
847
+ completed = Reline::Unicode.common_prefix(candidates, ignore_case: @config.completion_ignore_case)
848
+ return if completed.empty?
849
+
850
+ append_character = ''
851
+ if candidates.include?(completed)
852
+ if candidates.one?
853
+ append_character = quote || completion_append_character.to_s
854
+ @completion_state = CompletionState::PERFECT_MATCH
855
+ elsif @config.show_all_if_ambiguous
856
+ menu(candidates)
857
+ @completion_state = CompletionState::PERFECT_MATCH
892
858
  else
893
- @completion_state = CompletionState::MENU
894
- perform_completion(candidates, true) if @config.show_all_if_ambiguous
895
- end
896
- unless just_show_list
897
- @buffer_of_lines[@line_index] = (preposing + completed + append_character + postposing).split("\n")[@line_index] || String.new(encoding: encoding)
898
- line_to_pointer = (preposing + completed + append_character).split("\n")[@line_index] || String.new(encoding: encoding)
899
- @byte_pointer = line_to_pointer.bytesize
859
+ @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
900
860
  end
861
+ @perfect_matched = completed
862
+ else
863
+ @completion_state = CompletionState::MENU
864
+ menu(candidates) if @config.show_all_if_ambiguous
901
865
  end
866
+ @buffer_of_lines[@line_index] = (preposing + completed + append_character + postposing).split("\n")[@line_index] || String.new(encoding: encoding)
867
+ line_to_pointer = (preposing + completed + append_character).split("\n")[@line_index] || String.new(encoding: encoding)
868
+ @byte_pointer = line_to_pointer.bytesize
902
869
  end
903
870
 
904
871
  def dialog_proc_scope_completion_journey_data
@@ -927,8 +894,8 @@ class Reline::LineEditor
927
894
  end
928
895
 
929
896
  private def retrieve_completion_journey_state
930
- preposing, target, postposing = retrieve_completion_block
931
- list = call_completion_proc
897
+ preposing, target, postposing, quote = retrieve_completion_block
898
+ list = call_completion_proc(preposing, target, postposing, quote)
932
899
  return unless list.is_a?(Array)
933
900
 
934
901
  candidates = list.select{ |item| item.start_with?(target) }
@@ -1068,20 +1035,11 @@ class Reline::LineEditor
1068
1035
  end
1069
1036
 
1070
1037
  private def normal_char(key)
1071
- @multibyte_buffer << key.combined_char
1072
- if @multibyte_buffer.size > 1
1073
- if @multibyte_buffer.dup.force_encoding(encoding).valid_encoding?
1074
- process_key(@multibyte_buffer.dup.force_encoding(encoding), nil)
1075
- @multibyte_buffer.clear
1076
- else
1077
- # invalid
1078
- return
1079
- end
1080
- else # single byte
1081
- return if key.char >= 128 # maybe, first byte of multi byte
1038
+ if key.char < 0x80
1082
1039
  method_symbol = @config.editing_mode.get_method(key.combined_char)
1083
1040
  process_key(key.combined_char, method_symbol)
1084
- @multibyte_buffer.clear
1041
+ else
1042
+ process_key(key.char.chr(encoding), nil)
1085
1043
  end
1086
1044
  if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
1087
1045
  byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
@@ -1178,9 +1136,8 @@ class Reline::LineEditor
1178
1136
  end
1179
1137
  end
1180
1138
 
1181
- def call_completion_proc
1182
- result = retrieve_completion_block(true)
1183
- pre, target, post = result
1139
+ def call_completion_proc(pre, target, post, quote)
1140
+ Reline.core.instance_variable_set(:@completion_quote_character, quote)
1184
1141
  result = call_completion_proc_with_checking_args(pre, target, post)
1185
1142
  Reline.core.instance_variable_set(:@completion_quote_character, nil)
1186
1143
  result
@@ -1256,72 +1213,32 @@ class Reline::LineEditor
1256
1213
  process_auto_indent
1257
1214
  end
1258
1215
 
1259
- def retrieve_completion_block(set_completion_quote_character = false)
1260
- if Reline.completer_word_break_characters.empty?
1261
- word_break_regexp = nil
1262
- else
1263
- word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
1264
- end
1265
- if Reline.completer_quote_characters.empty?
1266
- quote_characters_regexp = nil
1267
- else
1268
- quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
1269
- end
1270
- before = current_line.byteslice(0, @byte_pointer)
1271
- rest = nil
1272
- break_pointer = nil
1216
+ def retrieve_completion_block
1217
+ quote_characters = Reline.completer_quote_characters
1218
+ before = current_line.byteslice(0, @byte_pointer).grapheme_clusters
1273
1219
  quote = nil
1274
- closing_quote = nil
1275
- escaped_quote = nil
1276
- i = 0
1277
- while i < @byte_pointer do
1278
- slice = current_line.byteslice(i, @byte_pointer - i)
1279
- unless slice.valid_encoding?
1280
- i += 1
1281
- next
1282
- end
1283
- if quote and slice.start_with?(closing_quote)
1284
- quote = nil
1285
- i += 1
1286
- rest = nil
1287
- elsif quote and slice.start_with?(escaped_quote)
1288
- # skip
1289
- i += 2
1290
- elsif quote_characters_regexp and slice =~ quote_characters_regexp # find new "
1291
- rest = $'
1292
- quote = $&
1293
- closing_quote = /(?!\\)#{Regexp.escape(quote)}/
1294
- escaped_quote = /\\#{Regexp.escape(quote)}/
1295
- i += 1
1296
- break_pointer = i - 1
1297
- elsif word_break_regexp and not quote and slice =~ word_break_regexp
1298
- rest = $'
1299
- i += 1
1300
- before = current_line.byteslice(i, @byte_pointer - i)
1301
- break_pointer = i
1302
- else
1303
- i += 1
1304
- end
1305
- end
1306
- postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
1307
- if rest
1308
- preposing = current_line.byteslice(0, break_pointer)
1309
- target = rest
1310
- if set_completion_quote_character and quote
1311
- Reline.core.instance_variable_set(:@completion_quote_character, quote)
1312
- if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote
1313
- insert_text(quote)
1220
+ # Calcualte closing quote when cursor is at the end of the line
1221
+ if current_line.bytesize == @byte_pointer && !quote_characters.empty?
1222
+ escaped = false
1223
+ before.each do |c|
1224
+ if escaped
1225
+ escaped = false
1226
+ next
1227
+ elsif c == '\\'
1228
+ escaped = true
1229
+ elsif quote
1230
+ quote = nil if c == quote
1231
+ elsif quote_characters.include?(c)
1232
+ quote = c
1314
1233
  end
1315
1234
  end
1316
- else
1317
- preposing = ''
1318
- if break_pointer
1319
- preposing = current_line.byteslice(0, break_pointer)
1320
- else
1321
- preposing = ''
1322
- end
1323
- target = before
1324
1235
  end
1236
+
1237
+ word_break_characters = quote_characters + Reline.completer_word_break_characters
1238
+ break_index = before.rindex { |c| word_break_characters.include?(c) || quote_characters.include?(c) } || -1
1239
+ preposing = before.take(break_index + 1).join
1240
+ target = before.drop(break_index + 1).join
1241
+ postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
1325
1242
  lines = whole_lines
1326
1243
  if @line_index > 0
1327
1244
  preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
@@ -1329,7 +1246,7 @@ class Reline::LineEditor
1329
1246
  if (lines.size - 1) > @line_index
1330
1247
  postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
1331
1248
  end
1332
- [preposing.encode(encoding), target.encode(encoding), postposing.encode(encoding)]
1249
+ [preposing.encode(encoding), target.encode(encoding), postposing.encode(encoding), quote&.encode(encoding)]
1333
1250
  end
1334
1251
 
1335
1252
  def confirm_multiline_termination
@@ -1460,10 +1377,11 @@ class Reline::LineEditor
1460
1377
  @completion_occurs = move_completed_list(:down)
1461
1378
  else
1462
1379
  @completion_journey_state = nil
1463
- result = call_completion_proc
1380
+ pre, target, post, quote = retrieve_completion_block
1381
+ result = call_completion_proc(pre, target, post, quote)
1464
1382
  if result.is_a?(Array)
1465
1383
  @completion_occurs = true
1466
- perform_completion(result, false)
1384
+ perform_completion(pre, target, post, quote, result)
1467
1385
  end
1468
1386
  end
1469
1387
  end
@@ -1582,7 +1500,7 @@ class Reline::LineEditor
1582
1500
  alias_method :backward_char, :ed_prev_char
1583
1501
 
1584
1502
  private def vi_first_print(key)
1585
- @byte_pointer, = Reline::Unicode.vi_first_print(current_line)
1503
+ @byte_pointer = Reline::Unicode.vi_first_print(current_line)
1586
1504
  end
1587
1505
 
1588
1506
  private def ed_move_to_beg(key)
@@ -1598,7 +1516,6 @@ class Reline::LineEditor
1598
1516
 
1599
1517
  private def generate_searcher(search_key)
1600
1518
  search_word = String.new(encoding: encoding)
1601
- multibyte_buf = String.new(encoding: 'ASCII-8BIT')
1602
1519
  hit_pointer = nil
1603
1520
  lambda do |key|
1604
1521
  search_again = false
@@ -1613,11 +1530,7 @@ class Reline::LineEditor
1613
1530
  search_again = true if search_key == key
1614
1531
  search_key = key
1615
1532
  else
1616
- multibyte_buf << key
1617
- if multibyte_buf.dup.force_encoding(encoding).valid_encoding?
1618
- search_word << multibyte_buf.dup.force_encoding(encoding)
1619
- multibyte_buf.clear
1620
- end
1533
+ search_word << key
1621
1534
  end
1622
1535
  hit = nil
1623
1536
  if not search_word.empty? and @line_backup_in_history&.include?(search_word)
@@ -1927,9 +1840,11 @@ class Reline::LineEditor
1927
1840
  if current_line.empty? or @byte_pointer < current_line.bytesize
1928
1841
  em_delete(key)
1929
1842
  elsif !@config.autocompletion # show completed list
1930
- result = call_completion_proc
1843
+ pre, target, post, quote = retrieve_completion_block
1844
+ result = call_completion_proc(pre, target, post, quote)
1931
1845
  if result.is_a?(Array)
1932
- perform_completion(result, true)
1846
+ candidates = filter_normalize_candidates(target, result)
1847
+ menu(candidates)
1933
1848
  end
1934
1849
  end
1935
1850
  end
@@ -1961,7 +1876,7 @@ class Reline::LineEditor
1961
1876
 
1962
1877
  private def em_next_word(key)
1963
1878
  if current_line.bytesize > @byte_pointer
1964
- byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
1879
+ byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
1965
1880
  @byte_pointer += byte_size
1966
1881
  end
1967
1882
  end
@@ -1969,7 +1884,7 @@ class Reline::LineEditor
1969
1884
 
1970
1885
  private def ed_prev_word(key)
1971
1886
  if @byte_pointer > 0
1972
- byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
1887
+ byte_size = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
1973
1888
  @byte_pointer -= byte_size
1974
1889
  end
1975
1890
  end
@@ -1977,7 +1892,7 @@ class Reline::LineEditor
1977
1892
 
1978
1893
  private def em_delete_next_word(key)
1979
1894
  if current_line.bytesize > @byte_pointer
1980
- byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
1895
+ byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
1981
1896
  line, word = byteslice!(current_line, @byte_pointer, byte_size)
1982
1897
  set_current_line(line)
1983
1898
  @kill_ring.append(word)
@@ -1987,7 +1902,7 @@ class Reline::LineEditor
1987
1902
 
1988
1903
  private def ed_delete_prev_word(key)
1989
1904
  if @byte_pointer > 0
1990
- byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
1905
+ byte_size = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
1991
1906
  line, word = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
1992
1907
  set_current_line(line, @byte_pointer - byte_size)
1993
1908
  @kill_ring.append(word, true)
@@ -2027,7 +1942,7 @@ class Reline::LineEditor
2027
1942
 
2028
1943
  private def em_capitol_case(key)
2029
1944
  if current_line.bytesize > @byte_pointer
2030
- byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
1945
+ byte_size, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
2031
1946
  before = current_line.byteslice(0, @byte_pointer)
2032
1947
  after = current_line.byteslice((@byte_pointer + byte_size)..-1)
2033
1948
  set_current_line(before + new_str + after, @byte_pointer + new_str.bytesize)
@@ -2037,7 +1952,7 @@ class Reline::LineEditor
2037
1952
 
2038
1953
  private def em_lower_case(key)
2039
1954
  if current_line.bytesize > @byte_pointer
2040
- byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
1955
+ byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
2041
1956
  part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
2042
1957
  mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
2043
1958
  }.join
@@ -2050,7 +1965,7 @@ class Reline::LineEditor
2050
1965
 
2051
1966
  private def em_upper_case(key)
2052
1967
  if current_line.bytesize > @byte_pointer
2053
- byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
1968
+ byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
2054
1969
  part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
2055
1970
  mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
2056
1971
  }.join
@@ -2063,7 +1978,7 @@ class Reline::LineEditor
2063
1978
 
2064
1979
  private def em_kill_region(key)
2065
1980
  if @byte_pointer > 0
2066
- byte_size, _ = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
1981
+ byte_size = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
2067
1982
  line, deleted = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
2068
1983
  set_current_line(line, @byte_pointer - byte_size)
2069
1984
  @kill_ring.append(deleted, true)
@@ -2094,7 +2009,7 @@ class Reline::LineEditor
2094
2009
 
2095
2010
  private def vi_next_word(key, arg: 1)
2096
2011
  if current_line.bytesize > @byte_pointer
2097
- byte_size, _ = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
2012
+ byte_size = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
2098
2013
  @byte_pointer += byte_size
2099
2014
  end
2100
2015
  arg -= 1
@@ -2103,7 +2018,7 @@ class Reline::LineEditor
2103
2018
 
2104
2019
  private def vi_prev_word(key, arg: 1)
2105
2020
  if @byte_pointer > 0
2106
- byte_size, _ = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
2021
+ byte_size = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
2107
2022
  @byte_pointer -= byte_size
2108
2023
  end
2109
2024
  arg -= 1
@@ -2112,7 +2027,7 @@ class Reline::LineEditor
2112
2027
 
2113
2028
  private def vi_end_word(key, arg: 1, inclusive: false)
2114
2029
  if current_line.bytesize > @byte_pointer
2115
- byte_size, _ = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
2030
+ byte_size = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
2116
2031
  @byte_pointer += byte_size
2117
2032
  end
2118
2033
  arg -= 1
@@ -2127,7 +2042,7 @@ class Reline::LineEditor
2127
2042
 
2128
2043
  private def vi_next_big_word(key, arg: 1)
2129
2044
  if current_line.bytesize > @byte_pointer
2130
- byte_size, _ = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
2045
+ byte_size = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
2131
2046
  @byte_pointer += byte_size
2132
2047
  end
2133
2048
  arg -= 1
@@ -2136,7 +2051,7 @@ class Reline::LineEditor
2136
2051
 
2137
2052
  private def vi_prev_big_word(key, arg: 1)
2138
2053
  if @byte_pointer > 0
2139
- byte_size, _ = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
2054
+ byte_size = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
2140
2055
  @byte_pointer -= byte_size
2141
2056
  end
2142
2057
  arg -= 1
@@ -2145,7 +2060,7 @@ class Reline::LineEditor
2145
2060
 
2146
2061
  private def vi_end_big_word(key, arg: 1, inclusive: false)
2147
2062
  if current_line.bytesize > @byte_pointer
2148
- byte_size, _ = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
2063
+ byte_size = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
2149
2064
  @byte_pointer += byte_size
2150
2065
  end
2151
2066
  arg -= 1
@@ -121,9 +121,14 @@ class Reline::Unicode
121
121
  end
122
122
  end
123
123
 
124
- def self.split_by_width(str, max_width, encoding = str.encoding, offset: 0)
124
+ # This method is used by IRB
125
+ def self.split_by_width(str, max_width)
126
+ lines = split_line_by_width(str, max_width)
127
+ [lines, lines.size]
128
+ end
129
+
130
+ def self.split_line_by_width(str, max_width, encoding = str.encoding, offset: 0)
125
131
  lines = [String.new(encoding: encoding)]
126
- height = 1
127
132
  width = offset
128
133
  rest = str.encode(Encoding::UTF_8)
129
134
  in_zero_width = false
@@ -151,9 +156,7 @@ class Reline::Unicode
151
156
  mbchar_width = get_mbchar_width(gc)
152
157
  if (width += mbchar_width) > max_width
153
158
  width = mbchar_width
154
- lines << nil
155
159
  lines << seq.dup
156
- height += 1
157
160
  end
158
161
  end
159
162
  lines.last << gc
@@ -161,11 +164,9 @@ class Reline::Unicode
161
164
  end
162
165
  # The cursor moves to next line in first
163
166
  if width == max_width
164
- lines << nil
165
167
  lines << String.new(encoding: encoding)
166
- height += 1
167
168
  end
168
- [lines, height]
169
+ lines
169
170
  end
170
171
 
171
172
  def self.strip_non_printing_start_end(prompt)
@@ -261,27 +262,23 @@ class Reline::Unicode
261
262
  end
262
263
 
263
264
  def self.em_forward_word(line, byte_pointer)
264
- width = 0
265
265
  byte_size = 0
266
266
  while line.bytesize > (byte_pointer + byte_size)
267
267
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
268
268
  mbchar = line.byteslice(byte_pointer + byte_size, size)
269
269
  break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
270
- width += get_mbchar_width(mbchar)
271
270
  byte_size += size
272
271
  end
273
272
  while line.bytesize > (byte_pointer + byte_size)
274
273
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
275
274
  mbchar = line.byteslice(byte_pointer + byte_size, size)
276
275
  break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
277
- width += get_mbchar_width(mbchar)
278
276
  byte_size += size
279
277
  end
280
- [byte_size, width]
278
+ byte_size
281
279
  end
282
280
 
283
281
  def self.em_forward_word_with_capitalization(line, byte_pointer)
284
- width = 0
285
282
  byte_size = 0
286
283
  new_str = String.new
287
284
  while line.bytesize > (byte_pointer + byte_size)
@@ -289,7 +286,6 @@ class Reline::Unicode
289
286
  mbchar = line.byteslice(byte_pointer + byte_size, size)
290
287
  break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
291
288
  new_str += mbchar
292
- width += get_mbchar_width(mbchar)
293
289
  byte_size += size
294
290
  end
295
291
  first = true
@@ -303,50 +299,43 @@ class Reline::Unicode
303
299
  else
304
300
  new_str += mbchar.downcase
305
301
  end
306
- width += get_mbchar_width(mbchar)
307
302
  byte_size += size
308
303
  end
309
- [byte_size, width, new_str]
304
+ [byte_size, new_str]
310
305
  end
311
306
 
312
307
  def self.em_backward_word(line, byte_pointer)
313
- width = 0
314
308
  byte_size = 0
315
309
  while 0 < (byte_pointer - byte_size)
316
310
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
317
311
  mbchar = line.byteslice(byte_pointer - byte_size - size, size)
318
312
  break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
319
- width += get_mbchar_width(mbchar)
320
313
  byte_size += size
321
314
  end
322
315
  while 0 < (byte_pointer - byte_size)
323
316
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
324
317
  mbchar = line.byteslice(byte_pointer - byte_size - size, size)
325
318
  break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
326
- width += get_mbchar_width(mbchar)
327
319
  byte_size += size
328
320
  end
329
- [byte_size, width]
321
+ byte_size
330
322
  end
331
323
 
332
324
  def self.em_big_backward_word(line, byte_pointer)
333
- width = 0
334
325
  byte_size = 0
335
326
  while 0 < (byte_pointer - byte_size)
336
327
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
337
328
  mbchar = line.byteslice(byte_pointer - byte_size - size, size)
338
329
  break if mbchar =~ /\S/
339
- width += get_mbchar_width(mbchar)
340
330
  byte_size += size
341
331
  end
342
332
  while 0 < (byte_pointer - byte_size)
343
333
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
344
334
  mbchar = line.byteslice(byte_pointer - byte_size - size, size)
345
335
  break if mbchar =~ /\s/
346
- width += get_mbchar_width(mbchar)
347
336
  byte_size += size
348
337
  end
349
- [byte_size, width]
338
+ byte_size
350
339
  end
351
340
 
352
341
  def self.ed_transpose_words(line, byte_pointer)
@@ -451,73 +440,61 @@ class Reline::Unicode
451
440
  end
452
441
 
453
442
  def self.vi_big_forward_word(line, byte_pointer)
454
- width = 0
455
443
  byte_size = 0
456
444
  while (line.bytesize - 1) > (byte_pointer + byte_size)
457
445
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
458
446
  mbchar = line.byteslice(byte_pointer + byte_size, size)
459
447
  break if mbchar =~ /\s/
460
- width += get_mbchar_width(mbchar)
461
448
  byte_size += size
462
449
  end
463
450
  while (line.bytesize - 1) > (byte_pointer + byte_size)
464
451
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
465
452
  mbchar = line.byteslice(byte_pointer + byte_size, size)
466
453
  break if mbchar =~ /\S/
467
- width += get_mbchar_width(mbchar)
468
454
  byte_size += size
469
455
  end
470
- [byte_size, width]
456
+ byte_size
471
457
  end
472
458
 
473
459
  def self.vi_big_forward_end_word(line, byte_pointer)
474
460
  if (line.bytesize - 1) > byte_pointer
475
461
  size = get_next_mbchar_size(line, byte_pointer)
476
- mbchar = line.byteslice(byte_pointer, size)
477
- width = get_mbchar_width(mbchar)
478
462
  byte_size = size
479
463
  else
480
- return [0, 0]
464
+ return 0
481
465
  end
482
466
  while (line.bytesize - 1) > (byte_pointer + byte_size)
483
467
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
484
468
  mbchar = line.byteslice(byte_pointer + byte_size, size)
485
469
  break if mbchar =~ /\S/
486
- width += get_mbchar_width(mbchar)
487
470
  byte_size += size
488
471
  end
489
- prev_width = width
490
472
  prev_byte_size = byte_size
491
473
  while line.bytesize > (byte_pointer + byte_size)
492
474
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
493
475
  mbchar = line.byteslice(byte_pointer + byte_size, size)
494
476
  break if mbchar =~ /\s/
495
- prev_width = width
496
477
  prev_byte_size = byte_size
497
- width += get_mbchar_width(mbchar)
498
478
  byte_size += size
499
479
  end
500
- [prev_byte_size, prev_width]
480
+ prev_byte_size
501
481
  end
502
482
 
503
483
  def self.vi_big_backward_word(line, byte_pointer)
504
- width = 0
505
484
  byte_size = 0
506
485
  while 0 < (byte_pointer - byte_size)
507
486
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
508
487
  mbchar = line.byteslice(byte_pointer - byte_size - size, size)
509
488
  break if mbchar =~ /\S/
510
- width += get_mbchar_width(mbchar)
511
489
  byte_size += size
512
490
  end
513
491
  while 0 < (byte_pointer - byte_size)
514
492
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
515
493
  mbchar = line.byteslice(byte_pointer - byte_size - size, size)
516
494
  break if mbchar =~ /\s/
517
- width += get_mbchar_width(mbchar)
518
495
  byte_size += size
519
496
  end
520
- [byte_size, width]
497
+ byte_size
521
498
  end
522
499
 
523
500
  def self.vi_forward_word(line, byte_pointer, drop_terminate_spaces = false)
@@ -531,10 +508,9 @@ class Reline::Unicode
531
508
  else
532
509
  started_by = :non_word_printable
533
510
  end
534
- width = get_mbchar_width(mbchar)
535
511
  byte_size = size
536
512
  else
537
- return [0, 0]
513
+ return 0
538
514
  end
539
515
  while line.bytesize > (byte_pointer + byte_size)
540
516
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
@@ -547,18 +523,16 @@ class Reline::Unicode
547
523
  when :non_word_printable
548
524
  break if mbchar =~ /\w|\s/
549
525
  end
550
- width += get_mbchar_width(mbchar)
551
526
  byte_size += size
552
527
  end
553
- return [byte_size, width] if drop_terminate_spaces
528
+ return byte_size if drop_terminate_spaces
554
529
  while line.bytesize > (byte_pointer + byte_size)
555
530
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
556
531
  mbchar = line.byteslice(byte_pointer + byte_size, size)
557
532
  break if mbchar =~ /\S/
558
- width += get_mbchar_width(mbchar)
559
533
  byte_size += size
560
534
  end
561
- [byte_size, width]
535
+ byte_size
562
536
  end
563
537
 
564
538
  def self.vi_forward_end_word(line, byte_pointer)
@@ -572,10 +546,9 @@ class Reline::Unicode
572
546
  else
573
547
  started_by = :non_word_printable
574
548
  end
575
- width = get_mbchar_width(mbchar)
576
549
  byte_size = size
577
550
  else
578
- return [0, 0]
551
+ return 0
579
552
  end
580
553
  if (line.bytesize - 1) > (byte_pointer + byte_size)
581
554
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
@@ -587,13 +560,11 @@ class Reline::Unicode
587
560
  else
588
561
  second = :non_word_printable
589
562
  end
590
- second_width = get_mbchar_width(mbchar)
591
563
  second_byte_size = size
592
564
  else
593
- return [byte_size, width]
565
+ return byte_size
594
566
  end
595
567
  if second == :space
596
- width += second_width
597
568
  byte_size += second_byte_size
598
569
  while (line.bytesize - 1) > (byte_pointer + byte_size)
599
570
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
@@ -606,7 +577,6 @@ class Reline::Unicode
606
577
  end
607
578
  break
608
579
  end
609
- width += get_mbchar_width(mbchar)
610
580
  byte_size += size
611
581
  end
612
582
  else
@@ -614,12 +584,10 @@ class Reline::Unicode
614
584
  when [:word, :non_word_printable], [:non_word_printable, :word]
615
585
  started_by = second
616
586
  else
617
- width += second_width
618
587
  byte_size += second_byte_size
619
588
  started_by = second
620
589
  end
621
590
  end
622
- prev_width = width
623
591
  prev_byte_size = byte_size
624
592
  while line.bytesize > (byte_pointer + byte_size)
625
593
  size = get_next_mbchar_size(line, byte_pointer + byte_size)
@@ -630,16 +598,13 @@ class Reline::Unicode
630
598
  when :non_word_printable
631
599
  break if mbchar =~ /[\w\s]/
632
600
  end
633
- prev_width = width
634
601
  prev_byte_size = byte_size
635
- width += get_mbchar_width(mbchar)
636
602
  byte_size += size
637
603
  end
638
- [prev_byte_size, prev_width]
604
+ prev_byte_size
639
605
  end
640
606
 
641
607
  def self.vi_backward_word(line, byte_pointer)
642
- width = 0
643
608
  byte_size = 0
644
609
  while 0 < (byte_pointer - byte_size)
645
610
  size = get_prev_mbchar_size(line, byte_pointer - byte_size)
@@ -652,7 +617,6 @@ class Reline::Unicode
652
617
  end
653
618
  break
654
619
  end
655
- width += get_mbchar_width(mbchar)
656
620
  byte_size += size
657
621
  end
658
622
  while 0 < (byte_pointer - byte_size)
@@ -664,14 +628,25 @@ class Reline::Unicode
664
628
  when :non_word_printable
665
629
  break if mbchar =~ /[\w\s]/
666
630
  end
667
- width += get_mbchar_width(mbchar)
668
631
  byte_size += size
669
632
  end
670
- [byte_size, width]
633
+ byte_size
634
+ end
635
+
636
+ def self.common_prefix(list, ignore_case: false)
637
+ return '' if list.empty?
638
+
639
+ common_prefix_gcs = list.first.grapheme_clusters
640
+ list.each do |item|
641
+ gcs = item.grapheme_clusters
642
+ common_prefix_gcs = common_prefix_gcs.take_while.with_index do |gc, i|
643
+ ignore_case ? gc.casecmp?(gcs[i]) : gc == gcs[i]
644
+ end
645
+ end
646
+ common_prefix_gcs.join
671
647
  end
672
648
 
673
649
  def self.vi_first_print(line)
674
- width = 0
675
650
  byte_size = 0
676
651
  while (line.bytesize - 1) > byte_size
677
652
  size = get_next_mbchar_size(line, byte_size)
@@ -679,9 +654,8 @@ class Reline::Unicode
679
654
  if mbchar =~ /\S/
680
655
  break
681
656
  end
682
- width += get_mbchar_width(mbchar)
683
657
  byte_size += size
684
658
  end
685
- [byte_size, width]
659
+ byte_size
686
660
  end
687
661
  end
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.5.11'
2
+ VERSION = '0.5.12'
3
3
  end
data/lib/reline.rb CHANGED
@@ -6,7 +6,6 @@ require 'reline/key_actor'
6
6
  require 'reline/key_stroke'
7
7
  require 'reline/line_editor'
8
8
  require 'reline/history'
9
- require 'reline/terminfo'
10
9
  require 'reline/io'
11
10
  require 'reline/face'
12
11
  require 'rbconfig'
@@ -308,6 +307,7 @@ module Reline
308
307
  otio = io_gate.prep
309
308
 
310
309
  may_req_ambiguous_char_width
310
+ key_stroke.encoding = encoding
311
311
  line_editor.reset(prompt)
312
312
  if multiline
313
313
  line_editor.multiline_on
@@ -486,7 +486,7 @@ module Reline
486
486
  def self.core
487
487
  @core ||= Core.new { |core|
488
488
  core.config = Reline::Config.new
489
- core.key_stroke = Reline::KeyStroke.new(core.config)
489
+ core.key_stroke = Reline::KeyStroke.new(core.config, core.encoding)
490
490
  core.line_editor = Reline::LineEditor.new(core.config)
491
491
 
492
492
  core.basic_word_break_characters = " \t\n`><=;|&{("
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.11
4
+ version: 0.5.12
5
5
  platform: ruby
6
+ original_platform: ''
6
7
  authors:
7
8
  - aycabta
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2024-11-08 00:00:00.000000000 Z
11
+ date: 2024-11-28 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: io-console
@@ -50,7 +51,6 @@ files:
50
51
  - lib/reline/key_stroke.rb
51
52
  - lib/reline/kill_ring.rb
52
53
  - lib/reline/line_editor.rb
53
- - lib/reline/terminfo.rb
54
54
  - lib/reline/unicode.rb
55
55
  - lib/reline/unicode/east_asian_width.rb
56
56
  - lib/reline/version.rb
@@ -1,158 +0,0 @@
1
- begin
2
- # Ignore warning `Add fiddle to your Gemfile or gemspec` in Ruby 3.4.
3
- # terminfo.rb and ansi.rb supports fiddle unavailable environment.
4
- verbose, $VERBOSE = $VERBOSE, nil
5
- require 'fiddle'
6
- require 'fiddle/import'
7
- rescue LoadError
8
- module Reline::Terminfo
9
- def self.curses_dl
10
- false
11
- end
12
- end
13
- ensure
14
- $VERBOSE = verbose
15
- end
16
-
17
- module Reline::Terminfo
18
- extend Fiddle::Importer
19
-
20
- class TerminfoError < StandardError; end
21
-
22
- def self.curses_dl_files
23
- case RUBY_PLATFORM
24
- when /mingw/, /mswin/
25
- # aren't supported
26
- []
27
- when /cygwin/
28
- %w[cygncursesw-10.dll cygncurses-10.dll]
29
- when /darwin/
30
- %w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
31
- else
32
- %w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
33
- end
34
- end
35
-
36
- @curses_dl = false
37
- def self.curses_dl
38
- return @curses_dl unless @curses_dl == false
39
- if Fiddle.const_defined?(:TYPE_VARIADIC)
40
- curses_dl_files.each do |curses_name|
41
- result = Fiddle::Handle.new(curses_name)
42
- rescue Fiddle::DLError
43
- next
44
- else
45
- @curses_dl = result
46
- break
47
- end
48
- end
49
- @curses_dl = nil if @curses_dl == false
50
- @curses_dl
51
- end
52
- end if not Reline.const_defined?(:Terminfo) or not Reline::Terminfo.respond_to?(:curses_dl)
53
-
54
- module Reline::Terminfo
55
- dlload curses_dl
56
- #extern 'int setupterm(char *term, int fildes, int *errret)'
57
- @setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
58
- #extern 'char *tigetstr(char *capname)'
59
- @tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
60
- begin
61
- #extern 'char *tiparm(const char *str, ...)'
62
- @tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
63
- rescue Fiddle::DLError
64
- # OpenBSD lacks tiparm
65
- #extern 'char *tparm(const char *str, ...)'
66
- @tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
67
- end
68
- begin
69
- #extern 'int tigetflag(char *str)'
70
- @tigetflag = Fiddle::Function.new(curses_dl['tigetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
71
- rescue Fiddle::DLError
72
- # OpenBSD lacks tigetflag
73
- #extern 'int tgetflag(char *str)'
74
- @tigetflag = Fiddle::Function.new(curses_dl['tgetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
75
- end
76
- begin
77
- #extern 'int tigetnum(char *str)'
78
- @tigetnum = Fiddle::Function.new(curses_dl['tigetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
79
- rescue Fiddle::DLError
80
- # OpenBSD lacks tigetnum
81
- #extern 'int tgetnum(char *str)'
82
- @tigetnum = Fiddle::Function.new(curses_dl['tgetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
83
- end
84
-
85
- def self.setupterm(term, fildes)
86
- errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
87
- ret = @setupterm.(term, fildes, errret_int)
88
- case ret
89
- when 0 # OK
90
- @term_supported = true
91
- when -1 # ERR
92
- @term_supported = false
93
- end
94
- end
95
-
96
- class StringWithTiparm < String
97
- def tiparm(*args) # for method chain
98
- Reline::Terminfo.tiparm(self, *args)
99
- end
100
- end
101
-
102
- def self.tigetstr(capname)
103
- raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
104
- capability = @tigetstr.(capname)
105
- case capability.to_i
106
- when 0, -1
107
- raise TerminfoError, "can't find capability: #{capname}"
108
- end
109
- StringWithTiparm.new(capability.to_s)
110
- end
111
-
112
- def self.tiparm(str, *args)
113
- new_args = []
114
- args.each do |a|
115
- new_args << Fiddle::TYPE_INT << a
116
- end
117
- @tiparm.(str, *new_args).to_s
118
- end
119
-
120
- def self.tigetflag(capname)
121
- raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
122
- flag = @tigetflag.(capname).to_i
123
- case flag
124
- when -1
125
- raise TerminfoError, "not boolean capability: #{capname}"
126
- when 0
127
- raise TerminfoError, "can't find capability: #{capname}"
128
- end
129
- flag
130
- end
131
-
132
- def self.tigetnum(capname)
133
- raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
134
- num = @tigetnum.(capname).to_i
135
- case num
136
- when -2
137
- raise TerminfoError, "not numeric capability: #{capname}"
138
- when -1
139
- raise TerminfoError, "can't find capability: #{capname}"
140
- end
141
- num
142
- end
143
-
144
- # NOTE: This means Fiddle and curses are enabled.
145
- def self.enabled?
146
- true
147
- end
148
-
149
- def self.term_supported?
150
- @term_supported
151
- end
152
- end if Reline::Terminfo.curses_dl
153
-
154
- module Reline::Terminfo
155
- def self.enabled?
156
- false
157
- end
158
- end unless Reline::Terminfo.curses_dl