reline 0.2.7 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reline/ansi.rb +64 -22
- data/lib/reline/config.rb +34 -3
- data/lib/reline/general_io.rb +3 -1
- data/lib/reline/key_actor/emacs.rb +1 -1
- data/lib/reline/key_stroke.rb +64 -14
- data/lib/reline/line_editor.rb +630 -72
- data/lib/reline/terminfo.rb +50 -5
- data/lib/reline/unicode.rb +42 -3
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +151 -49
- data/lib/reline.rb +127 -22
- metadata +3 -3
data/lib/reline/line_editor.rb
CHANGED
@@ -5,6 +5,7 @@ require 'tempfile'
|
|
5
5
|
|
6
6
|
class Reline::LineEditor
|
7
7
|
# TODO: undo
|
8
|
+
# TODO: Use "private alias_method" idiom after drop Ruby 2.5.
|
8
9
|
attr_reader :line
|
9
10
|
attr_reader :byte_pointer
|
10
11
|
attr_accessor :confirm_multiline_termination_proc
|
@@ -92,7 +93,7 @@ class Reline::LineEditor
|
|
92
93
|
mode_string
|
93
94
|
end
|
94
95
|
|
95
|
-
private def check_multiline_prompt(buffer
|
96
|
+
private def check_multiline_prompt(buffer)
|
96
97
|
if @vi_arg
|
97
98
|
prompt = "(arg: #{@vi_arg}) "
|
98
99
|
@rerender_all = true
|
@@ -120,7 +121,7 @@ class Reline::LineEditor
|
|
120
121
|
if use_cached_prompt_list
|
121
122
|
prompt_list = @cached_prompt_list
|
122
123
|
else
|
123
|
-
prompt_list = @cached_prompt_list = @prompt_proc.(buffer)
|
124
|
+
prompt_list = @cached_prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
|
124
125
|
@prompt_cache_time = Time.now.to_f
|
125
126
|
end
|
126
127
|
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
@@ -150,7 +151,75 @@ class Reline::LineEditor
|
|
150
151
|
@screen_size = Reline::IOGate.get_screen_size
|
151
152
|
@screen_height = @screen_size.first
|
152
153
|
reset_variables(prompt, encoding: encoding)
|
153
|
-
|
154
|
+
Reline::IOGate.set_winch_handler do
|
155
|
+
@resized = true
|
156
|
+
end
|
157
|
+
if ENV.key?('RELINE_ALT_SCROLLBAR')
|
158
|
+
@full_block = '::'
|
159
|
+
@upper_half_block = "''"
|
160
|
+
@lower_half_block = '..'
|
161
|
+
@block_elem_width = 2
|
162
|
+
elsif Reline::IOGate.win?
|
163
|
+
@full_block = '█'
|
164
|
+
@upper_half_block = '▀'
|
165
|
+
@lower_half_block = '▄'
|
166
|
+
@block_elem_width = 1
|
167
|
+
elsif @encoding == Encoding::UTF_8
|
168
|
+
@full_block = '█'
|
169
|
+
@upper_half_block = '▀'
|
170
|
+
@lower_half_block = '▄'
|
171
|
+
@block_elem_width = Reline::Unicode.calculate_width('█')
|
172
|
+
else
|
173
|
+
@full_block = '::'
|
174
|
+
@upper_half_block = "''"
|
175
|
+
@lower_half_block = '..'
|
176
|
+
@block_elem_width = 2
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def resize
|
181
|
+
return unless @resized
|
182
|
+
@resized = false
|
183
|
+
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
184
|
+
old_screen_size = @screen_size
|
185
|
+
@screen_size = Reline::IOGate.get_screen_size
|
186
|
+
@screen_height = @screen_size.first
|
187
|
+
if old_screen_size.last < @screen_size.last # columns increase
|
188
|
+
@rerender_all = true
|
189
|
+
rerender
|
190
|
+
else
|
191
|
+
back = 0
|
192
|
+
new_buffer = whole_lines
|
193
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
|
194
|
+
new_buffer.each_with_index do |line, index|
|
195
|
+
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
196
|
+
width = prompt_width + calculate_width(line)
|
197
|
+
height = calculate_height_by_width(width)
|
198
|
+
back += height
|
199
|
+
end
|
200
|
+
@highest_in_all = back
|
201
|
+
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
202
|
+
@first_line_started_from =
|
203
|
+
if @line_index.zero?
|
204
|
+
0
|
205
|
+
else
|
206
|
+
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
207
|
+
end
|
208
|
+
if @prompt_proc
|
209
|
+
prompt = prompt_list[@line_index]
|
210
|
+
prompt_width = calculate_width(prompt, true)
|
211
|
+
end
|
212
|
+
calculate_nearest_cursor
|
213
|
+
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
214
|
+
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
215
|
+
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
216
|
+
@rerender_all = true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def set_signal_handlers
|
221
|
+
@old_trap = Signal.trap('INT') {
|
222
|
+
clear_dialog
|
154
223
|
if @scroll_partial_screen
|
155
224
|
move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
|
156
225
|
else
|
@@ -166,50 +235,24 @@ class Reline::LineEditor
|
|
166
235
|
when 'EXIT'
|
167
236
|
exit
|
168
237
|
else
|
169
|
-
@old_trap.call
|
238
|
+
@old_trap.call if @old_trap.respond_to?(:call)
|
170
239
|
end
|
171
240
|
}
|
172
|
-
|
173
|
-
@
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
@rerender_all = true
|
179
|
-
rerender
|
180
|
-
else
|
181
|
-
back = 0
|
182
|
-
new_buffer = whole_lines
|
183
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
184
|
-
new_buffer.each_with_index do |line, index|
|
185
|
-
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
186
|
-
width = prompt_width + calculate_width(line)
|
187
|
-
height = calculate_height_by_width(width)
|
188
|
-
back += height
|
189
|
-
end
|
190
|
-
@highest_in_all = back
|
191
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
192
|
-
@first_line_started_from =
|
193
|
-
if @line_index.zero?
|
194
|
-
0
|
195
|
-
else
|
196
|
-
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
197
|
-
end
|
198
|
-
if @prompt_proc
|
199
|
-
prompt = prompt_list[@line_index]
|
200
|
-
prompt_width = calculate_width(prompt, true)
|
201
|
-
end
|
202
|
-
calculate_nearest_cursor
|
203
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
204
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
205
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
206
|
-
@rerender_all = true
|
207
|
-
end
|
241
|
+
begin
|
242
|
+
@old_tstp_trap = Signal.trap('TSTP') {
|
243
|
+
Reline::IOGate.ungetc("\C-z".ord)
|
244
|
+
@old_tstp_trap.call if @old_tstp_trap.respond_to?(:call)
|
245
|
+
}
|
246
|
+
rescue ArgumentError
|
208
247
|
end
|
209
248
|
end
|
210
249
|
|
211
250
|
def finalize
|
212
|
-
Signal.trap('
|
251
|
+
Signal.trap('INT', @old_trap)
|
252
|
+
begin
|
253
|
+
Signal.trap('TSTP', @old_tstp_trap)
|
254
|
+
rescue ArgumentError
|
255
|
+
end
|
213
256
|
end
|
214
257
|
|
215
258
|
def eof?
|
@@ -217,7 +260,7 @@ class Reline::LineEditor
|
|
217
260
|
end
|
218
261
|
|
219
262
|
def reset_variables(prompt = '', encoding:)
|
220
|
-
@prompt = prompt
|
263
|
+
@prompt = prompt.gsub("\n", "\\n")
|
221
264
|
@mark_pointer = nil
|
222
265
|
@encoding = encoding
|
223
266
|
@is_multiline = false
|
@@ -249,6 +292,9 @@ class Reline::LineEditor
|
|
249
292
|
@drop_terminate_spaces = false
|
250
293
|
@in_pasting = false
|
251
294
|
@auto_indent_proc = nil
|
295
|
+
@dialogs = []
|
296
|
+
@last_key = nil
|
297
|
+
@resized = false
|
252
298
|
reset_line
|
253
299
|
end
|
254
300
|
|
@@ -392,7 +438,7 @@ class Reline::LineEditor
|
|
392
438
|
show_menu
|
393
439
|
@menu_info = nil
|
394
440
|
end
|
395
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
441
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
396
442
|
if @cleared
|
397
443
|
clear_screen_buffer(prompt, prompt_list, prompt_width)
|
398
444
|
@cleared = false
|
@@ -403,7 +449,7 @@ class Reline::LineEditor
|
|
403
449
|
Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
|
404
450
|
Reline::IOGate.move_cursor_column(0)
|
405
451
|
@scroll_partial_screen = nil
|
406
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
452
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
407
453
|
if @previous_line_index
|
408
454
|
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
409
455
|
else
|
@@ -414,6 +460,7 @@ class Reline::LineEditor
|
|
414
460
|
Reline::IOGate.erase_after_cursor
|
415
461
|
end
|
416
462
|
@output.flush
|
463
|
+
clear_dialog
|
417
464
|
return
|
418
465
|
end
|
419
466
|
new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
|
@@ -424,6 +471,7 @@ class Reline::LineEditor
|
|
424
471
|
else
|
425
472
|
if @just_cursor_moving and not @rerender_all
|
426
473
|
rendered = just_move_cursor
|
474
|
+
render_dialog((prompt_width + @cursor) % @screen_size.last)
|
427
475
|
@just_cursor_moving = false
|
428
476
|
return
|
429
477
|
elsif @previous_line_index or new_highest_in_this != @highest_in_this
|
@@ -446,18 +494,20 @@ class Reline::LineEditor
|
|
446
494
|
new_lines = whole_lines
|
447
495
|
end
|
448
496
|
line = modify_lines(new_lines)[@line_index]
|
449
|
-
|
497
|
+
clear_dialog
|
498
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
450
499
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
451
500
|
move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
|
452
501
|
scroll_down(1)
|
453
502
|
Reline::IOGate.move_cursor_column(0)
|
454
503
|
Reline::IOGate.erase_after_cursor
|
455
|
-
|
456
|
-
|
504
|
+
else
|
505
|
+
if not rendered and not @in_pasting
|
457
506
|
line = modify_lines(whole_lines)[@line_index]
|
458
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
507
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
459
508
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
460
509
|
end
|
510
|
+
render_dialog((prompt_width + @cursor) % @screen_size.last)
|
461
511
|
end
|
462
512
|
@buffer_of_lines[@line_index] = @line
|
463
513
|
@rest_height = 0 if @scroll_partial_screen
|
@@ -472,6 +522,405 @@ class Reline::LineEditor
|
|
472
522
|
end
|
473
523
|
end
|
474
524
|
|
525
|
+
class DialogProcScope
|
526
|
+
def initialize(line_editor, config, proc_to_exec, context)
|
527
|
+
@line_editor = line_editor
|
528
|
+
@config = config
|
529
|
+
@proc_to_exec = proc_to_exec
|
530
|
+
@context = context
|
531
|
+
@cursor_pos = Reline::CursorPos.new
|
532
|
+
end
|
533
|
+
|
534
|
+
def context
|
535
|
+
@context
|
536
|
+
end
|
537
|
+
|
538
|
+
def retrieve_completion_block(set_completion_quote_character = false)
|
539
|
+
@line_editor.retrieve_completion_block(set_completion_quote_character)
|
540
|
+
end
|
541
|
+
|
542
|
+
def call_completion_proc_with_checking_args(pre, target, post)
|
543
|
+
@line_editor.call_completion_proc_with_checking_args(pre, target, post)
|
544
|
+
end
|
545
|
+
|
546
|
+
def set_dialog(dialog)
|
547
|
+
@dialog = dialog
|
548
|
+
end
|
549
|
+
|
550
|
+
def dialog
|
551
|
+
@dialog
|
552
|
+
end
|
553
|
+
|
554
|
+
def set_cursor_pos(col, row)
|
555
|
+
@cursor_pos.x = col
|
556
|
+
@cursor_pos.y = row
|
557
|
+
end
|
558
|
+
|
559
|
+
def set_key(key)
|
560
|
+
@key = key
|
561
|
+
end
|
562
|
+
|
563
|
+
def key
|
564
|
+
@key
|
565
|
+
end
|
566
|
+
|
567
|
+
def cursor_pos
|
568
|
+
@cursor_pos
|
569
|
+
end
|
570
|
+
|
571
|
+
def just_cursor_moving
|
572
|
+
@line_editor.instance_variable_get(:@just_cursor_moving)
|
573
|
+
end
|
574
|
+
|
575
|
+
def screen_width
|
576
|
+
@line_editor.instance_variable_get(:@screen_size).last
|
577
|
+
end
|
578
|
+
|
579
|
+
def completion_journey_data
|
580
|
+
@line_editor.instance_variable_get(:@completion_journey_data)
|
581
|
+
end
|
582
|
+
|
583
|
+
def config
|
584
|
+
@config
|
585
|
+
end
|
586
|
+
|
587
|
+
def call
|
588
|
+
instance_exec(&@proc_to_exec)
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
class Dialog
|
593
|
+
attr_reader :name, :contents, :width
|
594
|
+
attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
|
595
|
+
|
596
|
+
def initialize(name, config, proc_scope)
|
597
|
+
@name = name
|
598
|
+
@config = config
|
599
|
+
@proc_scope = proc_scope
|
600
|
+
@width = nil
|
601
|
+
@scroll_top = 0
|
602
|
+
@trap_key = nil
|
603
|
+
end
|
604
|
+
|
605
|
+
def set_cursor_pos(col, row)
|
606
|
+
@proc_scope.set_cursor_pos(col, row)
|
607
|
+
end
|
608
|
+
|
609
|
+
def width=(v)
|
610
|
+
@width = v
|
611
|
+
end
|
612
|
+
|
613
|
+
def contents=(contents)
|
614
|
+
@contents = contents
|
615
|
+
if contents and @width.nil?
|
616
|
+
@width = contents.map{ |line| Reline::Unicode.calculate_width(line, true) }.max
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
def call(key)
|
621
|
+
@proc_scope.set_dialog(self)
|
622
|
+
@proc_scope.set_key(key)
|
623
|
+
dialog_render_info = @proc_scope.call
|
624
|
+
if @trap_key
|
625
|
+
if @trap_key.any?{ |i| i.is_a?(Array) } # multiple trap
|
626
|
+
@trap_key.each do |t|
|
627
|
+
@config.add_oneshot_key_binding(t, @name)
|
628
|
+
end
|
629
|
+
elsif @trap_key.is_a?(Array)
|
630
|
+
@config.add_oneshot_key_binding(@trap_key, @name)
|
631
|
+
elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
|
632
|
+
@config.add_oneshot_key_binding([@trap_key], @name)
|
633
|
+
end
|
634
|
+
end
|
635
|
+
dialog_render_info
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
def add_dialog_proc(name, p, context = nil)
|
640
|
+
dialog = Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context))
|
641
|
+
if index = @dialogs.find_index { |d| d.name == name }
|
642
|
+
@dialogs[index] = dialog
|
643
|
+
else
|
644
|
+
@dialogs << dialog
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
DIALOG_DEFAULT_HEIGHT = 20
|
649
|
+
private def render_dialog(cursor_column)
|
650
|
+
@dialogs.each do |dialog|
|
651
|
+
render_each_dialog(dialog, cursor_column)
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
private def padding_space_with_escape_sequences(str, width)
|
656
|
+
str + (' ' * (width - calculate_width(str, true)))
|
657
|
+
end
|
658
|
+
|
659
|
+
private def render_each_dialog(dialog, cursor_column)
|
660
|
+
if @in_pasting
|
661
|
+
clear_each_dialog(dialog)
|
662
|
+
dialog.contents = nil
|
663
|
+
dialog.trap_key = nil
|
664
|
+
return
|
665
|
+
end
|
666
|
+
dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
|
667
|
+
dialog_render_info = dialog.call(@last_key)
|
668
|
+
if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
|
669
|
+
dialog.lines_backup = {
|
670
|
+
lines: modify_lines(whole_lines),
|
671
|
+
line_index: @line_index,
|
672
|
+
first_line_started_from: @first_line_started_from,
|
673
|
+
started_from: @started_from,
|
674
|
+
byte_pointer: @byte_pointer
|
675
|
+
}
|
676
|
+
clear_each_dialog(dialog)
|
677
|
+
dialog.contents = nil
|
678
|
+
dialog.trap_key = nil
|
679
|
+
return
|
680
|
+
end
|
681
|
+
old_dialog = dialog.clone
|
682
|
+
dialog.contents = dialog_render_info.contents
|
683
|
+
pointer = dialog.pointer
|
684
|
+
if dialog_render_info.width
|
685
|
+
dialog.width = dialog_render_info.width
|
686
|
+
else
|
687
|
+
dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
|
688
|
+
end
|
689
|
+
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
|
690
|
+
height = dialog.contents.size if dialog.contents.size < height
|
691
|
+
if dialog.contents.size > height
|
692
|
+
if dialog.pointer
|
693
|
+
if dialog.pointer < 0
|
694
|
+
dialog.scroll_top = 0
|
695
|
+
elsif (dialog.pointer - dialog.scroll_top) >= (height - 1)
|
696
|
+
dialog.scroll_top = dialog.pointer - (height - 1)
|
697
|
+
elsif (dialog.pointer - dialog.scroll_top) < 0
|
698
|
+
dialog.scroll_top = dialog.pointer
|
699
|
+
end
|
700
|
+
pointer = dialog.pointer - dialog.scroll_top
|
701
|
+
end
|
702
|
+
dialog.contents = dialog.contents[dialog.scroll_top, height]
|
703
|
+
end
|
704
|
+
if dialog.contents and dialog.scroll_top >= dialog.contents.size
|
705
|
+
dialog.scroll_top = dialog.contents.size - height
|
706
|
+
end
|
707
|
+
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
708
|
+
bar_max_height = height * 2
|
709
|
+
moving_distance = (dialog_render_info.contents.size - height) * 2
|
710
|
+
position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
|
711
|
+
bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
|
712
|
+
dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
|
713
|
+
else
|
714
|
+
dialog.scrollbar_pos = nil
|
715
|
+
end
|
716
|
+
upper_space = @first_line_started_from - @started_from
|
717
|
+
dialog.column = dialog_render_info.pos.x
|
718
|
+
dialog.width += @block_elem_width if dialog.scrollbar_pos
|
719
|
+
diff = (dialog.column + dialog.width) - (@screen_size.last)
|
720
|
+
if diff > 0
|
721
|
+
dialog.column -= diff
|
722
|
+
end
|
723
|
+
if (@rest_height - dialog_render_info.pos.y) >= height
|
724
|
+
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
725
|
+
elsif upper_space >= height
|
726
|
+
dialog.vertical_offset = dialog_render_info.pos.y - height
|
727
|
+
else
|
728
|
+
if (@rest_height - dialog_render_info.pos.y) < height
|
729
|
+
scroll_down(height + dialog_render_info.pos.y)
|
730
|
+
move_cursor_up(height + dialog_render_info.pos.y)
|
731
|
+
end
|
732
|
+
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
733
|
+
end
|
734
|
+
Reline::IOGate.hide_cursor
|
735
|
+
if dialog.column < 0
|
736
|
+
dialog.column = 0
|
737
|
+
dialog.width = @screen_size.last
|
738
|
+
end
|
739
|
+
reset_dialog(dialog, old_dialog)
|
740
|
+
move_cursor_down(dialog.vertical_offset)
|
741
|
+
Reline::IOGate.move_cursor_column(dialog.column)
|
742
|
+
dialog.contents.each_with_index do |item, i|
|
743
|
+
if i == pointer
|
744
|
+
bg_color = '45'
|
745
|
+
else
|
746
|
+
if dialog_render_info.bg_color
|
747
|
+
bg_color = dialog_render_info.bg_color
|
748
|
+
else
|
749
|
+
bg_color = '46'
|
750
|
+
end
|
751
|
+
end
|
752
|
+
str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
|
753
|
+
str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
|
754
|
+
@output.write "\e[#{bg_color}m#{str}"
|
755
|
+
if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
|
756
|
+
@output.write "\e[37m"
|
757
|
+
if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
|
758
|
+
@output.write @full_block
|
759
|
+
elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
760
|
+
@output.write @upper_half_block
|
761
|
+
str += ''
|
762
|
+
elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
763
|
+
@output.write @lower_half_block
|
764
|
+
else
|
765
|
+
@output.write ' ' * @block_elem_width
|
766
|
+
end
|
767
|
+
end
|
768
|
+
@output.write "\e[0m"
|
769
|
+
Reline::IOGate.move_cursor_column(dialog.column)
|
770
|
+
move_cursor_down(1) if i < (dialog.contents.size - 1)
|
771
|
+
end
|
772
|
+
Reline::IOGate.move_cursor_column(cursor_column)
|
773
|
+
move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
|
774
|
+
Reline::IOGate.show_cursor
|
775
|
+
dialog.lines_backup = {
|
776
|
+
lines: modify_lines(whole_lines),
|
777
|
+
line_index: @line_index,
|
778
|
+
first_line_started_from: @first_line_started_from,
|
779
|
+
started_from: @started_from,
|
780
|
+
byte_pointer: @byte_pointer
|
781
|
+
}
|
782
|
+
end
|
783
|
+
|
784
|
+
private def reset_dialog(dialog, old_dialog)
|
785
|
+
return if dialog.lines_backup.nil? or old_dialog.contents.nil?
|
786
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
|
787
|
+
visual_lines = []
|
788
|
+
visual_start = nil
|
789
|
+
dialog.lines_backup[:lines].each_with_index { |l, i|
|
790
|
+
pr = prompt_list ? prompt_list[i] : prompt
|
791
|
+
vl, _ = split_by_width(pr + l, @screen_size.last)
|
792
|
+
vl.compact!
|
793
|
+
if i == dialog.lines_backup[:line_index]
|
794
|
+
visual_start = visual_lines.size + dialog.lines_backup[:started_from]
|
795
|
+
end
|
796
|
+
visual_lines.concat(vl)
|
797
|
+
}
|
798
|
+
old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
|
799
|
+
y = @first_line_started_from + @started_from
|
800
|
+
y_diff = y - old_y
|
801
|
+
if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
|
802
|
+
# rerender top
|
803
|
+
move_cursor_down(old_dialog.vertical_offset - y_diff)
|
804
|
+
start = visual_start + old_dialog.vertical_offset
|
805
|
+
line_num = dialog.vertical_offset - old_dialog.vertical_offset
|
806
|
+
line_num.times do |i|
|
807
|
+
Reline::IOGate.move_cursor_column(old_dialog.column)
|
808
|
+
if visual_lines[start + i].nil?
|
809
|
+
s = ' ' * old_dialog.width
|
810
|
+
else
|
811
|
+
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
812
|
+
s = padding_space_with_escape_sequences(s, old_dialog.width)
|
813
|
+
end
|
814
|
+
@output.write "\e[0m#{s}\e[0m"
|
815
|
+
move_cursor_down(1) if i < (line_num - 1)
|
816
|
+
end
|
817
|
+
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
818
|
+
end
|
819
|
+
if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
|
820
|
+
# rerender bottom
|
821
|
+
move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
|
822
|
+
start = visual_start + dialog.vertical_offset + dialog.contents.size
|
823
|
+
line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
|
824
|
+
line_num.times do |i|
|
825
|
+
Reline::IOGate.move_cursor_column(old_dialog.column)
|
826
|
+
if visual_lines[start + i].nil?
|
827
|
+
s = ' ' * old_dialog.width
|
828
|
+
else
|
829
|
+
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
830
|
+
s = padding_space_with_escape_sequences(s, old_dialog.width)
|
831
|
+
end
|
832
|
+
@output.write "\e[0m#{s}\e[0m"
|
833
|
+
move_cursor_down(1) if i < (line_num - 1)
|
834
|
+
end
|
835
|
+
move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
|
836
|
+
end
|
837
|
+
if old_dialog.column < dialog.column
|
838
|
+
# rerender left
|
839
|
+
move_cursor_down(old_dialog.vertical_offset - y_diff)
|
840
|
+
width = dialog.column - old_dialog.column
|
841
|
+
start = visual_start + old_dialog.vertical_offset
|
842
|
+
line_num = old_dialog.contents.size
|
843
|
+
line_num.times do |i|
|
844
|
+
Reline::IOGate.move_cursor_column(old_dialog.column)
|
845
|
+
if visual_lines[start + i].nil?
|
846
|
+
s = ' ' * width
|
847
|
+
else
|
848
|
+
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
|
849
|
+
s = padding_space_with_escape_sequences(s, dialog.width)
|
850
|
+
end
|
851
|
+
@output.write "\e[0m#{s}\e[0m"
|
852
|
+
move_cursor_down(1) if i < (line_num - 1)
|
853
|
+
end
|
854
|
+
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
855
|
+
end
|
856
|
+
if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
|
857
|
+
# rerender right
|
858
|
+
move_cursor_down(old_dialog.vertical_offset + y_diff)
|
859
|
+
width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
|
860
|
+
start = visual_start + old_dialog.vertical_offset
|
861
|
+
line_num = old_dialog.contents.size
|
862
|
+
line_num.times do |i|
|
863
|
+
Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
|
864
|
+
if visual_lines[start + i].nil?
|
865
|
+
s = ' ' * width
|
866
|
+
else
|
867
|
+
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
|
868
|
+
rerender_width = old_dialog.width - dialog.width
|
869
|
+
s = padding_space_with_escape_sequences(s, rerender_width)
|
870
|
+
end
|
871
|
+
Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
|
872
|
+
@output.write "\e[0m#{s}\e[0m"
|
873
|
+
move_cursor_down(1) if i < (line_num - 1)
|
874
|
+
end
|
875
|
+
move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
|
876
|
+
end
|
877
|
+
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
878
|
+
end
|
879
|
+
|
880
|
+
private def clear_dialog
|
881
|
+
@dialogs.each do |dialog|
|
882
|
+
clear_each_dialog(dialog)
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
private def clear_each_dialog(dialog)
|
887
|
+
dialog.trap_key = nil
|
888
|
+
return unless dialog.contents
|
889
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
|
890
|
+
visual_lines = []
|
891
|
+
visual_lines_under_dialog = []
|
892
|
+
visual_start = nil
|
893
|
+
dialog.lines_backup[:lines].each_with_index { |l, i|
|
894
|
+
pr = prompt_list ? prompt_list[i] : prompt
|
895
|
+
vl, _ = split_by_width(pr + l, @screen_size.last)
|
896
|
+
vl.compact!
|
897
|
+
if i == dialog.lines_backup[:line_index]
|
898
|
+
visual_start = visual_lines.size + dialog.lines_backup[:started_from] + dialog.vertical_offset
|
899
|
+
end
|
900
|
+
visual_lines.concat(vl)
|
901
|
+
}
|
902
|
+
visual_lines_under_dialog = visual_lines[visual_start, dialog.contents.size]
|
903
|
+
visual_lines_under_dialog = [] if visual_lines_under_dialog.nil?
|
904
|
+
Reline::IOGate.hide_cursor
|
905
|
+
move_cursor_down(dialog.vertical_offset)
|
906
|
+
dialog_vertical_size = dialog.contents.size
|
907
|
+
dialog_vertical_size.times do |i|
|
908
|
+
if i < visual_lines_under_dialog.size
|
909
|
+
Reline::IOGate.move_cursor_column(dialog.column)
|
910
|
+
str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
|
911
|
+
str = padding_space_with_escape_sequences(str, dialog.width)
|
912
|
+
@output.write "\e[0m#{str}\e[0m"
|
913
|
+
else
|
914
|
+
Reline::IOGate.move_cursor_column(dialog.column)
|
915
|
+
@output.write "\e[0m#{' ' * dialog.width}\e[0m"
|
916
|
+
end
|
917
|
+
move_cursor_down(1) if i < (dialog_vertical_size - 1)
|
918
|
+
end
|
919
|
+
move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
|
920
|
+
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
921
|
+
Reline::IOGate.show_cursor
|
922
|
+
end
|
923
|
+
|
475
924
|
private def calculate_scroll_partial_screen(highest_in_all, cursor_y)
|
476
925
|
if @screen_height < highest_in_all
|
477
926
|
old_scroll_partial_screen = @scroll_partial_screen
|
@@ -522,7 +971,7 @@ class Reline::LineEditor
|
|
522
971
|
end
|
523
972
|
|
524
973
|
def just_move_cursor
|
525
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines
|
974
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
|
526
975
|
move_cursor_up(@started_from)
|
527
976
|
new_first_line_started_from =
|
528
977
|
if @line_index.zero?
|
@@ -559,7 +1008,7 @@ class Reline::LineEditor
|
|
559
1008
|
else
|
560
1009
|
new_lines = whole_lines
|
561
1010
|
end
|
562
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines
|
1011
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
563
1012
|
all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
|
564
1013
|
diff = all_height - @highest_in_all
|
565
1014
|
move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
|
@@ -606,7 +1055,7 @@ class Reline::LineEditor
|
|
606
1055
|
Reline::IOGate.move_cursor_column(0)
|
607
1056
|
back = 0
|
608
1057
|
new_buffer = whole_lines
|
609
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer
|
1058
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
|
610
1059
|
new_buffer.each_with_index do |line, index|
|
611
1060
|
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
612
1061
|
width = prompt_width + calculate_width(line)
|
@@ -813,7 +1262,7 @@ class Reline::LineEditor
|
|
813
1262
|
height = render_partial(prompt, prompt_width, line, back, with_control: false)
|
814
1263
|
end
|
815
1264
|
if index < (@buffer_of_lines.size - 1)
|
816
|
-
move_cursor_down(
|
1265
|
+
move_cursor_down(1)
|
817
1266
|
back += height
|
818
1267
|
end
|
819
1268
|
end
|
@@ -932,6 +1381,16 @@ class Reline::LineEditor
|
|
932
1381
|
@completion_journey_data = CompletionJourneyData.new(
|
933
1382
|
preposing, postposing,
|
934
1383
|
[target] + list.select{ |item| item.start_with?(target) }, 0)
|
1384
|
+
if @completion_journey_data.list.size == 1
|
1385
|
+
@completion_journey_data.pointer = 0
|
1386
|
+
else
|
1387
|
+
case direction
|
1388
|
+
when :up
|
1389
|
+
@completion_journey_data.pointer = @completion_journey_data.list.size - 1
|
1390
|
+
when :down
|
1391
|
+
@completion_journey_data.pointer = 1
|
1392
|
+
end
|
1393
|
+
end
|
935
1394
|
@completion_state = CompletionState::JOURNEY
|
936
1395
|
else
|
937
1396
|
case direction
|
@@ -946,13 +1405,15 @@ class Reline::LineEditor
|
|
946
1405
|
@completion_journey_data.pointer = 0
|
947
1406
|
end
|
948
1407
|
end
|
949
|
-
completed = @completion_journey_data.list[@completion_journey_data.pointer]
|
950
|
-
@line = @completion_journey_data.preposing + completed + @completion_journey_data.postposing
|
951
|
-
line_to_pointer = @completion_journey_data.preposing + completed
|
952
|
-
@cursor_max = calculate_width(@line)
|
953
|
-
@cursor = calculate_width(line_to_pointer)
|
954
|
-
@byte_pointer = line_to_pointer.bytesize
|
955
1408
|
end
|
1409
|
+
completed = @completion_journey_data.list[@completion_journey_data.pointer]
|
1410
|
+
new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
|
1411
|
+
@line = new_line.nil? ? String.new(encoding: @encoding) : new_line
|
1412
|
+
line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
|
1413
|
+
line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
|
1414
|
+
@cursor_max = calculate_width(@line)
|
1415
|
+
@cursor = calculate_width(line_to_pointer)
|
1416
|
+
@byte_pointer = line_to_pointer.bytesize
|
956
1417
|
end
|
957
1418
|
|
958
1419
|
private def run_for_operators(key, method_symbol, &block)
|
@@ -984,7 +1445,10 @@ class Reline::LineEditor
|
|
984
1445
|
end
|
985
1446
|
@waiting_operator_proc = nil
|
986
1447
|
@waiting_operator_vi_arg = nil
|
987
|
-
@vi_arg
|
1448
|
+
if @vi_arg
|
1449
|
+
@rerender_all = true
|
1450
|
+
@vi_arg = nil
|
1451
|
+
end
|
988
1452
|
else
|
989
1453
|
block.(false)
|
990
1454
|
end
|
@@ -1035,7 +1499,10 @@ class Reline::LineEditor
|
|
1035
1499
|
wrap_method_call(method_symbol, method_obj, key) if method_obj
|
1036
1500
|
end
|
1037
1501
|
@kill_ring.process
|
1038
|
-
@vi_arg
|
1502
|
+
if @vi_arg
|
1503
|
+
@rerender_al = true
|
1504
|
+
@vi_arg = nil
|
1505
|
+
end
|
1039
1506
|
elsif @vi_arg
|
1040
1507
|
if key.chr =~ /[0-9]/
|
1041
1508
|
ed_argument_digit(key)
|
@@ -1052,7 +1519,10 @@ class Reline::LineEditor
|
|
1052
1519
|
ed_insert(key) unless @config.editing_mode_is?(:vi_command)
|
1053
1520
|
end
|
1054
1521
|
@kill_ring.process
|
1055
|
-
@vi_arg
|
1522
|
+
if @vi_arg
|
1523
|
+
@rerender_all = true
|
1524
|
+
@vi_arg = nil
|
1525
|
+
end
|
1056
1526
|
end
|
1057
1527
|
elsif @waiting_proc
|
1058
1528
|
@waiting_proc.(key)
|
@@ -1110,6 +1580,13 @@ class Reline::LineEditor
|
|
1110
1580
|
end
|
1111
1581
|
|
1112
1582
|
def input_key(key)
|
1583
|
+
@last_key = key
|
1584
|
+
@config.reset_oneshot_key_bindings
|
1585
|
+
@dialogs.each do |dialog|
|
1586
|
+
if key.char.instance_of?(Symbol) and key.char == dialog.name
|
1587
|
+
return
|
1588
|
+
end
|
1589
|
+
end
|
1113
1590
|
@just_cursor_moving = nil
|
1114
1591
|
if key.char.nil?
|
1115
1592
|
if @first_char
|
@@ -1127,7 +1604,20 @@ class Reline::LineEditor
|
|
1127
1604
|
if result.is_a?(Array)
|
1128
1605
|
completion_occurs = true
|
1129
1606
|
process_insert
|
1130
|
-
|
1607
|
+
if @config.autocompletion
|
1608
|
+
move_completed_list(result, :down)
|
1609
|
+
else
|
1610
|
+
complete(result)
|
1611
|
+
end
|
1612
|
+
end
|
1613
|
+
end
|
1614
|
+
elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
|
1615
|
+
if not @config.disable_completion and @config.autocompletion
|
1616
|
+
result = call_completion_proc
|
1617
|
+
if result.is_a?(Array)
|
1618
|
+
completion_occurs = true
|
1619
|
+
process_insert
|
1620
|
+
move_completed_list(result, :up)
|
1131
1621
|
end
|
1132
1622
|
end
|
1133
1623
|
elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
@@ -1146,6 +1636,7 @@ class Reline::LineEditor
|
|
1146
1636
|
end
|
1147
1637
|
unless completion_occurs
|
1148
1638
|
@completion_state = CompletionState::NORMAL
|
1639
|
+
@completion_journey_data = nil
|
1149
1640
|
end
|
1150
1641
|
if not @in_pasting and @just_cursor_moving.nil?
|
1151
1642
|
if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
|
@@ -1165,7 +1656,13 @@ class Reline::LineEditor
|
|
1165
1656
|
|
1166
1657
|
def call_completion_proc
|
1167
1658
|
result = retrieve_completion_block(true)
|
1168
|
-
|
1659
|
+
pre, target, post = result
|
1660
|
+
result = call_completion_proc_with_checking_args(pre, target, post)
|
1661
|
+
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
1662
|
+
result
|
1663
|
+
end
|
1664
|
+
|
1665
|
+
def call_completion_proc_with_checking_args(pre, target, post)
|
1169
1666
|
if @completion_proc and target
|
1170
1667
|
argnum = @completion_proc.parameters.inject(0) { |result, item|
|
1171
1668
|
case item.first
|
@@ -1179,12 +1676,11 @@ class Reline::LineEditor
|
|
1179
1676
|
when 1
|
1180
1677
|
result = @completion_proc.(target)
|
1181
1678
|
when 2
|
1182
|
-
result = @completion_proc.(target,
|
1679
|
+
result = @completion_proc.(target, pre)
|
1183
1680
|
when 3..Float::INFINITY
|
1184
|
-
result = @completion_proc.(target,
|
1681
|
+
result = @completion_proc.(target, pre, post)
|
1185
1682
|
end
|
1186
1683
|
end
|
1187
|
-
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
1188
1684
|
result
|
1189
1685
|
end
|
1190
1686
|
|
@@ -1465,6 +1961,8 @@ class Reline::LineEditor
|
|
1465
1961
|
end
|
1466
1962
|
end
|
1467
1963
|
|
1964
|
+
# Editline:: +ed-unassigned+ This editor command always results in an error.
|
1965
|
+
# GNU Readline:: There is no corresponding macro.
|
1468
1966
|
private def ed_unassigned(key) end # do nothing
|
1469
1967
|
|
1470
1968
|
private def process_insert(force: false)
|
@@ -1482,6 +1980,19 @@ class Reline::LineEditor
|
|
1482
1980
|
@continuous_insertion_buffer.clear
|
1483
1981
|
end
|
1484
1982
|
|
1983
|
+
# Editline:: +ed-insert+ (vi input: almost all; emacs: printable characters)
|
1984
|
+
# In insert mode, insert the input character left of the cursor
|
1985
|
+
# position. In replace mode, overwrite the character at the
|
1986
|
+
# cursor and move the cursor to the right by one character
|
1987
|
+
# position. Accept an argument to do this repeatedly. It is an
|
1988
|
+
# error if the input character is the NUL character (+Ctrl-@+).
|
1989
|
+
# Failure to enlarge the edit buffer also results in an error.
|
1990
|
+
# Editline:: +ed-digit+ (emacs: 0 to 9) If in argument input mode, append
|
1991
|
+
# the input digit to the argument being read. Otherwise, call
|
1992
|
+
# +ed-insert+. It is an error if the input character is not a
|
1993
|
+
# digit or if the existing argument is already greater than a
|
1994
|
+
# million.
|
1995
|
+
# GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
|
1485
1996
|
private def ed_insert(key)
|
1486
1997
|
str = nil
|
1487
1998
|
width = nil
|
@@ -1518,8 +2029,16 @@ class Reline::LineEditor
|
|
1518
2029
|
last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
1519
2030
|
@byte_pointer += bytesize
|
1520
2031
|
last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
|
1521
|
-
|
1522
|
-
|
2032
|
+
combined_char = last_mbchar + str
|
2033
|
+
if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1
|
2034
|
+
# combined char
|
2035
|
+
last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar)
|
2036
|
+
combined_char_width = Reline::Unicode.get_mbchar_width(combined_char)
|
2037
|
+
if combined_char_width > last_mbchar_width
|
2038
|
+
width = combined_char_width - last_mbchar_width
|
2039
|
+
else
|
2040
|
+
width = 0
|
2041
|
+
end
|
1523
2042
|
end
|
1524
2043
|
@cursor += width
|
1525
2044
|
@cursor_max += width
|
@@ -1532,6 +2051,8 @@ class Reline::LineEditor
|
|
1532
2051
|
arg.times do
|
1533
2052
|
if key == "\C-j".ord or key == "\C-m".ord
|
1534
2053
|
key_newline(key)
|
2054
|
+
elsif key == 0
|
2055
|
+
# Ignore NUL.
|
1535
2056
|
else
|
1536
2057
|
ed_insert(key)
|
1537
2058
|
end
|
@@ -1966,6 +2487,7 @@ class Reline::LineEditor
|
|
1966
2487
|
arg -= 1
|
1967
2488
|
ed_prev_history(key, arg: arg) if arg > 0
|
1968
2489
|
end
|
2490
|
+
alias_method :previous_history, :ed_prev_history
|
1969
2491
|
|
1970
2492
|
private def ed_next_history(key, arg: 1)
|
1971
2493
|
if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
|
@@ -2013,6 +2535,7 @@ class Reline::LineEditor
|
|
2013
2535
|
arg -= 1
|
2014
2536
|
ed_next_history(key, arg: arg) if arg > 0
|
2015
2537
|
end
|
2538
|
+
alias_method :next_history, :ed_next_history
|
2016
2539
|
|
2017
2540
|
private def ed_newline(key)
|
2018
2541
|
process_insert(force: true)
|
@@ -2047,7 +2570,7 @@ class Reline::LineEditor
|
|
2047
2570
|
end
|
2048
2571
|
end
|
2049
2572
|
|
2050
|
-
private def em_delete_prev_char(key)
|
2573
|
+
private def em_delete_prev_char(key, arg: 1)
|
2051
2574
|
if @is_multiline and @cursor == 0 and @line_index > 0
|
2052
2575
|
@buffer_of_lines[@line_index] = @line
|
2053
2576
|
@cursor = calculate_width(@buffer_of_lines[@line_index - 1])
|
@@ -2065,9 +2588,16 @@ class Reline::LineEditor
|
|
2065
2588
|
@cursor -= width
|
2066
2589
|
@cursor_max -= width
|
2067
2590
|
end
|
2591
|
+
arg -= 1
|
2592
|
+
em_delete_prev_char(key, arg: arg) if arg > 0
|
2068
2593
|
end
|
2069
2594
|
alias_method :backward_delete_char, :em_delete_prev_char
|
2070
2595
|
|
2596
|
+
# Editline:: +ed-kill-line+ (vi command: +D+, +Ctrl-K+; emacs: +Ctrl-K+,
|
2597
|
+
# +Ctrl-U+) + Kill from the cursor to the end of the line.
|
2598
|
+
# GNU Readline:: +kill-line+ (+C-k+) Kill the text from point to the end of
|
2599
|
+
# the line. With a negative numeric argument, kill backward
|
2600
|
+
# from the cursor to the beginning of the current line.
|
2071
2601
|
private def ed_kill_line(key)
|
2072
2602
|
if @line.bytesize > @byte_pointer
|
2073
2603
|
@line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
|
@@ -2084,8 +2614,14 @@ class Reline::LineEditor
|
|
2084
2614
|
@rest_height += 1
|
2085
2615
|
end
|
2086
2616
|
end
|
2617
|
+
alias_method :kill_line, :ed_kill_line
|
2087
2618
|
|
2088
|
-
|
2619
|
+
# Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
|
2620
|
+
# beginning of the edit buffer to the cursor and save it to the
|
2621
|
+
# cut buffer.
|
2622
|
+
# GNU Readline:: +unix-line-discard+ (+C-u+) Kill backward from the cursor
|
2623
|
+
# to the beginning of the current line.
|
2624
|
+
private def vi_kill_line_prev(key)
|
2089
2625
|
if @byte_pointer > 0
|
2090
2626
|
@line, deleted = byteslice!(@line, 0, @byte_pointer)
|
2091
2627
|
@byte_pointer = 0
|
@@ -2094,7 +2630,22 @@ class Reline::LineEditor
|
|
2094
2630
|
@cursor = 0
|
2095
2631
|
end
|
2096
2632
|
end
|
2097
|
-
alias_method :
|
2633
|
+
alias_method :unix_line_discard, :vi_kill_line_prev
|
2634
|
+
|
2635
|
+
# Editline:: +em-kill-line+ (not bound) Delete the entire contents of the
|
2636
|
+
# edit buffer and save it to the cut buffer. +vi-kill-line-prev+
|
2637
|
+
# GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
|
2638
|
+
# current line, no matter where point is.
|
2639
|
+
private def em_kill_line(key)
|
2640
|
+
if @line.size > 0
|
2641
|
+
@kill_ring.append(@line.dup, true)
|
2642
|
+
@line.clear
|
2643
|
+
@byte_pointer = 0
|
2644
|
+
@cursor_max = 0
|
2645
|
+
@cursor = 0
|
2646
|
+
end
|
2647
|
+
end
|
2648
|
+
alias_method :kill_whole_line, :em_kill_line
|
2098
2649
|
|
2099
2650
|
private def em_delete(key)
|
2100
2651
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
@@ -2599,7 +3150,14 @@ class Reline::LineEditor
|
|
2599
3150
|
|
2600
3151
|
private def ed_argument_digit(key)
|
2601
3152
|
if @vi_arg.nil?
|
2602
|
-
|
3153
|
+
if key.chr.to_i.zero?
|
3154
|
+
if key.anybits?(0b10000000)
|
3155
|
+
unescaped_key = key ^ 0b10000000
|
3156
|
+
unless unescaped_key.chr.to_i.zero?
|
3157
|
+
@vi_arg = unescaped_key.chr.to_i
|
3158
|
+
end
|
3159
|
+
end
|
3160
|
+
else
|
2603
3161
|
@vi_arg = key.chr.to_i
|
2604
3162
|
end
|
2605
3163
|
else
|