reline 0.2.8.pre.9 → 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 +50 -23
- data/lib/reline/config.rb +5 -0
- data/lib/reline/general_io.rb +2 -1
- data/lib/reline/key_actor/emacs.rb +1 -1
- data/lib/reline/key_stroke.rb +60 -62
- data/lib/reline/line_editor.rb +206 -92
- data/lib/reline/terminfo.rb +50 -5
- data/lib/reline/unicode.rb +9 -1
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +121 -50
- data/lib/reline.rb +29 -21
- metadata +5 -5
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,6 +151,73 @@ 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)
|
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
|
153
221
|
@old_trap = Signal.trap('INT') {
|
154
222
|
clear_dialog
|
155
223
|
if @scroll_partial_screen
|
@@ -167,7 +235,7 @@ class Reline::LineEditor
|
|
167
235
|
when 'EXIT'
|
168
236
|
exit
|
169
237
|
else
|
170
|
-
@old_trap.call
|
238
|
+
@old_trap.call if @old_trap.respond_to?(:call)
|
171
239
|
end
|
172
240
|
}
|
173
241
|
begin
|
@@ -177,44 +245,6 @@ class Reline::LineEditor
|
|
177
245
|
}
|
178
246
|
rescue ArgumentError
|
179
247
|
end
|
180
|
-
Reline::IOGate.set_winch_handler do
|
181
|
-
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
182
|
-
old_screen_size = @screen_size
|
183
|
-
@screen_size = Reline::IOGate.get_screen_size
|
184
|
-
@screen_height = @screen_size.first
|
185
|
-
if old_screen_size.last < @screen_size.last # columns increase
|
186
|
-
@rerender_all = true
|
187
|
-
rerender
|
188
|
-
else
|
189
|
-
back = 0
|
190
|
-
new_buffer = whole_lines
|
191
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
192
|
-
new_buffer.each_with_index do |line, index|
|
193
|
-
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
194
|
-
width = prompt_width + calculate_width(line)
|
195
|
-
height = calculate_height_by_width(width)
|
196
|
-
back += height
|
197
|
-
end
|
198
|
-
@highest_in_all = back
|
199
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
200
|
-
@first_line_started_from =
|
201
|
-
if @line_index.zero?
|
202
|
-
0
|
203
|
-
else
|
204
|
-
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
205
|
-
end
|
206
|
-
if @prompt_proc
|
207
|
-
prompt = prompt_list[@line_index]
|
208
|
-
prompt_width = calculate_width(prompt, true)
|
209
|
-
end
|
210
|
-
calculate_nearest_cursor
|
211
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
212
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
213
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
214
|
-
@rerender_all = true
|
215
|
-
end
|
216
|
-
end
|
217
|
-
@block_elem_width = Reline::Unicode.calculate_width('█')
|
218
248
|
end
|
219
249
|
|
220
250
|
def finalize
|
@@ -230,7 +260,7 @@ class Reline::LineEditor
|
|
230
260
|
end
|
231
261
|
|
232
262
|
def reset_variables(prompt = '', encoding:)
|
233
|
-
@prompt = prompt
|
263
|
+
@prompt = prompt.gsub("\n", "\\n")
|
234
264
|
@mark_pointer = nil
|
235
265
|
@encoding = encoding
|
236
266
|
@is_multiline = false
|
@@ -264,6 +294,7 @@ class Reline::LineEditor
|
|
264
294
|
@auto_indent_proc = nil
|
265
295
|
@dialogs = []
|
266
296
|
@last_key = nil
|
297
|
+
@resized = false
|
267
298
|
reset_line
|
268
299
|
end
|
269
300
|
|
@@ -407,7 +438,7 @@ class Reline::LineEditor
|
|
407
438
|
show_menu
|
408
439
|
@menu_info = nil
|
409
440
|
end
|
410
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
441
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
411
442
|
if @cleared
|
412
443
|
clear_screen_buffer(prompt, prompt_list, prompt_width)
|
413
444
|
@cleared = false
|
@@ -418,7 +449,7 @@ class Reline::LineEditor
|
|
418
449
|
Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
|
419
450
|
Reline::IOGate.move_cursor_column(0)
|
420
451
|
@scroll_partial_screen = nil
|
421
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
452
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
422
453
|
if @previous_line_index
|
423
454
|
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
424
455
|
else
|
@@ -464,7 +495,7 @@ class Reline::LineEditor
|
|
464
495
|
end
|
465
496
|
line = modify_lines(new_lines)[@line_index]
|
466
497
|
clear_dialog
|
467
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines
|
498
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
468
499
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
469
500
|
move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
|
470
501
|
scroll_down(1)
|
@@ -473,7 +504,7 @@ class Reline::LineEditor
|
|
473
504
|
else
|
474
505
|
if not rendered and not @in_pasting
|
475
506
|
line = modify_lines(whole_lines)[@line_index]
|
476
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
507
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
477
508
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
478
509
|
end
|
479
510
|
render_dialog((prompt_width + @cursor) % @screen_size.last)
|
@@ -560,7 +591,7 @@ class Reline::LineEditor
|
|
560
591
|
|
561
592
|
class Dialog
|
562
593
|
attr_reader :name, :contents, :width
|
563
|
-
attr_accessor :scroll_top, :scrollbar_pos, :column, :vertical_offset, :lines_backup, :trap_key
|
594
|
+
attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
|
564
595
|
|
565
596
|
def initialize(name, config, proc_scope)
|
566
597
|
@name = name
|
@@ -568,6 +599,7 @@ class Reline::LineEditor
|
|
568
599
|
@proc_scope = proc_scope
|
569
600
|
@width = nil
|
570
601
|
@scroll_top = 0
|
602
|
+
@trap_key = nil
|
571
603
|
end
|
572
604
|
|
573
605
|
def set_cursor_pos(col, row)
|
@@ -605,11 +637,15 @@ class Reline::LineEditor
|
|
605
637
|
end
|
606
638
|
|
607
639
|
def add_dialog_proc(name, p, context = nil)
|
608
|
-
|
609
|
-
@dialogs
|
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
|
610
646
|
end
|
611
647
|
|
612
|
-
|
648
|
+
DIALOG_DEFAULT_HEIGHT = 20
|
613
649
|
private def render_dialog(cursor_column)
|
614
650
|
@dialogs.each do |dialog|
|
615
651
|
render_each_dialog(dialog, cursor_column)
|
@@ -622,6 +658,7 @@ class Reline::LineEditor
|
|
622
658
|
|
623
659
|
private def render_each_dialog(dialog, cursor_column)
|
624
660
|
if @in_pasting
|
661
|
+
clear_each_dialog(dialog)
|
625
662
|
dialog.contents = nil
|
626
663
|
dialog.trap_key = nil
|
627
664
|
return
|
@@ -643,27 +680,30 @@ class Reline::LineEditor
|
|
643
680
|
end
|
644
681
|
old_dialog = dialog.clone
|
645
682
|
dialog.contents = dialog_render_info.contents
|
646
|
-
pointer =
|
683
|
+
pointer = dialog.pointer
|
647
684
|
if dialog_render_info.width
|
648
685
|
dialog.width = dialog_render_info.width
|
649
686
|
else
|
650
687
|
dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
|
651
688
|
end
|
652
|
-
height = dialog_render_info.height ||
|
689
|
+
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
|
653
690
|
height = dialog.contents.size if dialog.contents.size < height
|
654
691
|
if dialog.contents.size > height
|
655
|
-
if
|
656
|
-
if
|
692
|
+
if dialog.pointer
|
693
|
+
if dialog.pointer < 0
|
657
694
|
dialog.scroll_top = 0
|
658
|
-
elsif (
|
659
|
-
dialog.scroll_top =
|
660
|
-
elsif (
|
661
|
-
dialog.scroll_top =
|
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
|
662
699
|
end
|
663
|
-
pointer =
|
700
|
+
pointer = dialog.pointer - dialog.scroll_top
|
664
701
|
end
|
665
702
|
dialog.contents = dialog.contents[dialog.scroll_top, height]
|
666
703
|
end
|
704
|
+
if dialog.contents and dialog.scroll_top >= dialog.contents.size
|
705
|
+
dialog.scroll_top = dialog.contents.size - height
|
706
|
+
end
|
667
707
|
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
668
708
|
bar_max_height = height * 2
|
669
709
|
moving_distance = (dialog_render_info.contents.size - height) * 2
|
@@ -674,25 +714,28 @@ class Reline::LineEditor
|
|
674
714
|
dialog.scrollbar_pos = nil
|
675
715
|
end
|
676
716
|
upper_space = @first_line_started_from - @started_from
|
677
|
-
lower_space = @highest_in_all - @first_line_started_from - @started_from - 1
|
678
717
|
dialog.column = dialog_render_info.pos.x
|
679
|
-
|
718
|
+
dialog.width += @block_elem_width if dialog.scrollbar_pos
|
719
|
+
diff = (dialog.column + dialog.width) - (@screen_size.last)
|
680
720
|
if diff > 0
|
681
721
|
dialog.column -= diff
|
682
722
|
end
|
683
|
-
if (
|
723
|
+
if (@rest_height - dialog_render_info.pos.y) >= height
|
684
724
|
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
685
725
|
elsif upper_space >= height
|
686
726
|
dialog.vertical_offset = dialog_render_info.pos.y - height
|
687
727
|
else
|
688
|
-
if (
|
728
|
+
if (@rest_height - dialog_render_info.pos.y) < height
|
689
729
|
scroll_down(height + dialog_render_info.pos.y)
|
690
730
|
move_cursor_up(height + dialog_render_info.pos.y)
|
691
731
|
end
|
692
732
|
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
693
733
|
end
|
694
734
|
Reline::IOGate.hide_cursor
|
695
|
-
dialog.
|
735
|
+
if dialog.column < 0
|
736
|
+
dialog.column = 0
|
737
|
+
dialog.width = @screen_size.last
|
738
|
+
end
|
696
739
|
reset_dialog(dialog, old_dialog)
|
697
740
|
move_cursor_down(dialog.vertical_offset)
|
698
741
|
Reline::IOGate.move_cursor_column(dialog.column)
|
@@ -711,19 +754,18 @@ class Reline::LineEditor
|
|
711
754
|
@output.write "\e[#{bg_color}m#{str}"
|
712
755
|
if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
|
713
756
|
@output.write "\e[37m"
|
714
|
-
if dialog.scrollbar_pos <= (i * 2) and (i * 2 +
|
715
|
-
@output.write
|
757
|
+
if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
|
758
|
+
@output.write @full_block
|
716
759
|
elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
717
|
-
@output.write
|
760
|
+
@output.write @upper_half_block
|
718
761
|
str += ''
|
719
|
-
elsif dialog.scrollbar_pos <= (i * 2 +
|
720
|
-
@output.write
|
762
|
+
elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
763
|
+
@output.write @lower_half_block
|
721
764
|
else
|
722
765
|
@output.write ' ' * @block_elem_width
|
723
766
|
end
|
724
|
-
@output.write "\e[39m"
|
725
767
|
end
|
726
|
-
@output.write "\e[
|
768
|
+
@output.write "\e[0m"
|
727
769
|
Reline::IOGate.move_cursor_column(dialog.column)
|
728
770
|
move_cursor_down(1) if i < (dialog.contents.size - 1)
|
729
771
|
end
|
@@ -741,7 +783,7 @@ class Reline::LineEditor
|
|
741
783
|
|
742
784
|
private def reset_dialog(dialog, old_dialog)
|
743
785
|
return if dialog.lines_backup.nil? or old_dialog.contents.nil?
|
744
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines]
|
786
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
|
745
787
|
visual_lines = []
|
746
788
|
visual_start = nil
|
747
789
|
dialog.lines_backup[:lines].each_with_index { |l, i|
|
@@ -769,7 +811,7 @@ class Reline::LineEditor
|
|
769
811
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
770
812
|
s = padding_space_with_escape_sequences(s, old_dialog.width)
|
771
813
|
end
|
772
|
-
@output.write "\e[
|
814
|
+
@output.write "\e[0m#{s}\e[0m"
|
773
815
|
move_cursor_down(1) if i < (line_num - 1)
|
774
816
|
end
|
775
817
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
@@ -787,7 +829,7 @@ class Reline::LineEditor
|
|
787
829
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
788
830
|
s = padding_space_with_escape_sequences(s, old_dialog.width)
|
789
831
|
end
|
790
|
-
@output.write "\e[
|
832
|
+
@output.write "\e[0m#{s}\e[0m"
|
791
833
|
move_cursor_down(1) if i < (line_num - 1)
|
792
834
|
end
|
793
835
|
move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
|
@@ -806,7 +848,7 @@ class Reline::LineEditor
|
|
806
848
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
|
807
849
|
s = padding_space_with_escape_sequences(s, dialog.width)
|
808
850
|
end
|
809
|
-
@output.write "\e[
|
851
|
+
@output.write "\e[0m#{s}\e[0m"
|
810
852
|
move_cursor_down(1) if i < (line_num - 1)
|
811
853
|
end
|
812
854
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
@@ -823,10 +865,11 @@ class Reline::LineEditor
|
|
823
865
|
s = ' ' * width
|
824
866
|
else
|
825
867
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
|
826
|
-
|
868
|
+
rerender_width = old_dialog.width - dialog.width
|
869
|
+
s = padding_space_with_escape_sequences(s, rerender_width)
|
827
870
|
end
|
828
871
|
Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
|
829
|
-
@output.write "\e[
|
872
|
+
@output.write "\e[0m#{s}\e[0m"
|
830
873
|
move_cursor_down(1) if i < (line_num - 1)
|
831
874
|
end
|
832
875
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
|
@@ -843,7 +886,7 @@ class Reline::LineEditor
|
|
843
886
|
private def clear_each_dialog(dialog)
|
844
887
|
dialog.trap_key = nil
|
845
888
|
return unless dialog.contents
|
846
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines]
|
889
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
|
847
890
|
visual_lines = []
|
848
891
|
visual_lines_under_dialog = []
|
849
892
|
visual_start = nil
|
@@ -866,10 +909,10 @@ class Reline::LineEditor
|
|
866
909
|
Reline::IOGate.move_cursor_column(dialog.column)
|
867
910
|
str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
|
868
911
|
str = padding_space_with_escape_sequences(str, dialog.width)
|
869
|
-
@output.write "\e[
|
912
|
+
@output.write "\e[0m#{str}\e[0m"
|
870
913
|
else
|
871
914
|
Reline::IOGate.move_cursor_column(dialog.column)
|
872
|
-
@output.write "\e[
|
915
|
+
@output.write "\e[0m#{' ' * dialog.width}\e[0m"
|
873
916
|
end
|
874
917
|
move_cursor_down(1) if i < (dialog_vertical_size - 1)
|
875
918
|
end
|
@@ -928,7 +971,7 @@ class Reline::LineEditor
|
|
928
971
|
end
|
929
972
|
|
930
973
|
def just_move_cursor
|
931
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines
|
974
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
|
932
975
|
move_cursor_up(@started_from)
|
933
976
|
new_first_line_started_from =
|
934
977
|
if @line_index.zero?
|
@@ -965,7 +1008,7 @@ class Reline::LineEditor
|
|
965
1008
|
else
|
966
1009
|
new_lines = whole_lines
|
967
1010
|
end
|
968
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines
|
1011
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
969
1012
|
all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
|
970
1013
|
diff = all_height - @highest_in_all
|
971
1014
|
move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
|
@@ -1012,7 +1055,7 @@ class Reline::LineEditor
|
|
1012
1055
|
Reline::IOGate.move_cursor_column(0)
|
1013
1056
|
back = 0
|
1014
1057
|
new_buffer = whole_lines
|
1015
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer
|
1058
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
|
1016
1059
|
new_buffer.each_with_index do |line, index|
|
1017
1060
|
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
1018
1061
|
width = prompt_width + calculate_width(line)
|
@@ -1402,7 +1445,10 @@ class Reline::LineEditor
|
|
1402
1445
|
end
|
1403
1446
|
@waiting_operator_proc = nil
|
1404
1447
|
@waiting_operator_vi_arg = nil
|
1405
|
-
@vi_arg
|
1448
|
+
if @vi_arg
|
1449
|
+
@rerender_all = true
|
1450
|
+
@vi_arg = nil
|
1451
|
+
end
|
1406
1452
|
else
|
1407
1453
|
block.(false)
|
1408
1454
|
end
|
@@ -1453,7 +1499,10 @@ class Reline::LineEditor
|
|
1453
1499
|
wrap_method_call(method_symbol, method_obj, key) if method_obj
|
1454
1500
|
end
|
1455
1501
|
@kill_ring.process
|
1456
|
-
@vi_arg
|
1502
|
+
if @vi_arg
|
1503
|
+
@rerender_al = true
|
1504
|
+
@vi_arg = nil
|
1505
|
+
end
|
1457
1506
|
elsif @vi_arg
|
1458
1507
|
if key.chr =~ /[0-9]/
|
1459
1508
|
ed_argument_digit(key)
|
@@ -1470,7 +1519,10 @@ class Reline::LineEditor
|
|
1470
1519
|
ed_insert(key) unless @config.editing_mode_is?(:vi_command)
|
1471
1520
|
end
|
1472
1521
|
@kill_ring.process
|
1473
|
-
@vi_arg
|
1522
|
+
if @vi_arg
|
1523
|
+
@rerender_all = true
|
1524
|
+
@vi_arg = nil
|
1525
|
+
end
|
1474
1526
|
end
|
1475
1527
|
elsif @waiting_proc
|
1476
1528
|
@waiting_proc.(key)
|
@@ -1909,6 +1961,8 @@ class Reline::LineEditor
|
|
1909
1961
|
end
|
1910
1962
|
end
|
1911
1963
|
|
1964
|
+
# Editline:: +ed-unassigned+ This editor command always results in an error.
|
1965
|
+
# GNU Readline:: There is no corresponding macro.
|
1912
1966
|
private def ed_unassigned(key) end # do nothing
|
1913
1967
|
|
1914
1968
|
private def process_insert(force: false)
|
@@ -1926,6 +1980,19 @@ class Reline::LineEditor
|
|
1926
1980
|
@continuous_insertion_buffer.clear
|
1927
1981
|
end
|
1928
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.
|
1929
1996
|
private def ed_insert(key)
|
1930
1997
|
str = nil
|
1931
1998
|
width = nil
|
@@ -1962,8 +2029,16 @@ class Reline::LineEditor
|
|
1962
2029
|
last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
1963
2030
|
@byte_pointer += bytesize
|
1964
2031
|
last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
|
1965
|
-
|
1966
|
-
|
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
|
1967
2042
|
end
|
1968
2043
|
@cursor += width
|
1969
2044
|
@cursor_max += width
|
@@ -1976,6 +2051,8 @@ class Reline::LineEditor
|
|
1976
2051
|
arg.times do
|
1977
2052
|
if key == "\C-j".ord or key == "\C-m".ord
|
1978
2053
|
key_newline(key)
|
2054
|
+
elsif key == 0
|
2055
|
+
# Ignore NUL.
|
1979
2056
|
else
|
1980
2057
|
ed_insert(key)
|
1981
2058
|
end
|
@@ -2410,6 +2487,7 @@ class Reline::LineEditor
|
|
2410
2487
|
arg -= 1
|
2411
2488
|
ed_prev_history(key, arg: arg) if arg > 0
|
2412
2489
|
end
|
2490
|
+
alias_method :previous_history, :ed_prev_history
|
2413
2491
|
|
2414
2492
|
private def ed_next_history(key, arg: 1)
|
2415
2493
|
if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
|
@@ -2457,6 +2535,7 @@ class Reline::LineEditor
|
|
2457
2535
|
arg -= 1
|
2458
2536
|
ed_next_history(key, arg: arg) if arg > 0
|
2459
2537
|
end
|
2538
|
+
alias_method :next_history, :ed_next_history
|
2460
2539
|
|
2461
2540
|
private def ed_newline(key)
|
2462
2541
|
process_insert(force: true)
|
@@ -2491,7 +2570,7 @@ class Reline::LineEditor
|
|
2491
2570
|
end
|
2492
2571
|
end
|
2493
2572
|
|
2494
|
-
private def em_delete_prev_char(key)
|
2573
|
+
private def em_delete_prev_char(key, arg: 1)
|
2495
2574
|
if @is_multiline and @cursor == 0 and @line_index > 0
|
2496
2575
|
@buffer_of_lines[@line_index] = @line
|
2497
2576
|
@cursor = calculate_width(@buffer_of_lines[@line_index - 1])
|
@@ -2509,9 +2588,16 @@ class Reline::LineEditor
|
|
2509
2588
|
@cursor -= width
|
2510
2589
|
@cursor_max -= width
|
2511
2590
|
end
|
2591
|
+
arg -= 1
|
2592
|
+
em_delete_prev_char(key, arg: arg) if arg > 0
|
2512
2593
|
end
|
2513
2594
|
alias_method :backward_delete_char, :em_delete_prev_char
|
2514
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.
|
2515
2601
|
private def ed_kill_line(key)
|
2516
2602
|
if @line.bytesize > @byte_pointer
|
2517
2603
|
@line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
|
@@ -2528,8 +2614,14 @@ class Reline::LineEditor
|
|
2528
2614
|
@rest_height += 1
|
2529
2615
|
end
|
2530
2616
|
end
|
2617
|
+
alias_method :kill_line, :ed_kill_line
|
2531
2618
|
|
2532
|
-
|
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)
|
2533
2625
|
if @byte_pointer > 0
|
2534
2626
|
@line, deleted = byteslice!(@line, 0, @byte_pointer)
|
2535
2627
|
@byte_pointer = 0
|
@@ -2538,7 +2630,22 @@ class Reline::LineEditor
|
|
2538
2630
|
@cursor = 0
|
2539
2631
|
end
|
2540
2632
|
end
|
2541
|
-
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
|
2542
2649
|
|
2543
2650
|
private def em_delete(key)
|
2544
2651
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
@@ -3043,7 +3150,14 @@ class Reline::LineEditor
|
|
3043
3150
|
|
3044
3151
|
private def ed_argument_digit(key)
|
3045
3152
|
if @vi_arg.nil?
|
3046
|
-
|
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
|
3047
3161
|
@vi_arg = key.chr.to_i
|
3048
3162
|
end
|
3049
3163
|
else
|