reline 0.2.7 → 0.3.0
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 +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 +12 -4
- 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 +2 -2
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
|