reline 0.0.7 → 0.1.4
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/README.md +4 -0
- data/lib/reline.rb +51 -24
- data/lib/reline/ansi.rb +59 -26
- data/lib/reline/config.rb +34 -8
- data/lib/reline/general_io.rb +8 -0
- data/lib/reline/history.rb +34 -14
- data/lib/reline/key_actor/emacs.rb +7 -7
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/line_editor.rb +439 -90
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +41 -4
- metadata +18 -4
data/lib/reline/general_io.rb
CHANGED
data/lib/reline/history.rb
CHANGED
@@ -13,13 +13,13 @@ class Reline::History < Array
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def [](index)
|
16
|
-
index = check_index(index)
|
16
|
+
index = check_index(index) unless index.is_a?(Range)
|
17
17
|
super(index)
|
18
18
|
end
|
19
19
|
|
20
20
|
def []=(index, val)
|
21
21
|
index = check_index(index)
|
22
|
-
super(index, String.new(val, encoding:
|
22
|
+
super(index, String.new(val, encoding: Reline.encoding_system_needs))
|
23
23
|
end
|
24
24
|
|
25
25
|
def concat(*val)
|
@@ -29,27 +29,47 @@ class Reline::History < Array
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def push(*val)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
# If history_size is zero, all histories are dropped.
|
33
|
+
return self if @config.history_size.zero?
|
34
|
+
# If history_size is negative, history size is unlimited.
|
35
|
+
if @config.history_size.positive?
|
36
|
+
diff = size + val.size - @config.history_size
|
37
|
+
if diff > 0
|
38
|
+
if diff <= size
|
39
|
+
shift(diff)
|
40
|
+
else
|
41
|
+
diff -= size
|
42
|
+
clear
|
43
|
+
val.shift(diff)
|
44
|
+
end
|
40
45
|
end
|
41
46
|
end
|
42
|
-
super(*(val.map{ |v|
|
47
|
+
super(*(val.map{ |v|
|
48
|
+
String.new(v, encoding: Reline.encoding_system_needs)
|
49
|
+
}))
|
43
50
|
end
|
44
51
|
|
45
52
|
def <<(val)
|
46
|
-
|
47
|
-
|
53
|
+
# If history_size is zero, all histories are dropped.
|
54
|
+
return self if @config.history_size.zero?
|
55
|
+
# If history_size is negative, history size is unlimited.
|
56
|
+
if @config.history_size.positive?
|
57
|
+
shift if size + 1 > @config.history_size
|
58
|
+
end
|
59
|
+
super(String.new(val, encoding: Reline.encoding_system_needs))
|
48
60
|
end
|
49
61
|
|
50
62
|
private def check_index(index)
|
51
63
|
index += size if index < 0
|
52
|
-
|
64
|
+
if index < -2147483648 or 2147483647 < index
|
65
|
+
raise RangeError.new("integer #{index} too big to convert to `int'")
|
66
|
+
end
|
67
|
+
# If history_size is negative, history size is unlimited.
|
68
|
+
if @config.history_size.positive?
|
69
|
+
if index < -@config.history_size or @config.history_size < index
|
70
|
+
raise RangeError.new("index=<#{index}>")
|
71
|
+
end
|
72
|
+
end
|
53
73
|
raise IndexError.new("index=<#{index}>") if index < 0 or size <= index
|
54
74
|
index
|
55
75
|
end
|
@@ -9,7 +9,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
9
9
|
# 3 ^C
|
10
10
|
:ed_ignore,
|
11
11
|
# 4 ^D
|
12
|
-
:
|
12
|
+
:em_delete,
|
13
13
|
# 5 ^E
|
14
14
|
:ed_move_to_end,
|
15
15
|
# 6 ^F
|
@@ -37,9 +37,9 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
37
37
|
# 17 ^Q
|
38
38
|
:ed_quoted_insert,
|
39
39
|
# 18 ^R
|
40
|
-
:
|
40
|
+
:vi_search_prev,
|
41
41
|
# 19 ^S
|
42
|
-
:
|
42
|
+
:vi_search_next,
|
43
43
|
# 20 ^T
|
44
44
|
:ed_transpose_chars,
|
45
45
|
# 21 ^U
|
@@ -413,11 +413,11 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
413
413
|
# 205 M-M
|
414
414
|
:ed_unassigned,
|
415
415
|
# 206 M-N
|
416
|
-
:
|
416
|
+
:vi_search_next,
|
417
417
|
# 207 M-O
|
418
418
|
:ed_sequence_lead_in,
|
419
419
|
# 208 M-P
|
420
|
-
:
|
420
|
+
:vi_search_prev,
|
421
421
|
# 209 M-Q
|
422
422
|
:ed_unassigned,
|
423
423
|
# 210 M-R
|
@@ -477,11 +477,11 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
477
477
|
# 237 M-m
|
478
478
|
:ed_unassigned,
|
479
479
|
# 238 M-n
|
480
|
-
:
|
480
|
+
:vi_search_next,
|
481
481
|
# 239 M-o
|
482
482
|
:ed_unassigned,
|
483
483
|
# 240 M-p
|
484
|
-
:
|
484
|
+
:vi_search_prev,
|
485
485
|
# 241 M-q
|
486
486
|
:ed_unassigned,
|
487
487
|
# 242 M-r
|
@@ -37,7 +37,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
|
|
37
37
|
# 17 ^Q
|
38
38
|
:ed_ignore,
|
39
39
|
# 18 ^R
|
40
|
-
:
|
40
|
+
:vi_search_prev,
|
41
41
|
# 19 ^S
|
42
42
|
:ed_ignore,
|
43
43
|
# 20 ^T
|
@@ -151,7 +151,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
|
|
151
151
|
# 74 J
|
152
152
|
:vi_join_lines,
|
153
153
|
# 75 K
|
154
|
-
:
|
154
|
+
:vi_search_prev,
|
155
155
|
# 76 L
|
156
156
|
:ed_unassigned,
|
157
157
|
# 77 M
|
data/lib/reline/line_editor.rb
CHANGED
@@ -10,6 +10,7 @@ class Reline::LineEditor
|
|
10
10
|
attr_reader :byte_pointer
|
11
11
|
attr_accessor :confirm_multiline_termination_proc
|
12
12
|
attr_accessor :completion_proc
|
13
|
+
attr_accessor :completion_append_character
|
13
14
|
attr_accessor :output_modifier_proc
|
14
15
|
attr_accessor :prompt_proc
|
15
16
|
attr_accessor :auto_indent_proc
|
@@ -43,6 +44,7 @@ class Reline::LineEditor
|
|
43
44
|
COMPLETION = :completion
|
44
45
|
MENU = :menu
|
45
46
|
JOURNEY = :journey
|
47
|
+
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
|
46
48
|
PERFECT_MATCH = :perfect_match
|
47
49
|
end
|
48
50
|
|
@@ -55,9 +57,10 @@ class Reline::LineEditor
|
|
55
57
|
NON_PRINTING_END = "\2"
|
56
58
|
WIDTH_SCANNER = /\G(?:#{NON_PRINTING_START}|#{NON_PRINTING_END}|#{CSI_REGEXP}|#{OSC_REGEXP}|\X)/
|
57
59
|
|
58
|
-
def initialize(config)
|
60
|
+
def initialize(config, encoding)
|
59
61
|
@config = config
|
60
|
-
|
62
|
+
@completion_append_character = ''
|
63
|
+
reset_variables(encoding: encoding)
|
61
64
|
end
|
62
65
|
|
63
66
|
private def check_multiline_prompt(buffer, prompt)
|
@@ -82,10 +85,10 @@ class Reline::LineEditor
|
|
82
85
|
end
|
83
86
|
end
|
84
87
|
|
85
|
-
def reset(prompt = '', encoding
|
88
|
+
def reset(prompt = '', encoding:)
|
86
89
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
87
90
|
@screen_size = Reline::IOGate.get_screen_size
|
88
|
-
reset_variables(prompt, encoding)
|
91
|
+
reset_variables(prompt, encoding: encoding)
|
89
92
|
@old_trap = Signal.trap('SIGINT') {
|
90
93
|
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
91
94
|
raise Interrupt
|
@@ -136,7 +139,7 @@ class Reline::LineEditor
|
|
136
139
|
@eof
|
137
140
|
end
|
138
141
|
|
139
|
-
def reset_variables(prompt = '', encoding
|
142
|
+
def reset_variables(prompt = '', encoding:)
|
140
143
|
@prompt = prompt
|
141
144
|
@mark_pointer = nil
|
142
145
|
@encoding = encoding
|
@@ -314,9 +317,9 @@ class Reline::LineEditor
|
|
314
317
|
if @menu_info
|
315
318
|
scroll_down(@highest_in_all - @first_line_started_from)
|
316
319
|
@rerender_all = true
|
317
|
-
@menu_info.list.each do |item|
|
320
|
+
@menu_info.list.sort!.each do |item|
|
318
321
|
Reline::IOGate.move_cursor_column(0)
|
319
|
-
@output.
|
322
|
+
@output.write item
|
320
323
|
@output.flush
|
321
324
|
scroll_down(1)
|
322
325
|
end
|
@@ -504,12 +507,20 @@ class Reline::LineEditor
|
|
504
507
|
Reline::IOGate.move_cursor_column(0)
|
505
508
|
visual_lines.each_with_index do |line, index|
|
506
509
|
if line.nil?
|
507
|
-
Reline::IOGate.
|
508
|
-
|
509
|
-
|
510
|
+
if Reline::IOGate.win? and calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
|
511
|
+
# A newline is automatically inserted if a character is rendered at eol on command prompt.
|
512
|
+
else
|
513
|
+
Reline::IOGate.erase_after_cursor
|
514
|
+
move_cursor_down(1)
|
515
|
+
Reline::IOGate.move_cursor_column(0)
|
516
|
+
end
|
510
517
|
next
|
511
518
|
end
|
512
|
-
@output.
|
519
|
+
@output.write line
|
520
|
+
if Reline::IOGate.win? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
|
521
|
+
# A newline is automatically inserted if a character is rendered at eol on command prompt.
|
522
|
+
@rest_height -= 1 if @rest_height > 0
|
523
|
+
end
|
513
524
|
@output.flush
|
514
525
|
if @first_prompt
|
515
526
|
@first_prompt = false
|
@@ -532,7 +543,7 @@ class Reline::LineEditor
|
|
532
543
|
return before if before.nil? || before.empty?
|
533
544
|
|
534
545
|
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
|
535
|
-
after.lines(chomp: true)
|
546
|
+
after.lines("\n", chomp: true)
|
536
547
|
else
|
537
548
|
before
|
538
549
|
end
|
@@ -549,10 +560,14 @@ class Reline::LineEditor
|
|
549
560
|
private def complete_internal_proc(list, is_menu)
|
550
561
|
preposing, target, postposing = retrieve_completion_block
|
551
562
|
list = list.select { |i|
|
552
|
-
if i and
|
553
|
-
raise Encoding::CompatibilityError
|
563
|
+
if i and not Encoding.compatible?(target.encoding, i.encoding)
|
564
|
+
raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{i.encoding.name}"
|
565
|
+
end
|
566
|
+
if @config.completion_ignore_case
|
567
|
+
i&.downcase&.start_with?(target.downcase)
|
568
|
+
else
|
569
|
+
i&.start_with?(target)
|
554
570
|
end
|
555
|
-
i&.start_with?(target)
|
556
571
|
}
|
557
572
|
if is_menu
|
558
573
|
menu(target, list)
|
@@ -569,10 +584,18 @@ class Reline::LineEditor
|
|
569
584
|
size = [memo_mbchars.size, item_mbchars.size].min
|
570
585
|
result = ''
|
571
586
|
size.times do |i|
|
572
|
-
if
|
573
|
-
|
587
|
+
if @config.completion_ignore_case
|
588
|
+
if memo_mbchars[i].casecmp?(item_mbchars[i])
|
589
|
+
result << memo_mbchars[i]
|
590
|
+
else
|
591
|
+
break
|
592
|
+
end
|
574
593
|
else
|
575
|
-
|
594
|
+
if memo_mbchars[i] == item_mbchars[i]
|
595
|
+
result << memo_mbchars[i]
|
596
|
+
else
|
597
|
+
break
|
598
|
+
end
|
576
599
|
end
|
577
600
|
end
|
578
601
|
result
|
@@ -580,27 +603,43 @@ class Reline::LineEditor
|
|
580
603
|
[target, preposing, completed, postposing]
|
581
604
|
end
|
582
605
|
|
583
|
-
private def complete(list)
|
606
|
+
private def complete(list, just_show_list = false)
|
584
607
|
case @completion_state
|
585
608
|
when CompletionState::NORMAL, CompletionState::JOURNEY
|
586
609
|
@completion_state = CompletionState::COMPLETION
|
587
610
|
when CompletionState::PERFECT_MATCH
|
588
611
|
@dig_perfect_match_proc&.(@perfect_matched)
|
589
612
|
end
|
590
|
-
|
613
|
+
if just_show_list
|
614
|
+
is_menu = true
|
615
|
+
elsif @completion_state == CompletionState::MENU
|
616
|
+
is_menu = true
|
617
|
+
elsif @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
|
618
|
+
is_menu = true
|
619
|
+
else
|
620
|
+
is_menu = false
|
621
|
+
end
|
591
622
|
result = complete_internal_proc(list, is_menu)
|
623
|
+
if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
|
624
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
625
|
+
end
|
592
626
|
return if result.nil?
|
593
627
|
target, preposing, completed, postposing = result
|
594
628
|
return if completed.nil?
|
595
|
-
if target <= completed and (@completion_state == CompletionState::COMPLETION
|
596
|
-
@completion_state = CompletionState::MENU
|
629
|
+
if target <= completed and (@completion_state == CompletionState::COMPLETION)
|
597
630
|
if list.include?(completed)
|
598
|
-
|
631
|
+
if list.one?
|
632
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
633
|
+
else
|
634
|
+
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
635
|
+
end
|
599
636
|
@perfect_matched = completed
|
637
|
+
else
|
638
|
+
@completion_state = CompletionState::MENU
|
600
639
|
end
|
601
|
-
if target < completed
|
602
|
-
@line = preposing + completed + postposing
|
603
|
-
line_to_pointer = preposing + completed
|
640
|
+
if not just_show_list and target < completed
|
641
|
+
@line = preposing + completed + completion_append_character.to_s + postposing
|
642
|
+
line_to_pointer = preposing + completed + completion_append_character.to_s
|
604
643
|
@cursor_max = calculate_width(@line)
|
605
644
|
@cursor = calculate_width(line_to_pointer)
|
606
645
|
@byte_pointer = line_to_pointer.bytesize
|
@@ -610,7 +649,8 @@ class Reline::LineEditor
|
|
610
649
|
|
611
650
|
private def move_completed_list(list, direction)
|
612
651
|
case @completion_state
|
613
|
-
when CompletionState::NORMAL, CompletionState::COMPLETION,
|
652
|
+
when CompletionState::NORMAL, CompletionState::COMPLETION,
|
653
|
+
CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
|
614
654
|
@completion_state = CompletionState::JOURNEY
|
615
655
|
result = retrieve_completion_block
|
616
656
|
return if result.nil?
|
@@ -776,20 +816,20 @@ class Reline::LineEditor
|
|
776
816
|
@first_char = false
|
777
817
|
completion_occurs = false
|
778
818
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
819
|
+
unless @config.disable_completion
|
820
|
+
result = call_completion_proc
|
821
|
+
if result.is_a?(Array)
|
822
|
+
completion_occurs = true
|
823
|
+
complete(result)
|
824
|
+
end
|
785
825
|
end
|
786
|
-
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
826
|
+
elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
827
|
+
unless @config.disable_completion
|
828
|
+
result = call_completion_proc
|
829
|
+
if result.is_a?(Array)
|
830
|
+
completion_occurs = true
|
831
|
+
move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
|
832
|
+
end
|
793
833
|
end
|
794
834
|
elsif Symbol === key.char and respond_to?(key.char, true)
|
795
835
|
process_key(key.char, key.char)
|
@@ -804,6 +844,14 @@ class Reline::LineEditor
|
|
804
844
|
end
|
805
845
|
end
|
806
846
|
|
847
|
+
def call_completion_proc
|
848
|
+
result = retrieve_completion_block(true)
|
849
|
+
slice = result[1]
|
850
|
+
result = @completion_proc.(slice) if @completion_proc and slice
|
851
|
+
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
852
|
+
result
|
853
|
+
end
|
854
|
+
|
807
855
|
private def process_auto_indent
|
808
856
|
return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
|
809
857
|
if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
|
@@ -815,12 +863,9 @@ class Reline::LineEditor
|
|
815
863
|
@line = ' ' * new_indent + @line.lstrip
|
816
864
|
|
817
865
|
new_indent = nil
|
818
|
-
(new_lines[-2].size + 1)
|
819
|
-
|
820
|
-
|
821
|
-
new_indent = result
|
822
|
-
break
|
823
|
-
end
|
866
|
+
result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
|
867
|
+
if result
|
868
|
+
new_indent = result
|
824
869
|
end
|
825
870
|
if new_indent&.>= 0
|
826
871
|
@line = ' ' * new_indent + @line.lstrip
|
@@ -848,7 +893,7 @@ class Reline::LineEditor
|
|
848
893
|
@check_new_auto_indent = false
|
849
894
|
end
|
850
895
|
|
851
|
-
def retrieve_completion_block
|
896
|
+
def retrieve_completion_block(set_completion_quote_character = false)
|
852
897
|
word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
|
853
898
|
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
|
854
899
|
before = @line.byteslice(0, @byte_pointer)
|
@@ -867,31 +912,46 @@ class Reline::LineEditor
|
|
867
912
|
if quote and slice.start_with?(closing_quote)
|
868
913
|
quote = nil
|
869
914
|
i += 1
|
915
|
+
rest = nil
|
870
916
|
elsif quote and slice.start_with?(escaped_quote)
|
871
917
|
# skip
|
872
918
|
i += 2
|
873
919
|
elsif slice =~ quote_characters_regexp # find new "
|
920
|
+
rest = $'
|
874
921
|
quote = $&
|
875
922
|
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
876
923
|
escaped_quote = /\\#{Regexp.escape(quote)}/
|
877
924
|
i += 1
|
925
|
+
break_pointer = i - 1
|
878
926
|
elsif not quote and slice =~ word_break_regexp
|
879
927
|
rest = $'
|
880
928
|
i += 1
|
929
|
+
before = @line.byteslice(i, @byte_pointer - i)
|
881
930
|
break_pointer = i
|
882
931
|
else
|
883
932
|
i += 1
|
884
933
|
end
|
885
934
|
end
|
935
|
+
postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
|
886
936
|
if rest
|
887
937
|
preposing = @line.byteslice(0, break_pointer)
|
888
938
|
target = rest
|
939
|
+
if set_completion_quote_character and quote
|
940
|
+
Reline.core.instance_variable_set(:@completion_quote_character, quote)
|
941
|
+
if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote
|
942
|
+
insert_text(quote)
|
943
|
+
end
|
944
|
+
end
|
889
945
|
else
|
890
946
|
preposing = ''
|
947
|
+
if break_pointer
|
948
|
+
preposing = @line.byteslice(0, break_pointer)
|
949
|
+
else
|
950
|
+
preposing = ''
|
951
|
+
end
|
891
952
|
target = before
|
892
953
|
end
|
893
|
-
|
894
|
-
[preposing, target, postposing]
|
954
|
+
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
895
955
|
end
|
896
956
|
|
897
957
|
def confirm_multiline_termination
|
@@ -1043,6 +1103,11 @@ class Reline::LineEditor
|
|
1043
1103
|
|
1044
1104
|
private def ed_insert(key)
|
1045
1105
|
if key.instance_of?(String)
|
1106
|
+
begin
|
1107
|
+
key.encode(Encoding::UTF_8)
|
1108
|
+
rescue Encoding::UndefinedConversionError
|
1109
|
+
return
|
1110
|
+
end
|
1046
1111
|
width = Reline::Unicode.get_mbchar_width(key)
|
1047
1112
|
if @cursor == @cursor_max
|
1048
1113
|
@line += key
|
@@ -1053,6 +1118,11 @@ class Reline::LineEditor
|
|
1053
1118
|
@cursor += width
|
1054
1119
|
@cursor_max += width
|
1055
1120
|
else
|
1121
|
+
begin
|
1122
|
+
key.chr.encode(Encoding::UTF_8)
|
1123
|
+
rescue Encoding::UndefinedConversionError
|
1124
|
+
return
|
1125
|
+
end
|
1056
1126
|
if @cursor == @cursor_max
|
1057
1127
|
@line += key.chr
|
1058
1128
|
else
|
@@ -1144,25 +1214,34 @@ class Reline::LineEditor
|
|
1144
1214
|
end
|
1145
1215
|
alias_method :end_of_line, :ed_move_to_end
|
1146
1216
|
|
1147
|
-
private def
|
1148
|
-
|
1149
|
-
|
1150
|
-
else
|
1151
|
-
@line_backup_in_history = @line
|
1152
|
-
end
|
1153
|
-
searcher = Fiber.new do
|
1217
|
+
private def generate_searcher
|
1218
|
+
Fiber.new do |first_key|
|
1219
|
+
prev_search_key = first_key
|
1154
1220
|
search_word = String.new(encoding: @encoding)
|
1155
1221
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1156
1222
|
last_hit = nil
|
1223
|
+
case first_key
|
1224
|
+
when "\C-r".ord
|
1225
|
+
prompt_name = 'reverse-i-search'
|
1226
|
+
when "\C-s".ord
|
1227
|
+
prompt_name = 'i-search'
|
1228
|
+
end
|
1157
1229
|
loop do
|
1158
1230
|
key = Fiber.yield(search_word)
|
1231
|
+
search_again = false
|
1159
1232
|
case key
|
1160
|
-
when
|
1233
|
+
when -1 # determined
|
1234
|
+
Reline.last_incremental_search = search_word
|
1235
|
+
break
|
1236
|
+
when "\C-h".ord, "\C-?".ord
|
1161
1237
|
grapheme_clusters = search_word.grapheme_clusters
|
1162
1238
|
if grapheme_clusters.size > 0
|
1163
1239
|
grapheme_clusters.pop
|
1164
1240
|
search_word = grapheme_clusters.join
|
1165
1241
|
end
|
1242
|
+
when "\C-r".ord, "\C-s".ord
|
1243
|
+
search_again = true if prev_search_key == key
|
1244
|
+
prev_search_key = key
|
1166
1245
|
else
|
1167
1246
|
multibyte_buf << key
|
1168
1247
|
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
@@ -1171,18 +1250,61 @@ class Reline::LineEditor
|
|
1171
1250
|
end
|
1172
1251
|
end
|
1173
1252
|
hit = nil
|
1174
|
-
if @line_backup_in_history
|
1253
|
+
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1175
1254
|
@history_pointer = nil
|
1176
1255
|
hit = @line_backup_in_history
|
1177
1256
|
else
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1257
|
+
if search_again
|
1258
|
+
if search_word.empty? and Reline.last_incremental_search
|
1259
|
+
search_word = Reline.last_incremental_search
|
1260
|
+
end
|
1261
|
+
if @history_pointer # TODO
|
1262
|
+
case prev_search_key
|
1263
|
+
when "\C-r".ord
|
1264
|
+
history_pointer_base = 0
|
1265
|
+
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1266
|
+
when "\C-s".ord
|
1267
|
+
history_pointer_base = @history_pointer + 1
|
1268
|
+
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1269
|
+
end
|
1270
|
+
else
|
1271
|
+
history_pointer_base = 0
|
1272
|
+
history = Reline::HISTORY
|
1273
|
+
end
|
1274
|
+
elsif @history_pointer
|
1275
|
+
case prev_search_key
|
1276
|
+
when "\C-r".ord
|
1277
|
+
history_pointer_base = 0
|
1278
|
+
history = Reline::HISTORY[0..@history_pointer]
|
1279
|
+
when "\C-s".ord
|
1280
|
+
history_pointer_base = @history_pointer
|
1281
|
+
history = Reline::HISTORY[@history_pointer..-1]
|
1282
|
+
end
|
1283
|
+
else
|
1284
|
+
history_pointer_base = 0
|
1285
|
+
history = Reline::HISTORY
|
1286
|
+
end
|
1287
|
+
case prev_search_key
|
1288
|
+
when "\C-r".ord
|
1289
|
+
hit_index = history.rindex { |item|
|
1290
|
+
item.include?(search_word)
|
1291
|
+
}
|
1292
|
+
when "\C-s".ord
|
1293
|
+
hit_index = history.index { |item|
|
1294
|
+
item.include?(search_word)
|
1295
|
+
}
|
1296
|
+
end
|
1181
1297
|
if hit_index
|
1182
|
-
@history_pointer = hit_index
|
1298
|
+
@history_pointer = history_pointer_base + hit_index
|
1183
1299
|
hit = Reline::HISTORY[@history_pointer]
|
1184
1300
|
end
|
1185
1301
|
end
|
1302
|
+
case prev_search_key
|
1303
|
+
when "\C-r".ord
|
1304
|
+
prompt_name = 'reverse-i-search'
|
1305
|
+
when "\C-s".ord
|
1306
|
+
prompt_name = 'i-search'
|
1307
|
+
end
|
1186
1308
|
if hit
|
1187
1309
|
if @is_multiline
|
1188
1310
|
@buffer_of_lines = hit.split("\n")
|
@@ -1190,47 +1312,77 @@ class Reline::LineEditor
|
|
1190
1312
|
@line_index = @buffer_of_lines.size - 1
|
1191
1313
|
@line = @buffer_of_lines.last
|
1192
1314
|
@rerender_all = true
|
1193
|
-
@searching_prompt = "(
|
1315
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1194
1316
|
else
|
1195
1317
|
@line = hit
|
1196
|
-
@searching_prompt = "(
|
1318
|
+
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
1197
1319
|
end
|
1198
1320
|
last_hit = hit
|
1199
1321
|
else
|
1200
1322
|
if @is_multiline
|
1201
1323
|
@rerender_all = true
|
1202
|
-
@searching_prompt = "(failed
|
1324
|
+
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
1203
1325
|
else
|
1204
|
-
@searching_prompt = "(failed
|
1326
|
+
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
1205
1327
|
end
|
1206
1328
|
end
|
1207
1329
|
end
|
1208
1330
|
end
|
1209
|
-
|
1331
|
+
end
|
1332
|
+
|
1333
|
+
private def incremental_search_history(key)
|
1334
|
+
unless @history_pointer
|
1335
|
+
if @is_multiline
|
1336
|
+
@line_backup_in_history = whole_buffer
|
1337
|
+
else
|
1338
|
+
@line_backup_in_history = @line
|
1339
|
+
end
|
1340
|
+
end
|
1341
|
+
searcher = generate_searcher
|
1342
|
+
searcher.resume(key)
|
1210
1343
|
@searching_prompt = "(reverse-i-search)`': "
|
1211
1344
|
@waiting_proc = ->(k) {
|
1212
1345
|
case k
|
1213
|
-
when "\C-j".ord
|
1346
|
+
when "\C-j".ord
|
1214
1347
|
if @history_pointer
|
1215
|
-
|
1348
|
+
buffer = Reline::HISTORY[@history_pointer]
|
1216
1349
|
else
|
1217
|
-
|
1350
|
+
buffer = @line_backup_in_history
|
1351
|
+
end
|
1352
|
+
if @is_multiline
|
1353
|
+
@buffer_of_lines = buffer.split("\n")
|
1354
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1355
|
+
@line_index = @buffer_of_lines.size - 1
|
1356
|
+
@line = @buffer_of_lines.last
|
1357
|
+
@rerender_all = true
|
1358
|
+
else
|
1359
|
+
@line = buffer
|
1218
1360
|
end
|
1219
1361
|
@searching_prompt = nil
|
1220
1362
|
@waiting_proc = nil
|
1221
1363
|
@cursor_max = calculate_width(@line)
|
1222
1364
|
@cursor = @byte_pointer = 0
|
1365
|
+
searcher.resume(-1)
|
1223
1366
|
when "\C-g".ord
|
1224
|
-
|
1367
|
+
if @is_multiline
|
1368
|
+
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1369
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1370
|
+
@line_index = @buffer_of_lines.size - 1
|
1371
|
+
@line = @buffer_of_lines.last
|
1372
|
+
@rerender_all = true
|
1373
|
+
else
|
1374
|
+
@line = @line_backup_in_history
|
1375
|
+
end
|
1225
1376
|
@history_pointer = nil
|
1226
1377
|
@searching_prompt = nil
|
1227
1378
|
@waiting_proc = nil
|
1228
1379
|
@line_backup_in_history = nil
|
1229
1380
|
@cursor_max = calculate_width(@line)
|
1230
1381
|
@cursor = @byte_pointer = 0
|
1382
|
+
@rerender_all = true
|
1231
1383
|
else
|
1232
1384
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1233
|
-
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k ==
|
1385
|
+
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1234
1386
|
searcher.resume(k)
|
1235
1387
|
else
|
1236
1388
|
if @history_pointer
|
@@ -1253,13 +1405,120 @@ class Reline::LineEditor
|
|
1253
1405
|
@waiting_proc = nil
|
1254
1406
|
@cursor_max = calculate_width(@line)
|
1255
1407
|
@cursor = @byte_pointer = 0
|
1408
|
+
searcher.resume(-1)
|
1256
1409
|
end
|
1257
1410
|
end
|
1258
1411
|
}
|
1259
1412
|
end
|
1260
1413
|
|
1261
|
-
private def
|
1414
|
+
private def vi_search_prev(key)
|
1415
|
+
incremental_search_history(key)
|
1416
|
+
end
|
1417
|
+
alias_method :reverse_search_history, :vi_search_prev
|
1418
|
+
|
1419
|
+
private def vi_search_next(key)
|
1420
|
+
incremental_search_history(key)
|
1262
1421
|
end
|
1422
|
+
alias_method :forward_search_history, :vi_search_next
|
1423
|
+
|
1424
|
+
private def ed_search_prev_history(key, arg: 1)
|
1425
|
+
history = nil
|
1426
|
+
h_pointer = nil
|
1427
|
+
line_no = nil
|
1428
|
+
substr = @line.slice(0, @byte_pointer)
|
1429
|
+
if @history_pointer.nil?
|
1430
|
+
return if not @line.empty? and substr.empty?
|
1431
|
+
history = Reline::HISTORY
|
1432
|
+
elsif @history_pointer.zero?
|
1433
|
+
history = nil
|
1434
|
+
h_pointer = nil
|
1435
|
+
else
|
1436
|
+
history = Reline::HISTORY.slice(0, @history_pointer)
|
1437
|
+
end
|
1438
|
+
return if history.nil?
|
1439
|
+
if @is_multiline
|
1440
|
+
h_pointer = history.rindex { |h|
|
1441
|
+
h.split("\n").each_with_index { |l, i|
|
1442
|
+
if l.start_with?(substr)
|
1443
|
+
line_no = i
|
1444
|
+
break
|
1445
|
+
end
|
1446
|
+
}
|
1447
|
+
not line_no.nil?
|
1448
|
+
}
|
1449
|
+
else
|
1450
|
+
h_pointer = history.rindex { |l|
|
1451
|
+
l.start_with?(substr)
|
1452
|
+
}
|
1453
|
+
end
|
1454
|
+
return if h_pointer.nil?
|
1455
|
+
@history_pointer = h_pointer
|
1456
|
+
if @is_multiline
|
1457
|
+
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1458
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1459
|
+
@line_index = line_no
|
1460
|
+
@line = @buffer_of_lines.last
|
1461
|
+
@rerender_all = true
|
1462
|
+
else
|
1463
|
+
@line = Reline::HISTORY[@history_pointer]
|
1464
|
+
end
|
1465
|
+
@cursor_max = calculate_width(@line)
|
1466
|
+
arg -= 1
|
1467
|
+
ed_search_prev_history(key, arg: arg) if arg > 0
|
1468
|
+
end
|
1469
|
+
alias_method :history_search_backward, :ed_search_prev_history
|
1470
|
+
|
1471
|
+
private def ed_search_next_history(key, arg: 1)
|
1472
|
+
substr = @line.slice(0, @byte_pointer)
|
1473
|
+
if @history_pointer.nil?
|
1474
|
+
return
|
1475
|
+
elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty?
|
1476
|
+
return
|
1477
|
+
end
|
1478
|
+
history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
|
1479
|
+
h_pointer = nil
|
1480
|
+
line_no = nil
|
1481
|
+
if @is_multiline
|
1482
|
+
h_pointer = history.index { |h|
|
1483
|
+
h.split("\n").each_with_index { |l, i|
|
1484
|
+
if l.start_with?(substr)
|
1485
|
+
line_no = i
|
1486
|
+
break
|
1487
|
+
end
|
1488
|
+
}
|
1489
|
+
not line_no.nil?
|
1490
|
+
}
|
1491
|
+
else
|
1492
|
+
h_pointer = history.index { |l|
|
1493
|
+
l.start_with?(substr)
|
1494
|
+
}
|
1495
|
+
end
|
1496
|
+
h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
|
1497
|
+
return if h_pointer.nil? and not substr.empty?
|
1498
|
+
@history_pointer = h_pointer
|
1499
|
+
if @is_multiline
|
1500
|
+
if @history_pointer.nil? and substr.empty?
|
1501
|
+
@buffer_of_lines = []
|
1502
|
+
@line_index = 0
|
1503
|
+
else
|
1504
|
+
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1505
|
+
@line_index = line_no
|
1506
|
+
end
|
1507
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1508
|
+
@line = @buffer_of_lines.last
|
1509
|
+
@rerender_all = true
|
1510
|
+
else
|
1511
|
+
if @history_pointer.nil? and substr.empty?
|
1512
|
+
@line = ''
|
1513
|
+
else
|
1514
|
+
@line = Reline::HISTORY[@history_pointer]
|
1515
|
+
end
|
1516
|
+
end
|
1517
|
+
@cursor_max = calculate_width(@line)
|
1518
|
+
arg -= 1
|
1519
|
+
ed_search_next_history(key, arg: arg) if arg > 0
|
1520
|
+
end
|
1521
|
+
alias_method :history_search_forward, :ed_search_next_history
|
1263
1522
|
|
1264
1523
|
private def ed_prev_history(key, arg: 1)
|
1265
1524
|
if @is_multiline and @line_index > 0
|
@@ -1417,6 +1676,14 @@ class Reline::LineEditor
|
|
1417
1676
|
@byte_pointer = @line.bytesize
|
1418
1677
|
@cursor = @cursor_max = calculate_width(@line)
|
1419
1678
|
@kill_ring.append(deleted)
|
1679
|
+
elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1680
|
+
@cursor = calculate_width(@line)
|
1681
|
+
@byte_pointer = @line.bytesize
|
1682
|
+
@line += @buffer_of_lines.delete_at(@line_index + 1)
|
1683
|
+
@cursor_max = calculate_width(@line)
|
1684
|
+
@buffer_of_lines[@line_index] = @line
|
1685
|
+
@rerender_all = true
|
1686
|
+
@rest_height += 1
|
1420
1687
|
end
|
1421
1688
|
end
|
1422
1689
|
|
@@ -1430,7 +1697,7 @@ class Reline::LineEditor
|
|
1430
1697
|
end
|
1431
1698
|
end
|
1432
1699
|
|
1433
|
-
private def
|
1700
|
+
private def em_delete(key)
|
1434
1701
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
1435
1702
|
@line = nil
|
1436
1703
|
if @buffer_of_lines.size > 1
|
@@ -1455,7 +1722,19 @@ class Reline::LineEditor
|
|
1455
1722
|
@rest_height += 1
|
1456
1723
|
end
|
1457
1724
|
end
|
1458
|
-
alias_method :delete_char, :
|
1725
|
+
alias_method :delete_char, :em_delete
|
1726
|
+
|
1727
|
+
private def em_delete_or_list(key)
|
1728
|
+
if @line.empty? or @byte_pointer < @line.bytesize
|
1729
|
+
em_delete(key)
|
1730
|
+
else # show completed list
|
1731
|
+
result = call_completion_proc
|
1732
|
+
if result.is_a?(Array)
|
1733
|
+
complete(result, true)
|
1734
|
+
end
|
1735
|
+
end
|
1736
|
+
end
|
1737
|
+
alias_method :delete_char_or_list, :em_delete_or_list
|
1459
1738
|
|
1460
1739
|
private def em_yank(key)
|
1461
1740
|
yanked = @kill_ring.yank
|
@@ -1718,6 +1997,16 @@ class Reline::LineEditor
|
|
1718
1997
|
end
|
1719
1998
|
end
|
1720
1999
|
|
2000
|
+
private def vi_insert_at_bol(key)
|
2001
|
+
ed_move_to_beg(key)
|
2002
|
+
@config.editing_mode = :vi_insert
|
2003
|
+
end
|
2004
|
+
|
2005
|
+
private def vi_add_at_eol(key)
|
2006
|
+
ed_move_to_end(key)
|
2007
|
+
@config.editing_mode = :vi_insert
|
2008
|
+
end
|
2009
|
+
|
1721
2010
|
private def ed_delete_prev_char(key, arg: 1)
|
1722
2011
|
deleted = ''
|
1723
2012
|
arg.times do
|
@@ -1740,6 +2029,18 @@ class Reline::LineEditor
|
|
1740
2029
|
end
|
1741
2030
|
|
1742
2031
|
private def vi_change_meta(key)
|
2032
|
+
@waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
|
2033
|
+
if byte_pointer_diff > 0
|
2034
|
+
@line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
|
2035
|
+
elsif byte_pointer_diff < 0
|
2036
|
+
@line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2037
|
+
end
|
2038
|
+
copy_for_vi(cut)
|
2039
|
+
@cursor += cursor_diff if cursor_diff < 0
|
2040
|
+
@cursor_max -= cursor_diff.abs
|
2041
|
+
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
2042
|
+
@config.editing_mode = :vi_insert
|
2043
|
+
}
|
1743
2044
|
end
|
1744
2045
|
|
1745
2046
|
private def vi_delete_meta(key)
|
@@ -1759,18 +2060,6 @@ class Reline::LineEditor
|
|
1759
2060
|
private def vi_yank(key)
|
1760
2061
|
end
|
1761
2062
|
|
1762
|
-
private def vi_end_of_transmission(key)
|
1763
|
-
if @line.empty?
|
1764
|
-
@line = nil
|
1765
|
-
if @buffer_of_lines.size > 1
|
1766
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
1767
|
-
end
|
1768
|
-
Reline::IOGate.move_cursor_column(0)
|
1769
|
-
@eof = true
|
1770
|
-
finish
|
1771
|
-
end
|
1772
|
-
end
|
1773
|
-
|
1774
2063
|
private def vi_list_or_eof(key)
|
1775
2064
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
1776
2065
|
@line = nil
|
@@ -1781,9 +2070,11 @@ class Reline::LineEditor
|
|
1781
2070
|
@eof = true
|
1782
2071
|
finish
|
1783
2072
|
else
|
1784
|
-
|
2073
|
+
ed_newline(key)
|
1785
2074
|
end
|
1786
2075
|
end
|
2076
|
+
alias_method :vi_end_of_transmission, :vi_list_or_eof
|
2077
|
+
alias_method :vi_eof_maybe, :vi_list_or_eof
|
1787
2078
|
|
1788
2079
|
private def ed_delete_next_char(key, arg: 1)
|
1789
2080
|
byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
|
@@ -1915,12 +2206,17 @@ class Reline::LineEditor
|
|
1915
2206
|
@waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg) }
|
1916
2207
|
end
|
1917
2208
|
|
1918
|
-
private def
|
2209
|
+
private def vi_to_next_char(key, arg: 1)
|
2210
|
+
@waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, true) }
|
2211
|
+
end
|
2212
|
+
|
2213
|
+
private def search_next_char(key, arg, need_prev_char = false)
|
1919
2214
|
if key.instance_of?(String)
|
1920
2215
|
inputed_char = key
|
1921
2216
|
else
|
1922
2217
|
inputed_char = key.chr
|
1923
2218
|
end
|
2219
|
+
prev_total = nil
|
1924
2220
|
total = nil
|
1925
2221
|
found = false
|
1926
2222
|
@line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
|
@@ -1938,13 +2234,66 @@ class Reline::LineEditor
|
|
1938
2234
|
end
|
1939
2235
|
end
|
1940
2236
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2237
|
+
prev_total = total
|
1941
2238
|
total = [total.first + mbchar.bytesize, total.last + width]
|
1942
2239
|
end
|
1943
2240
|
end
|
1944
|
-
if found and total
|
2241
|
+
if not need_prev_char and found and total
|
1945
2242
|
byte_size, width = total
|
1946
2243
|
@byte_pointer += byte_size
|
1947
2244
|
@cursor += width
|
2245
|
+
elsif need_prev_char and found and prev_total
|
2246
|
+
byte_size, width = prev_total
|
2247
|
+
@byte_pointer += byte_size
|
2248
|
+
@cursor += width
|
2249
|
+
end
|
2250
|
+
@waiting_proc = nil
|
2251
|
+
end
|
2252
|
+
|
2253
|
+
private def vi_prev_char(key, arg: 1)
|
2254
|
+
@waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg) }
|
2255
|
+
end
|
2256
|
+
|
2257
|
+
private def vi_to_prev_char(key, arg: 1)
|
2258
|
+
@waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg, true) }
|
2259
|
+
end
|
2260
|
+
|
2261
|
+
private def search_prev_char(key, arg, need_next_char = false)
|
2262
|
+
if key.instance_of?(String)
|
2263
|
+
inputed_char = key
|
2264
|
+
else
|
2265
|
+
inputed_char = key.chr
|
2266
|
+
end
|
2267
|
+
prev_total = nil
|
2268
|
+
total = nil
|
2269
|
+
found = false
|
2270
|
+
@line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
|
2271
|
+
# total has [byte_size, cursor]
|
2272
|
+
unless total
|
2273
|
+
# skip cursor point
|
2274
|
+
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2275
|
+
total = [mbchar.bytesize, width]
|
2276
|
+
else
|
2277
|
+
if inputed_char == mbchar
|
2278
|
+
arg -= 1
|
2279
|
+
if arg.zero?
|
2280
|
+
found = true
|
2281
|
+
break
|
2282
|
+
end
|
2283
|
+
end
|
2284
|
+
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2285
|
+
prev_total = total
|
2286
|
+
total = [total.first + mbchar.bytesize, total.last + width]
|
2287
|
+
end
|
2288
|
+
end
|
2289
|
+
if not need_next_char and found and total
|
2290
|
+
byte_size, width = total
|
2291
|
+
@byte_pointer -= byte_size
|
2292
|
+
@cursor -= width
|
2293
|
+
elsif need_next_char and found and prev_total
|
2294
|
+
byte_size, width = prev_total
|
2295
|
+
@byte_pointer -= byte_size
|
2296
|
+
@cursor -= width
|
1948
2297
|
end
|
1949
2298
|
@waiting_proc = nil
|
1950
2299
|
end
|