reline 0.2.8.pre.8 → 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 +50 -23
- data/lib/reline/config.rb +10 -2
- 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 +239 -110
- data/lib/reline/terminfo.rb +12 -4
- 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 +31 -23
- metadata +4 -5
- data/lib/reline/line_editor.rb.orig +0 -3199
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,74 @@ 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') {
|
154
222
|
clear_dialog
|
155
223
|
if @scroll_partial_screen
|
156
224
|
move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
|
@@ -167,50 +235,24 @@ 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
|
-
|
174
|
-
@
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
@rerender_all = true
|
180
|
-
rerender
|
181
|
-
else
|
182
|
-
back = 0
|
183
|
-
new_buffer = whole_lines
|
184
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
185
|
-
new_buffer.each_with_index do |line, index|
|
186
|
-
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
187
|
-
width = prompt_width + calculate_width(line)
|
188
|
-
height = calculate_height_by_width(width)
|
189
|
-
back += height
|
190
|
-
end
|
191
|
-
@highest_in_all = back
|
192
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
193
|
-
@first_line_started_from =
|
194
|
-
if @line_index.zero?
|
195
|
-
0
|
196
|
-
else
|
197
|
-
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
198
|
-
end
|
199
|
-
if @prompt_proc
|
200
|
-
prompt = prompt_list[@line_index]
|
201
|
-
prompt_width = calculate_width(prompt, true)
|
202
|
-
end
|
203
|
-
calculate_nearest_cursor
|
204
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
205
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
206
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
207
|
-
@rerender_all = true
|
208
|
-
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
|
209
247
|
end
|
210
248
|
end
|
211
249
|
|
212
250
|
def finalize
|
213
|
-
Signal.trap('
|
251
|
+
Signal.trap('INT', @old_trap)
|
252
|
+
begin
|
253
|
+
Signal.trap('TSTP', @old_tstp_trap)
|
254
|
+
rescue ArgumentError
|
255
|
+
end
|
214
256
|
end
|
215
257
|
|
216
258
|
def eof?
|
@@ -218,7 +260,7 @@ class Reline::LineEditor
|
|
218
260
|
end
|
219
261
|
|
220
262
|
def reset_variables(prompt = '', encoding:)
|
221
|
-
@prompt = prompt
|
263
|
+
@prompt = prompt.gsub("\n", "\\n")
|
222
264
|
@mark_pointer = nil
|
223
265
|
@encoding = encoding
|
224
266
|
@is_multiline = false
|
@@ -252,6 +294,7 @@ class Reline::LineEditor
|
|
252
294
|
@auto_indent_proc = nil
|
253
295
|
@dialogs = []
|
254
296
|
@last_key = nil
|
297
|
+
@resized = false
|
255
298
|
reset_line
|
256
299
|
end
|
257
300
|
|
@@ -395,7 +438,7 @@ class Reline::LineEditor
|
|
395
438
|
show_menu
|
396
439
|
@menu_info = nil
|
397
440
|
end
|
398
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
441
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
399
442
|
if @cleared
|
400
443
|
clear_screen_buffer(prompt, prompt_list, prompt_width)
|
401
444
|
@cleared = false
|
@@ -406,7 +449,7 @@ class Reline::LineEditor
|
|
406
449
|
Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
|
407
450
|
Reline::IOGate.move_cursor_column(0)
|
408
451
|
@scroll_partial_screen = nil
|
409
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
452
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
410
453
|
if @previous_line_index
|
411
454
|
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
412
455
|
else
|
@@ -452,7 +495,7 @@ class Reline::LineEditor
|
|
452
495
|
end
|
453
496
|
line = modify_lines(new_lines)[@line_index]
|
454
497
|
clear_dialog
|
455
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines
|
498
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
456
499
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
457
500
|
move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
|
458
501
|
scroll_down(1)
|
@@ -461,7 +504,7 @@ class Reline::LineEditor
|
|
461
504
|
else
|
462
505
|
if not rendered and not @in_pasting
|
463
506
|
line = modify_lines(whole_lines)[@line_index]
|
464
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines
|
507
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
|
465
508
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
466
509
|
end
|
467
510
|
render_dialog((prompt_width + @cursor) % @screen_size.last)
|
@@ -548,7 +591,7 @@ class Reline::LineEditor
|
|
548
591
|
|
549
592
|
class Dialog
|
550
593
|
attr_reader :name, :contents, :width
|
551
|
-
attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup, :trap_key
|
594
|
+
attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
|
552
595
|
|
553
596
|
def initialize(name, config, proc_scope)
|
554
597
|
@name = name
|
@@ -556,6 +599,7 @@ class Reline::LineEditor
|
|
556
599
|
@proc_scope = proc_scope
|
557
600
|
@width = nil
|
558
601
|
@scroll_top = 0
|
602
|
+
@trap_key = nil
|
559
603
|
end
|
560
604
|
|
561
605
|
def set_cursor_pos(col, row)
|
@@ -593,11 +637,15 @@ class Reline::LineEditor
|
|
593
637
|
end
|
594
638
|
|
595
639
|
def add_dialog_proc(name, p, context = nil)
|
596
|
-
|
597
|
-
@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
|
598
646
|
end
|
599
647
|
|
600
|
-
|
648
|
+
DIALOG_DEFAULT_HEIGHT = 20
|
601
649
|
private def render_dialog(cursor_column)
|
602
650
|
@dialogs.each do |dialog|
|
603
651
|
render_each_dialog(dialog, cursor_column)
|
@@ -610,6 +658,7 @@ class Reline::LineEditor
|
|
610
658
|
|
611
659
|
private def render_each_dialog(dialog, cursor_column)
|
612
660
|
if @in_pasting
|
661
|
+
clear_each_dialog(dialog)
|
613
662
|
dialog.contents = nil
|
614
663
|
dialog.trap_key = nil
|
615
664
|
return
|
@@ -631,56 +680,65 @@ class Reline::LineEditor
|
|
631
680
|
end
|
632
681
|
old_dialog = dialog.clone
|
633
682
|
dialog.contents = dialog_render_info.contents
|
634
|
-
pointer =
|
683
|
+
pointer = dialog.pointer
|
635
684
|
if dialog_render_info.width
|
636
685
|
dialog.width = dialog_render_info.width
|
637
686
|
else
|
638
687
|
dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
|
639
688
|
end
|
640
|
-
height = dialog_render_info.height ||
|
689
|
+
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
|
641
690
|
height = dialog.contents.size if dialog.contents.size < height
|
642
691
|
if dialog.contents.size > height
|
643
|
-
if
|
644
|
-
if
|
692
|
+
if dialog.pointer
|
693
|
+
if dialog.pointer < 0
|
645
694
|
dialog.scroll_top = 0
|
646
|
-
elsif (
|
647
|
-
dialog.scroll_top =
|
648
|
-
elsif (
|
649
|
-
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
|
650
699
|
end
|
651
|
-
pointer =
|
700
|
+
pointer = dialog.pointer - dialog.scroll_top
|
652
701
|
end
|
653
702
|
dialog.contents = dialog.contents[dialog.scroll_top, height]
|
654
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
|
655
716
|
upper_space = @first_line_started_from - @started_from
|
656
|
-
lower_space = @highest_in_all - @first_line_started_from - @started_from - 1
|
657
717
|
dialog.column = dialog_render_info.pos.x
|
658
|
-
|
718
|
+
dialog.width += @block_elem_width if dialog.scrollbar_pos
|
719
|
+
diff = (dialog.column + dialog.width) - (@screen_size.last)
|
659
720
|
if diff > 0
|
660
721
|
dialog.column -= diff
|
661
722
|
end
|
662
|
-
if (
|
723
|
+
if (@rest_height - dialog_render_info.pos.y) >= height
|
663
724
|
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
664
725
|
elsif upper_space >= height
|
665
726
|
dialog.vertical_offset = dialog_render_info.pos.y - height
|
666
727
|
else
|
667
|
-
if (
|
728
|
+
if (@rest_height - dialog_render_info.pos.y) < height
|
668
729
|
scroll_down(height + dialog_render_info.pos.y)
|
669
730
|
move_cursor_up(height + dialog_render_info.pos.y)
|
670
731
|
end
|
671
732
|
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
672
733
|
end
|
673
734
|
Reline::IOGate.hide_cursor
|
735
|
+
if dialog.column < 0
|
736
|
+
dialog.column = 0
|
737
|
+
dialog.width = @screen_size.last
|
738
|
+
end
|
674
739
|
reset_dialog(dialog, old_dialog)
|
675
740
|
move_cursor_down(dialog.vertical_offset)
|
676
741
|
Reline::IOGate.move_cursor_column(dialog.column)
|
677
|
-
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
678
|
-
bar_max_height = height * 2
|
679
|
-
moving_distance = (dialog_render_info.contents.size - height) * 2
|
680
|
-
position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
|
681
|
-
bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
|
682
|
-
position = ((bar_max_height - bar_height) * position_ratio).floor.to_i
|
683
|
-
end
|
684
742
|
dialog.contents.each_with_index do |item, i|
|
685
743
|
if i == pointer
|
686
744
|
bg_color = '45'
|
@@ -691,27 +749,26 @@ class Reline::LineEditor
|
|
691
749
|
bg_color = '46'
|
692
750
|
end
|
693
751
|
end
|
694
|
-
|
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)
|
695
754
|
@output.write "\e[#{bg_color}m#{str}"
|
696
|
-
if
|
755
|
+
if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
|
697
756
|
@output.write "\e[37m"
|
698
|
-
if
|
699
|
-
@output.write
|
700
|
-
elsif
|
701
|
-
@output.write
|
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
|
702
761
|
str += ''
|
703
|
-
elsif
|
704
|
-
@output.write
|
762
|
+
elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
763
|
+
@output.write @lower_half_block
|
705
764
|
else
|
706
|
-
@output.write ' '
|
765
|
+
@output.write ' ' * @block_elem_width
|
707
766
|
end
|
708
|
-
@output.write "\e[39m"
|
709
767
|
end
|
710
|
-
@output.write "\e[
|
768
|
+
@output.write "\e[0m"
|
711
769
|
Reline::IOGate.move_cursor_column(dialog.column)
|
712
770
|
move_cursor_down(1) if i < (dialog.contents.size - 1)
|
713
771
|
end
|
714
|
-
dialog.width += 1 if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
715
772
|
Reline::IOGate.move_cursor_column(cursor_column)
|
716
773
|
move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
|
717
774
|
Reline::IOGate.show_cursor
|
@@ -726,7 +783,7 @@ class Reline::LineEditor
|
|
726
783
|
|
727
784
|
private def reset_dialog(dialog, old_dialog)
|
728
785
|
return if dialog.lines_backup.nil? or old_dialog.contents.nil?
|
729
|
-
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])
|
730
787
|
visual_lines = []
|
731
788
|
visual_start = nil
|
732
789
|
dialog.lines_backup[:lines].each_with_index { |l, i|
|
@@ -749,12 +806,12 @@ class Reline::LineEditor
|
|
749
806
|
line_num.times do |i|
|
750
807
|
Reline::IOGate.move_cursor_column(old_dialog.column)
|
751
808
|
if visual_lines[start + i].nil?
|
752
|
-
s = ' ' *
|
809
|
+
s = ' ' * old_dialog.width
|
753
810
|
else
|
754
|
-
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column,
|
755
|
-
s = padding_space_with_escape_sequences(s,
|
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)
|
756
813
|
end
|
757
|
-
@output.write "\e[
|
814
|
+
@output.write "\e[0m#{s}\e[0m"
|
758
815
|
move_cursor_down(1) if i < (line_num - 1)
|
759
816
|
end
|
760
817
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
@@ -767,12 +824,12 @@ class Reline::LineEditor
|
|
767
824
|
line_num.times do |i|
|
768
825
|
Reline::IOGate.move_cursor_column(old_dialog.column)
|
769
826
|
if visual_lines[start + i].nil?
|
770
|
-
s = ' ' *
|
827
|
+
s = ' ' * old_dialog.width
|
771
828
|
else
|
772
|
-
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column,
|
773
|
-
s = padding_space_with_escape_sequences(s,
|
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)
|
774
831
|
end
|
775
|
-
@output.write "\e[
|
832
|
+
@output.write "\e[0m#{s}\e[0m"
|
776
833
|
move_cursor_down(1) if i < (line_num - 1)
|
777
834
|
end
|
778
835
|
move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
|
@@ -791,7 +848,7 @@ class Reline::LineEditor
|
|
791
848
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
|
792
849
|
s = padding_space_with_escape_sequences(s, dialog.width)
|
793
850
|
end
|
794
|
-
@output.write "\e[
|
851
|
+
@output.write "\e[0m#{s}\e[0m"
|
795
852
|
move_cursor_down(1) if i < (line_num - 1)
|
796
853
|
end
|
797
854
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
@@ -808,10 +865,11 @@ class Reline::LineEditor
|
|
808
865
|
s = ' ' * width
|
809
866
|
else
|
810
867
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
|
811
|
-
|
868
|
+
rerender_width = old_dialog.width - dialog.width
|
869
|
+
s = padding_space_with_escape_sequences(s, rerender_width)
|
812
870
|
end
|
813
871
|
Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
|
814
|
-
@output.write "\e[
|
872
|
+
@output.write "\e[0m#{s}\e[0m"
|
815
873
|
move_cursor_down(1) if i < (line_num - 1)
|
816
874
|
end
|
817
875
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
|
@@ -828,7 +886,7 @@ class Reline::LineEditor
|
|
828
886
|
private def clear_each_dialog(dialog)
|
829
887
|
dialog.trap_key = nil
|
830
888
|
return unless dialog.contents
|
831
|
-
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])
|
832
890
|
visual_lines = []
|
833
891
|
visual_lines_under_dialog = []
|
834
892
|
visual_start = nil
|
@@ -851,10 +909,10 @@ class Reline::LineEditor
|
|
851
909
|
Reline::IOGate.move_cursor_column(dialog.column)
|
852
910
|
str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
|
853
911
|
str = padding_space_with_escape_sequences(str, dialog.width)
|
854
|
-
@output.write "\e[
|
912
|
+
@output.write "\e[0m#{str}\e[0m"
|
855
913
|
else
|
856
914
|
Reline::IOGate.move_cursor_column(dialog.column)
|
857
|
-
@output.write "\e[
|
915
|
+
@output.write "\e[0m#{' ' * dialog.width}\e[0m"
|
858
916
|
end
|
859
917
|
move_cursor_down(1) if i < (dialog_vertical_size - 1)
|
860
918
|
end
|
@@ -913,7 +971,7 @@ class Reline::LineEditor
|
|
913
971
|
end
|
914
972
|
|
915
973
|
def just_move_cursor
|
916
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines
|
974
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
|
917
975
|
move_cursor_up(@started_from)
|
918
976
|
new_first_line_started_from =
|
919
977
|
if @line_index.zero?
|
@@ -950,7 +1008,7 @@ class Reline::LineEditor
|
|
950
1008
|
else
|
951
1009
|
new_lines = whole_lines
|
952
1010
|
end
|
953
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines
|
1011
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
954
1012
|
all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
|
955
1013
|
diff = all_height - @highest_in_all
|
956
1014
|
move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
|
@@ -997,7 +1055,7 @@ class Reline::LineEditor
|
|
997
1055
|
Reline::IOGate.move_cursor_column(0)
|
998
1056
|
back = 0
|
999
1057
|
new_buffer = whole_lines
|
1000
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer
|
1058
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
|
1001
1059
|
new_buffer.each_with_index do |line, index|
|
1002
1060
|
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
1003
1061
|
width = prompt_width + calculate_width(line)
|
@@ -1204,7 +1262,7 @@ class Reline::LineEditor
|
|
1204
1262
|
height = render_partial(prompt, prompt_width, line, back, with_control: false)
|
1205
1263
|
end
|
1206
1264
|
if index < (@buffer_of_lines.size - 1)
|
1207
|
-
move_cursor_down(
|
1265
|
+
move_cursor_down(1)
|
1208
1266
|
back += height
|
1209
1267
|
end
|
1210
1268
|
end
|
@@ -1387,7 +1445,10 @@ class Reline::LineEditor
|
|
1387
1445
|
end
|
1388
1446
|
@waiting_operator_proc = nil
|
1389
1447
|
@waiting_operator_vi_arg = nil
|
1390
|
-
@vi_arg
|
1448
|
+
if @vi_arg
|
1449
|
+
@rerender_all = true
|
1450
|
+
@vi_arg = nil
|
1451
|
+
end
|
1391
1452
|
else
|
1392
1453
|
block.(false)
|
1393
1454
|
end
|
@@ -1438,7 +1499,10 @@ class Reline::LineEditor
|
|
1438
1499
|
wrap_method_call(method_symbol, method_obj, key) if method_obj
|
1439
1500
|
end
|
1440
1501
|
@kill_ring.process
|
1441
|
-
@vi_arg
|
1502
|
+
if @vi_arg
|
1503
|
+
@rerender_al = true
|
1504
|
+
@vi_arg = nil
|
1505
|
+
end
|
1442
1506
|
elsif @vi_arg
|
1443
1507
|
if key.chr =~ /[0-9]/
|
1444
1508
|
ed_argument_digit(key)
|
@@ -1455,7 +1519,10 @@ class Reline::LineEditor
|
|
1455
1519
|
ed_insert(key) unless @config.editing_mode_is?(:vi_command)
|
1456
1520
|
end
|
1457
1521
|
@kill_ring.process
|
1458
|
-
@vi_arg
|
1522
|
+
if @vi_arg
|
1523
|
+
@rerender_all = true
|
1524
|
+
@vi_arg = nil
|
1525
|
+
end
|
1459
1526
|
end
|
1460
1527
|
elsif @waiting_proc
|
1461
1528
|
@waiting_proc.(key)
|
@@ -1894,6 +1961,8 @@ class Reline::LineEditor
|
|
1894
1961
|
end
|
1895
1962
|
end
|
1896
1963
|
|
1964
|
+
# Editline:: +ed-unassigned+ This editor command always results in an error.
|
1965
|
+
# GNU Readline:: There is no corresponding macro.
|
1897
1966
|
private def ed_unassigned(key) end # do nothing
|
1898
1967
|
|
1899
1968
|
private def process_insert(force: false)
|
@@ -1911,6 +1980,19 @@ class Reline::LineEditor
|
|
1911
1980
|
@continuous_insertion_buffer.clear
|
1912
1981
|
end
|
1913
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.
|
1914
1996
|
private def ed_insert(key)
|
1915
1997
|
str = nil
|
1916
1998
|
width = nil
|
@@ -1947,8 +2029,16 @@ class Reline::LineEditor
|
|
1947
2029
|
last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
1948
2030
|
@byte_pointer += bytesize
|
1949
2031
|
last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
|
1950
|
-
|
1951
|
-
|
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
|
1952
2042
|
end
|
1953
2043
|
@cursor += width
|
1954
2044
|
@cursor_max += width
|
@@ -1961,6 +2051,8 @@ class Reline::LineEditor
|
|
1961
2051
|
arg.times do
|
1962
2052
|
if key == "\C-j".ord or key == "\C-m".ord
|
1963
2053
|
key_newline(key)
|
2054
|
+
elsif key == 0
|
2055
|
+
# Ignore NUL.
|
1964
2056
|
else
|
1965
2057
|
ed_insert(key)
|
1966
2058
|
end
|
@@ -2395,6 +2487,7 @@ class Reline::LineEditor
|
|
2395
2487
|
arg -= 1
|
2396
2488
|
ed_prev_history(key, arg: arg) if arg > 0
|
2397
2489
|
end
|
2490
|
+
alias_method :previous_history, :ed_prev_history
|
2398
2491
|
|
2399
2492
|
private def ed_next_history(key, arg: 1)
|
2400
2493
|
if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
|
@@ -2442,6 +2535,7 @@ class Reline::LineEditor
|
|
2442
2535
|
arg -= 1
|
2443
2536
|
ed_next_history(key, arg: arg) if arg > 0
|
2444
2537
|
end
|
2538
|
+
alias_method :next_history, :ed_next_history
|
2445
2539
|
|
2446
2540
|
private def ed_newline(key)
|
2447
2541
|
process_insert(force: true)
|
@@ -2476,7 +2570,7 @@ class Reline::LineEditor
|
|
2476
2570
|
end
|
2477
2571
|
end
|
2478
2572
|
|
2479
|
-
private def em_delete_prev_char(key)
|
2573
|
+
private def em_delete_prev_char(key, arg: 1)
|
2480
2574
|
if @is_multiline and @cursor == 0 and @line_index > 0
|
2481
2575
|
@buffer_of_lines[@line_index] = @line
|
2482
2576
|
@cursor = calculate_width(@buffer_of_lines[@line_index - 1])
|
@@ -2494,9 +2588,16 @@ class Reline::LineEditor
|
|
2494
2588
|
@cursor -= width
|
2495
2589
|
@cursor_max -= width
|
2496
2590
|
end
|
2591
|
+
arg -= 1
|
2592
|
+
em_delete_prev_char(key, arg: arg) if arg > 0
|
2497
2593
|
end
|
2498
2594
|
alias_method :backward_delete_char, :em_delete_prev_char
|
2499
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.
|
2500
2601
|
private def ed_kill_line(key)
|
2501
2602
|
if @line.bytesize > @byte_pointer
|
2502
2603
|
@line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
|
@@ -2513,8 +2614,14 @@ class Reline::LineEditor
|
|
2513
2614
|
@rest_height += 1
|
2514
2615
|
end
|
2515
2616
|
end
|
2617
|
+
alias_method :kill_line, :ed_kill_line
|
2516
2618
|
|
2517
|
-
|
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)
|
2518
2625
|
if @byte_pointer > 0
|
2519
2626
|
@line, deleted = byteslice!(@line, 0, @byte_pointer)
|
2520
2627
|
@byte_pointer = 0
|
@@ -2523,7 +2630,22 @@ class Reline::LineEditor
|
|
2523
2630
|
@cursor = 0
|
2524
2631
|
end
|
2525
2632
|
end
|
2526
|
-
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
|
2527
2649
|
|
2528
2650
|
private def em_delete(key)
|
2529
2651
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
@@ -3028,7 +3150,14 @@ class Reline::LineEditor
|
|
3028
3150
|
|
3029
3151
|
private def ed_argument_digit(key)
|
3030
3152
|
if @vi_arg.nil?
|
3031
|
-
|
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
|
3032
3161
|
@vi_arg = key.chr.to_i
|
3033
3162
|
end
|
3034
3163
|
else
|