reline 0.5.10 → 0.6.1
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/config.rb +22 -26
- data/lib/reline/history.rb +3 -3
- data/lib/reline/io/ansi.rb +70 -124
- data/lib/reline/io/dumb.rb +16 -2
- data/lib/reline/io/windows.rb +77 -60
- data/lib/reline/io.rb +14 -0
- data/lib/reline/key_actor/base.rb +10 -4
- data/lib/reline/key_actor/emacs.rb +96 -96
- data/lib/reline/key_actor/vi_command.rb +182 -182
- data/lib/reline/key_actor/vi_insert.rb +137 -137
- data/lib/reline/key_stroke.rb +26 -16
- data/lib/reline/line_editor.rb +295 -489
- data/lib/reline/unicode/east_asian_width.rb +41 -15
- data/lib/reline/unicode.rb +141 -397
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +40 -31
- metadata +3 -4
- data/lib/reline/terminfo.rb +0 -158
data/lib/reline/line_editor.rb
CHANGED
@@ -13,7 +13,6 @@ class Reline::LineEditor
|
|
13
13
|
attr_accessor :prompt_proc
|
14
14
|
attr_accessor :auto_indent_proc
|
15
15
|
attr_accessor :dig_perfect_match_proc
|
16
|
-
attr_writer :output
|
17
16
|
|
18
17
|
VI_MOTIONS = %i{
|
19
18
|
ed_prev_char
|
@@ -36,7 +35,6 @@ class Reline::LineEditor
|
|
36
35
|
|
37
36
|
module CompletionState
|
38
37
|
NORMAL = :normal
|
39
|
-
COMPLETION = :completion
|
40
38
|
MENU = :menu
|
41
39
|
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
|
42
40
|
PERFECT_MATCH = :perfect_match
|
@@ -72,17 +70,21 @@ class Reline::LineEditor
|
|
72
70
|
|
73
71
|
MINIMUM_SCROLLBAR_HEIGHT = 1
|
74
72
|
|
75
|
-
def initialize(config
|
73
|
+
def initialize(config)
|
76
74
|
@config = config
|
77
75
|
@completion_append_character = ''
|
78
76
|
@screen_size = [0, 0] # Should be initialized with actual winsize in LineEditor#reset
|
79
|
-
reset_variables
|
77
|
+
reset_variables
|
80
78
|
end
|
81
79
|
|
82
80
|
def io_gate
|
83
81
|
Reline::IOGate
|
84
82
|
end
|
85
83
|
|
84
|
+
def encoding
|
85
|
+
io_gate.encoding
|
86
|
+
end
|
87
|
+
|
86
88
|
def set_pasting_state(in_pasting)
|
87
89
|
# While pasting, text to be inserted is stored to @continuous_insertion_buffer.
|
88
90
|
# After pasting, this buffer should be force inserted.
|
@@ -136,9 +138,9 @@ class Reline::LineEditor
|
|
136
138
|
end
|
137
139
|
end
|
138
140
|
|
139
|
-
def reset(prompt = ''
|
141
|
+
def reset(prompt = '')
|
140
142
|
@screen_size = Reline::IOGate.get_screen_size
|
141
|
-
reset_variables(prompt
|
143
|
+
reset_variables(prompt)
|
142
144
|
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
|
143
145
|
if ENV.key?('RELINE_ALT_SCROLLBAR')
|
144
146
|
@full_block = '::'
|
@@ -150,7 +152,7 @@ class Reline::LineEditor
|
|
150
152
|
@upper_half_block = '▀'
|
151
153
|
@lower_half_block = '▄'
|
152
154
|
@block_elem_width = 1
|
153
|
-
elsif
|
155
|
+
elsif encoding == Encoding::UTF_8
|
154
156
|
@full_block = '█'
|
155
157
|
@upper_half_block = '▀'
|
156
158
|
@lower_half_block = '▄'
|
@@ -219,10 +221,9 @@ class Reline::LineEditor
|
|
219
221
|
@eof
|
220
222
|
end
|
221
223
|
|
222
|
-
def reset_variables(prompt = ''
|
224
|
+
def reset_variables(prompt = '')
|
223
225
|
@prompt = prompt.gsub("\n", "\\n")
|
224
226
|
@mark_pointer = nil
|
225
|
-
@encoding = encoding
|
226
227
|
@is_multiline = false
|
227
228
|
@finished = false
|
228
229
|
@history_pointer = nil
|
@@ -239,7 +240,7 @@ class Reline::LineEditor
|
|
239
240
|
@searching_prompt = nil
|
240
241
|
@just_cursor_moving = false
|
241
242
|
@eof = false
|
242
|
-
@continuous_insertion_buffer = String.new(encoding:
|
243
|
+
@continuous_insertion_buffer = String.new(encoding: encoding)
|
243
244
|
@scroll_partial_screen = 0
|
244
245
|
@drop_terminate_spaces = false
|
245
246
|
@in_pasting = false
|
@@ -249,9 +250,9 @@ class Reline::LineEditor
|
|
249
250
|
@resized = false
|
250
251
|
@cache = {}
|
251
252
|
@rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
|
252
|
-
@
|
253
|
-
@
|
254
|
-
@
|
253
|
+
@undo_redo_history = [[[""], 0, 0]]
|
254
|
+
@undo_redo_index = 0
|
255
|
+
@restoring = false
|
255
256
|
@prev_action_state = NullActionState
|
256
257
|
@next_action_state = NullActionState
|
257
258
|
reset_line
|
@@ -259,11 +260,10 @@ class Reline::LineEditor
|
|
259
260
|
|
260
261
|
def reset_line
|
261
262
|
@byte_pointer = 0
|
262
|
-
@buffer_of_lines = [String.new(encoding:
|
263
|
+
@buffer_of_lines = [String.new(encoding: encoding)]
|
263
264
|
@line_index = 0
|
264
265
|
@cache.clear
|
265
266
|
@line_backup_in_history = nil
|
266
|
-
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
|
267
267
|
end
|
268
268
|
|
269
269
|
def multiline_on
|
@@ -275,7 +275,7 @@ class Reline::LineEditor
|
|
275
275
|
end
|
276
276
|
|
277
277
|
private def insert_new_line(cursor_line, next_line)
|
278
|
-
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding:
|
278
|
+
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: encoding))
|
279
279
|
@buffer_of_lines[@line_index] = cursor_line
|
280
280
|
@line_index += 1
|
281
281
|
@byte_pointer = 0
|
@@ -297,8 +297,8 @@ class Reline::LineEditor
|
|
297
297
|
end
|
298
298
|
end
|
299
299
|
|
300
|
-
private def
|
301
|
-
Reline::Unicode.
|
300
|
+
private def split_line_by_width(str, max_width, offset: 0)
|
301
|
+
Reline::Unicode.split_line_by_width(str, max_width, encoding, offset: offset)
|
302
302
|
end
|
303
303
|
|
304
304
|
def current_byte_pointer_cursor
|
@@ -388,8 +388,8 @@ class Reline::LineEditor
|
|
388
388
|
if (cached = cached_wraps[[prompt, line]])
|
389
389
|
next cached
|
390
390
|
end
|
391
|
-
*wrapped_prompts, code_line_prompt =
|
392
|
-
wrapped_lines =
|
391
|
+
*wrapped_prompts, code_line_prompt = split_line_by_width(prompt, width)
|
392
|
+
wrapped_lines = split_line_by_width(line, width, offset: calculate_width(code_line_prompt, true))
|
393
393
|
wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
|
394
394
|
end
|
395
395
|
end
|
@@ -413,7 +413,7 @@ class Reline::LineEditor
|
|
413
413
|
# do nothing
|
414
414
|
elsif level == :blank
|
415
415
|
Reline::IOGate.move_cursor_column base_x
|
416
|
-
|
416
|
+
Reline::IOGate.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
|
417
417
|
else
|
418
418
|
x, w, content = new_items[level]
|
419
419
|
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
|
@@ -423,7 +423,7 @@ class Reline::LineEditor
|
|
423
423
|
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
424
424
|
end
|
425
425
|
Reline::IOGate.move_cursor_column x + pos
|
426
|
-
|
426
|
+
Reline::IOGate.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
|
427
427
|
end
|
428
428
|
base_x += width
|
429
429
|
end
|
@@ -436,8 +436,8 @@ class Reline::LineEditor
|
|
436
436
|
# Calculate cursor position in word wrapped content.
|
437
437
|
def wrapped_cursor_position
|
438
438
|
prompt_width = calculate_width(prompt_list[@line_index], true)
|
439
|
-
line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
|
440
|
-
wrapped_line_before_cursor =
|
439
|
+
line_before_cursor = Reline::Unicode.escape_for_print(whole_lines[@line_index].byteslice(0, @byte_pointer))
|
440
|
+
wrapped_line_before_cursor = split_line_by_width(' ' * prompt_width + line_before_cursor, screen_width)
|
441
441
|
wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
|
442
442
|
wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
|
443
443
|
[wrapped_cursor_x, wrapped_cursor_y]
|
@@ -459,18 +459,23 @@ class Reline::LineEditor
|
|
459
459
|
end
|
460
460
|
|
461
461
|
def render_finished
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
462
|
+
Reline::IOGate.buffered_output do
|
463
|
+
render_differential([], 0, 0)
|
464
|
+
lines = @buffer_of_lines.size.times.map do |i|
|
465
|
+
line = Reline::Unicode.strip_non_printing_start_end(prompt_list[i]) + modified_lines[i]
|
466
|
+
wrapped_lines = split_line_by_width(line, screen_width)
|
467
|
+
wrapped_lines.last.empty? ? "#{line} " : line
|
468
|
+
end
|
469
|
+
Reline::IOGate.write lines.map { |l| "#{l}\r\n" }.join
|
467
470
|
end
|
468
|
-
@output.puts lines.map { |l| "#{l}\r\n" }.join
|
469
471
|
end
|
470
472
|
|
471
473
|
def print_nomultiline_prompt
|
474
|
+
Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
|
472
475
|
# Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
|
473
|
-
|
476
|
+
Reline::IOGate.write Reline::Unicode.strip_non_printing_start_end(@prompt) if @prompt && !@is_multiline
|
477
|
+
ensure
|
478
|
+
Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
|
474
479
|
end
|
475
480
|
|
476
481
|
def render
|
@@ -499,13 +504,16 @@ class Reline::LineEditor
|
|
499
504
|
end
|
500
505
|
end
|
501
506
|
|
502
|
-
|
507
|
+
Reline::IOGate.buffered_output do
|
508
|
+
render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
|
509
|
+
end
|
503
510
|
end
|
504
511
|
|
505
512
|
# Reflects lines to be rendered and new cursor position to the screen
|
506
513
|
# by calculating the difference from the previous render.
|
507
514
|
|
508
515
|
private def render_differential(new_lines, new_cursor_x, new_cursor_y)
|
516
|
+
Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
|
509
517
|
rendered_lines = @rendered_screen.lines
|
510
518
|
cursor_y = @rendered_screen.cursor_y
|
511
519
|
if new_lines != rendered_lines
|
@@ -534,8 +542,11 @@ class Reline::LineEditor
|
|
534
542
|
Reline::IOGate.show_cursor
|
535
543
|
end
|
536
544
|
Reline::IOGate.move_cursor_column new_cursor_x
|
545
|
+
new_cursor_y = new_cursor_y.clamp(0, screen_height - 1)
|
537
546
|
Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
|
538
547
|
@rendered_screen.cursor_y = new_cursor_y
|
548
|
+
ensure
|
549
|
+
Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
|
539
550
|
end
|
540
551
|
|
541
552
|
private def clear_rendered_screen_cache
|
@@ -570,8 +581,9 @@ class Reline::LineEditor
|
|
570
581
|
@context
|
571
582
|
end
|
572
583
|
|
573
|
-
def retrieve_completion_block(
|
574
|
-
@line_editor.retrieve_completion_block
|
584
|
+
def retrieve_completion_block(_unused = false)
|
585
|
+
preposing, target, postposing, _quote = @line_editor.retrieve_completion_block
|
586
|
+
[preposing, target, postposing]
|
575
587
|
end
|
576
588
|
|
577
589
|
def call_completion_proc_with_checking_args(pre, target, post)
|
@@ -791,98 +803,73 @@ class Reline::LineEditor
|
|
791
803
|
@config.editing_mode
|
792
804
|
end
|
793
805
|
|
794
|
-
private def menu(
|
806
|
+
private def menu(list)
|
795
807
|
@menu_info = MenuInfo.new(list)
|
796
808
|
end
|
797
809
|
|
798
|
-
private def
|
799
|
-
|
800
|
-
list
|
801
|
-
|
802
|
-
|
810
|
+
private def filter_normalize_candidates(target, list)
|
811
|
+
target = target.downcase if @config.completion_ignore_case
|
812
|
+
list.select do |item|
|
813
|
+
next unless item
|
814
|
+
unless Encoding.compatible?(target.encoding, item.encoding)
|
815
|
+
# Workaround for Readline test
|
816
|
+
if defined?(::Readline) && ::Readline == ::Reline
|
817
|
+
raise Encoding::CompatibilityError, "incompatible character encodings: #{target.encoding} and #{item.encoding}"
|
818
|
+
end
|
803
819
|
end
|
820
|
+
|
804
821
|
if @config.completion_ignore_case
|
805
|
-
|
822
|
+
item.downcase.start_with?(target)
|
806
823
|
else
|
807
|
-
|
808
|
-
end
|
809
|
-
}.uniq
|
810
|
-
if is_menu
|
811
|
-
menu(target, list)
|
812
|
-
return nil
|
813
|
-
end
|
814
|
-
completed = list.inject { |memo, item|
|
815
|
-
begin
|
816
|
-
memo_mbchars = memo.unicode_normalize.grapheme_clusters
|
817
|
-
item_mbchars = item.unicode_normalize.grapheme_clusters
|
818
|
-
rescue Encoding::CompatibilityError
|
819
|
-
memo_mbchars = memo.grapheme_clusters
|
820
|
-
item_mbchars = item.grapheme_clusters
|
821
|
-
end
|
822
|
-
size = [memo_mbchars.size, item_mbchars.size].min
|
823
|
-
result = +''
|
824
|
-
size.times do |i|
|
825
|
-
if @config.completion_ignore_case
|
826
|
-
if memo_mbchars[i].casecmp?(item_mbchars[i])
|
827
|
-
result << memo_mbchars[i]
|
828
|
-
else
|
829
|
-
break
|
830
|
-
end
|
831
|
-
else
|
832
|
-
if memo_mbchars[i] == item_mbchars[i]
|
833
|
-
result << memo_mbchars[i]
|
834
|
-
else
|
835
|
-
break
|
836
|
-
end
|
837
|
-
end
|
824
|
+
item.start_with?(target)
|
838
825
|
end
|
839
|
-
|
840
|
-
|
841
|
-
|
826
|
+
end.map do |item|
|
827
|
+
item.unicode_normalize
|
828
|
+
rescue Encoding::CompatibilityError
|
829
|
+
item
|
830
|
+
end.uniq
|
842
831
|
end
|
843
832
|
|
844
|
-
private def perform_completion(
|
833
|
+
private def perform_completion(preposing, target, postposing, quote, list)
|
834
|
+
candidates = filter_normalize_candidates(target, list)
|
835
|
+
|
845
836
|
case @completion_state
|
846
|
-
when CompletionState::NORMAL
|
847
|
-
@completion_state = CompletionState::COMPLETION
|
848
837
|
when CompletionState::PERFECT_MATCH
|
849
|
-
@dig_perfect_match_proc
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
is_menu = false
|
859
|
-
end
|
860
|
-
result = complete_internal_proc(list, is_menu)
|
861
|
-
if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
|
838
|
+
if @dig_perfect_match_proc
|
839
|
+
@dig_perfect_match_proc.call(@perfect_matched)
|
840
|
+
return
|
841
|
+
end
|
842
|
+
when CompletionState::MENU
|
843
|
+
menu(candidates)
|
844
|
+
return
|
845
|
+
when CompletionState::MENU_WITH_PERFECT_MATCH
|
846
|
+
menu(candidates)
|
862
847
|
@completion_state = CompletionState::PERFECT_MATCH
|
848
|
+
return
|
863
849
|
end
|
864
|
-
|
865
|
-
|
866
|
-
return if completed.
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
@
|
850
|
+
|
851
|
+
completed = Reline::Unicode.common_prefix(candidates, ignore_case: @config.completion_ignore_case)
|
852
|
+
return if completed.empty?
|
853
|
+
|
854
|
+
append_character = ''
|
855
|
+
if candidates.include?(completed)
|
856
|
+
if candidates.one?
|
857
|
+
append_character = quote || completion_append_character.to_s
|
858
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
859
|
+
elsif @config.show_all_if_ambiguous
|
860
|
+
menu(candidates)
|
861
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
876
862
|
else
|
877
|
-
@completion_state = CompletionState::
|
878
|
-
perform_completion(list, true) if @config.show_all_if_ambiguous
|
879
|
-
end
|
880
|
-
if not just_show_list and target < completed
|
881
|
-
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
|
882
|
-
line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n")[@line_index] || String.new(encoding: @encoding)
|
883
|
-
@byte_pointer = line_to_pointer.bytesize
|
863
|
+
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
884
864
|
end
|
865
|
+
@perfect_matched = completed
|
866
|
+
else
|
867
|
+
@completion_state = CompletionState::MENU
|
868
|
+
menu(candidates) if @config.show_all_if_ambiguous
|
885
869
|
end
|
870
|
+
@buffer_of_lines[@line_index] = (preposing + completed + append_character + postposing).split("\n")[@line_index] || String.new(encoding: encoding)
|
871
|
+
line_to_pointer = (preposing + completed + append_character).split("\n")[@line_index] || String.new(encoding: encoding)
|
872
|
+
@byte_pointer = line_to_pointer.bytesize
|
886
873
|
end
|
887
874
|
|
888
875
|
def dialog_proc_scope_completion_journey_data
|
@@ -911,8 +898,8 @@ class Reline::LineEditor
|
|
911
898
|
end
|
912
899
|
|
913
900
|
private def retrieve_completion_journey_state
|
914
|
-
preposing, target, postposing = retrieve_completion_block
|
915
|
-
list = call_completion_proc
|
901
|
+
preposing, target, postposing, quote = retrieve_completion_block
|
902
|
+
list = call_completion_proc(preposing, target, postposing, quote)
|
916
903
|
return unless list.is_a?(Array)
|
917
904
|
|
918
905
|
candidates = list.select{ |item| item.start_with?(target) }
|
@@ -925,28 +912,36 @@ class Reline::LineEditor
|
|
925
912
|
)
|
926
913
|
end
|
927
914
|
|
928
|
-
private def run_for_operators(key, method_symbol
|
915
|
+
private def run_for_operators(key, method_symbol)
|
916
|
+
# Reject multibyte input (converted to ed_insert) in vi_command mode
|
917
|
+
return if method_symbol == :ed_insert && @config.editing_mode_is?(:vi_command) && !@waiting_proc
|
918
|
+
|
919
|
+
if ARGUMENT_DIGIT_METHODS.include?(method_symbol) && !@waiting_proc
|
920
|
+
wrap_method_call(method_symbol, key, false)
|
921
|
+
return
|
922
|
+
end
|
923
|
+
|
929
924
|
if @vi_waiting_operator
|
930
|
-
if VI_MOTIONS.include?(method_symbol)
|
925
|
+
if @waiting_proc || VI_MOTIONS.include?(method_symbol)
|
931
926
|
old_byte_pointer = @byte_pointer
|
932
927
|
@vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
|
933
|
-
|
928
|
+
wrap_method_call(method_symbol, key, true)
|
934
929
|
unless @waiting_proc
|
935
930
|
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
936
931
|
@byte_pointer = old_byte_pointer
|
937
|
-
|
938
|
-
wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
|
932
|
+
__send__(@vi_waiting_operator, byte_pointer_diff)
|
939
933
|
cleanup_waiting
|
940
934
|
end
|
941
935
|
else
|
942
936
|
# Ignores operator when not motion is given.
|
943
|
-
|
937
|
+
wrap_method_call(method_symbol, key, false)
|
944
938
|
cleanup_waiting
|
945
939
|
end
|
946
|
-
@vi_arg = nil
|
947
940
|
else
|
948
|
-
|
941
|
+
wrap_method_call(method_symbol, key, false)
|
949
942
|
end
|
943
|
+
@vi_arg = nil
|
944
|
+
@kill_ring.process
|
950
945
|
end
|
951
946
|
|
952
947
|
private def argumentable?(method_obj)
|
@@ -959,20 +954,23 @@ class Reline::LineEditor
|
|
959
954
|
method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :inclusive }
|
960
955
|
end
|
961
956
|
|
962
|
-
def wrap_method_call(method_symbol,
|
963
|
-
if @
|
964
|
-
|
965
|
-
|
957
|
+
def wrap_method_call(method_symbol, key, with_operator)
|
958
|
+
if @waiting_proc
|
959
|
+
@waiting_proc.call(key)
|
960
|
+
return
|
966
961
|
end
|
962
|
+
|
963
|
+
return unless respond_to?(method_symbol, true)
|
964
|
+
method_obj = method(method_symbol)
|
967
965
|
if @vi_arg and argumentable?(method_obj)
|
968
|
-
if
|
969
|
-
method_obj.(key, arg: @vi_arg, inclusive:
|
966
|
+
if inclusive?(method_obj)
|
967
|
+
method_obj.(key, arg: @vi_arg, inclusive: with_operator)
|
970
968
|
else
|
971
969
|
method_obj.(key, arg: @vi_arg)
|
972
970
|
end
|
973
971
|
else
|
974
|
-
if
|
975
|
-
method_obj.(key, inclusive:
|
972
|
+
if inclusive?(method_obj)
|
973
|
+
method_obj.(key, inclusive: with_operator)
|
976
974
|
else
|
977
975
|
method_obj.(key)
|
978
976
|
end
|
@@ -987,90 +985,20 @@ class Reline::LineEditor
|
|
987
985
|
@drop_terminate_spaces = false
|
988
986
|
end
|
989
987
|
|
990
|
-
|
991
|
-
|
992
|
-
cleanup_waiting
|
993
|
-
elsif @waiting_proc
|
994
|
-
old_byte_pointer = @byte_pointer
|
995
|
-
@waiting_proc.call(key)
|
996
|
-
if @vi_waiting_operator
|
997
|
-
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
998
|
-
@byte_pointer = old_byte_pointer
|
999
|
-
method_obj = method(@vi_waiting_operator)
|
1000
|
-
wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
|
1001
|
-
cleanup_waiting
|
1002
|
-
end
|
1003
|
-
@kill_ring.process
|
1004
|
-
return
|
1005
|
-
end
|
988
|
+
ARGUMENT_DIGIT_METHODS = %i[ed_digit vi_zero ed_argument_digit]
|
989
|
+
VI_WAITING_ACCEPT_METHODS = %i[vi_change_meta vi_delete_meta vi_yank ed_insert ed_argument_digit]
|
1006
990
|
|
1007
|
-
|
1008
|
-
|
991
|
+
private def process_key(key, method_symbol)
|
992
|
+
if @waiting_proc
|
993
|
+
cleanup_waiting unless key.size == 1
|
1009
994
|
end
|
1010
|
-
if
|
1011
|
-
|
1012
|
-
run_for_operators(key, method_symbol) do |with_operator|
|
1013
|
-
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
1014
|
-
end
|
1015
|
-
else
|
1016
|
-
wrap_method_call(method_symbol, method_obj, key) if method_obj
|
1017
|
-
end
|
1018
|
-
@kill_ring.process
|
1019
|
-
if @vi_arg
|
1020
|
-
@vi_arg = nil
|
1021
|
-
end
|
1022
|
-
elsif @vi_arg
|
1023
|
-
if key.chr =~ /[0-9]/
|
1024
|
-
ed_argument_digit(key)
|
1025
|
-
else
|
1026
|
-
if argumentable?(method_obj)
|
1027
|
-
run_for_operators(key, method_symbol) do |with_operator|
|
1028
|
-
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
1029
|
-
end
|
1030
|
-
elsif method_obj
|
1031
|
-
wrap_method_call(method_symbol, method_obj, key)
|
1032
|
-
else
|
1033
|
-
ed_insert(key) unless @config.editing_mode_is?(:vi_command)
|
1034
|
-
end
|
1035
|
-
@kill_ring.process
|
1036
|
-
if @vi_arg
|
1037
|
-
@vi_arg = nil
|
1038
|
-
end
|
1039
|
-
end
|
1040
|
-
elsif method_obj
|
1041
|
-
if method_symbol == :ed_argument_digit
|
1042
|
-
wrap_method_call(method_symbol, method_obj, key)
|
1043
|
-
else
|
1044
|
-
run_for_operators(key, method_symbol) do |with_operator|
|
1045
|
-
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
1046
|
-
end
|
1047
|
-
end
|
1048
|
-
@kill_ring.process
|
1049
|
-
else
|
1050
|
-
ed_insert(key) unless @config.editing_mode_is?(:vi_command)
|
995
|
+
if @vi_waiting_operator
|
996
|
+
cleanup_waiting unless VI_WAITING_ACCEPT_METHODS.include?(method_symbol) || VI_MOTIONS.include?(method_symbol)
|
1051
997
|
end
|
1052
|
-
end
|
1053
998
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
|
1058
|
-
process_key(@multibyte_buffer.dup.force_encoding(@encoding), nil)
|
1059
|
-
@multibyte_buffer.clear
|
1060
|
-
else
|
1061
|
-
# invalid
|
1062
|
-
return
|
1063
|
-
end
|
1064
|
-
else # single byte
|
1065
|
-
return if key.char >= 128 # maybe, first byte of multi byte
|
1066
|
-
method_symbol = @config.editing_mode.get_method(key.combined_char)
|
1067
|
-
process_key(key.combined_char, method_symbol)
|
1068
|
-
@multibyte_buffer.clear
|
1069
|
-
end
|
1070
|
-
if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
|
1071
|
-
byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
|
1072
|
-
@byte_pointer -= byte_size
|
1073
|
-
end
|
999
|
+
process_insert(force: method_symbol != :ed_insert)
|
1000
|
+
|
1001
|
+
run_for_operators(key, method_symbol)
|
1074
1002
|
end
|
1075
1003
|
|
1076
1004
|
def update(key)
|
@@ -1084,25 +1012,22 @@ class Reline::LineEditor
|
|
1084
1012
|
end
|
1085
1013
|
|
1086
1014
|
def input_key(key)
|
1087
|
-
|
1015
|
+
old_buffer_of_lines = @buffer_of_lines.dup
|
1088
1016
|
@config.reset_oneshot_key_bindings
|
1089
|
-
@dialogs.each do |dialog|
|
1090
|
-
if key.char.instance_of?(Symbol) and key.char == dialog.name
|
1091
|
-
return
|
1092
|
-
end
|
1093
|
-
end
|
1094
1017
|
if key.char.nil?
|
1095
1018
|
process_insert(force: true)
|
1096
1019
|
@eof = buffer_empty?
|
1097
1020
|
finish
|
1098
1021
|
return
|
1099
1022
|
end
|
1023
|
+
return if @dialogs.any? { |dialog| dialog.name == key.method_symbol }
|
1024
|
+
|
1100
1025
|
@completion_occurs = false
|
1101
1026
|
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1027
|
+
process_key(key.char, key.method_symbol)
|
1028
|
+
if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
|
1029
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
|
1030
|
+
@byte_pointer -= byte_size
|
1106
1031
|
end
|
1107
1032
|
|
1108
1033
|
@prev_action_state, @next_action_state = @next_action_state, NullActionState
|
@@ -1112,15 +1037,16 @@ class Reline::LineEditor
|
|
1112
1037
|
@completion_journey_state = nil
|
1113
1038
|
end
|
1114
1039
|
|
1115
|
-
|
1116
|
-
|
1040
|
+
modified = old_buffer_of_lines != @buffer_of_lines
|
1041
|
+
|
1042
|
+
push_undo_redo(modified) unless @restoring
|
1043
|
+
@restoring = false
|
1117
1044
|
|
1118
1045
|
if @in_pasting
|
1119
1046
|
clear_dialogs
|
1120
1047
|
return
|
1121
1048
|
end
|
1122
1049
|
|
1123
|
-
modified = @old_buffer_of_lines != @buffer_of_lines
|
1124
1050
|
if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
|
1125
1051
|
# Auto complete starts only when edited
|
1126
1052
|
process_insert(force: true)
|
@@ -1129,26 +1055,17 @@ class Reline::LineEditor
|
|
1129
1055
|
modified
|
1130
1056
|
end
|
1131
1057
|
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1058
|
+
MAX_UNDO_REDO_HISTORY_SIZE = 100
|
1059
|
+
def push_undo_redo(modified)
|
1060
|
+
if modified
|
1061
|
+
@undo_redo_history = @undo_redo_history[0..@undo_redo_index]
|
1062
|
+
@undo_redo_history.push([@buffer_of_lines.dup, @byte_pointer, @line_index])
|
1063
|
+
if @undo_redo_history.size > MAX_UNDO_REDO_HISTORY_SIZE
|
1064
|
+
@undo_redo_history.shift
|
1065
|
+
end
|
1066
|
+
@undo_redo_index = @undo_redo_history.size - 1
|
1139
1067
|
else
|
1140
|
-
@
|
1141
|
-
@input_lines_position += 1
|
1142
|
-
@input_lines.push([@buffer_of_lines.dup, @byte_pointer, @line_index])
|
1143
|
-
end
|
1144
|
-
trim_input_lines
|
1145
|
-
end
|
1146
|
-
|
1147
|
-
MAX_INPUT_LINES = 100
|
1148
|
-
def trim_input_lines
|
1149
|
-
if @input_lines.size > MAX_INPUT_LINES
|
1150
|
-
@input_lines.shift
|
1151
|
-
@input_lines_position -= 1
|
1068
|
+
@undo_redo_history[@undo_redo_index] = [@buffer_of_lines.dup, @byte_pointer, @line_index]
|
1152
1069
|
end
|
1153
1070
|
end
|
1154
1071
|
|
@@ -1162,9 +1079,8 @@ class Reline::LineEditor
|
|
1162
1079
|
end
|
1163
1080
|
end
|
1164
1081
|
|
1165
|
-
def call_completion_proc
|
1166
|
-
|
1167
|
-
pre, target, post = result
|
1082
|
+
def call_completion_proc(pre, target, post, quote)
|
1083
|
+
Reline.core.instance_variable_set(:@completion_quote_character, quote)
|
1168
1084
|
result = call_completion_proc_with_checking_args(pre, target, post)
|
1169
1085
|
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
1170
1086
|
result
|
@@ -1228,84 +1144,32 @@ class Reline::LineEditor
|
|
1228
1144
|
process_auto_indent
|
1229
1145
|
end
|
1230
1146
|
|
1231
|
-
def
|
1232
|
-
|
1233
|
-
|
1234
|
-
@line_index = line_index
|
1235
|
-
if byte_pointer
|
1236
|
-
@byte_pointer = byte_pointer
|
1237
|
-
else
|
1238
|
-
calculate_nearest_cursor(cursor)
|
1239
|
-
end
|
1240
|
-
process_auto_indent
|
1241
|
-
end
|
1242
|
-
|
1243
|
-
def retrieve_completion_block(set_completion_quote_character = false)
|
1244
|
-
if Reline.completer_word_break_characters.empty?
|
1245
|
-
word_break_regexp = nil
|
1246
|
-
else
|
1247
|
-
word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
|
1248
|
-
end
|
1249
|
-
if Reline.completer_quote_characters.empty?
|
1250
|
-
quote_characters_regexp = nil
|
1251
|
-
else
|
1252
|
-
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
|
1253
|
-
end
|
1254
|
-
before = current_line.byteslice(0, @byte_pointer)
|
1255
|
-
rest = nil
|
1256
|
-
break_pointer = nil
|
1147
|
+
def retrieve_completion_block
|
1148
|
+
quote_characters = Reline.completer_quote_characters
|
1149
|
+
before = current_line.byteslice(0, @byte_pointer).grapheme_clusters
|
1257
1150
|
quote = nil
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
elsif quote and slice.start_with?(escaped_quote)
|
1272
|
-
# skip
|
1273
|
-
i += 2
|
1274
|
-
elsif quote_characters_regexp and slice =~ quote_characters_regexp # find new "
|
1275
|
-
rest = $'
|
1276
|
-
quote = $&
|
1277
|
-
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
1278
|
-
escaped_quote = /\\#{Regexp.escape(quote)}/
|
1279
|
-
i += 1
|
1280
|
-
break_pointer = i - 1
|
1281
|
-
elsif word_break_regexp and not quote and slice =~ word_break_regexp
|
1282
|
-
rest = $'
|
1283
|
-
i += 1
|
1284
|
-
before = current_line.byteslice(i, @byte_pointer - i)
|
1285
|
-
break_pointer = i
|
1286
|
-
else
|
1287
|
-
i += 1
|
1288
|
-
end
|
1289
|
-
end
|
1290
|
-
postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
|
1291
|
-
if rest
|
1292
|
-
preposing = current_line.byteslice(0, break_pointer)
|
1293
|
-
target = rest
|
1294
|
-
if set_completion_quote_character and quote
|
1295
|
-
Reline.core.instance_variable_set(:@completion_quote_character, quote)
|
1296
|
-
if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote
|
1297
|
-
insert_text(quote)
|
1151
|
+
# Calculate closing quote when cursor is at the end of the line
|
1152
|
+
if current_line.bytesize == @byte_pointer && !quote_characters.empty?
|
1153
|
+
escaped = false
|
1154
|
+
before.each do |c|
|
1155
|
+
if escaped
|
1156
|
+
escaped = false
|
1157
|
+
next
|
1158
|
+
elsif c == '\\'
|
1159
|
+
escaped = true
|
1160
|
+
elsif quote
|
1161
|
+
quote = nil if c == quote
|
1162
|
+
elsif quote_characters.include?(c)
|
1163
|
+
quote = c
|
1298
1164
|
end
|
1299
1165
|
end
|
1300
|
-
else
|
1301
|
-
preposing = ''
|
1302
|
-
if break_pointer
|
1303
|
-
preposing = current_line.byteslice(0, break_pointer)
|
1304
|
-
else
|
1305
|
-
preposing = ''
|
1306
|
-
end
|
1307
|
-
target = before
|
1308
1166
|
end
|
1167
|
+
|
1168
|
+
word_break_characters = quote_characters + Reline.completer_word_break_characters
|
1169
|
+
break_index = before.rindex { |c| word_break_characters.include?(c) || quote_characters.include?(c) } || -1
|
1170
|
+
preposing = before.take(break_index + 1).join
|
1171
|
+
target = before.drop(break_index + 1).join
|
1172
|
+
postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
|
1309
1173
|
lines = whole_lines
|
1310
1174
|
if @line_index > 0
|
1311
1175
|
preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
|
@@ -1313,7 +1177,7 @@ class Reline::LineEditor
|
|
1313
1177
|
if (lines.size - 1) > @line_index
|
1314
1178
|
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1315
1179
|
end
|
1316
|
-
[preposing.encode(
|
1180
|
+
[preposing.encode(encoding), target.encode(encoding), postposing.encode(encoding), quote&.encode(encoding)]
|
1317
1181
|
end
|
1318
1182
|
|
1319
1183
|
def confirm_multiline_termination
|
@@ -1322,15 +1186,13 @@ class Reline::LineEditor
|
|
1322
1186
|
end
|
1323
1187
|
|
1324
1188
|
def insert_multiline_text(text)
|
1325
|
-
save_old_buffer
|
1326
1189
|
pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
|
1327
1190
|
post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
|
1328
|
-
lines = (pre + text.gsub(/\r\n?/, "\n") + post).split("\n", -1)
|
1191
|
+
lines = (pre + Reline::Unicode.safe_encode(text, encoding).gsub(/\r\n?/, "\n") + post).split("\n", -1)
|
1329
1192
|
lines << '' if lines.empty?
|
1330
1193
|
@buffer_of_lines[@line_index, 1] = lines
|
1331
1194
|
@line_index += lines.size - 1
|
1332
1195
|
@byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
|
1333
|
-
push_input_lines
|
1334
1196
|
end
|
1335
1197
|
|
1336
1198
|
def insert_text(text)
|
@@ -1370,7 +1232,7 @@ class Reline::LineEditor
|
|
1370
1232
|
last += current_line.bytesize if last < 0
|
1371
1233
|
first += current_line.bytesize if first < 0
|
1372
1234
|
range = range.exclude_end? ? first...last : first..last
|
1373
|
-
line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(
|
1235
|
+
line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(encoding)
|
1374
1236
|
set_current_line(line)
|
1375
1237
|
else
|
1376
1238
|
set_current_line(current_line.byteslice(0, start))
|
@@ -1444,10 +1306,11 @@ class Reline::LineEditor
|
|
1444
1306
|
@completion_occurs = move_completed_list(:down)
|
1445
1307
|
else
|
1446
1308
|
@completion_journey_state = nil
|
1447
|
-
|
1309
|
+
pre, target, post, quote = retrieve_completion_block
|
1310
|
+
result = call_completion_proc(pre, target, post, quote)
|
1448
1311
|
if result.is_a?(Array)
|
1449
1312
|
@completion_occurs = true
|
1450
|
-
perform_completion(
|
1313
|
+
perform_completion(pre, target, post, quote, result)
|
1451
1314
|
end
|
1452
1315
|
end
|
1453
1316
|
end
|
@@ -1495,21 +1358,11 @@ class Reline::LineEditor
|
|
1495
1358
|
# digit or if the existing argument is already greater than a
|
1496
1359
|
# million.
|
1497
1360
|
# GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
|
1498
|
-
private def ed_insert(
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
return
|
1504
|
-
end
|
1505
|
-
str = key
|
1506
|
-
else
|
1507
|
-
begin
|
1508
|
-
key.chr.encode(Encoding::UTF_8)
|
1509
|
-
rescue Encoding::UndefinedConversionError
|
1510
|
-
return
|
1511
|
-
end
|
1512
|
-
str = key.chr
|
1361
|
+
private def ed_insert(str)
|
1362
|
+
begin
|
1363
|
+
str.encode(Encoding::UTF_8)
|
1364
|
+
rescue Encoding::UndefinedConversionError
|
1365
|
+
return
|
1513
1366
|
end
|
1514
1367
|
if @in_pasting
|
1515
1368
|
@continuous_insertion_buffer << str
|
@@ -1520,24 +1373,26 @@ class Reline::LineEditor
|
|
1520
1373
|
|
1521
1374
|
insert_text(str)
|
1522
1375
|
end
|
1523
|
-
alias_method :ed_digit, :ed_insert
|
1524
1376
|
alias_method :self_insert, :ed_insert
|
1525
1377
|
|
1526
|
-
private def
|
1527
|
-
@
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1378
|
+
private def ed_digit(key)
|
1379
|
+
if @vi_arg
|
1380
|
+
ed_argument_digit(key)
|
1381
|
+
else
|
1382
|
+
ed_insert(key)
|
1383
|
+
end
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
private def insert_raw_char(str, arg: 1)
|
1387
|
+
arg.times do
|
1388
|
+
if str == "\C-j" or str == "\C-m"
|
1389
|
+
key_newline(str)
|
1390
|
+
elsif str != "\0"
|
1391
|
+
# Ignore NUL.
|
1392
|
+
ed_insert(str)
|
1536
1393
|
end
|
1537
|
-
|
1538
|
-
}
|
1394
|
+
end
|
1539
1395
|
end
|
1540
|
-
alias_method :quoted_insert, :ed_quoted_insert
|
1541
1396
|
|
1542
1397
|
private def ed_next_char(key, arg: 1)
|
1543
1398
|
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
@@ -1566,14 +1421,21 @@ class Reline::LineEditor
|
|
1566
1421
|
alias_method :backward_char, :ed_prev_char
|
1567
1422
|
|
1568
1423
|
private def vi_first_print(key)
|
1569
|
-
@byte_pointer
|
1424
|
+
@byte_pointer = Reline::Unicode.vi_first_print(current_line)
|
1570
1425
|
end
|
1571
1426
|
|
1572
1427
|
private def ed_move_to_beg(key)
|
1573
1428
|
@byte_pointer = 0
|
1574
1429
|
end
|
1575
1430
|
alias_method :beginning_of_line, :ed_move_to_beg
|
1576
|
-
|
1431
|
+
|
1432
|
+
private def vi_zero(key)
|
1433
|
+
if @vi_arg
|
1434
|
+
ed_argument_digit(key)
|
1435
|
+
else
|
1436
|
+
ed_move_to_beg(key)
|
1437
|
+
end
|
1438
|
+
end
|
1577
1439
|
|
1578
1440
|
private def ed_move_to_end(key)
|
1579
1441
|
@byte_pointer = current_line.bytesize
|
@@ -1581,27 +1443,22 @@ class Reline::LineEditor
|
|
1581
1443
|
alias_method :end_of_line, :ed_move_to_end
|
1582
1444
|
|
1583
1445
|
private def generate_searcher(search_key)
|
1584
|
-
search_word = String.new(encoding:
|
1585
|
-
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1446
|
+
search_word = String.new(encoding: encoding)
|
1586
1447
|
hit_pointer = nil
|
1587
1448
|
lambda do |key|
|
1588
1449
|
search_again = false
|
1589
1450
|
case key
|
1590
|
-
when "\C-h"
|
1451
|
+
when "\C-h", "\C-?"
|
1591
1452
|
grapheme_clusters = search_word.grapheme_clusters
|
1592
1453
|
if grapheme_clusters.size > 0
|
1593
1454
|
grapheme_clusters.pop
|
1594
1455
|
search_word = grapheme_clusters.join
|
1595
1456
|
end
|
1596
|
-
when "\C-r"
|
1457
|
+
when "\C-r", "\C-s"
|
1597
1458
|
search_again = true if search_key == key
|
1598
1459
|
search_key = key
|
1599
1460
|
else
|
1600
|
-
|
1601
|
-
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1602
|
-
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1603
|
-
multibyte_buf.clear
|
1604
|
-
end
|
1461
|
+
search_word << key
|
1605
1462
|
end
|
1606
1463
|
hit = nil
|
1607
1464
|
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
@@ -1614,10 +1471,10 @@ class Reline::LineEditor
|
|
1614
1471
|
end
|
1615
1472
|
if @history_pointer
|
1616
1473
|
case search_key
|
1617
|
-
when "\C-r"
|
1474
|
+
when "\C-r"
|
1618
1475
|
history_pointer_base = 0
|
1619
1476
|
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1620
|
-
when "\C-s"
|
1477
|
+
when "\C-s"
|
1621
1478
|
history_pointer_base = @history_pointer + 1
|
1622
1479
|
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1623
1480
|
end
|
@@ -1627,10 +1484,10 @@ class Reline::LineEditor
|
|
1627
1484
|
end
|
1628
1485
|
elsif @history_pointer
|
1629
1486
|
case search_key
|
1630
|
-
when "\C-r"
|
1487
|
+
when "\C-r"
|
1631
1488
|
history_pointer_base = 0
|
1632
1489
|
history = Reline::HISTORY[0..@history_pointer]
|
1633
|
-
when "\C-s"
|
1490
|
+
when "\C-s"
|
1634
1491
|
history_pointer_base = @history_pointer
|
1635
1492
|
history = Reline::HISTORY[@history_pointer..-1]
|
1636
1493
|
end
|
@@ -1639,11 +1496,11 @@ class Reline::LineEditor
|
|
1639
1496
|
history = Reline::HISTORY
|
1640
1497
|
end
|
1641
1498
|
case search_key
|
1642
|
-
when "\C-r"
|
1499
|
+
when "\C-r"
|
1643
1500
|
hit_index = history.rindex { |item|
|
1644
1501
|
item.include?(search_word)
|
1645
1502
|
}
|
1646
|
-
when "\C-s"
|
1503
|
+
when "\C-s"
|
1647
1504
|
hit_index = history.index { |item|
|
1648
1505
|
item.include?(search_word)
|
1649
1506
|
}
|
@@ -1654,9 +1511,9 @@ class Reline::LineEditor
|
|
1654
1511
|
end
|
1655
1512
|
end
|
1656
1513
|
case search_key
|
1657
|
-
when "\C-r"
|
1514
|
+
when "\C-r"
|
1658
1515
|
prompt_name = 'reverse-i-search'
|
1659
|
-
when "\C-s"
|
1516
|
+
when "\C-s"
|
1660
1517
|
prompt_name = 'i-search'
|
1661
1518
|
end
|
1662
1519
|
prompt_name = "failed #{prompt_name}" unless hit
|
@@ -1665,57 +1522,28 @@ class Reline::LineEditor
|
|
1665
1522
|
end
|
1666
1523
|
|
1667
1524
|
private def incremental_search_history(key)
|
1668
|
-
|
1669
|
-
@line_backup_in_history = whole_buffer
|
1670
|
-
end
|
1525
|
+
backup = @buffer_of_lines.dup, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history
|
1671
1526
|
searcher = generate_searcher(key)
|
1672
1527
|
@searching_prompt = "(reverse-i-search)`': "
|
1673
|
-
termination_keys = ["\C-j"
|
1674
|
-
termination_keys.concat(@config.isearch_terminators
|
1528
|
+
termination_keys = ["\C-j"]
|
1529
|
+
termination_keys.concat(@config.isearch_terminators.chars) if @config.isearch_terminators
|
1675
1530
|
@waiting_proc = ->(k) {
|
1676
|
-
|
1677
|
-
|
1678
|
-
|
1679
|
-
buffer = Reline::HISTORY[@history_pointer]
|
1680
|
-
else
|
1681
|
-
buffer = @line_backup_in_history
|
1682
|
-
end
|
1683
|
-
@buffer_of_lines = buffer.split("\n")
|
1684
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1685
|
-
@line_index = @buffer_of_lines.size - 1
|
1531
|
+
if k == "\C-g"
|
1532
|
+
# cancel search and restore buffer
|
1533
|
+
@buffer_of_lines, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history = backup
|
1686
1534
|
@searching_prompt = nil
|
1687
1535
|
@waiting_proc = nil
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
@
|
1692
|
-
@
|
1693
|
-
move_history(
|
1536
|
+
elsif !termination_keys.include?(k) && (k.match?(/[[:print:]]/) || k == "\C-h" || k == "\C-?" || k == "\C-r" || k == "\C-s")
|
1537
|
+
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1538
|
+
Reline.last_incremental_search = search_word
|
1539
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1540
|
+
@searching_prompt += ': ' unless @is_multiline
|
1541
|
+
move_history(hit_pointer, line: :end, cursor: :end) if hit_pointer
|
1542
|
+
else
|
1543
|
+
# terminaton_keys and other keys will terminalte
|
1544
|
+
move_history(@history_pointer, line: :end, cursor: :start)
|
1694
1545
|
@searching_prompt = nil
|
1695
1546
|
@waiting_proc = nil
|
1696
|
-
@byte_pointer = 0
|
1697
|
-
else
|
1698
|
-
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1699
|
-
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1700
|
-
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1701
|
-
Reline.last_incremental_search = search_word
|
1702
|
-
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1703
|
-
@searching_prompt += ': ' unless @is_multiline
|
1704
|
-
move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
|
1705
|
-
else
|
1706
|
-
if @history_pointer
|
1707
|
-
line = Reline::HISTORY[@history_pointer]
|
1708
|
-
else
|
1709
|
-
line = @line_backup_in_history
|
1710
|
-
end
|
1711
|
-
@line_backup_in_history = whole_buffer
|
1712
|
-
@buffer_of_lines = line.split("\n")
|
1713
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1714
|
-
@line_index = @buffer_of_lines.size - 1
|
1715
|
-
@searching_prompt = nil
|
1716
|
-
@waiting_proc = nil
|
1717
|
-
@byte_pointer = 0
|
1718
|
-
end
|
1719
1547
|
end
|
1720
1548
|
}
|
1721
1549
|
end
|
@@ -1770,14 +1598,14 @@ class Reline::LineEditor
|
|
1770
1598
|
end
|
1771
1599
|
alias_method :history_search_forward, :ed_search_next_history
|
1772
1600
|
|
1773
|
-
private def move_history(history_pointer, line:, cursor
|
1601
|
+
private def move_history(history_pointer, line:, cursor:)
|
1774
1602
|
history_pointer ||= Reline::HISTORY.size
|
1775
1603
|
return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
|
1776
1604
|
old_history_pointer = @history_pointer || Reline::HISTORY.size
|
1777
1605
|
if old_history_pointer == Reline::HISTORY.size
|
1778
|
-
@line_backup_in_history =
|
1606
|
+
@line_backup_in_history = whole_buffer
|
1779
1607
|
else
|
1780
|
-
Reline::HISTORY[old_history_pointer] = whole_buffer
|
1608
|
+
Reline::HISTORY[old_history_pointer] = whole_buffer
|
1781
1609
|
end
|
1782
1610
|
if history_pointer == Reline::HISTORY.size
|
1783
1611
|
buf = @line_backup_in_history
|
@@ -1787,7 +1615,7 @@ class Reline::LineEditor
|
|
1787
1615
|
@history_pointer = history_pointer
|
1788
1616
|
end
|
1789
1617
|
@buffer_of_lines = buf.split("\n")
|
1790
|
-
@buffer_of_lines = [String.new(encoding:
|
1618
|
+
@buffer_of_lines = [String.new(encoding: encoding)] if @buffer_of_lines.empty?
|
1791
1619
|
@line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
|
1792
1620
|
@byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
|
1793
1621
|
end
|
@@ -1837,17 +1665,10 @@ class Reline::LineEditor
|
|
1837
1665
|
finish
|
1838
1666
|
end
|
1839
1667
|
else
|
1840
|
-
if @line_index ==
|
1841
|
-
if confirm_multiline_termination
|
1842
|
-
finish
|
1843
|
-
else
|
1844
|
-
key_newline(key)
|
1845
|
-
end
|
1846
|
-
else
|
1847
|
-
# should check confirm_multiline_termination to finish?
|
1848
|
-
@line_index = @buffer_of_lines.size - 1
|
1849
|
-
@byte_pointer = current_line.bytesize
|
1668
|
+
if @line_index == @buffer_of_lines.size - 1 && confirm_multiline_termination
|
1850
1669
|
finish
|
1670
|
+
else
|
1671
|
+
key_newline(key)
|
1851
1672
|
end
|
1852
1673
|
end
|
1853
1674
|
else
|
@@ -1855,6 +1676,11 @@ class Reline::LineEditor
|
|
1855
1676
|
end
|
1856
1677
|
end
|
1857
1678
|
|
1679
|
+
private def ed_force_submit(_key)
|
1680
|
+
process_insert(force: true)
|
1681
|
+
finish
|
1682
|
+
end
|
1683
|
+
|
1858
1684
|
private def em_delete_prev_char(key, arg: 1)
|
1859
1685
|
arg.times do
|
1860
1686
|
if @byte_pointer == 0 and @line_index > 0
|
@@ -1921,7 +1747,7 @@ class Reline::LineEditor
|
|
1921
1747
|
alias_method :kill_whole_line, :em_kill_line
|
1922
1748
|
|
1923
1749
|
private def em_delete(key)
|
1924
|
-
if buffer_empty? and key == "\C-d"
|
1750
|
+
if buffer_empty? and key == "\C-d"
|
1925
1751
|
@eof = true
|
1926
1752
|
finish
|
1927
1753
|
elsif @byte_pointer < current_line.bytesize
|
@@ -1939,9 +1765,11 @@ class Reline::LineEditor
|
|
1939
1765
|
if current_line.empty? or @byte_pointer < current_line.bytesize
|
1940
1766
|
em_delete(key)
|
1941
1767
|
elsif !@config.autocompletion # show completed list
|
1942
|
-
|
1768
|
+
pre, target, post, quote = retrieve_completion_block
|
1769
|
+
result = call_completion_proc(pre, target, post, quote)
|
1943
1770
|
if result.is_a?(Array)
|
1944
|
-
|
1771
|
+
candidates = filter_normalize_candidates(target, result)
|
1772
|
+
menu(candidates)
|
1945
1773
|
end
|
1946
1774
|
end
|
1947
1775
|
end
|
@@ -1973,7 +1801,7 @@ class Reline::LineEditor
|
|
1973
1801
|
|
1974
1802
|
private def em_next_word(key)
|
1975
1803
|
if current_line.bytesize > @byte_pointer
|
1976
|
-
byte_size
|
1804
|
+
byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
1977
1805
|
@byte_pointer += byte_size
|
1978
1806
|
end
|
1979
1807
|
end
|
@@ -1981,7 +1809,7 @@ class Reline::LineEditor
|
|
1981
1809
|
|
1982
1810
|
private def ed_prev_word(key)
|
1983
1811
|
if @byte_pointer > 0
|
1984
|
-
byte_size
|
1812
|
+
byte_size = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
|
1985
1813
|
@byte_pointer -= byte_size
|
1986
1814
|
end
|
1987
1815
|
end
|
@@ -1989,7 +1817,7 @@ class Reline::LineEditor
|
|
1989
1817
|
|
1990
1818
|
private def em_delete_next_word(key)
|
1991
1819
|
if current_line.bytesize > @byte_pointer
|
1992
|
-
byte_size
|
1820
|
+
byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
1993
1821
|
line, word = byteslice!(current_line, @byte_pointer, byte_size)
|
1994
1822
|
set_current_line(line)
|
1995
1823
|
@kill_ring.append(word)
|
@@ -1999,7 +1827,7 @@ class Reline::LineEditor
|
|
1999
1827
|
|
2000
1828
|
private def ed_delete_prev_word(key)
|
2001
1829
|
if @byte_pointer > 0
|
2002
|
-
byte_size
|
1830
|
+
byte_size = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
|
2003
1831
|
line, word = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
|
2004
1832
|
set_current_line(line, @byte_pointer - byte_size)
|
2005
1833
|
@kill_ring.append(word, true)
|
@@ -2039,7 +1867,7 @@ class Reline::LineEditor
|
|
2039
1867
|
|
2040
1868
|
private def em_capitol_case(key)
|
2041
1869
|
if current_line.bytesize > @byte_pointer
|
2042
|
-
byte_size,
|
1870
|
+
byte_size, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
|
2043
1871
|
before = current_line.byteslice(0, @byte_pointer)
|
2044
1872
|
after = current_line.byteslice((@byte_pointer + byte_size)..-1)
|
2045
1873
|
set_current_line(before + new_str + after, @byte_pointer + new_str.bytesize)
|
@@ -2049,7 +1877,7 @@ class Reline::LineEditor
|
|
2049
1877
|
|
2050
1878
|
private def em_lower_case(key)
|
2051
1879
|
if current_line.bytesize > @byte_pointer
|
2052
|
-
byte_size
|
1880
|
+
byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2053
1881
|
part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
|
2054
1882
|
mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
|
2055
1883
|
}.join
|
@@ -2062,7 +1890,7 @@ class Reline::LineEditor
|
|
2062
1890
|
|
2063
1891
|
private def em_upper_case(key)
|
2064
1892
|
if current_line.bytesize > @byte_pointer
|
2065
|
-
byte_size
|
1893
|
+
byte_size = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2066
1894
|
part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
|
2067
1895
|
mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
|
2068
1896
|
}.join
|
@@ -2075,7 +1903,7 @@ class Reline::LineEditor
|
|
2075
1903
|
|
2076
1904
|
private def em_kill_region(key)
|
2077
1905
|
if @byte_pointer > 0
|
2078
|
-
byte_size
|
1906
|
+
byte_size = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
|
2079
1907
|
line, deleted = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
|
2080
1908
|
set_current_line(line, @byte_pointer - byte_size)
|
2081
1909
|
@kill_ring.append(deleted, true)
|
@@ -2106,7 +1934,7 @@ class Reline::LineEditor
|
|
2106
1934
|
|
2107
1935
|
private def vi_next_word(key, arg: 1)
|
2108
1936
|
if current_line.bytesize > @byte_pointer
|
2109
|
-
byte_size
|
1937
|
+
byte_size = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
|
2110
1938
|
@byte_pointer += byte_size
|
2111
1939
|
end
|
2112
1940
|
arg -= 1
|
@@ -2115,7 +1943,7 @@ class Reline::LineEditor
|
|
2115
1943
|
|
2116
1944
|
private def vi_prev_word(key, arg: 1)
|
2117
1945
|
if @byte_pointer > 0
|
2118
|
-
byte_size
|
1946
|
+
byte_size = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
|
2119
1947
|
@byte_pointer -= byte_size
|
2120
1948
|
end
|
2121
1949
|
arg -= 1
|
@@ -2124,7 +1952,7 @@ class Reline::LineEditor
|
|
2124
1952
|
|
2125
1953
|
private def vi_end_word(key, arg: 1, inclusive: false)
|
2126
1954
|
if current_line.bytesize > @byte_pointer
|
2127
|
-
byte_size
|
1955
|
+
byte_size = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
|
2128
1956
|
@byte_pointer += byte_size
|
2129
1957
|
end
|
2130
1958
|
arg -= 1
|
@@ -2139,7 +1967,7 @@ class Reline::LineEditor
|
|
2139
1967
|
|
2140
1968
|
private def vi_next_big_word(key, arg: 1)
|
2141
1969
|
if current_line.bytesize > @byte_pointer
|
2142
|
-
byte_size
|
1970
|
+
byte_size = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
|
2143
1971
|
@byte_pointer += byte_size
|
2144
1972
|
end
|
2145
1973
|
arg -= 1
|
@@ -2148,7 +1976,7 @@ class Reline::LineEditor
|
|
2148
1976
|
|
2149
1977
|
private def vi_prev_big_word(key, arg: 1)
|
2150
1978
|
if @byte_pointer > 0
|
2151
|
-
byte_size
|
1979
|
+
byte_size = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
|
2152
1980
|
@byte_pointer -= byte_size
|
2153
1981
|
end
|
2154
1982
|
arg -= 1
|
@@ -2157,7 +1985,7 @@ class Reline::LineEditor
|
|
2157
1985
|
|
2158
1986
|
private def vi_end_big_word(key, arg: 1, inclusive: false)
|
2159
1987
|
if current_line.bytesize > @byte_pointer
|
2160
|
-
byte_size
|
1988
|
+
byte_size = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
|
2161
1989
|
@byte_pointer += byte_size
|
2162
1990
|
end
|
2163
1991
|
arg -= 1
|
@@ -2312,7 +2140,7 @@ class Reline::LineEditor
|
|
2312
2140
|
}
|
2313
2141
|
system("#{ENV['EDITOR']} #{path}")
|
2314
2142
|
@buffer_of_lines = File.read(path).split("\n")
|
2315
|
-
@buffer_of_lines = [String.new(encoding:
|
2143
|
+
@buffer_of_lines = [String.new(encoding: encoding)] if @buffer_of_lines.empty?
|
2316
2144
|
@line_index = 0
|
2317
2145
|
finish
|
2318
2146
|
end
|
@@ -2337,20 +2165,9 @@ class Reline::LineEditor
|
|
2337
2165
|
end
|
2338
2166
|
|
2339
2167
|
private def ed_argument_digit(key)
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2343
|
-
unescaped_key = key ^ 0b10000000
|
2344
|
-
unless unescaped_key.chr.to_i.zero?
|
2345
|
-
@vi_arg = unescaped_key.chr.to_i
|
2346
|
-
end
|
2347
|
-
end
|
2348
|
-
else
|
2349
|
-
@vi_arg = key.chr.to_i
|
2350
|
-
end
|
2351
|
-
else
|
2352
|
-
@vi_arg = @vi_arg * 10 + key.chr.to_i
|
2353
|
-
end
|
2168
|
+
# key is expected to be `ESC digit` or `digit`
|
2169
|
+
num = key[/\d/].to_i
|
2170
|
+
@vi_arg = (@vi_arg || 0) * 10 + num
|
2354
2171
|
end
|
2355
2172
|
|
2356
2173
|
private def vi_to_column(key, arg: 0)
|
@@ -2369,7 +2186,7 @@ class Reline::LineEditor
|
|
2369
2186
|
before = current_line.byteslice(0, @byte_pointer)
|
2370
2187
|
remaining_point = @byte_pointer + byte_size
|
2371
2188
|
after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
|
2372
|
-
set_current_line(before + k
|
2189
|
+
set_current_line(before + k + after)
|
2373
2190
|
@waiting_proc = nil
|
2374
2191
|
elsif arg > 1
|
2375
2192
|
byte_size = 0
|
@@ -2379,7 +2196,7 @@ class Reline::LineEditor
|
|
2379
2196
|
before = current_line.byteslice(0, @byte_pointer)
|
2380
2197
|
remaining_point = @byte_pointer + byte_size
|
2381
2198
|
after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
|
2382
|
-
replaced = k
|
2199
|
+
replaced = k * arg
|
2383
2200
|
set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
|
2384
2201
|
@waiting_proc = nil
|
2385
2202
|
end
|
@@ -2395,11 +2212,6 @@ class Reline::LineEditor
|
|
2395
2212
|
end
|
2396
2213
|
|
2397
2214
|
private def search_next_char(key, arg, need_prev_char: false, inclusive: false)
|
2398
|
-
if key.instance_of?(String)
|
2399
|
-
inputed_char = key
|
2400
|
-
else
|
2401
|
-
inputed_char = key.chr
|
2402
|
-
end
|
2403
2215
|
prev_total = nil
|
2404
2216
|
total = nil
|
2405
2217
|
found = false
|
@@ -2410,7 +2222,7 @@ class Reline::LineEditor
|
|
2410
2222
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2411
2223
|
total = [mbchar.bytesize, width]
|
2412
2224
|
else
|
2413
|
-
if
|
2225
|
+
if key == mbchar
|
2414
2226
|
arg -= 1
|
2415
2227
|
if arg.zero?
|
2416
2228
|
found = true
|
@@ -2447,11 +2259,6 @@ class Reline::LineEditor
|
|
2447
2259
|
end
|
2448
2260
|
|
2449
2261
|
private def search_prev_char(key, arg, need_next_char = false)
|
2450
|
-
if key.instance_of?(String)
|
2451
|
-
inputed_char = key
|
2452
|
-
else
|
2453
|
-
inputed_char = key.chr
|
2454
|
-
end
|
2455
2262
|
prev_total = nil
|
2456
2263
|
total = nil
|
2457
2264
|
found = false
|
@@ -2462,7 +2269,7 @@ class Reline::LineEditor
|
|
2462
2269
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2463
2270
|
total = [mbchar.bytesize, width]
|
2464
2271
|
else
|
2465
|
-
if
|
2272
|
+
if key == mbchar
|
2466
2273
|
arg -= 1
|
2467
2274
|
if arg.zero?
|
2468
2275
|
found = true
|
@@ -2514,24 +2321,23 @@ class Reline::LineEditor
|
|
2514
2321
|
@config.editing_mode = :vi_insert
|
2515
2322
|
end
|
2516
2323
|
|
2517
|
-
private def
|
2518
|
-
@
|
2324
|
+
private def move_undo_redo(direction)
|
2325
|
+
@restoring = true
|
2326
|
+
return unless (0..@undo_redo_history.size - 1).cover?(@undo_redo_index + direction)
|
2519
2327
|
|
2520
|
-
|
2328
|
+
@undo_redo_index += direction
|
2329
|
+
buffer_of_lines, byte_pointer, line_index = @undo_redo_history[@undo_redo_index]
|
2330
|
+
@buffer_of_lines = buffer_of_lines.dup
|
2331
|
+
@line_index = line_index
|
2332
|
+
@byte_pointer = byte_pointer
|
2333
|
+
end
|
2521
2334
|
|
2522
|
-
|
2523
|
-
|
2524
|
-
set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
|
2335
|
+
private def undo(_key)
|
2336
|
+
move_undo_redo(-1)
|
2525
2337
|
end
|
2526
2338
|
|
2527
2339
|
private def redo(_key)
|
2528
|
-
|
2529
|
-
|
2530
|
-
return if @input_lines_position >= @input_lines.size - 1
|
2531
|
-
|
2532
|
-
@input_lines_position += 1
|
2533
|
-
target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
|
2534
|
-
set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
|
2340
|
+
move_undo_redo(+1)
|
2535
2341
|
end
|
2536
2342
|
|
2537
2343
|
private def prev_action_state_value(type)
|