reline 0.5.0 → 0.5.3
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 +12 -6
- data/lib/reline/general_io.rb +1 -0
- 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 +443 -560
- data/lib/reline/terminfo.rb +7 -14
- data/lib/reline/unicode.rb +2 -2
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +1 -1
- data/lib/reline.rb +31 -42
- metadata +2 -2
data/lib/reline/line_editor.rb
CHANGED
@@ -33,23 +33,42 @@ 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
|
41
39
|
NORMAL = :normal
|
42
40
|
COMPLETION = :completion
|
43
41
|
MENU = :menu
|
44
|
-
JOURNEY = :journey
|
45
42
|
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
|
46
43
|
PERFECT_MATCH = :perfect_match
|
47
44
|
end
|
48
45
|
|
49
46
|
RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
|
50
47
|
|
51
|
-
|
52
|
-
|
48
|
+
CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
|
49
|
+
|
50
|
+
class MenuInfo
|
51
|
+
attr_reader :list
|
52
|
+
|
53
|
+
def initialize(list)
|
54
|
+
@list = list
|
55
|
+
end
|
56
|
+
|
57
|
+
def lines(screen_width)
|
58
|
+
return [] if @list.empty?
|
59
|
+
|
60
|
+
list = @list.sort
|
61
|
+
sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
|
62
|
+
item_width = sizes.max + 2
|
63
|
+
num_cols = [screen_width / item_width, 1].max
|
64
|
+
num_rows = list.size.fdiv(num_cols).ceil
|
65
|
+
list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
|
66
|
+
aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
|
67
|
+
aligned.map do |row|
|
68
|
+
row.join.rstrip
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
53
72
|
|
54
73
|
MINIMUM_SCROLLBAR_HEIGHT = 1
|
55
74
|
|
@@ -93,7 +112,11 @@ class Reline::LineEditor
|
|
93
112
|
else
|
94
113
|
prompt = @prompt
|
95
114
|
end
|
96
|
-
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
|
97
120
|
prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
|
98
121
|
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
99
122
|
prompt_list = [prompt] if prompt_list.empty?
|
@@ -117,9 +140,6 @@ class Reline::LineEditor
|
|
117
140
|
@screen_size = Reline::IOGate.get_screen_size
|
118
141
|
reset_variables(prompt, encoding: encoding)
|
119
142
|
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
|
120
|
-
Reline::IOGate.set_winch_handler do
|
121
|
-
@resized = true
|
122
|
-
end
|
123
143
|
if ENV.key?('RELINE_ALT_SCROLLBAR')
|
124
144
|
@full_block = '::'
|
125
145
|
@upper_half_block = "''"
|
@@ -143,7 +163,12 @@ class Reline::LineEditor
|
|
143
163
|
end
|
144
164
|
end
|
145
165
|
|
146
|
-
def
|
166
|
+
def handle_signal
|
167
|
+
handle_interrupted
|
168
|
+
handle_resized
|
169
|
+
end
|
170
|
+
|
171
|
+
private def handle_resized
|
147
172
|
return unless @resized
|
148
173
|
|
149
174
|
@screen_size = Reline::IOGate.get_screen_size
|
@@ -156,25 +181,35 @@ class Reline::LineEditor
|
|
156
181
|
render_differential
|
157
182
|
end
|
158
183
|
|
184
|
+
private def handle_interrupted
|
185
|
+
return unless @interrupted
|
186
|
+
|
187
|
+
@interrupted = false
|
188
|
+
clear_dialogs
|
189
|
+
scrolldown = render_differential
|
190
|
+
Reline::IOGate.scroll_down scrolldown
|
191
|
+
Reline::IOGate.move_cursor_column 0
|
192
|
+
@rendered_screen.lines = []
|
193
|
+
@rendered_screen.cursor_y = 0
|
194
|
+
case @old_trap
|
195
|
+
when 'DEFAULT', 'SYSTEM_DEFAULT'
|
196
|
+
raise Interrupt
|
197
|
+
when 'IGNORE'
|
198
|
+
# Do nothing
|
199
|
+
when 'EXIT'
|
200
|
+
exit
|
201
|
+
else
|
202
|
+
@old_trap.call if @old_trap.respond_to?(:call)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
159
206
|
def set_signal_handlers
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
@rendered_screen.cursor_y = 0
|
167
|
-
case @old_trap
|
168
|
-
when 'DEFAULT', 'SYSTEM_DEFAULT'
|
169
|
-
raise Interrupt
|
170
|
-
when 'IGNORE'
|
171
|
-
# Do nothing
|
172
|
-
when 'EXIT'
|
173
|
-
exit
|
174
|
-
else
|
175
|
-
@old_trap.call if @old_trap.respond_to?(:call)
|
176
|
-
end
|
177
|
-
}
|
207
|
+
Reline::IOGate.set_winch_handler do
|
208
|
+
@resized = true
|
209
|
+
end
|
210
|
+
@old_trap = Signal.trap('INT') do
|
211
|
+
@interrupted = true
|
212
|
+
end
|
178
213
|
end
|
179
214
|
|
180
215
|
def finalize
|
@@ -191,16 +226,16 @@ class Reline::LineEditor
|
|
191
226
|
@encoding = encoding
|
192
227
|
@is_multiline = false
|
193
228
|
@finished = false
|
194
|
-
@cleared = false
|
195
229
|
@history_pointer = nil
|
196
230
|
@kill_ring ||= Reline::KillRing.new
|
197
231
|
@vi_clipboard = ''
|
198
232
|
@vi_arg = nil
|
199
233
|
@waiting_proc = nil
|
200
|
-
@
|
201
|
-
@
|
202
|
-
@
|
234
|
+
@vi_waiting_operator = nil
|
235
|
+
@vi_waiting_operator_arg = nil
|
236
|
+
@completion_journey_state = nil
|
203
237
|
@completion_state = CompletionState::NORMAL
|
238
|
+
@completion_occurs = false
|
204
239
|
@perfect_matched = nil
|
205
240
|
@menu_info = nil
|
206
241
|
@searching_prompt = nil
|
@@ -213,6 +248,7 @@ class Reline::LineEditor
|
|
213
248
|
@in_pasting = false
|
214
249
|
@auto_indent_proc = nil
|
215
250
|
@dialogs = []
|
251
|
+
@interrupted = false
|
216
252
|
@resized = false
|
217
253
|
@cache = {}
|
218
254
|
@rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
|
@@ -259,8 +295,8 @@ class Reline::LineEditor
|
|
259
295
|
end
|
260
296
|
end
|
261
297
|
|
262
|
-
private def split_by_width(str, max_width)
|
263
|
-
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)
|
264
300
|
end
|
265
301
|
|
266
302
|
def current_byte_pointer_cursor
|
@@ -334,7 +370,7 @@ class Reline::LineEditor
|
|
334
370
|
@scroll_partial_screen
|
335
371
|
end
|
336
372
|
|
337
|
-
def
|
373
|
+
def wrapped_prompt_and_input_lines
|
338
374
|
with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
|
339
375
|
prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
|
340
376
|
cached_wraps = {}
|
@@ -345,9 +381,14 @@ class Reline::LineEditor
|
|
345
381
|
end
|
346
382
|
|
347
383
|
n.times.map do |i|
|
348
|
-
prompt = prompts[i]
|
349
|
-
line = lines[i]
|
350
|
-
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] }
|
351
392
|
end
|
352
393
|
end
|
353
394
|
end
|
@@ -390,7 +431,7 @@ class Reline::LineEditor
|
|
390
431
|
prompt_width = calculate_width(prompt_list[@line_index], true)
|
391
432
|
line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
|
392
433
|
wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
|
393
|
-
wrapped_cursor_y =
|
434
|
+
wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
|
394
435
|
wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
|
395
436
|
[wrapped_cursor_x, wrapped_cursor_y]
|
396
437
|
end
|
@@ -454,11 +495,12 @@ class Reline::LineEditor
|
|
454
495
|
wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
|
455
496
|
|
456
497
|
rendered_lines = @rendered_screen.lines
|
457
|
-
new_lines =
|
458
|
-
|
498
|
+
new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
|
499
|
+
prompt_width = Reline::Unicode.calculate_width(prompt, true)
|
500
|
+
[[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
|
459
501
|
end
|
460
502
|
if @menu_info
|
461
|
-
@menu_info.
|
503
|
+
@menu_info.lines(screen_width).each do |item|
|
462
504
|
new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
|
463
505
|
end
|
464
506
|
@menu_info = nil # TODO: do not change state here
|
@@ -471,7 +513,8 @@ class Reline::LineEditor
|
|
471
513
|
y_range.each do |row|
|
472
514
|
next if row < 0 || row >= screen_height
|
473
515
|
dialog_rows = new_lines[row] ||= []
|
474
|
-
|
516
|
+
# index 0 is for prompt, index 1 is for line, index 2.. is for dialog
|
517
|
+
dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
|
475
518
|
end
|
476
519
|
end
|
477
520
|
|
@@ -508,10 +551,6 @@ class Reline::LineEditor
|
|
508
551
|
new_lines.size - y
|
509
552
|
end
|
510
553
|
|
511
|
-
def current_row
|
512
|
-
wrapped_lines.flatten[wrapped_cursor_y]
|
513
|
-
end
|
514
|
-
|
515
554
|
def upper_space_height(wrapped_cursor_y)
|
516
555
|
wrapped_cursor_y - screen_scroll_top
|
517
556
|
end
|
@@ -520,23 +559,13 @@ class Reline::LineEditor
|
|
520
559
|
screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
|
521
560
|
end
|
522
561
|
|
523
|
-
def handle_cleared
|
524
|
-
return unless @cleared
|
525
|
-
|
526
|
-
@cleared = false
|
527
|
-
Reline::IOGate.clear_screen
|
528
|
-
@screen_size = Reline::IOGate.get_screen_size
|
529
|
-
@rendered_screen.lines = []
|
530
|
-
@rendered_screen.base_y = 0
|
531
|
-
@rendered_screen.cursor_y = 0
|
532
|
-
end
|
533
|
-
|
534
562
|
def rerender
|
535
|
-
handle_cleared
|
536
563
|
render_differential unless @in_pasting
|
537
564
|
end
|
538
565
|
|
539
566
|
class DialogProcScope
|
567
|
+
CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
|
568
|
+
|
540
569
|
def initialize(line_editor, config, proc_to_exec, context)
|
541
570
|
@line_editor = line_editor
|
542
571
|
@config = config
|
@@ -600,7 +629,7 @@ class Reline::LineEditor
|
|
600
629
|
end
|
601
630
|
|
602
631
|
def completion_journey_data
|
603
|
-
@line_editor.
|
632
|
+
@line_editor.dialog_proc_scope_completion_journey_data
|
604
633
|
end
|
605
634
|
|
606
635
|
def config
|
@@ -771,7 +800,7 @@ class Reline::LineEditor
|
|
771
800
|
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
|
772
801
|
after.lines("\n").map { |l| l.chomp('') }
|
773
802
|
else
|
774
|
-
before
|
803
|
+
before.map { |l| Reline::Unicode.escape_for_print(l) }
|
775
804
|
end
|
776
805
|
end
|
777
806
|
|
@@ -779,8 +808,8 @@ class Reline::LineEditor
|
|
779
808
|
@config.editing_mode
|
780
809
|
end
|
781
810
|
|
782
|
-
private def menu(
|
783
|
-
@menu_info = MenuInfo.new(
|
811
|
+
private def menu(_target, list)
|
812
|
+
@menu_info = MenuInfo.new(list)
|
784
813
|
end
|
785
814
|
|
786
815
|
private def complete_internal_proc(list, is_menu)
|
@@ -829,9 +858,9 @@ class Reline::LineEditor
|
|
829
858
|
[target, preposing, completed, postposing]
|
830
859
|
end
|
831
860
|
|
832
|
-
private def complete(list, just_show_list
|
861
|
+
private def complete(list, just_show_list)
|
833
862
|
case @completion_state
|
834
|
-
when CompletionState::NORMAL
|
863
|
+
when CompletionState::NORMAL
|
835
864
|
@completion_state = CompletionState::COMPLETION
|
836
865
|
when CompletionState::PERFECT_MATCH
|
837
866
|
@dig_perfect_match_proc&.(@perfect_matched)
|
@@ -858,10 +887,12 @@ class Reline::LineEditor
|
|
858
887
|
@completion_state = CompletionState::PERFECT_MATCH
|
859
888
|
else
|
860
889
|
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
890
|
+
complete(list, true) if @config.show_all_if_ambiguous
|
861
891
|
end
|
862
892
|
@perfect_matched = completed
|
863
893
|
else
|
864
894
|
@completion_state = CompletionState::MENU
|
895
|
+
complete(list, true) if @config.show_all_if_ambiguous
|
865
896
|
end
|
866
897
|
if not just_show_list and target < completed
|
867
898
|
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
|
@@ -871,80 +902,64 @@ class Reline::LineEditor
|
|
871
902
|
end
|
872
903
|
end
|
873
904
|
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
@
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
end
|
894
|
-
end
|
895
|
-
@completion_state = CompletionState::JOURNEY
|
896
|
-
else
|
897
|
-
case direction
|
898
|
-
when :up
|
899
|
-
@completion_journey_data.pointer -= 1
|
900
|
-
if @completion_journey_data.pointer < 0
|
901
|
-
@completion_journey_data.pointer = @completion_journey_data.list.size - 1
|
902
|
-
end
|
903
|
-
when :down
|
904
|
-
@completion_journey_data.pointer += 1
|
905
|
-
if @completion_journey_data.pointer >= @completion_journey_data.list.size
|
906
|
-
@completion_journey_data.pointer = 0
|
907
|
-
end
|
908
|
-
end
|
905
|
+
def dialog_proc_scope_completion_journey_data
|
906
|
+
return nil unless @completion_journey_state
|
907
|
+
line_index = @completion_journey_state.line_index
|
908
|
+
pre_lines = @buffer_of_lines[0...line_index].map { |line| line + "\n" }
|
909
|
+
post_lines = @buffer_of_lines[(line_index + 1)..-1].map { |line| line + "\n" }
|
910
|
+
DialogProcScope::CompletionJourneyData.new(
|
911
|
+
pre_lines.join + @completion_journey_state.pre,
|
912
|
+
@completion_journey_state.post + post_lines.join,
|
913
|
+
@completion_journey_state.list,
|
914
|
+
@completion_journey_state.pointer
|
915
|
+
)
|
916
|
+
end
|
917
|
+
|
918
|
+
private def move_completed_list(direction)
|
919
|
+
@completion_journey_state ||= retrieve_completion_journey_state
|
920
|
+
return false unless @completion_journey_state
|
921
|
+
|
922
|
+
if (delta = { up: -1, down: +1 }[direction])
|
923
|
+
@completion_journey_state.pointer = (@completion_journey_state.pointer + delta) % @completion_journey_state.list.size
|
909
924
|
end
|
910
|
-
completed = @
|
911
|
-
|
912
|
-
|
913
|
-
|
925
|
+
completed = @completion_journey_state.list[@completion_journey_state.pointer]
|
926
|
+
set_current_line(@completion_journey_state.pre + completed + @completion_journey_state.post, @completion_journey_state.pre.bytesize + completed.bytesize)
|
927
|
+
true
|
928
|
+
end
|
929
|
+
|
930
|
+
private def retrieve_completion_journey_state
|
931
|
+
preposing, target, postposing = retrieve_completion_block
|
932
|
+
list = call_completion_proc
|
933
|
+
return unless list.is_a?(Array)
|
934
|
+
|
935
|
+
candidates = list.select{ |item| item.start_with?(target) }
|
936
|
+
return if candidates.empty?
|
937
|
+
|
938
|
+
pre = preposing.split("\n", -1).last || ''
|
939
|
+
post = postposing.split("\n", -1).first || ''
|
940
|
+
CompletionJourneyState.new(
|
941
|
+
@line_index, pre, target, post, [target] + candidates, 0
|
942
|
+
)
|
914
943
|
end
|
915
944
|
|
916
945
|
private def run_for_operators(key, method_symbol, &block)
|
917
|
-
if @
|
946
|
+
if @vi_waiting_operator
|
918
947
|
if VI_MOTIONS.include?(method_symbol)
|
919
948
|
old_byte_pointer = @byte_pointer
|
920
|
-
@vi_arg = @
|
949
|
+
@vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
|
921
950
|
block.(true)
|
922
951
|
unless @waiting_proc
|
923
952
|
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
924
953
|
@byte_pointer = old_byte_pointer
|
925
|
-
@
|
926
|
-
|
927
|
-
old_waiting_proc = @waiting_proc
|
928
|
-
old_waiting_operator_proc = @waiting_operator_proc
|
929
|
-
current_waiting_operator_proc = @waiting_operator_proc
|
930
|
-
@waiting_proc = proc { |k|
|
931
|
-
old_byte_pointer = @byte_pointer
|
932
|
-
old_waiting_proc.(k)
|
933
|
-
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
934
|
-
@byte_pointer = old_byte_pointer
|
935
|
-
current_waiting_operator_proc.(byte_pointer_diff)
|
936
|
-
@waiting_operator_proc = old_waiting_operator_proc
|
937
|
-
}
|
954
|
+
send(@vi_waiting_operator, byte_pointer_diff)
|
955
|
+
cleanup_waiting
|
938
956
|
end
|
939
957
|
else
|
940
958
|
# Ignores operator when not motion is given.
|
941
959
|
block.(false)
|
960
|
+
cleanup_waiting
|
942
961
|
end
|
943
|
-
@
|
944
|
-
@waiting_operator_vi_arg = nil
|
945
|
-
if @vi_arg
|
946
|
-
@vi_arg = nil
|
947
|
-
end
|
962
|
+
@vi_arg = nil
|
948
963
|
else
|
949
964
|
block.(false)
|
950
965
|
end
|
@@ -961,7 +976,7 @@ class Reline::LineEditor
|
|
961
976
|
end
|
962
977
|
|
963
978
|
def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
|
964
|
-
if @config.editing_mode_is?(:emacs, :vi_insert) and @
|
979
|
+
if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
|
965
980
|
not_insertion = method_symbol != :ed_insert
|
966
981
|
process_insert(force: not_insertion)
|
967
982
|
end
|
@@ -980,11 +995,32 @@ class Reline::LineEditor
|
|
980
995
|
end
|
981
996
|
end
|
982
997
|
|
998
|
+
private def cleanup_waiting
|
999
|
+
@waiting_proc = nil
|
1000
|
+
@vi_waiting_operator = nil
|
1001
|
+
@vi_waiting_operator_arg = nil
|
1002
|
+
@searching_prompt = nil
|
1003
|
+
@drop_terminate_spaces = false
|
1004
|
+
end
|
1005
|
+
|
983
1006
|
private def process_key(key, method_symbol)
|
1007
|
+
if key.is_a?(Symbol)
|
1008
|
+
cleanup_waiting
|
1009
|
+
elsif @waiting_proc
|
1010
|
+
old_byte_pointer = @byte_pointer
|
1011
|
+
@waiting_proc.call(key)
|
1012
|
+
if @vi_waiting_operator
|
1013
|
+
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
1014
|
+
@byte_pointer = old_byte_pointer
|
1015
|
+
send(@vi_waiting_operator, byte_pointer_diff)
|
1016
|
+
cleanup_waiting
|
1017
|
+
end
|
1018
|
+
@kill_ring.process
|
1019
|
+
return
|
1020
|
+
end
|
1021
|
+
|
984
1022
|
if method_symbol and respond_to?(method_symbol, true)
|
985
1023
|
method_obj = method(method_symbol)
|
986
|
-
else
|
987
|
-
method_obj = nil
|
988
1024
|
end
|
989
1025
|
if method_symbol and key.is_a?(Symbol)
|
990
1026
|
if @vi_arg and argumentable?(method_obj)
|
@@ -1006,8 +1042,6 @@ class Reline::LineEditor
|
|
1006
1042
|
run_for_operators(key, method_symbol) do |with_operator|
|
1007
1043
|
wrap_method_call(method_symbol, method_obj, key, with_operator)
|
1008
1044
|
end
|
1009
|
-
elsif @waiting_proc
|
1010
|
-
@waiting_proc.(key)
|
1011
1045
|
elsif method_obj
|
1012
1046
|
wrap_method_call(method_symbol, method_obj, key)
|
1013
1047
|
else
|
@@ -1018,9 +1052,6 @@ class Reline::LineEditor
|
|
1018
1052
|
@vi_arg = nil
|
1019
1053
|
end
|
1020
1054
|
end
|
1021
|
-
elsif @waiting_proc
|
1022
|
-
@waiting_proc.(key)
|
1023
|
-
@kill_ring.process
|
1024
1055
|
elsif method_obj
|
1025
1056
|
if method_symbol == :ed_argument_digit
|
1026
1057
|
wrap_method_call(method_symbol, method_obj, key)
|
@@ -1097,52 +1128,51 @@ class Reline::LineEditor
|
|
1097
1128
|
end
|
1098
1129
|
old_lines = @buffer_of_lines.dup
|
1099
1130
|
@first_char = false
|
1100
|
-
completion_occurs = false
|
1131
|
+
@completion_occurs = false
|
1101
1132
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
1102
|
-
|
1103
|
-
|
1104
|
-
if
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1133
|
+
if !@config.disable_completion
|
1134
|
+
process_insert(force: true)
|
1135
|
+
if @config.autocompletion
|
1136
|
+
@completion_state = CompletionState::NORMAL
|
1137
|
+
@completion_occurs = move_completed_list(:down)
|
1138
|
+
else
|
1139
|
+
@completion_journey_state = nil
|
1140
|
+
result = call_completion_proc
|
1141
|
+
if result.is_a?(Array)
|
1142
|
+
@completion_occurs = true
|
1143
|
+
complete(result, false)
|
1111
1144
|
end
|
1112
1145
|
end
|
1113
1146
|
end
|
1114
|
-
elsif @config.editing_mode_is?(:
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
move_completed_list(result, :up)
|
1121
|
-
end
|
1122
|
-
end
|
1123
|
-
elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
1124
|
-
unless @config.disable_completion
|
1125
|
-
result = call_completion_proc
|
1126
|
-
if result.is_a?(Array)
|
1127
|
-
completion_occurs = true
|
1128
|
-
process_insert
|
1129
|
-
move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
|
1130
|
-
end
|
1147
|
+
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
1148
|
+
# In vi mode, move completed list even if autocompletion is off
|
1149
|
+
if not @config.disable_completion
|
1150
|
+
process_insert(force: true)
|
1151
|
+
@completion_state = CompletionState::NORMAL
|
1152
|
+
@completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
|
1131
1153
|
end
|
1132
1154
|
elsif Symbol === key.char and respond_to?(key.char, true)
|
1133
1155
|
process_key(key.char, key.char)
|
1134
1156
|
else
|
1135
1157
|
normal_char(key)
|
1136
1158
|
end
|
1137
|
-
unless completion_occurs
|
1159
|
+
unless @completion_occurs
|
1138
1160
|
@completion_state = CompletionState::NORMAL
|
1139
|
-
@
|
1161
|
+
@completion_journey_state = nil
|
1140
1162
|
end
|
1163
|
+
|
1141
1164
|
if @in_pasting
|
1142
1165
|
clear_dialogs
|
1143
|
-
|
1144
|
-
|
1166
|
+
return
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
modified = old_lines != @buffer_of_lines
|
1170
|
+
if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
|
1171
|
+
# Auto complete starts only when edited
|
1172
|
+
process_insert(force: true)
|
1173
|
+
@completion_journey_state = retrieve_completion_journey_state
|
1145
1174
|
end
|
1175
|
+
modified
|
1146
1176
|
end
|
1147
1177
|
|
1148
1178
|
def scroll_into_view
|
@@ -1194,15 +1224,16 @@ class Reline::LineEditor
|
|
1194
1224
|
new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
|
1195
1225
|
return unless new_indent
|
1196
1226
|
|
1197
|
-
|
1227
|
+
new_line = ' ' * new_indent + line.lstrip
|
1228
|
+
@buffer_of_lines[line_index] = new_line
|
1198
1229
|
if @line_index == line_index
|
1199
|
-
|
1200
|
-
@byte_pointer = [@byte_pointer +
|
1230
|
+
indent_diff = new_line.bytesize - line.bytesize
|
1231
|
+
@byte_pointer = [@byte_pointer + indent_diff, 0].max
|
1201
1232
|
end
|
1202
1233
|
end
|
1203
1234
|
|
1204
1235
|
def line()
|
1205
|
-
|
1236
|
+
@buffer_of_lines.join("\n") unless eof?
|
1206
1237
|
end
|
1207
1238
|
|
1208
1239
|
def current_line
|
@@ -1286,14 +1317,12 @@ class Reline::LineEditor
|
|
1286
1317
|
end
|
1287
1318
|
target = before
|
1288
1319
|
end
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1296
|
-
end
|
1320
|
+
lines = whole_lines
|
1321
|
+
if @line_index > 0
|
1322
|
+
preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
|
1323
|
+
end
|
1324
|
+
if (lines.size - 1) > @line_index
|
1325
|
+
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1297
1326
|
end
|
1298
1327
|
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
1299
1328
|
end
|
@@ -1315,20 +1344,16 @@ class Reline::LineEditor
|
|
1315
1344
|
|
1316
1345
|
def delete_text(start = nil, length = nil)
|
1317
1346
|
if start.nil? and length.nil?
|
1318
|
-
if @
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
@byte_pointer = 0
|
1329
|
-
end
|
1330
|
-
else
|
1331
|
-
set_current_line('', 0)
|
1347
|
+
if @buffer_of_lines.size == 1
|
1348
|
+
@buffer_of_lines[@line_index] = ''
|
1349
|
+
@byte_pointer = 0
|
1350
|
+
elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
|
1351
|
+
@buffer_of_lines.pop
|
1352
|
+
@line_index -= 1
|
1353
|
+
@byte_pointer = 0
|
1354
|
+
elsif @line_index < (@buffer_of_lines.size - 1)
|
1355
|
+
@buffer_of_lines.delete_at(@line_index)
|
1356
|
+
@byte_pointer = 0
|
1332
1357
|
end
|
1333
1358
|
elsif not start.nil? and not length.nil?
|
1334
1359
|
if current_line
|
@@ -1405,6 +1430,14 @@ class Reline::LineEditor
|
|
1405
1430
|
end
|
1406
1431
|
end
|
1407
1432
|
|
1433
|
+
private def completion_journey_up(key)
|
1434
|
+
if not @config.disable_completion and @config.autocompletion
|
1435
|
+
@completion_state = CompletionState::NORMAL
|
1436
|
+
@completion_occurs = move_completed_list(:up)
|
1437
|
+
end
|
1438
|
+
end
|
1439
|
+
alias_method :menu_complete_backward, :completion_journey_up
|
1440
|
+
|
1408
1441
|
# Editline:: +ed-unassigned+ This editor command always results in an error.
|
1409
1442
|
# GNU Readline:: There is no corresponding macro.
|
1410
1443
|
private def ed_unassigned(key) end # do nothing
|
@@ -1476,7 +1509,7 @@ class Reline::LineEditor
|
|
1476
1509
|
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1477
1510
|
if (@byte_pointer < current_line.bytesize)
|
1478
1511
|
@byte_pointer += byte_size
|
1479
|
-
elsif @
|
1512
|
+
elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
|
1480
1513
|
@byte_pointer = 0
|
1481
1514
|
@line_index += 1
|
1482
1515
|
end
|
@@ -1489,7 +1522,7 @@ class Reline::LineEditor
|
|
1489
1522
|
if @byte_pointer > 0
|
1490
1523
|
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
1491
1524
|
@byte_pointer -= byte_size
|
1492
|
-
elsif @
|
1525
|
+
elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
|
1493
1526
|
@line_index -= 1
|
1494
1527
|
@byte_pointer = current_line.bytesize
|
1495
1528
|
end
|
@@ -1506,6 +1539,7 @@ class Reline::LineEditor
|
|
1506
1539
|
@byte_pointer = 0
|
1507
1540
|
end
|
1508
1541
|
alias_method :beginning_of_line, :ed_move_to_beg
|
1542
|
+
alias_method :vi_zero, :ed_move_to_beg
|
1509
1543
|
|
1510
1544
|
private def ed_move_to_end(key)
|
1511
1545
|
@byte_pointer = 0
|
@@ -1516,131 +1550,95 @@ class Reline::LineEditor
|
|
1516
1550
|
end
|
1517
1551
|
alias_method :end_of_line, :ed_move_to_end
|
1518
1552
|
|
1519
|
-
private def generate_searcher
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
case
|
1526
|
-
when "\C-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1553
|
+
private def generate_searcher(search_key)
|
1554
|
+
search_word = String.new(encoding: @encoding)
|
1555
|
+
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1556
|
+
hit_pointer = nil
|
1557
|
+
lambda do |key|
|
1558
|
+
search_again = false
|
1559
|
+
case key
|
1560
|
+
when "\C-h".ord, "\C-?".ord
|
1561
|
+
grapheme_clusters = search_word.grapheme_clusters
|
1562
|
+
if grapheme_clusters.size > 0
|
1563
|
+
grapheme_clusters.pop
|
1564
|
+
search_word = grapheme_clusters.join
|
1565
|
+
end
|
1566
|
+
when "\C-r".ord, "\C-s".ord
|
1567
|
+
search_again = true if search_key == key
|
1568
|
+
search_key = key
|
1569
|
+
else
|
1570
|
+
multibyte_buf << key
|
1571
|
+
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1572
|
+
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1573
|
+
multibyte_buf.clear
|
1574
|
+
end
|
1530
1575
|
end
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
grapheme_clusters = search_word.grapheme_clusters
|
1540
|
-
if grapheme_clusters.size > 0
|
1541
|
-
grapheme_clusters.pop
|
1542
|
-
search_word = grapheme_clusters.join
|
1543
|
-
end
|
1544
|
-
when "\C-r".ord, "\C-s".ord
|
1545
|
-
search_again = true if prev_search_key == key
|
1546
|
-
prev_search_key = key
|
1547
|
-
else
|
1548
|
-
multibyte_buf << key
|
1549
|
-
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1550
|
-
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1551
|
-
multibyte_buf.clear
|
1576
|
+
hit = nil
|
1577
|
+
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1578
|
+
hit_pointer = Reline::HISTORY.size
|
1579
|
+
hit = @line_backup_in_history
|
1580
|
+
else
|
1581
|
+
if search_again
|
1582
|
+
if search_word.empty? and Reline.last_incremental_search
|
1583
|
+
search_word = Reline.last_incremental_search
|
1552
1584
|
end
|
1553
|
-
|
1554
|
-
|
1555
|
-
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1556
|
-
@history_pointer = nil
|
1557
|
-
hit = @line_backup_in_history
|
1558
|
-
else
|
1559
|
-
if search_again
|
1560
|
-
if search_word.empty? and Reline.last_incremental_search
|
1561
|
-
search_word = Reline.last_incremental_search
|
1562
|
-
end
|
1563
|
-
if @history_pointer
|
1564
|
-
case prev_search_key
|
1565
|
-
when "\C-r".ord
|
1566
|
-
history_pointer_base = 0
|
1567
|
-
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1568
|
-
when "\C-s".ord
|
1569
|
-
history_pointer_base = @history_pointer + 1
|
1570
|
-
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1571
|
-
end
|
1572
|
-
else
|
1573
|
-
history_pointer_base = 0
|
1574
|
-
history = Reline::HISTORY
|
1575
|
-
end
|
1576
|
-
elsif @history_pointer
|
1577
|
-
case prev_search_key
|
1585
|
+
if @history_pointer
|
1586
|
+
case search_key
|
1578
1587
|
when "\C-r".ord
|
1579
1588
|
history_pointer_base = 0
|
1580
|
-
history = Reline::HISTORY[0
|
1589
|
+
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1581
1590
|
when "\C-s".ord
|
1582
|
-
history_pointer_base = @history_pointer
|
1583
|
-
history = Reline::HISTORY[@history_pointer..-1]
|
1591
|
+
history_pointer_base = @history_pointer + 1
|
1592
|
+
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1584
1593
|
end
|
1585
1594
|
else
|
1586
1595
|
history_pointer_base = 0
|
1587
1596
|
history = Reline::HISTORY
|
1588
1597
|
end
|
1589
|
-
|
1598
|
+
elsif @history_pointer
|
1599
|
+
case search_key
|
1590
1600
|
when "\C-r".ord
|
1591
|
-
|
1592
|
-
|
1593
|
-
}
|
1601
|
+
history_pointer_base = 0
|
1602
|
+
history = Reline::HISTORY[0..@history_pointer]
|
1594
1603
|
when "\C-s".ord
|
1595
|
-
|
1596
|
-
|
1597
|
-
}
|
1598
|
-
end
|
1599
|
-
if hit_index
|
1600
|
-
@history_pointer = history_pointer_base + hit_index
|
1601
|
-
hit = Reline::HISTORY[@history_pointer]
|
1604
|
+
history_pointer_base = @history_pointer
|
1605
|
+
history = Reline::HISTORY[@history_pointer..-1]
|
1602
1606
|
end
|
1607
|
+
else
|
1608
|
+
history_pointer_base = 0
|
1609
|
+
history = Reline::HISTORY
|
1603
1610
|
end
|
1604
|
-
case
|
1611
|
+
case search_key
|
1605
1612
|
when "\C-r".ord
|
1606
|
-
|
1613
|
+
hit_index = history.rindex { |item|
|
1614
|
+
item.include?(search_word)
|
1615
|
+
}
|
1607
1616
|
when "\C-s".ord
|
1608
|
-
|
1617
|
+
hit_index = history.index { |item|
|
1618
|
+
item.include?(search_word)
|
1619
|
+
}
|
1609
1620
|
end
|
1610
|
-
if
|
1611
|
-
|
1612
|
-
|
1613
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1614
|
-
@line_index = @buffer_of_lines.size - 1
|
1615
|
-
@byte_pointer = current_line.bytesize
|
1616
|
-
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1617
|
-
else
|
1618
|
-
@buffer_of_lines = [hit]
|
1619
|
-
@byte_pointer = hit.bytesize
|
1620
|
-
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
1621
|
-
end
|
1622
|
-
last_hit = hit
|
1623
|
-
else
|
1624
|
-
if @is_multiline
|
1625
|
-
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
1626
|
-
else
|
1627
|
-
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
1628
|
-
end
|
1621
|
+
if hit_index
|
1622
|
+
hit_pointer = history_pointer_base + hit_index
|
1623
|
+
hit = Reline::HISTORY[hit_pointer]
|
1629
1624
|
end
|
1630
1625
|
end
|
1626
|
+
case search_key
|
1627
|
+
when "\C-r".ord
|
1628
|
+
prompt_name = 'reverse-i-search'
|
1629
|
+
when "\C-s".ord
|
1630
|
+
prompt_name = 'i-search'
|
1631
|
+
end
|
1632
|
+
prompt_name = "failed #{prompt_name}" unless hit
|
1633
|
+
[search_word, prompt_name, hit_pointer]
|
1631
1634
|
end
|
1632
1635
|
end
|
1633
1636
|
|
1634
1637
|
private def incremental_search_history(key)
|
1635
1638
|
unless @history_pointer
|
1636
|
-
|
1637
|
-
@line_backup_in_history = whole_buffer
|
1638
|
-
else
|
1639
|
-
@line_backup_in_history = current_line
|
1640
|
-
end
|
1639
|
+
@line_backup_in_history = whole_buffer
|
1641
1640
|
end
|
1642
|
-
searcher = generate_searcher
|
1643
|
-
searcher.resume(key)
|
1641
|
+
searcher = generate_searcher(key)
|
1644
1642
|
@searching_prompt = "(reverse-i-search)`': "
|
1645
1643
|
termination_keys = ["\C-j".ord]
|
1646
1644
|
termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
|
@@ -1652,53 +1650,41 @@ class Reline::LineEditor
|
|
1652
1650
|
else
|
1653
1651
|
buffer = @line_backup_in_history
|
1654
1652
|
end
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
@line_index = @buffer_of_lines.size - 1
|
1659
|
-
else
|
1660
|
-
@buffer_of_lines = [buffer]
|
1661
|
-
end
|
1653
|
+
@buffer_of_lines = buffer.split("\n")
|
1654
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1655
|
+
@line_index = @buffer_of_lines.size - 1
|
1662
1656
|
@searching_prompt = nil
|
1663
1657
|
@waiting_proc = nil
|
1664
1658
|
@byte_pointer = 0
|
1665
|
-
searcher.resume(-1)
|
1666
1659
|
when "\C-g".ord
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
|
1671
|
-
else
|
1672
|
-
@buffer_of_lines = [@line_backup_in_history]
|
1673
|
-
end
|
1674
|
-
@history_pointer = nil
|
1660
|
+
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1661
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1662
|
+
@line_index = @buffer_of_lines.size - 1
|
1663
|
+
move_history(nil, line: :end, cursor: :end, save_buffer: false)
|
1675
1664
|
@searching_prompt = nil
|
1676
1665
|
@waiting_proc = nil
|
1677
|
-
@line_backup_in_history = nil
|
1678
1666
|
@byte_pointer = 0
|
1679
1667
|
else
|
1680
1668
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1681
1669
|
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1682
|
-
searcher.
|
1670
|
+
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1671
|
+
Reline.last_incremental_search = search_word
|
1672
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1673
|
+
@searching_prompt += ': ' unless @is_multiline
|
1674
|
+
move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
|
1683
1675
|
else
|
1684
1676
|
if @history_pointer
|
1685
1677
|
line = Reline::HISTORY[@history_pointer]
|
1686
1678
|
else
|
1687
1679
|
line = @line_backup_in_history
|
1688
1680
|
end
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
@line_index = @buffer_of_lines.size - 1
|
1694
|
-
else
|
1695
|
-
@line_backup_in_history = current_line
|
1696
|
-
@buffer_of_lines = [line]
|
1697
|
-
end
|
1681
|
+
@line_backup_in_history = whole_buffer
|
1682
|
+
@buffer_of_lines = line.split("\n")
|
1683
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1684
|
+
@line_index = @buffer_of_lines.size - 1
|
1698
1685
|
@searching_prompt = nil
|
1699
1686
|
@waiting_proc = nil
|
1700
1687
|
@byte_pointer = 0
|
1701
|
-
searcher.resume(-1)
|
1702
1688
|
end
|
1703
1689
|
end
|
1704
1690
|
}
|
@@ -1714,191 +1700,95 @@ class Reline::LineEditor
|
|
1714
1700
|
end
|
1715
1701
|
alias_method :forward_search_history, :vi_search_next
|
1716
1702
|
|
1717
|
-
private def
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
return if not current_line.empty? and substr.empty?
|
1724
|
-
history = Reline::HISTORY
|
1725
|
-
elsif @history_pointer.zero?
|
1726
|
-
history = nil
|
1727
|
-
h_pointer = nil
|
1728
|
-
else
|
1729
|
-
history = Reline::HISTORY.slice(0, @history_pointer)
|
1730
|
-
end
|
1731
|
-
return if history.nil?
|
1732
|
-
if @is_multiline
|
1733
|
-
h_pointer = history.rindex { |h|
|
1734
|
-
h.split("\n").each_with_index { |l, i|
|
1735
|
-
if l.start_with?(substr)
|
1736
|
-
line_no = i
|
1737
|
-
break
|
1738
|
-
end
|
1739
|
-
}
|
1740
|
-
not line_no.nil?
|
1741
|
-
}
|
1742
|
-
else
|
1743
|
-
h_pointer = history.rindex { |l|
|
1744
|
-
l.start_with?(substr)
|
1745
|
-
}
|
1746
|
-
end
|
1747
|
-
return if h_pointer.nil?
|
1748
|
-
@history_pointer = h_pointer
|
1749
|
-
cursor = current_byte_pointer_cursor
|
1750
|
-
if @is_multiline
|
1751
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1752
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1753
|
-
@line_index = line_no
|
1754
|
-
calculate_nearest_cursor(cursor)
|
1755
|
-
else
|
1756
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1757
|
-
calculate_nearest_cursor(cursor)
|
1703
|
+
private def search_history(prefix, pointer_range)
|
1704
|
+
pointer_range.each do |pointer|
|
1705
|
+
lines = Reline::HISTORY[pointer].split("\n")
|
1706
|
+
lines.each_with_index do |line, index|
|
1707
|
+
return [pointer, index] if line.start_with?(prefix)
|
1708
|
+
end
|
1758
1709
|
end
|
1710
|
+
nil
|
1711
|
+
end
|
1712
|
+
|
1713
|
+
private def ed_search_prev_history(key, arg: 1)
|
1714
|
+
substr = current_line.byteslice(0, @byte_pointer)
|
1715
|
+
return if @history_pointer == 0
|
1716
|
+
return if @history_pointer.nil? && substr.empty? && !current_line.empty?
|
1717
|
+
|
1718
|
+
history_range = 0...(@history_pointer || Reline::HISTORY.size)
|
1719
|
+
h_pointer, line_index = search_history(substr, history_range.reverse_each)
|
1720
|
+
return unless h_pointer
|
1721
|
+
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1759
1722
|
arg -= 1
|
1760
1723
|
ed_search_prev_history(key, arg: arg) if arg > 0
|
1761
1724
|
end
|
1762
1725
|
alias_method :history_search_backward, :ed_search_prev_history
|
1763
1726
|
|
1764
1727
|
private def ed_search_next_history(key, arg: 1)
|
1765
|
-
substr = current_line.
|
1766
|
-
if @history_pointer.nil?
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
end
|
1771
|
-
history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
|
1772
|
-
h_pointer = nil
|
1773
|
-
line_no = nil
|
1774
|
-
if @is_multiline
|
1775
|
-
h_pointer = history.index { |h|
|
1776
|
-
h.split("\n").each_with_index { |l, i|
|
1777
|
-
if l.start_with?(substr)
|
1778
|
-
line_no = i
|
1779
|
-
break
|
1780
|
-
end
|
1781
|
-
}
|
1782
|
-
not line_no.nil?
|
1783
|
-
}
|
1784
|
-
else
|
1785
|
-
h_pointer = history.index { |l|
|
1786
|
-
l.start_with?(substr)
|
1787
|
-
}
|
1788
|
-
end
|
1789
|
-
h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
|
1728
|
+
substr = current_line.byteslice(0, @byte_pointer)
|
1729
|
+
return if @history_pointer.nil?
|
1730
|
+
|
1731
|
+
history_range = @history_pointer + 1...Reline::HISTORY.size
|
1732
|
+
h_pointer, line_index = search_history(substr, history_range)
|
1790
1733
|
return if h_pointer.nil? and not substr.empty?
|
1791
|
-
|
1792
|
-
|
1793
|
-
if @history_pointer.nil? and substr.empty?
|
1794
|
-
@buffer_of_lines = []
|
1795
|
-
@line_index = 0
|
1796
|
-
@byte_pointer = 0
|
1797
|
-
else
|
1798
|
-
cursor = current_byte_pointer_cursor
|
1799
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1800
|
-
@line_index = line_no
|
1801
|
-
calculate_nearest_cursor(cursor)
|
1802
|
-
end
|
1803
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1804
|
-
else
|
1805
|
-
if @history_pointer.nil? and substr.empty?
|
1806
|
-
set_current_line('', 0)
|
1807
|
-
else
|
1808
|
-
set_current_line(Reline::HISTORY[@history_pointer])
|
1809
|
-
end
|
1810
|
-
end
|
1734
|
+
|
1735
|
+
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1811
1736
|
arg -= 1
|
1812
1737
|
ed_search_next_history(key, arg: arg) if arg > 0
|
1813
1738
|
end
|
1814
1739
|
alias_method :history_search_forward, :ed_search_next_history
|
1815
1740
|
|
1741
|
+
private def move_history(history_pointer, line:, cursor:, save_buffer: true)
|
1742
|
+
history_pointer ||= Reline::HISTORY.size
|
1743
|
+
return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
|
1744
|
+
old_history_pointer = @history_pointer || Reline::HISTORY.size
|
1745
|
+
if old_history_pointer == Reline::HISTORY.size
|
1746
|
+
@line_backup_in_history = save_buffer ? whole_buffer : ''
|
1747
|
+
else
|
1748
|
+
Reline::HISTORY[old_history_pointer] = whole_buffer if save_buffer
|
1749
|
+
end
|
1750
|
+
if history_pointer == Reline::HISTORY.size
|
1751
|
+
buf = @line_backup_in_history
|
1752
|
+
@history_pointer = @line_backup_in_history = nil
|
1753
|
+
else
|
1754
|
+
buf = Reline::HISTORY[history_pointer]
|
1755
|
+
@history_pointer = history_pointer
|
1756
|
+
end
|
1757
|
+
@buffer_of_lines = buf.split("\n")
|
1758
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1759
|
+
@line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
|
1760
|
+
@byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
|
1761
|
+
end
|
1762
|
+
|
1816
1763
|
private def ed_prev_history(key, arg: 1)
|
1817
|
-
if @
|
1764
|
+
if @line_index > 0
|
1818
1765
|
cursor = current_byte_pointer_cursor
|
1819
1766
|
@line_index -= 1
|
1820
1767
|
calculate_nearest_cursor(cursor)
|
1821
1768
|
return
|
1822
1769
|
end
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
cursor = current_byte_pointer_cursor
|
1829
|
-
if @is_multiline
|
1830
|
-
@line_backup_in_history = whole_buffer
|
1831
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1832
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1833
|
-
@line_index = @buffer_of_lines.size - 1
|
1834
|
-
calculate_nearest_cursor(cursor)
|
1835
|
-
else
|
1836
|
-
@line_backup_in_history = whole_buffer
|
1837
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1838
|
-
calculate_nearest_cursor(cursor)
|
1839
|
-
end
|
1840
|
-
elsif @history_pointer.zero?
|
1841
|
-
return
|
1842
|
-
else
|
1843
|
-
if @is_multiline
|
1844
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1845
|
-
@history_pointer -= 1
|
1846
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1847
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1848
|
-
@line_index = @buffer_of_lines.size - 1
|
1849
|
-
else
|
1850
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1851
|
-
@history_pointer -= 1
|
1852
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1853
|
-
end
|
1854
|
-
end
|
1855
|
-
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1856
|
-
@byte_pointer = current_line.bytesize
|
1857
|
-
elsif @config.editing_mode_is?(:vi_command)
|
1858
|
-
@byte_pointer = 0
|
1859
|
-
end
|
1770
|
+
move_history(
|
1771
|
+
(@history_pointer || Reline::HISTORY.size) - 1,
|
1772
|
+
line: :end,
|
1773
|
+
cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
|
1774
|
+
)
|
1860
1775
|
arg -= 1
|
1861
1776
|
ed_prev_history(key, arg: arg) if arg > 0
|
1862
1777
|
end
|
1863
1778
|
alias_method :previous_history, :ed_prev_history
|
1864
1779
|
|
1865
1780
|
private def ed_next_history(key, arg: 1)
|
1866
|
-
if @
|
1781
|
+
if @line_index < (@buffer_of_lines.size - 1)
|
1867
1782
|
cursor = current_byte_pointer_cursor
|
1868
1783
|
@line_index += 1
|
1869
1784
|
calculate_nearest_cursor(cursor)
|
1870
1785
|
return
|
1871
1786
|
end
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1878
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1879
|
-
@line_index = 0
|
1880
|
-
else
|
1881
|
-
@history_pointer = nil
|
1882
|
-
@buffer_of_lines = [@line_backup_in_history]
|
1883
|
-
end
|
1884
|
-
else
|
1885
|
-
if @is_multiline
|
1886
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1887
|
-
@history_pointer += 1
|
1888
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1889
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1890
|
-
@line_index = 0
|
1891
|
-
else
|
1892
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1893
|
-
@history_pointer += 1
|
1894
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1895
|
-
end
|
1896
|
-
end
|
1897
|
-
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1898
|
-
@byte_pointer = current_line.bytesize
|
1899
|
-
elsif @config.editing_mode_is?(:vi_command)
|
1900
|
-
@byte_pointer = 0
|
1901
|
-
end
|
1787
|
+
move_history(
|
1788
|
+
(@history_pointer || Reline::HISTORY.size) + 1,
|
1789
|
+
line: :start,
|
1790
|
+
cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
|
1791
|
+
)
|
1902
1792
|
arg -= 1
|
1903
1793
|
ed_next_history(key, arg: arg) if arg > 0
|
1904
1794
|
end
|
@@ -1929,17 +1819,13 @@ class Reline::LineEditor
|
|
1929
1819
|
end
|
1930
1820
|
end
|
1931
1821
|
else
|
1932
|
-
if @history_pointer
|
1933
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1934
|
-
@history_pointer = nil
|
1935
|
-
end
|
1936
1822
|
finish
|
1937
1823
|
end
|
1938
1824
|
end
|
1939
1825
|
|
1940
1826
|
private def em_delete_prev_char(key, arg: 1)
|
1941
1827
|
arg.times do
|
1942
|
-
if @
|
1828
|
+
if @byte_pointer == 0 and @line_index > 0
|
1943
1829
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
1944
1830
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
1945
1831
|
@line_index -= 1
|
@@ -1963,7 +1849,7 @@ class Reline::LineEditor
|
|
1963
1849
|
line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
|
1964
1850
|
set_current_line(line, line.bytesize)
|
1965
1851
|
@kill_ring.append(deleted)
|
1966
|
-
elsif @
|
1852
|
+
elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1967
1853
|
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
1968
1854
|
end
|
1969
1855
|
end
|
@@ -2003,7 +1889,7 @@ class Reline::LineEditor
|
|
2003
1889
|
alias_method :kill_whole_line, :em_kill_line
|
2004
1890
|
|
2005
1891
|
private def em_delete(key)
|
2006
|
-
if current_line.empty? and
|
1892
|
+
if current_line.empty? and @buffer_of_lines.size == 1 and key == "\C-d".ord
|
2007
1893
|
@eof = true
|
2008
1894
|
finish
|
2009
1895
|
elsif @byte_pointer < current_line.bytesize
|
@@ -2011,7 +1897,7 @@ class Reline::LineEditor
|
|
2011
1897
|
mbchar = splitted_last.grapheme_clusters.first
|
2012
1898
|
line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
|
2013
1899
|
set_current_line(line)
|
2014
|
-
elsif @
|
1900
|
+
elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
2015
1901
|
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
2016
1902
|
end
|
2017
1903
|
end
|
@@ -2020,7 +1906,7 @@ class Reline::LineEditor
|
|
2020
1906
|
private def em_delete_or_list(key)
|
2021
1907
|
if current_line.empty? or @byte_pointer < current_line.bytesize
|
2022
1908
|
em_delete(key)
|
2023
|
-
|
1909
|
+
elsif !@config.autocompletion # show completed list
|
2024
1910
|
result = call_completion_proc
|
2025
1911
|
if result.is_a?(Array)
|
2026
1912
|
complete(result, true)
|
@@ -2046,7 +1932,11 @@ class Reline::LineEditor
|
|
2046
1932
|
alias_method :yank_pop, :em_yank_pop
|
2047
1933
|
|
2048
1934
|
private def ed_clear_screen(key)
|
2049
|
-
|
1935
|
+
Reline::IOGate.clear_screen
|
1936
|
+
@screen_size = Reline::IOGate.get_screen_size
|
1937
|
+
@rendered_screen.lines = []
|
1938
|
+
@rendered_screen.base_y = 0
|
1939
|
+
@rendered_screen.cursor_y = 0
|
2050
1940
|
end
|
2051
1941
|
alias_method :clear_screen, :ed_clear_screen
|
2052
1942
|
|
@@ -2250,7 +2140,7 @@ class Reline::LineEditor
|
|
2250
2140
|
end
|
2251
2141
|
|
2252
2142
|
private def vi_delete_prev_char(key)
|
2253
|
-
if @
|
2143
|
+
if @byte_pointer == 0 and @line_index > 0
|
2254
2144
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
2255
2145
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
2256
2146
|
@line_index -= 1
|
@@ -2287,54 +2177,67 @@ class Reline::LineEditor
|
|
2287
2177
|
copy_for_vi(deleted)
|
2288
2178
|
end
|
2289
2179
|
|
2290
|
-
private def
|
2291
|
-
@
|
2180
|
+
private def vi_change_meta(key, arg: nil)
|
2181
|
+
if @vi_waiting_operator
|
2182
|
+
set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
|
2183
|
+
@vi_waiting_operator = nil
|
2184
|
+
@vi_waiting_operator_arg = nil
|
2185
|
+
else
|
2186
|
+
@drop_terminate_spaces = true
|
2187
|
+
@vi_waiting_operator = :vi_change_meta_confirm
|
2188
|
+
@vi_waiting_operator_arg = arg || 1
|
2189
|
+
end
|
2292
2190
|
end
|
2293
2191
|
|
2294
|
-
private def
|
2295
|
-
|
2296
|
-
@
|
2297
|
-
|
2298
|
-
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2299
|
-
elsif byte_pointer_diff < 0
|
2300
|
-
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2301
|
-
end
|
2302
|
-
set_current_line(line)
|
2303
|
-
copy_for_vi(cut)
|
2304
|
-
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
2305
|
-
@config.editing_mode = :vi_insert
|
2306
|
-
@drop_terminate_spaces = false
|
2307
|
-
}
|
2308
|
-
@waiting_operator_vi_arg = arg
|
2192
|
+
private def vi_change_meta_confirm(byte_pointer_diff)
|
2193
|
+
vi_delete_meta_confirm(byte_pointer_diff)
|
2194
|
+
@config.editing_mode = :vi_insert
|
2195
|
+
@drop_terminate_spaces = false
|
2309
2196
|
end
|
2310
2197
|
|
2311
|
-
private def vi_delete_meta(key, arg:
|
2312
|
-
@
|
2313
|
-
if
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2320
|
-
}
|
2321
|
-
@waiting_operator_vi_arg = arg
|
2198
|
+
private def vi_delete_meta(key, arg: nil)
|
2199
|
+
if @vi_waiting_operator
|
2200
|
+
set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
|
2201
|
+
@vi_waiting_operator = nil
|
2202
|
+
@vi_waiting_operator_arg = nil
|
2203
|
+
else
|
2204
|
+
@vi_waiting_operator = :vi_delete_meta_confirm
|
2205
|
+
@vi_waiting_operator_arg = arg || 1
|
2206
|
+
end
|
2322
2207
|
end
|
2323
2208
|
|
2324
|
-
private def
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2209
|
+
private def vi_delete_meta_confirm(byte_pointer_diff)
|
2210
|
+
if byte_pointer_diff > 0
|
2211
|
+
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2212
|
+
elsif byte_pointer_diff < 0
|
2213
|
+
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2214
|
+
end
|
2215
|
+
copy_for_vi(cut)
|
2216
|
+
set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
|
2217
|
+
end
|
2218
|
+
|
2219
|
+
private def vi_yank(key, arg: nil)
|
2220
|
+
if @vi_waiting_operator
|
2221
|
+
copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
|
2222
|
+
@vi_waiting_operator = nil
|
2223
|
+
@vi_waiting_operator_arg = nil
|
2224
|
+
else
|
2225
|
+
@vi_waiting_operator = :vi_yank_confirm
|
2226
|
+
@vi_waiting_operator_arg = arg || 1
|
2227
|
+
end
|
2228
|
+
end
|
2229
|
+
|
2230
|
+
private def vi_yank_confirm(byte_pointer_diff)
|
2231
|
+
if byte_pointer_diff > 0
|
2232
|
+
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
2233
|
+
elsif byte_pointer_diff < 0
|
2234
|
+
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2235
|
+
end
|
2236
|
+
copy_for_vi(cut)
|
2334
2237
|
end
|
2335
2238
|
|
2336
2239
|
private def vi_list_or_eof(key)
|
2337
|
-
if
|
2240
|
+
if current_line.empty? and @buffer_of_lines.size == 1
|
2338
2241
|
set_current_line('', 0)
|
2339
2242
|
@eof = true
|
2340
2243
|
finish
|
@@ -2365,36 +2268,18 @@ class Reline::LineEditor
|
|
2365
2268
|
if Reline::HISTORY.empty?
|
2366
2269
|
return
|
2367
2270
|
end
|
2368
|
-
|
2369
|
-
@history_pointer = 0
|
2370
|
-
@line_backup_in_history = current_line
|
2371
|
-
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
2372
|
-
elsif @history_pointer.zero?
|
2373
|
-
return
|
2374
|
-
else
|
2375
|
-
Reline::HISTORY[@history_pointer] = current_line
|
2376
|
-
@history_pointer = 0
|
2377
|
-
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
2378
|
-
end
|
2271
|
+
move_history(0, line: :start, cursor: :start)
|
2379
2272
|
end
|
2380
2273
|
|
2381
2274
|
private def vi_histedit(key)
|
2382
2275
|
path = Tempfile.open { |fp|
|
2383
|
-
|
2384
|
-
fp.write whole_lines.join("\n")
|
2385
|
-
else
|
2386
|
-
fp.write current_line
|
2387
|
-
end
|
2276
|
+
fp.write whole_lines.join("\n")
|
2388
2277
|
fp.path
|
2389
2278
|
}
|
2390
2279
|
system("#{ENV['EDITOR']} #{path}")
|
2391
|
-
|
2392
|
-
|
2393
|
-
|
2394
|
-
@line_index = 0
|
2395
|
-
else
|
2396
|
-
@buffer_of_lines = File.read(path).split("\n")
|
2397
|
-
end
|
2280
|
+
@buffer_of_lines = File.read(path).split("\n")
|
2281
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2282
|
+
@line_index = 0
|
2398
2283
|
finish
|
2399
2284
|
end
|
2400
2285
|
|
@@ -2435,18 +2320,11 @@ class Reline::LineEditor
|
|
2435
2320
|
end
|
2436
2321
|
|
2437
2322
|
private def vi_to_column(key, arg: 0)
|
2438
|
-
|
2439
|
-
@byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |
|
2440
|
-
# total has [byte_size, cursor]
|
2323
|
+
# Implementing behavior of vi, not Readline's vi-mode.
|
2324
|
+
@byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |(total_byte_size, total_width), gc|
|
2441
2325
|
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
|
2442
|
-
if (
|
2443
|
-
|
2444
|
-
elsif (total.last + mbchar_width) >= current_row_width
|
2445
|
-
break total
|
2446
|
-
else
|
2447
|
-
total = [total.first + gc.bytesize, total.last + mbchar_width]
|
2448
|
-
total
|
2449
|
-
end
|
2326
|
+
break [total_byte_size, total_width] if (total_width + mbchar_width) >= arg
|
2327
|
+
[total_byte_size + gc.bytesize, total_width + mbchar_width]
|
2450
2328
|
}
|
2451
2329
|
end
|
2452
2330
|
|
@@ -2573,7 +2451,7 @@ class Reline::LineEditor
|
|
2573
2451
|
end
|
2574
2452
|
|
2575
2453
|
private def vi_join_lines(key, arg: 1)
|
2576
|
-
if @
|
2454
|
+
if @buffer_of_lines.size > @line_index + 1
|
2577
2455
|
next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
|
2578
2456
|
set_current_line(current_line + ' ' + next_line, current_line.bytesize)
|
2579
2457
|
end
|
@@ -2594,6 +2472,11 @@ class Reline::LineEditor
|
|
2594
2472
|
end
|
2595
2473
|
alias_method :exchange_point_and_mark, :em_exchange_mark
|
2596
2474
|
|
2597
|
-
private def
|
2475
|
+
private def emacs_editing_mode(key)
|
2476
|
+
@config.editing_mode = :emacs
|
2477
|
+
end
|
2478
|
+
|
2479
|
+
private def vi_editing_mode(key)
|
2480
|
+
@config.editing_mode = :vi_insert
|
2598
2481
|
end
|
2599
2482
|
end
|