reline 0.5.1 → 0.5.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/lib/reline/ansi.rb +1 -1
- data/lib/reline/config.rb +19 -19
- data/lib/reline/key_actor/emacs.rb +11 -11
- data/lib/reline/key_actor/vi_command.rb +23 -23
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/line_editor.rb +313 -467
- data/lib/reline/unicode.rb +60 -8
- data/lib/reline/version.rb +1 -1
- metadata +2 -2
data/lib/reline/line_editor.rb
CHANGED
@@ -33,8 +33,6 @@ class Reline::LineEditor
|
|
33
33
|
vi_next_big_word
|
34
34
|
vi_prev_big_word
|
35
35
|
vi_end_big_word
|
36
|
-
vi_repeat_next_char
|
37
|
-
vi_repeat_prev_char
|
38
36
|
}
|
39
37
|
|
40
38
|
module CompletionState
|
@@ -114,7 +112,11 @@ class Reline::LineEditor
|
|
114
112
|
else
|
115
113
|
prompt = @prompt
|
116
114
|
end
|
117
|
-
if
|
115
|
+
if !@is_multiline
|
116
|
+
mode_string = check_mode_string
|
117
|
+
prompt = mode_string + prompt if mode_string
|
118
|
+
[prompt] + [''] * (buffer.size - 1)
|
119
|
+
elsif @prompt_proc
|
118
120
|
prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
|
119
121
|
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
120
122
|
prompt_list = [prompt] if prompt_list.empty?
|
@@ -229,10 +231,11 @@ class Reline::LineEditor
|
|
229
231
|
@vi_clipboard = ''
|
230
232
|
@vi_arg = nil
|
231
233
|
@waiting_proc = nil
|
232
|
-
@
|
233
|
-
@
|
234
|
+
@vi_waiting_operator = nil
|
235
|
+
@vi_waiting_operator_arg = nil
|
234
236
|
@completion_journey_state = nil
|
235
237
|
@completion_state = CompletionState::NORMAL
|
238
|
+
@completion_occurs = false
|
236
239
|
@perfect_matched = nil
|
237
240
|
@menu_info = nil
|
238
241
|
@searching_prompt = nil
|
@@ -292,8 +295,8 @@ class Reline::LineEditor
|
|
292
295
|
end
|
293
296
|
end
|
294
297
|
|
295
|
-
private def split_by_width(str, max_width)
|
296
|
-
Reline::Unicode.split_by_width(str, max_width, @encoding)
|
298
|
+
private def split_by_width(str, max_width, offset: 0)
|
299
|
+
Reline::Unicode.split_by_width(str, max_width, @encoding, offset: offset)
|
297
300
|
end
|
298
301
|
|
299
302
|
def current_byte_pointer_cursor
|
@@ -367,7 +370,7 @@ class Reline::LineEditor
|
|
367
370
|
@scroll_partial_screen
|
368
371
|
end
|
369
372
|
|
370
|
-
def
|
373
|
+
def wrapped_prompt_and_input_lines
|
371
374
|
with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
|
372
375
|
prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
|
373
376
|
cached_wraps = {}
|
@@ -378,9 +381,14 @@ class Reline::LineEditor
|
|
378
381
|
end
|
379
382
|
|
380
383
|
n.times.map do |i|
|
381
|
-
prompt = prompts[i]
|
382
|
-
line = lines[i]
|
383
|
-
cached_wraps[[prompt, line]]
|
384
|
+
prompt = prompts[i] || ''
|
385
|
+
line = lines[i] || ''
|
386
|
+
if (cached = cached_wraps[[prompt, line]])
|
387
|
+
next cached
|
388
|
+
end
|
389
|
+
*wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
|
390
|
+
wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt)).first.compact
|
391
|
+
wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
|
384
392
|
end
|
385
393
|
end
|
386
394
|
end
|
@@ -406,8 +414,13 @@ class Reline::LineEditor
|
|
406
414
|
@output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
|
407
415
|
else
|
408
416
|
x, w, content = new_items[level]
|
409
|
-
|
410
|
-
|
417
|
+
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
|
418
|
+
cover_end = new_levels[base_x + width] == level
|
419
|
+
pos = 0
|
420
|
+
unless x == base_x && w == width
|
421
|
+
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
422
|
+
end
|
423
|
+
Reline::IOGate.move_cursor_column x + pos
|
411
424
|
@output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
|
412
425
|
end
|
413
426
|
base_x += width
|
@@ -423,7 +436,7 @@ class Reline::LineEditor
|
|
423
436
|
prompt_width = calculate_width(prompt_list[@line_index], true)
|
424
437
|
line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
|
425
438
|
wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
|
426
|
-
wrapped_cursor_y =
|
439
|
+
wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
|
427
440
|
wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
|
428
441
|
[wrapped_cursor_x, wrapped_cursor_y]
|
429
442
|
end
|
@@ -487,8 +500,9 @@ class Reline::LineEditor
|
|
487
500
|
wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
|
488
501
|
|
489
502
|
rendered_lines = @rendered_screen.lines
|
490
|
-
new_lines =
|
491
|
-
|
503
|
+
new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
|
504
|
+
prompt_width = Reline::Unicode.calculate_width(prompt, true)
|
505
|
+
[[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
|
492
506
|
end
|
493
507
|
if @menu_info
|
494
508
|
@menu_info.lines(screen_width).each do |item|
|
@@ -504,7 +518,8 @@ class Reline::LineEditor
|
|
504
518
|
y_range.each do |row|
|
505
519
|
next if row < 0 || row >= screen_height
|
506
520
|
dialog_rows = new_lines[row] ||= []
|
507
|
-
|
521
|
+
# index 0 is for prompt, index 1 is for line, index 2.. is for dialog
|
522
|
+
dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
|
508
523
|
end
|
509
524
|
end
|
510
525
|
|
@@ -541,10 +556,6 @@ class Reline::LineEditor
|
|
541
556
|
new_lines.size - y
|
542
557
|
end
|
543
558
|
|
544
|
-
def current_row
|
545
|
-
wrapped_lines.flatten[wrapped_cursor_y]
|
546
|
-
end
|
547
|
-
|
548
559
|
def upper_space_height(wrapped_cursor_y)
|
549
560
|
wrapped_cursor_y - screen_scroll_top
|
550
561
|
end
|
@@ -693,13 +704,6 @@ class Reline::LineEditor
|
|
693
704
|
|
694
705
|
DIALOG_DEFAULT_HEIGHT = 20
|
695
706
|
|
696
|
-
private def padding_space_with_escape_sequences(str, width)
|
697
|
-
padding_width = width - calculate_width(str, true)
|
698
|
-
# padding_width should be only positive value. But macOS and Alacritty returns negative value.
|
699
|
-
padding_width = 0 if padding_width < 0
|
700
|
-
str + (' ' * padding_width)
|
701
|
-
end
|
702
|
-
|
703
707
|
private def dialog_range(dialog, dialog_y)
|
704
708
|
x_range = dialog.column...dialog.column + dialog.width
|
705
709
|
y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
|
@@ -772,7 +776,7 @@ class Reline::LineEditor
|
|
772
776
|
dialog.contents = contents.map.with_index do |item, i|
|
773
777
|
line_sgr = i == pointer ? enhanced_sgr : default_sgr
|
774
778
|
str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
|
775
|
-
str =
|
779
|
+
str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
|
776
780
|
colored_content = "#{line_sgr}#{str}"
|
777
781
|
if scrollbar_pos
|
778
782
|
if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
|
@@ -881,10 +885,12 @@ class Reline::LineEditor
|
|
881
885
|
@completion_state = CompletionState::PERFECT_MATCH
|
882
886
|
else
|
883
887
|
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
888
|
+
complete(list, true) if @config.show_all_if_ambiguous
|
884
889
|
end
|
885
890
|
@perfect_matched = completed
|
886
891
|
else
|
887
892
|
@completion_state = CompletionState::MENU
|
893
|
+
complete(list, true) if @config.show_all_if_ambiguous
|
888
894
|
end
|
889
895
|
if not just_show_list and target < completed
|
890
896
|
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
|
@@ -935,37 +941,23 @@ class Reline::LineEditor
|
|
935
941
|
end
|
936
942
|
|
937
943
|
private def run_for_operators(key, method_symbol, &block)
|
938
|
-
if @
|
944
|
+
if @vi_waiting_operator
|
939
945
|
if VI_MOTIONS.include?(method_symbol)
|
940
946
|
old_byte_pointer = @byte_pointer
|
941
|
-
@vi_arg = @
|
947
|
+
@vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
|
942
948
|
block.(true)
|
943
949
|
unless @waiting_proc
|
944
950
|
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
945
951
|
@byte_pointer = old_byte_pointer
|
946
|
-
@
|
947
|
-
|
948
|
-
old_waiting_proc = @waiting_proc
|
949
|
-
old_waiting_operator_proc = @waiting_operator_proc
|
950
|
-
current_waiting_operator_proc = @waiting_operator_proc
|
951
|
-
@waiting_proc = proc { |k|
|
952
|
-
old_byte_pointer = @byte_pointer
|
953
|
-
old_waiting_proc.(k)
|
954
|
-
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
955
|
-
@byte_pointer = old_byte_pointer
|
956
|
-
current_waiting_operator_proc.(byte_pointer_diff)
|
957
|
-
@waiting_operator_proc = old_waiting_operator_proc
|
958
|
-
}
|
952
|
+
send(@vi_waiting_operator, byte_pointer_diff)
|
953
|
+
cleanup_waiting
|
959
954
|
end
|
960
955
|
else
|
961
956
|
# Ignores operator when not motion is given.
|
962
957
|
block.(false)
|
958
|
+
cleanup_waiting
|
963
959
|
end
|
964
|
-
@
|
965
|
-
@waiting_operator_vi_arg = nil
|
966
|
-
if @vi_arg
|
967
|
-
@vi_arg = nil
|
968
|
-
end
|
960
|
+
@vi_arg = nil
|
969
961
|
else
|
970
962
|
block.(false)
|
971
963
|
end
|
@@ -982,7 +974,7 @@ class Reline::LineEditor
|
|
982
974
|
end
|
983
975
|
|
984
976
|
def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
|
985
|
-
if @config.editing_mode_is?(:emacs, :vi_insert) and @
|
977
|
+
if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
|
986
978
|
not_insertion = method_symbol != :ed_insert
|
987
979
|
process_insert(force: not_insertion)
|
988
980
|
end
|
@@ -1001,11 +993,32 @@ class Reline::LineEditor
|
|
1001
993
|
end
|
1002
994
|
end
|
1003
995
|
|
996
|
+
private def cleanup_waiting
|
997
|
+
@waiting_proc = nil
|
998
|
+
@vi_waiting_operator = nil
|
999
|
+
@vi_waiting_operator_arg = nil
|
1000
|
+
@searching_prompt = nil
|
1001
|
+
@drop_terminate_spaces = false
|
1002
|
+
end
|
1003
|
+
|
1004
1004
|
private def process_key(key, method_symbol)
|
1005
|
+
if key.is_a?(Symbol)
|
1006
|
+
cleanup_waiting
|
1007
|
+
elsif @waiting_proc
|
1008
|
+
old_byte_pointer = @byte_pointer
|
1009
|
+
@waiting_proc.call(key)
|
1010
|
+
if @vi_waiting_operator
|
1011
|
+
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
1012
|
+
@byte_pointer = old_byte_pointer
|
1013
|
+
send(@vi_waiting_operator, byte_pointer_diff)
|
1014
|
+
cleanup_waiting
|
1015
|
+
end
|
1016
|
+
@kill_ring.process
|
1017
|
+
return
|
1018
|
+
end
|
1019
|
+
|
1005
1020
|
if method_symbol and respond_to?(method_symbol, true)
|
1006
1021
|
method_obj = method(method_symbol)
|
1007
|
-
else
|
1008
|
-
method_obj = nil
|
1009
1022
|
end
|
1010
1023
|
if method_symbol and key.is_a?(Symbol)
|
1011
1024
|
if @vi_arg and argumentable?(method_obj)
|
@@ -1027,8 +1040,6 @@ class Reline::LineEditor
|
|
1027
1040
|
run_for_operators(key, method_symbol) do |with_operator|
|
1028
1041
|
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
1029
1042
|
end
|
1030
|
-
elsif @waiting_proc
|
1031
|
-
@waiting_proc.(key)
|
1032
1043
|
elsif method_obj
|
1033
1044
|
wrap_method_call(method_symbol, method_obj, key)
|
1034
1045
|
else
|
@@ -1039,9 +1050,6 @@ class Reline::LineEditor
|
|
1039
1050
|
@vi_arg = nil
|
1040
1051
|
end
|
1041
1052
|
end
|
1042
|
-
elsif @waiting_proc
|
1043
|
-
@waiting_proc.(key)
|
1044
|
-
@kill_ring.process
|
1045
1053
|
elsif method_obj
|
1046
1054
|
if method_symbol == :ed_argument_digit
|
1047
1055
|
wrap_method_call(method_symbol, method_obj, key)
|
@@ -1110,6 +1118,7 @@ class Reline::LineEditor
|
|
1110
1118
|
end
|
1111
1119
|
end
|
1112
1120
|
if key.char.nil?
|
1121
|
+
process_insert(force: true)
|
1113
1122
|
if @first_char
|
1114
1123
|
@eof = true
|
1115
1124
|
end
|
@@ -1118,42 +1127,35 @@ class Reline::LineEditor
|
|
1118
1127
|
end
|
1119
1128
|
old_lines = @buffer_of_lines.dup
|
1120
1129
|
@first_char = false
|
1121
|
-
completion_occurs = false
|
1130
|
+
@completion_occurs = false
|
1122
1131
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
1123
1132
|
if !@config.disable_completion
|
1124
1133
|
process_insert(force: true)
|
1125
1134
|
if @config.autocompletion
|
1126
1135
|
@completion_state = CompletionState::NORMAL
|
1127
|
-
completion_occurs = move_completed_list(:down)
|
1136
|
+
@completion_occurs = move_completed_list(:down)
|
1128
1137
|
else
|
1129
1138
|
@completion_journey_state = nil
|
1130
1139
|
result = call_completion_proc
|
1131
1140
|
if result.is_a?(Array)
|
1132
|
-
completion_occurs = true
|
1141
|
+
@completion_occurs = true
|
1133
1142
|
complete(result, false)
|
1134
1143
|
end
|
1135
1144
|
end
|
1136
1145
|
end
|
1137
|
-
elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
|
1138
|
-
if not @config.disable_completion and @config.autocompletion
|
1139
|
-
process_insert(force: true)
|
1140
|
-
@completion_state = CompletionState::NORMAL
|
1141
|
-
completion_occurs = move_completed_list(:up)
|
1142
|
-
end
|
1143
1146
|
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
1144
1147
|
# In vi mode, move completed list even if autocompletion is off
|
1145
1148
|
if not @config.disable_completion
|
1146
1149
|
process_insert(force: true)
|
1147
1150
|
@completion_state = CompletionState::NORMAL
|
1148
|
-
completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
|
1151
|
+
@completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
|
1149
1152
|
end
|
1150
1153
|
elsif Symbol === key.char and respond_to?(key.char, true)
|
1151
1154
|
process_key(key.char, key.char)
|
1152
1155
|
else
|
1153
1156
|
normal_char(key)
|
1154
1157
|
end
|
1155
|
-
|
1156
|
-
unless completion_occurs
|
1158
|
+
unless @completion_occurs
|
1157
1159
|
@completion_state = CompletionState::NORMAL
|
1158
1160
|
@completion_journey_state = nil
|
1159
1161
|
end
|
@@ -1164,7 +1166,7 @@ class Reline::LineEditor
|
|
1164
1166
|
end
|
1165
1167
|
|
1166
1168
|
modified = old_lines != @buffer_of_lines
|
1167
|
-
if
|
1169
|
+
if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
|
1168
1170
|
# Auto complete starts only when edited
|
1169
1171
|
process_insert(force: true)
|
1170
1172
|
@completion_journey_state = retrieve_completion_journey_state
|
@@ -1230,7 +1232,7 @@ class Reline::LineEditor
|
|
1230
1232
|
end
|
1231
1233
|
|
1232
1234
|
def line()
|
1233
|
-
|
1235
|
+
@buffer_of_lines.join("\n") unless eof?
|
1234
1236
|
end
|
1235
1237
|
|
1236
1238
|
def current_line
|
@@ -1314,14 +1316,12 @@ class Reline::LineEditor
|
|
1314
1316
|
end
|
1315
1317
|
target = before
|
1316
1318
|
end
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1324
|
-
end
|
1319
|
+
lines = whole_lines
|
1320
|
+
if @line_index > 0
|
1321
|
+
preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
|
1322
|
+
end
|
1323
|
+
if (lines.size - 1) > @line_index
|
1324
|
+
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1325
1325
|
end
|
1326
1326
|
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
1327
1327
|
end
|
@@ -1343,20 +1343,16 @@ class Reline::LineEditor
|
|
1343
1343
|
|
1344
1344
|
def delete_text(start = nil, length = nil)
|
1345
1345
|
if start.nil? and length.nil?
|
1346
|
-
if @
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
@byte_pointer = 0
|
1357
|
-
end
|
1358
|
-
else
|
1359
|
-
set_current_line('', 0)
|
1346
|
+
if @buffer_of_lines.size == 1
|
1347
|
+
@buffer_of_lines[@line_index] = ''
|
1348
|
+
@byte_pointer = 0
|
1349
|
+
elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
|
1350
|
+
@buffer_of_lines.pop
|
1351
|
+
@line_index -= 1
|
1352
|
+
@byte_pointer = 0
|
1353
|
+
elsif @line_index < (@buffer_of_lines.size - 1)
|
1354
|
+
@buffer_of_lines.delete_at(@line_index)
|
1355
|
+
@byte_pointer = 0
|
1360
1356
|
end
|
1361
1357
|
elsif not start.nil? and not length.nil?
|
1362
1358
|
if current_line
|
@@ -1433,6 +1429,14 @@ class Reline::LineEditor
|
|
1433
1429
|
end
|
1434
1430
|
end
|
1435
1431
|
|
1432
|
+
private def completion_journey_up(key)
|
1433
|
+
if not @config.disable_completion and @config.autocompletion
|
1434
|
+
@completion_state = CompletionState::NORMAL
|
1435
|
+
@completion_occurs = move_completed_list(:up)
|
1436
|
+
end
|
1437
|
+
end
|
1438
|
+
alias_method :menu_complete_backward, :completion_journey_up
|
1439
|
+
|
1436
1440
|
# Editline:: +ed-unassigned+ This editor command always results in an error.
|
1437
1441
|
# GNU Readline:: There is no corresponding macro.
|
1438
1442
|
private def ed_unassigned(key) end # do nothing
|
@@ -1504,7 +1508,7 @@ class Reline::LineEditor
|
|
1504
1508
|
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1505
1509
|
if (@byte_pointer < current_line.bytesize)
|
1506
1510
|
@byte_pointer += byte_size
|
1507
|
-
elsif @
|
1511
|
+
elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
|
1508
1512
|
@byte_pointer = 0
|
1509
1513
|
@line_index += 1
|
1510
1514
|
end
|
@@ -1517,7 +1521,7 @@ class Reline::LineEditor
|
|
1517
1521
|
if @byte_pointer > 0
|
1518
1522
|
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
1519
1523
|
@byte_pointer -= byte_size
|
1520
|
-
elsif @
|
1524
|
+
elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
|
1521
1525
|
@line_index -= 1
|
1522
1526
|
@byte_pointer = current_line.bytesize
|
1523
1527
|
end
|
@@ -1534,141 +1538,102 @@ class Reline::LineEditor
|
|
1534
1538
|
@byte_pointer = 0
|
1535
1539
|
end
|
1536
1540
|
alias_method :beginning_of_line, :ed_move_to_beg
|
1541
|
+
alias_method :vi_zero, :ed_move_to_beg
|
1537
1542
|
|
1538
1543
|
private def ed_move_to_end(key)
|
1539
|
-
@byte_pointer =
|
1540
|
-
while @byte_pointer < current_line.bytesize
|
1541
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1542
|
-
@byte_pointer += byte_size
|
1543
|
-
end
|
1544
|
+
@byte_pointer = current_line.bytesize
|
1544
1545
|
end
|
1545
1546
|
alias_method :end_of_line, :ed_move_to_end
|
1546
1547
|
|
1547
|
-
private def generate_searcher
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
case
|
1554
|
-
when "\C-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1548
|
+
private def generate_searcher(search_key)
|
1549
|
+
search_word = String.new(encoding: @encoding)
|
1550
|
+
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1551
|
+
hit_pointer = nil
|
1552
|
+
lambda do |key|
|
1553
|
+
search_again = false
|
1554
|
+
case key
|
1555
|
+
when "\C-h".ord, "\C-?".ord
|
1556
|
+
grapheme_clusters = search_word.grapheme_clusters
|
1557
|
+
if grapheme_clusters.size > 0
|
1558
|
+
grapheme_clusters.pop
|
1559
|
+
search_word = grapheme_clusters.join
|
1560
|
+
end
|
1561
|
+
when "\C-r".ord, "\C-s".ord
|
1562
|
+
search_again = true if search_key == key
|
1563
|
+
search_key = key
|
1564
|
+
else
|
1565
|
+
multibyte_buf << key
|
1566
|
+
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1567
|
+
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1568
|
+
multibyte_buf.clear
|
1569
|
+
end
|
1558
1570
|
end
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1567
|
-
grapheme_clusters = search_word.grapheme_clusters
|
1568
|
-
if grapheme_clusters.size > 0
|
1569
|
-
grapheme_clusters.pop
|
1570
|
-
search_word = grapheme_clusters.join
|
1571
|
-
end
|
1572
|
-
when "\C-r".ord, "\C-s".ord
|
1573
|
-
search_again = true if prev_search_key == key
|
1574
|
-
prev_search_key = key
|
1575
|
-
else
|
1576
|
-
multibyte_buf << key
|
1577
|
-
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1578
|
-
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1579
|
-
multibyte_buf.clear
|
1571
|
+
hit = nil
|
1572
|
+
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1573
|
+
hit_pointer = Reline::HISTORY.size
|
1574
|
+
hit = @line_backup_in_history
|
1575
|
+
else
|
1576
|
+
if search_again
|
1577
|
+
if search_word.empty? and Reline.last_incremental_search
|
1578
|
+
search_word = Reline.last_incremental_search
|
1580
1579
|
end
|
1581
|
-
|
1582
|
-
|
1583
|
-
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1584
|
-
@history_pointer = nil
|
1585
|
-
hit = @line_backup_in_history
|
1586
|
-
else
|
1587
|
-
if search_again
|
1588
|
-
if search_word.empty? and Reline.last_incremental_search
|
1589
|
-
search_word = Reline.last_incremental_search
|
1590
|
-
end
|
1591
|
-
if @history_pointer
|
1592
|
-
case prev_search_key
|
1593
|
-
when "\C-r".ord
|
1594
|
-
history_pointer_base = 0
|
1595
|
-
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1596
|
-
when "\C-s".ord
|
1597
|
-
history_pointer_base = @history_pointer + 1
|
1598
|
-
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1599
|
-
end
|
1600
|
-
else
|
1601
|
-
history_pointer_base = 0
|
1602
|
-
history = Reline::HISTORY
|
1603
|
-
end
|
1604
|
-
elsif @history_pointer
|
1605
|
-
case prev_search_key
|
1580
|
+
if @history_pointer
|
1581
|
+
case search_key
|
1606
1582
|
when "\C-r".ord
|
1607
1583
|
history_pointer_base = 0
|
1608
|
-
history = Reline::HISTORY[0
|
1584
|
+
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1609
1585
|
when "\C-s".ord
|
1610
|
-
history_pointer_base = @history_pointer
|
1611
|
-
history = Reline::HISTORY[@history_pointer..-1]
|
1586
|
+
history_pointer_base = @history_pointer + 1
|
1587
|
+
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1612
1588
|
end
|
1613
1589
|
else
|
1614
1590
|
history_pointer_base = 0
|
1615
1591
|
history = Reline::HISTORY
|
1616
1592
|
end
|
1617
|
-
|
1593
|
+
elsif @history_pointer
|
1594
|
+
case search_key
|
1618
1595
|
when "\C-r".ord
|
1619
|
-
|
1620
|
-
|
1621
|
-
}
|
1596
|
+
history_pointer_base = 0
|
1597
|
+
history = Reline::HISTORY[0..@history_pointer]
|
1622
1598
|
when "\C-s".ord
|
1623
|
-
|
1624
|
-
|
1625
|
-
}
|
1626
|
-
end
|
1627
|
-
if hit_index
|
1628
|
-
@history_pointer = history_pointer_base + hit_index
|
1629
|
-
hit = Reline::HISTORY[@history_pointer]
|
1599
|
+
history_pointer_base = @history_pointer
|
1600
|
+
history = Reline::HISTORY[@history_pointer..-1]
|
1630
1601
|
end
|
1602
|
+
else
|
1603
|
+
history_pointer_base = 0
|
1604
|
+
history = Reline::HISTORY
|
1631
1605
|
end
|
1632
|
-
case
|
1606
|
+
case search_key
|
1633
1607
|
when "\C-r".ord
|
1634
|
-
|
1608
|
+
hit_index = history.rindex { |item|
|
1609
|
+
item.include?(search_word)
|
1610
|
+
}
|
1635
1611
|
when "\C-s".ord
|
1636
|
-
|
1612
|
+
hit_index = history.index { |item|
|
1613
|
+
item.include?(search_word)
|
1614
|
+
}
|
1637
1615
|
end
|
1638
|
-
if
|
1639
|
-
|
1640
|
-
|
1641
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1642
|
-
@line_index = @buffer_of_lines.size - 1
|
1643
|
-
@byte_pointer = current_line.bytesize
|
1644
|
-
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1645
|
-
else
|
1646
|
-
@buffer_of_lines = [hit]
|
1647
|
-
@byte_pointer = hit.bytesize
|
1648
|
-
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
1649
|
-
end
|
1650
|
-
last_hit = hit
|
1651
|
-
else
|
1652
|
-
if @is_multiline
|
1653
|
-
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
1654
|
-
else
|
1655
|
-
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
1656
|
-
end
|
1616
|
+
if hit_index
|
1617
|
+
hit_pointer = history_pointer_base + hit_index
|
1618
|
+
hit = Reline::HISTORY[hit_pointer]
|
1657
1619
|
end
|
1658
1620
|
end
|
1621
|
+
case search_key
|
1622
|
+
when "\C-r".ord
|
1623
|
+
prompt_name = 'reverse-i-search'
|
1624
|
+
when "\C-s".ord
|
1625
|
+
prompt_name = 'i-search'
|
1626
|
+
end
|
1627
|
+
prompt_name = "failed #{prompt_name}" unless hit
|
1628
|
+
[search_word, prompt_name, hit_pointer]
|
1659
1629
|
end
|
1660
1630
|
end
|
1661
1631
|
|
1662
1632
|
private def incremental_search_history(key)
|
1663
1633
|
unless @history_pointer
|
1664
|
-
|
1665
|
-
@line_backup_in_history = whole_buffer
|
1666
|
-
else
|
1667
|
-
@line_backup_in_history = current_line
|
1668
|
-
end
|
1634
|
+
@line_backup_in_history = whole_buffer
|
1669
1635
|
end
|
1670
|
-
searcher = generate_searcher
|
1671
|
-
searcher.resume(key)
|
1636
|
+
searcher = generate_searcher(key)
|
1672
1637
|
@searching_prompt = "(reverse-i-search)`': "
|
1673
1638
|
termination_keys = ["\C-j".ord]
|
1674
1639
|
termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
|
@@ -1680,53 +1645,41 @@ class Reline::LineEditor
|
|
1680
1645
|
else
|
1681
1646
|
buffer = @line_backup_in_history
|
1682
1647
|
end
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
@line_index = @buffer_of_lines.size - 1
|
1687
|
-
else
|
1688
|
-
@buffer_of_lines = [buffer]
|
1689
|
-
end
|
1648
|
+
@buffer_of_lines = buffer.split("\n")
|
1649
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1650
|
+
@line_index = @buffer_of_lines.size - 1
|
1690
1651
|
@searching_prompt = nil
|
1691
1652
|
@waiting_proc = nil
|
1692
1653
|
@byte_pointer = 0
|
1693
|
-
searcher.resume(-1)
|
1694
1654
|
when "\C-g".ord
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
else
|
1700
|
-
@buffer_of_lines = [@line_backup_in_history]
|
1701
|
-
end
|
1702
|
-
@history_pointer = nil
|
1655
|
+
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1656
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1657
|
+
@line_index = @buffer_of_lines.size - 1
|
1658
|
+
move_history(nil, line: :end, cursor: :end, save_buffer: false)
|
1703
1659
|
@searching_prompt = nil
|
1704
1660
|
@waiting_proc = nil
|
1705
|
-
@line_backup_in_history = nil
|
1706
1661
|
@byte_pointer = 0
|
1707
1662
|
else
|
1708
1663
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1709
1664
|
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1710
|
-
searcher.
|
1665
|
+
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1666
|
+
Reline.last_incremental_search = search_word
|
1667
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1668
|
+
@searching_prompt += ': ' unless @is_multiline
|
1669
|
+
move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
|
1711
1670
|
else
|
1712
1671
|
if @history_pointer
|
1713
1672
|
line = Reline::HISTORY[@history_pointer]
|
1714
1673
|
else
|
1715
1674
|
line = @line_backup_in_history
|
1716
1675
|
end
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
@line_index = @buffer_of_lines.size - 1
|
1722
|
-
else
|
1723
|
-
@line_backup_in_history = current_line
|
1724
|
-
@buffer_of_lines = [line]
|
1725
|
-
end
|
1676
|
+
@line_backup_in_history = whole_buffer
|
1677
|
+
@buffer_of_lines = line.split("\n")
|
1678
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1679
|
+
@line_index = @buffer_of_lines.size - 1
|
1726
1680
|
@searching_prompt = nil
|
1727
1681
|
@waiting_proc = nil
|
1728
1682
|
@byte_pointer = 0
|
1729
|
-
searcher.resume(-1)
|
1730
1683
|
end
|
1731
1684
|
end
|
1732
1685
|
}
|
@@ -1742,191 +1695,95 @@ class Reline::LineEditor
|
|
1742
1695
|
end
|
1743
1696
|
alias_method :forward_search_history, :vi_search_next
|
1744
1697
|
|
1745
|
-
private def
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
return if not current_line.empty? and substr.empty?
|
1752
|
-
history = Reline::HISTORY
|
1753
|
-
elsif @history_pointer.zero?
|
1754
|
-
history = nil
|
1755
|
-
h_pointer = nil
|
1756
|
-
else
|
1757
|
-
history = Reline::HISTORY.slice(0, @history_pointer)
|
1758
|
-
end
|
1759
|
-
return if history.nil?
|
1760
|
-
if @is_multiline
|
1761
|
-
h_pointer = history.rindex { |h|
|
1762
|
-
h.split("\n").each_with_index { |l, i|
|
1763
|
-
if l.start_with?(substr)
|
1764
|
-
line_no = i
|
1765
|
-
break
|
1766
|
-
end
|
1767
|
-
}
|
1768
|
-
not line_no.nil?
|
1769
|
-
}
|
1770
|
-
else
|
1771
|
-
h_pointer = history.rindex { |l|
|
1772
|
-
l.start_with?(substr)
|
1773
|
-
}
|
1774
|
-
end
|
1775
|
-
return if h_pointer.nil?
|
1776
|
-
@history_pointer = h_pointer
|
1777
|
-
cursor = current_byte_pointer_cursor
|
1778
|
-
if @is_multiline
|
1779
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1780
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1781
|
-
@line_index = line_no
|
1782
|
-
calculate_nearest_cursor(cursor)
|
1783
|
-
else
|
1784
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1785
|
-
calculate_nearest_cursor(cursor)
|
1698
|
+
private def search_history(prefix, pointer_range)
|
1699
|
+
pointer_range.each do |pointer|
|
1700
|
+
lines = Reline::HISTORY[pointer].split("\n")
|
1701
|
+
lines.each_with_index do |line, index|
|
1702
|
+
return [pointer, index] if line.start_with?(prefix)
|
1703
|
+
end
|
1786
1704
|
end
|
1705
|
+
nil
|
1706
|
+
end
|
1707
|
+
|
1708
|
+
private def ed_search_prev_history(key, arg: 1)
|
1709
|
+
substr = current_line.byteslice(0, @byte_pointer)
|
1710
|
+
return if @history_pointer == 0
|
1711
|
+
return if @history_pointer.nil? && substr.empty? && !current_line.empty?
|
1712
|
+
|
1713
|
+
history_range = 0...(@history_pointer || Reline::HISTORY.size)
|
1714
|
+
h_pointer, line_index = search_history(substr, history_range.reverse_each)
|
1715
|
+
return unless h_pointer
|
1716
|
+
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1787
1717
|
arg -= 1
|
1788
1718
|
ed_search_prev_history(key, arg: arg) if arg > 0
|
1789
1719
|
end
|
1790
1720
|
alias_method :history_search_backward, :ed_search_prev_history
|
1791
1721
|
|
1792
1722
|
private def ed_search_next_history(key, arg: 1)
|
1793
|
-
substr = current_line.
|
1794
|
-
if @history_pointer.nil?
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
end
|
1799
|
-
history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
|
1800
|
-
h_pointer = nil
|
1801
|
-
line_no = nil
|
1802
|
-
if @is_multiline
|
1803
|
-
h_pointer = history.index { |h|
|
1804
|
-
h.split("\n").each_with_index { |l, i|
|
1805
|
-
if l.start_with?(substr)
|
1806
|
-
line_no = i
|
1807
|
-
break
|
1808
|
-
end
|
1809
|
-
}
|
1810
|
-
not line_no.nil?
|
1811
|
-
}
|
1812
|
-
else
|
1813
|
-
h_pointer = history.index { |l|
|
1814
|
-
l.start_with?(substr)
|
1815
|
-
}
|
1816
|
-
end
|
1817
|
-
h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
|
1723
|
+
substr = current_line.byteslice(0, @byte_pointer)
|
1724
|
+
return if @history_pointer.nil?
|
1725
|
+
|
1726
|
+
history_range = @history_pointer + 1...Reline::HISTORY.size
|
1727
|
+
h_pointer, line_index = search_history(substr, history_range)
|
1818
1728
|
return if h_pointer.nil? and not substr.empty?
|
1819
|
-
|
1820
|
-
|
1821
|
-
if @history_pointer.nil? and substr.empty?
|
1822
|
-
@buffer_of_lines = []
|
1823
|
-
@line_index = 0
|
1824
|
-
@byte_pointer = 0
|
1825
|
-
else
|
1826
|
-
cursor = current_byte_pointer_cursor
|
1827
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1828
|
-
@line_index = line_no
|
1829
|
-
calculate_nearest_cursor(cursor)
|
1830
|
-
end
|
1831
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1832
|
-
else
|
1833
|
-
if @history_pointer.nil? and substr.empty?
|
1834
|
-
set_current_line('', 0)
|
1835
|
-
else
|
1836
|
-
set_current_line(Reline::HISTORY[@history_pointer])
|
1837
|
-
end
|
1838
|
-
end
|
1729
|
+
|
1730
|
+
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1839
1731
|
arg -= 1
|
1840
1732
|
ed_search_next_history(key, arg: arg) if arg > 0
|
1841
1733
|
end
|
1842
1734
|
alias_method :history_search_forward, :ed_search_next_history
|
1843
1735
|
|
1736
|
+
private def move_history(history_pointer, line:, cursor:, save_buffer: true)
|
1737
|
+
history_pointer ||= Reline::HISTORY.size
|
1738
|
+
return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
|
1739
|
+
old_history_pointer = @history_pointer || Reline::HISTORY.size
|
1740
|
+
if old_history_pointer == Reline::HISTORY.size
|
1741
|
+
@line_backup_in_history = save_buffer ? whole_buffer : ''
|
1742
|
+
else
|
1743
|
+
Reline::HISTORY[old_history_pointer] = whole_buffer if save_buffer
|
1744
|
+
end
|
1745
|
+
if history_pointer == Reline::HISTORY.size
|
1746
|
+
buf = @line_backup_in_history
|
1747
|
+
@history_pointer = @line_backup_in_history = nil
|
1748
|
+
else
|
1749
|
+
buf = Reline::HISTORY[history_pointer]
|
1750
|
+
@history_pointer = history_pointer
|
1751
|
+
end
|
1752
|
+
@buffer_of_lines = buf.split("\n")
|
1753
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1754
|
+
@line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
|
1755
|
+
@byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
|
1756
|
+
end
|
1757
|
+
|
1844
1758
|
private def ed_prev_history(key, arg: 1)
|
1845
|
-
if @
|
1759
|
+
if @line_index > 0
|
1846
1760
|
cursor = current_byte_pointer_cursor
|
1847
1761
|
@line_index -= 1
|
1848
1762
|
calculate_nearest_cursor(cursor)
|
1849
1763
|
return
|
1850
1764
|
end
|
1851
|
-
|
1852
|
-
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1856
|
-
cursor = current_byte_pointer_cursor
|
1857
|
-
if @is_multiline
|
1858
|
-
@line_backup_in_history = whole_buffer
|
1859
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1860
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1861
|
-
@line_index = @buffer_of_lines.size - 1
|
1862
|
-
calculate_nearest_cursor(cursor)
|
1863
|
-
else
|
1864
|
-
@line_backup_in_history = whole_buffer
|
1865
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1866
|
-
calculate_nearest_cursor(cursor)
|
1867
|
-
end
|
1868
|
-
elsif @history_pointer.zero?
|
1869
|
-
return
|
1870
|
-
else
|
1871
|
-
if @is_multiline
|
1872
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1873
|
-
@history_pointer -= 1
|
1874
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1875
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1876
|
-
@line_index = @buffer_of_lines.size - 1
|
1877
|
-
else
|
1878
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1879
|
-
@history_pointer -= 1
|
1880
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1881
|
-
end
|
1882
|
-
end
|
1883
|
-
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1884
|
-
@byte_pointer = current_line.bytesize
|
1885
|
-
elsif @config.editing_mode_is?(:vi_command)
|
1886
|
-
@byte_pointer = 0
|
1887
|
-
end
|
1765
|
+
move_history(
|
1766
|
+
(@history_pointer || Reline::HISTORY.size) - 1,
|
1767
|
+
line: :end,
|
1768
|
+
cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
|
1769
|
+
)
|
1888
1770
|
arg -= 1
|
1889
1771
|
ed_prev_history(key, arg: arg) if arg > 0
|
1890
1772
|
end
|
1891
1773
|
alias_method :previous_history, :ed_prev_history
|
1892
1774
|
|
1893
1775
|
private def ed_next_history(key, arg: 1)
|
1894
|
-
if @
|
1776
|
+
if @line_index < (@buffer_of_lines.size - 1)
|
1895
1777
|
cursor = current_byte_pointer_cursor
|
1896
1778
|
@line_index += 1
|
1897
1779
|
calculate_nearest_cursor(cursor)
|
1898
1780
|
return
|
1899
1781
|
end
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1906
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1907
|
-
@line_index = 0
|
1908
|
-
else
|
1909
|
-
@history_pointer = nil
|
1910
|
-
@buffer_of_lines = [@line_backup_in_history]
|
1911
|
-
end
|
1912
|
-
else
|
1913
|
-
if @is_multiline
|
1914
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1915
|
-
@history_pointer += 1
|
1916
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1917
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1918
|
-
@line_index = 0
|
1919
|
-
else
|
1920
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1921
|
-
@history_pointer += 1
|
1922
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1923
|
-
end
|
1924
|
-
end
|
1925
|
-
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1926
|
-
@byte_pointer = current_line.bytesize
|
1927
|
-
elsif @config.editing_mode_is?(:vi_command)
|
1928
|
-
@byte_pointer = 0
|
1929
|
-
end
|
1782
|
+
move_history(
|
1783
|
+
(@history_pointer || Reline::HISTORY.size) + 1,
|
1784
|
+
line: :start,
|
1785
|
+
cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
|
1786
|
+
)
|
1930
1787
|
arg -= 1
|
1931
1788
|
ed_next_history(key, arg: arg) if arg > 0
|
1932
1789
|
end
|
@@ -1957,17 +1814,13 @@ class Reline::LineEditor
|
|
1957
1814
|
end
|
1958
1815
|
end
|
1959
1816
|
else
|
1960
|
-
if @history_pointer
|
1961
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1962
|
-
@history_pointer = nil
|
1963
|
-
end
|
1964
1817
|
finish
|
1965
1818
|
end
|
1966
1819
|
end
|
1967
1820
|
|
1968
1821
|
private def em_delete_prev_char(key, arg: 1)
|
1969
1822
|
arg.times do
|
1970
|
-
if @
|
1823
|
+
if @byte_pointer == 0 and @line_index > 0
|
1971
1824
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
1972
1825
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
1973
1826
|
@line_index -= 1
|
@@ -1991,7 +1844,7 @@ class Reline::LineEditor
|
|
1991
1844
|
line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
|
1992
1845
|
set_current_line(line, line.bytesize)
|
1993
1846
|
@kill_ring.append(deleted)
|
1994
|
-
elsif @
|
1847
|
+
elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1995
1848
|
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
1996
1849
|
end
|
1997
1850
|
end
|
@@ -2031,7 +1884,7 @@ class Reline::LineEditor
|
|
2031
1884
|
alias_method :kill_whole_line, :em_kill_line
|
2032
1885
|
|
2033
1886
|
private def em_delete(key)
|
2034
|
-
if current_line.empty? and
|
1887
|
+
if current_line.empty? and @buffer_of_lines.size == 1 and key == "\C-d".ord
|
2035
1888
|
@eof = true
|
2036
1889
|
finish
|
2037
1890
|
elsif @byte_pointer < current_line.bytesize
|
@@ -2039,7 +1892,7 @@ class Reline::LineEditor
|
|
2039
1892
|
mbchar = splitted_last.grapheme_clusters.first
|
2040
1893
|
line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
|
2041
1894
|
set_current_line(line)
|
2042
|
-
elsif @
|
1895
|
+
elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
2043
1896
|
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
2044
1897
|
end
|
2045
1898
|
end
|
@@ -2282,7 +2135,7 @@ class Reline::LineEditor
|
|
2282
2135
|
end
|
2283
2136
|
|
2284
2137
|
private def vi_delete_prev_char(key)
|
2285
|
-
if @
|
2138
|
+
if @byte_pointer == 0 and @line_index > 0
|
2286
2139
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
2287
2140
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
2288
2141
|
@line_index -= 1
|
@@ -2319,54 +2172,67 @@ class Reline::LineEditor
|
|
2319
2172
|
copy_for_vi(deleted)
|
2320
2173
|
end
|
2321
2174
|
|
2322
|
-
private def
|
2323
|
-
@
|
2175
|
+
private def vi_change_meta(key, arg: nil)
|
2176
|
+
if @vi_waiting_operator
|
2177
|
+
set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
|
2178
|
+
@vi_waiting_operator = nil
|
2179
|
+
@vi_waiting_operator_arg = nil
|
2180
|
+
else
|
2181
|
+
@drop_terminate_spaces = true
|
2182
|
+
@vi_waiting_operator = :vi_change_meta_confirm
|
2183
|
+
@vi_waiting_operator_arg = arg || 1
|
2184
|
+
end
|
2324
2185
|
end
|
2325
2186
|
|
2326
|
-
private def
|
2327
|
-
|
2328
|
-
@
|
2329
|
-
|
2330
|
-
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2331
|
-
elsif byte_pointer_diff < 0
|
2332
|
-
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2333
|
-
end
|
2334
|
-
set_current_line(line)
|
2335
|
-
copy_for_vi(cut)
|
2336
|
-
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
2337
|
-
@config.editing_mode = :vi_insert
|
2338
|
-
@drop_terminate_spaces = false
|
2339
|
-
}
|
2340
|
-
@waiting_operator_vi_arg = arg
|
2187
|
+
private def vi_change_meta_confirm(byte_pointer_diff)
|
2188
|
+
vi_delete_meta_confirm(byte_pointer_diff)
|
2189
|
+
@config.editing_mode = :vi_insert
|
2190
|
+
@drop_terminate_spaces = false
|
2341
2191
|
end
|
2342
2192
|
|
2343
|
-
private def vi_delete_meta(key, arg:
|
2344
|
-
@
|
2345
|
-
if
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
}
|
2353
|
-
@waiting_operator_vi_arg = arg
|
2193
|
+
private def vi_delete_meta(key, arg: nil)
|
2194
|
+
if @vi_waiting_operator
|
2195
|
+
set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
|
2196
|
+
@vi_waiting_operator = nil
|
2197
|
+
@vi_waiting_operator_arg = nil
|
2198
|
+
else
|
2199
|
+
@vi_waiting_operator = :vi_delete_meta_confirm
|
2200
|
+
@vi_waiting_operator_arg = arg || 1
|
2201
|
+
end
|
2354
2202
|
end
|
2355
2203
|
|
2356
|
-
private def
|
2357
|
-
|
2358
|
-
|
2359
|
-
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2204
|
+
private def vi_delete_meta_confirm(byte_pointer_diff)
|
2205
|
+
if byte_pointer_diff > 0
|
2206
|
+
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2207
|
+
elsif byte_pointer_diff < 0
|
2208
|
+
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2209
|
+
end
|
2210
|
+
copy_for_vi(cut)
|
2211
|
+
set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
|
2212
|
+
end
|
2213
|
+
|
2214
|
+
private def vi_yank(key, arg: nil)
|
2215
|
+
if @vi_waiting_operator
|
2216
|
+
copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
|
2217
|
+
@vi_waiting_operator = nil
|
2218
|
+
@vi_waiting_operator_arg = nil
|
2219
|
+
else
|
2220
|
+
@vi_waiting_operator = :vi_yank_confirm
|
2221
|
+
@vi_waiting_operator_arg = arg || 1
|
2222
|
+
end
|
2223
|
+
end
|
2224
|
+
|
2225
|
+
private def vi_yank_confirm(byte_pointer_diff)
|
2226
|
+
if byte_pointer_diff > 0
|
2227
|
+
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
2228
|
+
elsif byte_pointer_diff < 0
|
2229
|
+
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2230
|
+
end
|
2231
|
+
copy_for_vi(cut)
|
2366
2232
|
end
|
2367
2233
|
|
2368
2234
|
private def vi_list_or_eof(key)
|
2369
|
-
if
|
2235
|
+
if current_line.empty? and @buffer_of_lines.size == 1
|
2370
2236
|
set_current_line('', 0)
|
2371
2237
|
@eof = true
|
2372
2238
|
finish
|
@@ -2397,36 +2263,18 @@ class Reline::LineEditor
|
|
2397
2263
|
if Reline::HISTORY.empty?
|
2398
2264
|
return
|
2399
2265
|
end
|
2400
|
-
|
2401
|
-
@history_pointer = 0
|
2402
|
-
@line_backup_in_history = current_line
|
2403
|
-
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
2404
|
-
elsif @history_pointer.zero?
|
2405
|
-
return
|
2406
|
-
else
|
2407
|
-
Reline::HISTORY[@history_pointer] = current_line
|
2408
|
-
@history_pointer = 0
|
2409
|
-
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
2410
|
-
end
|
2266
|
+
move_history(0, line: :start, cursor: :start)
|
2411
2267
|
end
|
2412
2268
|
|
2413
2269
|
private def vi_histedit(key)
|
2414
2270
|
path = Tempfile.open { |fp|
|
2415
|
-
|
2416
|
-
fp.write whole_lines.join("\n")
|
2417
|
-
else
|
2418
|
-
fp.write current_line
|
2419
|
-
end
|
2271
|
+
fp.write whole_lines.join("\n")
|
2420
2272
|
fp.path
|
2421
2273
|
}
|
2422
2274
|
system("#{ENV['EDITOR']} #{path}")
|
2423
|
-
|
2424
|
-
|
2425
|
-
|
2426
|
-
@line_index = 0
|
2427
|
-
else
|
2428
|
-
@buffer_of_lines = File.read(path).split("\n")
|
2429
|
-
end
|
2275
|
+
@buffer_of_lines = File.read(path).split("\n")
|
2276
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2277
|
+
@line_index = 0
|
2430
2278
|
finish
|
2431
2279
|
end
|
2432
2280
|
|
@@ -2467,18 +2315,11 @@ class Reline::LineEditor
|
|
2467
2315
|
end
|
2468
2316
|
|
2469
2317
|
private def vi_to_column(key, arg: 0)
|
2470
|
-
|
2471
|
-
@byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |
|
2472
|
-
# total has [byte_size, cursor]
|
2318
|
+
# Implementing behavior of vi, not Readline's vi-mode.
|
2319
|
+
@byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |(total_byte_size, total_width), gc|
|
2473
2320
|
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
|
2474
|
-
if (
|
2475
|
-
|
2476
|
-
elsif (total.last + mbchar_width) >= current_row_width
|
2477
|
-
break total
|
2478
|
-
else
|
2479
|
-
total = [total.first + gc.bytesize, total.last + mbchar_width]
|
2480
|
-
total
|
2481
|
-
end
|
2321
|
+
break [total_byte_size, total_width] if (total_width + mbchar_width) >= arg
|
2322
|
+
[total_byte_size + gc.bytesize, total_width + mbchar_width]
|
2482
2323
|
}
|
2483
2324
|
end
|
2484
2325
|
|
@@ -2605,7 +2446,7 @@ class Reline::LineEditor
|
|
2605
2446
|
end
|
2606
2447
|
|
2607
2448
|
private def vi_join_lines(key, arg: 1)
|
2608
|
-
if @
|
2449
|
+
if @buffer_of_lines.size > @line_index + 1
|
2609
2450
|
next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
|
2610
2451
|
set_current_line(current_line + ' ' + next_line, current_line.bytesize)
|
2611
2452
|
end
|
@@ -2626,6 +2467,11 @@ class Reline::LineEditor
|
|
2626
2467
|
end
|
2627
2468
|
alias_method :exchange_point_and_mark, :em_exchange_mark
|
2628
2469
|
|
2629
|
-
private def
|
2470
|
+
private def emacs_editing_mode(key)
|
2471
|
+
@config.editing_mode = :emacs
|
2472
|
+
end
|
2473
|
+
|
2474
|
+
private def vi_editing_mode(key)
|
2475
|
+
@config.editing_mode = :vi_insert
|
2630
2476
|
end
|
2631
2477
|
end
|