reline 0.5.11 → 0.5.12
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 +4 -4
- data/lib/reline/io/ansi.rb +7 -45
- data/lib/reline/io/dumb.rb +4 -1
- data/lib/reline/key_stroke.rb +19 -8
- data/lib/reline/line_editor.rb +111 -196
- data/lib/reline/unicode.rb +37 -63
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +2 -2
- metadata +3 -3
- data/lib/reline/terminfo.rb +0 -158
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14c0b8843530985ab335eb7dbb365d72708214a67b5a858d75d0aebe605050c3
|
4
|
+
data.tar.gz: ba60692647a18e520d1b8ed0fff6ac44b11048b3c8f2f2050a5651955db21c89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 242efcf7910a3981d12f7238df77b20d8c0a4fffb735bc59d53f8662e8fbb149d53c8081adf03bbb2b237f576a6f942ba66f01d6b46e1de29617fb29edb89a58
|
7
|
+
data.tar.gz: 9d80fef9e52a79300e6163b9dd5141fe412fc3caa32f108f9158108d54abef6ec23b93fc018afd5efdf374c38713e0973afe06adbbe148cae457ca45dd7024b7
|
data/lib/reline/io/ansi.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/reline/io/dumb.rb
CHANGED
@@ -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
|
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(_)
|
data/lib/reline/key_stroke.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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)]
|
data/lib/reline/line_editor.rb
CHANGED
@@ -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
|
304
|
-
Reline::Unicode.
|
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 =
|
395
|
-
wrapped_lines =
|
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 =
|
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
|
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(
|
583
|
-
@line_editor.retrieve_completion_block
|
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(
|
802
|
+
private def menu(list)
|
804
803
|
@menu_info = MenuInfo.new(list)
|
805
804
|
end
|
806
805
|
|
807
|
-
private def
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
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
|
-
|
818
|
+
item.downcase.start_with?(target)
|
815
819
|
else
|
816
|
-
|
820
|
+
item.start_with?(target)
|
817
821
|
end
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
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(
|
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
|
-
|
862
|
-
@completion_state = CompletionState::COMPLETION
|
835
|
+
@dig_perfect_match_proc.call(@perfect_matched)
|
836
|
+
return
|
863
837
|
end
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
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
|
-
|
879
|
-
|
880
|
-
return if completed.
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
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::
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
1260
|
-
|
1261
|
-
|
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
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
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
|
-
|
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(
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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,
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
data/lib/reline/unicode.rb
CHANGED
@@ -121,9 +121,14 @@ class Reline::Unicode
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
659
|
+
byte_size
|
686
660
|
end
|
687
661
|
end
|
data/lib/reline/version.rb
CHANGED
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.
|
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-
|
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
|
data/lib/reline/terminfo.rb
DELETED
@@ -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
|