reline 0.2.8.pre.7 → 0.2.8.pre.11
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 +8 -3
- data/lib/reline/config.rb +20 -3
- data/lib/reline/key_actor/emacs.rb +1 -1
- data/lib/reline/key_stroke.rb +63 -14
- data/lib/reline/line_editor.rb +223 -74
- data/lib/reline/terminfo.rb +1 -1
- data/lib/reline/unicode.rb +3 -3
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +18 -16
- data/lib/reline.rb +53 -27
- metadata +3 -4
- data/lib/reline/line_editor.rb.orig +0 -3156
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
|
@@ -150,7 +151,7 @@ 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
|
-
@old_trap = Signal.trap(
|
154
|
+
@old_trap = Signal.trap('INT') {
|
154
155
|
clear_dialog
|
155
156
|
if @scroll_partial_screen
|
156
157
|
move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
|
@@ -170,47 +171,85 @@ class Reline::LineEditor
|
|
170
171
|
@old_trap.call
|
171
172
|
end
|
172
173
|
}
|
174
|
+
begin
|
175
|
+
@old_tstp_trap = Signal.trap('TSTP') {
|
176
|
+
Reline::IOGate.ungetc("\C-z".ord)
|
177
|
+
@old_tstp_trap.call if @old_tstp_trap.respond_to?(:call)
|
178
|
+
}
|
179
|
+
rescue ArgumentError
|
180
|
+
end
|
173
181
|
Reline::IOGate.set_winch_handler do
|
174
|
-
@
|
175
|
-
|
176
|
-
|
177
|
-
@
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
182
|
+
@resized = true
|
183
|
+
end
|
184
|
+
if ENV.key?('RELINE_ALT_SCROLLBAR')
|
185
|
+
@full_block = '::'
|
186
|
+
@upper_half_block = "''"
|
187
|
+
@lower_half_block = '..'
|
188
|
+
@block_elem_width = 2
|
189
|
+
elsif Reline::IOGate.win?
|
190
|
+
@full_block = '█'
|
191
|
+
@upper_half_block = '▀'
|
192
|
+
@lower_half_block = '▄'
|
193
|
+
@block_elem_width = 1
|
194
|
+
elsif @encoding == Encoding::UTF_8
|
195
|
+
@full_block = '█'
|
196
|
+
@upper_half_block = '▀'
|
197
|
+
@lower_half_block = '▄'
|
198
|
+
@block_elem_width = Reline::Unicode.calculate_width('█')
|
199
|
+
else
|
200
|
+
@full_block = '::'
|
201
|
+
@upper_half_block = "''"
|
202
|
+
@lower_half_block = '..'
|
203
|
+
@block_elem_width = 2
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def resize
|
208
|
+
return unless @resized
|
209
|
+
@resized = false
|
210
|
+
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
211
|
+
old_screen_size = @screen_size
|
212
|
+
@screen_size = Reline::IOGate.get_screen_size
|
213
|
+
@screen_height = @screen_size.first
|
214
|
+
if old_screen_size.last < @screen_size.last # columns increase
|
215
|
+
@rerender_all = true
|
216
|
+
rerender
|
217
|
+
else
|
218
|
+
back = 0
|
219
|
+
new_buffer = whole_lines
|
220
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
221
|
+
new_buffer.each_with_index do |line, index|
|
222
|
+
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
223
|
+
width = prompt_width + calculate_width(line)
|
224
|
+
height = calculate_height_by_width(width)
|
225
|
+
back += height
|
226
|
+
end
|
227
|
+
@highest_in_all = back
|
228
|
+
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
229
|
+
@first_line_started_from =
|
230
|
+
if @line_index.zero?
|
231
|
+
0
|
232
|
+
else
|
233
|
+
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
202
234
|
end
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
207
|
-
@rerender_all = true
|
235
|
+
if @prompt_proc
|
236
|
+
prompt = prompt_list[@line_index]
|
237
|
+
prompt_width = calculate_width(prompt, true)
|
208
238
|
end
|
239
|
+
calculate_nearest_cursor
|
240
|
+
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
241
|
+
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
242
|
+
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
243
|
+
@rerender_all = true
|
209
244
|
end
|
210
245
|
end
|
211
246
|
|
212
247
|
def finalize
|
213
|
-
Signal.trap('
|
248
|
+
Signal.trap('INT', @old_trap)
|
249
|
+
begin
|
250
|
+
Signal.trap('TSTP', @old_tstp_trap)
|
251
|
+
rescue ArgumentError
|
252
|
+
end
|
214
253
|
end
|
215
254
|
|
216
255
|
def eof?
|
@@ -252,6 +291,7 @@ class Reline::LineEditor
|
|
252
291
|
@auto_indent_proc = nil
|
253
292
|
@dialogs = []
|
254
293
|
@last_key = nil
|
294
|
+
@resized = false
|
255
295
|
reset_line
|
256
296
|
end
|
257
297
|
|
@@ -548,13 +588,15 @@ class Reline::LineEditor
|
|
548
588
|
|
549
589
|
class Dialog
|
550
590
|
attr_reader :name, :contents, :width
|
551
|
-
attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup, :trap_key
|
591
|
+
attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
|
552
592
|
|
553
|
-
def initialize(name, proc_scope)
|
593
|
+
def initialize(name, config, proc_scope)
|
554
594
|
@name = name
|
595
|
+
@config = config
|
555
596
|
@proc_scope = proc_scope
|
556
597
|
@width = nil
|
557
598
|
@scroll_top = 0
|
599
|
+
@trap_key = nil
|
558
600
|
end
|
559
601
|
|
560
602
|
def set_cursor_pos(col, row)
|
@@ -575,16 +617,28 @@ class Reline::LineEditor
|
|
575
617
|
def call(key)
|
576
618
|
@proc_scope.set_dialog(self)
|
577
619
|
@proc_scope.set_key(key)
|
578
|
-
@proc_scope.call
|
620
|
+
dialog_render_info = @proc_scope.call
|
621
|
+
if @trap_key
|
622
|
+
if @trap_key.any?{ |i| i.is_a?(Array) } # multiple trap
|
623
|
+
@trap_key.each do |t|
|
624
|
+
@config.add_oneshot_key_binding(t, @name)
|
625
|
+
end
|
626
|
+
elsif @trap_key.is_a?(Array)
|
627
|
+
@config.add_oneshot_key_binding(@trap_key, @name)
|
628
|
+
elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
|
629
|
+
@config.add_oneshot_key_binding([@trap_key], @name)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
dialog_render_info
|
579
633
|
end
|
580
634
|
end
|
581
635
|
|
582
636
|
def add_dialog_proc(name, p, context = nil)
|
583
637
|
return if @dialogs.any? { |d| d.name == name }
|
584
|
-
@dialogs << Dialog.new(name, DialogProcScope.new(self, @config, p, context))
|
638
|
+
@dialogs << Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context))
|
585
639
|
end
|
586
640
|
|
587
|
-
|
641
|
+
DIALOG_DEFAULT_HEIGHT = 20
|
588
642
|
private def render_dialog(cursor_column)
|
589
643
|
@dialogs.each do |dialog|
|
590
644
|
render_each_dialog(dialog, cursor_column)
|
@@ -618,31 +672,44 @@ class Reline::LineEditor
|
|
618
672
|
end
|
619
673
|
old_dialog = dialog.clone
|
620
674
|
dialog.contents = dialog_render_info.contents
|
621
|
-
pointer =
|
675
|
+
pointer = dialog.pointer
|
622
676
|
if dialog_render_info.width
|
623
677
|
dialog.width = dialog_render_info.width
|
624
678
|
else
|
625
679
|
dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
|
626
680
|
end
|
627
|
-
height = dialog_render_info.height ||
|
681
|
+
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
|
628
682
|
height = dialog.contents.size if dialog.contents.size < height
|
629
683
|
if dialog.contents.size > height
|
630
|
-
if
|
631
|
-
if
|
684
|
+
if dialog.pointer
|
685
|
+
if dialog.pointer < 0
|
632
686
|
dialog.scroll_top = 0
|
633
|
-
elsif (
|
634
|
-
dialog.scroll_top =
|
635
|
-
elsif (
|
636
|
-
dialog.scroll_top =
|
687
|
+
elsif (dialog.pointer - dialog.scroll_top) >= (height - 1)
|
688
|
+
dialog.scroll_top = dialog.pointer - (height - 1)
|
689
|
+
elsif (dialog.pointer - dialog.scroll_top) < 0
|
690
|
+
dialog.scroll_top = dialog.pointer
|
637
691
|
end
|
638
|
-
pointer =
|
692
|
+
pointer = dialog.pointer - dialog.scroll_top
|
639
693
|
end
|
640
694
|
dialog.contents = dialog.contents[dialog.scroll_top, height]
|
641
695
|
end
|
696
|
+
if dialog.contents and dialog.scroll_top >= dialog.contents.size
|
697
|
+
dialog.scroll_top = dialog.contents.size - height
|
698
|
+
end
|
699
|
+
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
700
|
+
bar_max_height = height * 2
|
701
|
+
moving_distance = (dialog_render_info.contents.size - height) * 2
|
702
|
+
position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
|
703
|
+
bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
|
704
|
+
dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
|
705
|
+
else
|
706
|
+
dialog.scrollbar_pos = nil
|
707
|
+
end
|
642
708
|
upper_space = @first_line_started_from - @started_from
|
643
709
|
lower_space = @highest_in_all - @first_line_started_from - @started_from - 1
|
644
710
|
dialog.column = dialog_render_info.pos.x
|
645
|
-
|
711
|
+
dialog.width += @block_elem_width if dialog.scrollbar_pos
|
712
|
+
diff = (dialog.column + dialog.width) - (@screen_size.last)
|
646
713
|
if diff > 0
|
647
714
|
dialog.column -= diff
|
648
715
|
end
|
@@ -658,6 +725,10 @@ class Reline::LineEditor
|
|
658
725
|
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
659
726
|
end
|
660
727
|
Reline::IOGate.hide_cursor
|
728
|
+
if dialog.column < 0
|
729
|
+
dialog.column = 0
|
730
|
+
dialog.width = @screen_size.last
|
731
|
+
end
|
661
732
|
reset_dialog(dialog, old_dialog)
|
662
733
|
move_cursor_down(dialog.vertical_offset)
|
663
734
|
Reline::IOGate.move_cursor_column(dialog.column)
|
@@ -671,8 +742,23 @@ class Reline::LineEditor
|
|
671
742
|
bg_color = '46'
|
672
743
|
end
|
673
744
|
end
|
674
|
-
|
675
|
-
|
745
|
+
str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
|
746
|
+
str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
|
747
|
+
@output.write "\e[#{bg_color}m#{str}"
|
748
|
+
if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
|
749
|
+
@output.write "\e[37m"
|
750
|
+
if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
|
751
|
+
@output.write @full_block
|
752
|
+
elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
753
|
+
@output.write @upper_half_block
|
754
|
+
str += ''
|
755
|
+
elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
|
756
|
+
@output.write @lower_half_block
|
757
|
+
else
|
758
|
+
@output.write ' ' * @block_elem_width
|
759
|
+
end
|
760
|
+
end
|
761
|
+
@output.write "\e[0m"
|
676
762
|
Reline::IOGate.move_cursor_column(dialog.column)
|
677
763
|
move_cursor_down(1) if i < (dialog.contents.size - 1)
|
678
764
|
end
|
@@ -713,12 +799,12 @@ class Reline::LineEditor
|
|
713
799
|
line_num.times do |i|
|
714
800
|
Reline::IOGate.move_cursor_column(old_dialog.column)
|
715
801
|
if visual_lines[start + i].nil?
|
716
|
-
s = ' ' *
|
802
|
+
s = ' ' * old_dialog.width
|
717
803
|
else
|
718
|
-
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column,
|
719
|
-
s = padding_space_with_escape_sequences(s,
|
804
|
+
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
805
|
+
s = padding_space_with_escape_sequences(s, old_dialog.width)
|
720
806
|
end
|
721
|
-
@output.write "\e[
|
807
|
+
@output.write "\e[0m#{s}\e[0m"
|
722
808
|
move_cursor_down(1) if i < (line_num - 1)
|
723
809
|
end
|
724
810
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
@@ -731,12 +817,12 @@ class Reline::LineEditor
|
|
731
817
|
line_num.times do |i|
|
732
818
|
Reline::IOGate.move_cursor_column(old_dialog.column)
|
733
819
|
if visual_lines[start + i].nil?
|
734
|
-
s = ' ' *
|
820
|
+
s = ' ' * old_dialog.width
|
735
821
|
else
|
736
|
-
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column,
|
737
|
-
s = padding_space_with_escape_sequences(s,
|
822
|
+
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
|
823
|
+
s = padding_space_with_escape_sequences(s, old_dialog.width)
|
738
824
|
end
|
739
|
-
@output.write "\e[
|
825
|
+
@output.write "\e[0m#{s}\e[0m"
|
740
826
|
move_cursor_down(1) if i < (line_num - 1)
|
741
827
|
end
|
742
828
|
move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
|
@@ -755,7 +841,7 @@ class Reline::LineEditor
|
|
755
841
|
s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
|
756
842
|
s = padding_space_with_escape_sequences(s, dialog.width)
|
757
843
|
end
|
758
|
-
@output.write "\e[
|
844
|
+
@output.write "\e[0m#{s}\e[0m"
|
759
845
|
move_cursor_down(1) if i < (line_num - 1)
|
760
846
|
end
|
761
847
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
|
@@ -775,7 +861,7 @@ class Reline::LineEditor
|
|
775
861
|
s = padding_space_with_escape_sequences(s, dialog.width)
|
776
862
|
end
|
777
863
|
Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
|
778
|
-
@output.write "\e[
|
864
|
+
@output.write "\e[0m#{s}\e[0m"
|
779
865
|
move_cursor_down(1) if i < (line_num - 1)
|
780
866
|
end
|
781
867
|
move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
|
@@ -815,10 +901,10 @@ class Reline::LineEditor
|
|
815
901
|
Reline::IOGate.move_cursor_column(dialog.column)
|
816
902
|
str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
|
817
903
|
str = padding_space_with_escape_sequences(str, dialog.width)
|
818
|
-
@output.write "\e[
|
904
|
+
@output.write "\e[0m#{str}\e[0m"
|
819
905
|
else
|
820
906
|
Reline::IOGate.move_cursor_column(dialog.column)
|
821
|
-
@output.write "\e[
|
907
|
+
@output.write "\e[0m#{' ' * dialog.width}\e[0m"
|
822
908
|
end
|
823
909
|
move_cursor_down(1) if i < (dialog_vertical_size - 1)
|
824
910
|
end
|
@@ -1168,7 +1254,7 @@ class Reline::LineEditor
|
|
1168
1254
|
height = render_partial(prompt, prompt_width, line, back, with_control: false)
|
1169
1255
|
end
|
1170
1256
|
if index < (@buffer_of_lines.size - 1)
|
1171
|
-
move_cursor_down(
|
1257
|
+
move_cursor_down(1)
|
1172
1258
|
back += height
|
1173
1259
|
end
|
1174
1260
|
end
|
@@ -1351,7 +1437,10 @@ class Reline::LineEditor
|
|
1351
1437
|
end
|
1352
1438
|
@waiting_operator_proc = nil
|
1353
1439
|
@waiting_operator_vi_arg = nil
|
1354
|
-
@vi_arg
|
1440
|
+
if @vi_arg
|
1441
|
+
@rerender_all = true
|
1442
|
+
@vi_arg = nil
|
1443
|
+
end
|
1355
1444
|
else
|
1356
1445
|
block.(false)
|
1357
1446
|
end
|
@@ -1402,7 +1491,10 @@ class Reline::LineEditor
|
|
1402
1491
|
wrap_method_call(method_symbol, method_obj, key) if method_obj
|
1403
1492
|
end
|
1404
1493
|
@kill_ring.process
|
1405
|
-
@vi_arg
|
1494
|
+
if @vi_arg
|
1495
|
+
@rerender_al = true
|
1496
|
+
@vi_arg = nil
|
1497
|
+
end
|
1406
1498
|
elsif @vi_arg
|
1407
1499
|
if key.chr =~ /[0-9]/
|
1408
1500
|
ed_argument_digit(key)
|
@@ -1419,7 +1511,10 @@ class Reline::LineEditor
|
|
1419
1511
|
ed_insert(key) unless @config.editing_mode_is?(:vi_command)
|
1420
1512
|
end
|
1421
1513
|
@kill_ring.process
|
1422
|
-
@vi_arg
|
1514
|
+
if @vi_arg
|
1515
|
+
@rerender_all = true
|
1516
|
+
@vi_arg = nil
|
1517
|
+
end
|
1423
1518
|
end
|
1424
1519
|
elsif @waiting_proc
|
1425
1520
|
@waiting_proc.(key)
|
@@ -1478,9 +1573,9 @@ class Reline::LineEditor
|
|
1478
1573
|
|
1479
1574
|
def input_key(key)
|
1480
1575
|
@last_key = key
|
1576
|
+
@config.reset_oneshot_key_bindings
|
1481
1577
|
@dialogs.each do |dialog|
|
1482
|
-
|
1483
|
-
if dialog.trap_key and dialog.trap_key.match?(key)
|
1578
|
+
if key.char.instance_of?(Symbol) and key.char == dialog.name
|
1484
1579
|
return
|
1485
1580
|
end
|
1486
1581
|
end
|
@@ -1858,6 +1953,8 @@ class Reline::LineEditor
|
|
1858
1953
|
end
|
1859
1954
|
end
|
1860
1955
|
|
1956
|
+
# Editline:: +ed-unassigned+ This editor command always results in an error.
|
1957
|
+
# GNU Readline:: There is no corresponding macro.
|
1861
1958
|
private def ed_unassigned(key) end # do nothing
|
1862
1959
|
|
1863
1960
|
private def process_insert(force: false)
|
@@ -1875,6 +1972,19 @@ class Reline::LineEditor
|
|
1875
1972
|
@continuous_insertion_buffer.clear
|
1876
1973
|
end
|
1877
1974
|
|
1975
|
+
# Editline:: +ed-insert+ (vi input: almost all; emacs: printable characters)
|
1976
|
+
# In insert mode, insert the input character left of the cursor
|
1977
|
+
# position. In replace mode, overwrite the character at the
|
1978
|
+
# cursor and move the cursor to the right by one character
|
1979
|
+
# position. Accept an argument to do this repeatedly. It is an
|
1980
|
+
# error if the input character is the NUL character (+Ctrl-@+).
|
1981
|
+
# Failure to enlarge the edit buffer also results in an error.
|
1982
|
+
# Editline:: +ed-digit+ (emacs: 0 to 9) If in argument input mode, append
|
1983
|
+
# the input digit to the argument being read. Otherwise, call
|
1984
|
+
# +ed-insert+. It is an error if the input character is not a
|
1985
|
+
# digit or if the existing argument is already greater than a
|
1986
|
+
# million.
|
1987
|
+
# GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
|
1878
1988
|
private def ed_insert(key)
|
1879
1989
|
str = nil
|
1880
1990
|
width = nil
|
@@ -1925,6 +2035,8 @@ class Reline::LineEditor
|
|
1925
2035
|
arg.times do
|
1926
2036
|
if key == "\C-j".ord or key == "\C-m".ord
|
1927
2037
|
key_newline(key)
|
2038
|
+
elsif key == 0
|
2039
|
+
# Ignore NUL.
|
1928
2040
|
else
|
1929
2041
|
ed_insert(key)
|
1930
2042
|
end
|
@@ -2359,6 +2471,7 @@ class Reline::LineEditor
|
|
2359
2471
|
arg -= 1
|
2360
2472
|
ed_prev_history(key, arg: arg) if arg > 0
|
2361
2473
|
end
|
2474
|
+
alias_method :previous_history, :ed_prev_history
|
2362
2475
|
|
2363
2476
|
private def ed_next_history(key, arg: 1)
|
2364
2477
|
if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
|
@@ -2406,6 +2519,7 @@ class Reline::LineEditor
|
|
2406
2519
|
arg -= 1
|
2407
2520
|
ed_next_history(key, arg: arg) if arg > 0
|
2408
2521
|
end
|
2522
|
+
alias_method :next_history, :ed_next_history
|
2409
2523
|
|
2410
2524
|
private def ed_newline(key)
|
2411
2525
|
process_insert(force: true)
|
@@ -2440,7 +2554,7 @@ class Reline::LineEditor
|
|
2440
2554
|
end
|
2441
2555
|
end
|
2442
2556
|
|
2443
|
-
private def em_delete_prev_char(key)
|
2557
|
+
private def em_delete_prev_char(key, arg: 1)
|
2444
2558
|
if @is_multiline and @cursor == 0 and @line_index > 0
|
2445
2559
|
@buffer_of_lines[@line_index] = @line
|
2446
2560
|
@cursor = calculate_width(@buffer_of_lines[@line_index - 1])
|
@@ -2458,9 +2572,16 @@ class Reline::LineEditor
|
|
2458
2572
|
@cursor -= width
|
2459
2573
|
@cursor_max -= width
|
2460
2574
|
end
|
2575
|
+
arg -= 1
|
2576
|
+
em_delete_prev_char(key, arg: arg) if arg > 0
|
2461
2577
|
end
|
2462
2578
|
alias_method :backward_delete_char, :em_delete_prev_char
|
2463
2579
|
|
2580
|
+
# Editline:: +ed-kill-line+ (vi command: +D+, +Ctrl-K+; emacs: +Ctrl-K+,
|
2581
|
+
# +Ctrl-U+) + Kill from the cursor to the end of the line.
|
2582
|
+
# GNU Readline:: +kill-line+ (+C-k+) Kill the text from point to the end of
|
2583
|
+
# the line. With a negative numeric argument, kill backward
|
2584
|
+
# from the cursor to the beginning of the current line.
|
2464
2585
|
private def ed_kill_line(key)
|
2465
2586
|
if @line.bytesize > @byte_pointer
|
2466
2587
|
@line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
|
@@ -2477,8 +2598,14 @@ class Reline::LineEditor
|
|
2477
2598
|
@rest_height += 1
|
2478
2599
|
end
|
2479
2600
|
end
|
2601
|
+
alias_method :kill_line, :ed_kill_line
|
2480
2602
|
|
2481
|
-
|
2603
|
+
# Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
|
2604
|
+
# beginning of the edit buffer to the cursor and save it to the
|
2605
|
+
# cut buffer.
|
2606
|
+
# GNU Readline:: +unix-line-discard+ (+C-u+) Kill backward from the cursor
|
2607
|
+
# to the beginning of the current line.
|
2608
|
+
private def vi_kill_line_prev(key)
|
2482
2609
|
if @byte_pointer > 0
|
2483
2610
|
@line, deleted = byteslice!(@line, 0, @byte_pointer)
|
2484
2611
|
@byte_pointer = 0
|
@@ -2487,7 +2614,22 @@ class Reline::LineEditor
|
|
2487
2614
|
@cursor = 0
|
2488
2615
|
end
|
2489
2616
|
end
|
2490
|
-
alias_method :
|
2617
|
+
alias_method :unix_line_discard, :vi_kill_line_prev
|
2618
|
+
|
2619
|
+
# Editline:: +em-kill-line+ (not bound) Delete the entire contents of the
|
2620
|
+
# edit buffer and save it to the cut buffer. +vi-kill-line-prev+
|
2621
|
+
# GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
|
2622
|
+
# current line, no matter where point is.
|
2623
|
+
private def em_kill_line(key)
|
2624
|
+
if @line.size > 0
|
2625
|
+
@kill_ring.append(@line.dup, true)
|
2626
|
+
@line.clear
|
2627
|
+
@byte_pointer = 0
|
2628
|
+
@cursor_max = 0
|
2629
|
+
@cursor = 0
|
2630
|
+
end
|
2631
|
+
end
|
2632
|
+
alias_method :kill_whole_line, :em_kill_line
|
2491
2633
|
|
2492
2634
|
private def em_delete(key)
|
2493
2635
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
@@ -2992,7 +3134,14 @@ class Reline::LineEditor
|
|
2992
3134
|
|
2993
3135
|
private def ed_argument_digit(key)
|
2994
3136
|
if @vi_arg.nil?
|
2995
|
-
|
3137
|
+
if key.chr.to_i.zero?
|
3138
|
+
if key.anybits?(0b10000000)
|
3139
|
+
unescaped_key = key ^ 0b10000000
|
3140
|
+
unless unescaped_key.chr.to_i.zero?
|
3141
|
+
@vi_arg = unescaped_key.chr.to_i
|
3142
|
+
end
|
3143
|
+
end
|
3144
|
+
else
|
2996
3145
|
@vi_arg = key.chr.to_i
|
2997
3146
|
end
|
2998
3147
|
else
|
data/lib/reline/terminfo.rb
CHANGED
@@ -71,7 +71,7 @@ module Reline::Terminfo
|
|
71
71
|
def self.setupterm(term, fildes)
|
72
72
|
errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
|
73
73
|
ret = @setupterm.(term, fildes, errret_int)
|
74
|
-
errret = errret_int.
|
74
|
+
errret = errret_int.unpack1('i')
|
75
75
|
case ret
|
76
76
|
when 0 # OK
|
77
77
|
0
|
data/lib/reline/unicode.rb
CHANGED
@@ -101,9 +101,9 @@ class Reline::Unicode
|
|
101
101
|
|
102
102
|
def self.get_mbchar_width(mbchar)
|
103
103
|
ord = mbchar.ord
|
104
|
-
if (0x00 <= ord and ord <= 0x1F)
|
104
|
+
if (0x00 <= ord and ord <= 0x1F) # in EscapedPairs
|
105
105
|
return 2
|
106
|
-
elsif (0x20 <= ord and ord <= 0x7E)
|
106
|
+
elsif (0x20 <= ord and ord <= 0x7E) # printable ASCII chars
|
107
107
|
return 1
|
108
108
|
end
|
109
109
|
m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE)
|
@@ -185,7 +185,7 @@ class Reline::Unicode
|
|
185
185
|
[lines, height]
|
186
186
|
end
|
187
187
|
|
188
|
-
# Take a chunk of a String with escape sequences.
|
188
|
+
# Take a chunk of a String cut by width with escape sequences.
|
189
189
|
def self.take_range(str, start_col, max_width, encoding = str.encoding)
|
190
190
|
chunk = String.new(encoding: encoding)
|
191
191
|
total_width = 0
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -184,7 +184,7 @@ class Reline::Windows
|
|
184
184
|
# DWORD FileNameLength;
|
185
185
|
# WCHAR FileName[1];
|
186
186
|
# } FILE_NAME_INFO
|
187
|
-
len = p_buffer[0, 4].
|
187
|
+
len = p_buffer[0, 4].unpack1("L")
|
188
188
|
name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
|
189
189
|
|
190
190
|
# Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
|
@@ -234,22 +234,23 @@ class Reline::Windows
|
|
234
234
|
def self.check_input_event
|
235
235
|
num_of_events = 0.chr * 8
|
236
236
|
while @@output_buf.empty? #or true
|
237
|
+
Reline.core.line_editor.resize
|
237
238
|
next if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
|
238
|
-
next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.
|
239
|
+
next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
|
239
240
|
input_record = 0.chr * 18
|
240
241
|
read_event = 0.chr * 4
|
241
242
|
if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_record, 1, read_event) != 0
|
242
|
-
event = input_record[0, 2].
|
243
|
+
event = input_record[0, 2].unpack1('s*')
|
243
244
|
case event
|
244
245
|
when WINDOW_BUFFER_SIZE_EVENT
|
245
246
|
@@winch_handler.()
|
246
247
|
when KEY_EVENT
|
247
|
-
key_down = input_record[4, 4].
|
248
|
-
repeat_count = input_record[8, 2].
|
249
|
-
virtual_key_code = input_record[10, 2].
|
250
|
-
virtual_scan_code = input_record[12, 2].
|
251
|
-
char_code = input_record[14, 2].
|
252
|
-
control_key_state = input_record[16, 2].
|
248
|
+
key_down = input_record[4, 4].unpack1('l*')
|
249
|
+
repeat_count = input_record[8, 2].unpack1('s*')
|
250
|
+
virtual_key_code = input_record[10, 2].unpack1('s*')
|
251
|
+
virtual_scan_code = input_record[12, 2].unpack1('s*')
|
252
|
+
char_code = input_record[14, 2].unpack1('S*')
|
253
|
+
control_key_state = input_record[16, 2].unpack1('S*')
|
253
254
|
is_key_down = key_down.zero? ? false : true
|
254
255
|
if is_key_down
|
255
256
|
process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
|
@@ -291,8 +292,8 @@ class Reline::Windows
|
|
291
292
|
def self.cursor_pos
|
292
293
|
csbi = 0.chr * 22
|
293
294
|
@@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
|
294
|
-
x = csbi[4, 2].
|
295
|
-
y = csbi[6, 2].
|
295
|
+
x = csbi[4, 2].unpack1('s*')
|
296
|
+
y = csbi[6, 2].unpack1('s*')
|
296
297
|
Reline::CursorPos.new(x, y)
|
297
298
|
end
|
298
299
|
|
@@ -322,12 +323,13 @@ class Reline::Windows
|
|
322
323
|
end
|
323
324
|
|
324
325
|
def self.erase_after_cursor
|
325
|
-
csbi = 0.chr *
|
326
|
+
csbi = 0.chr * 22
|
326
327
|
@@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
|
327
|
-
|
328
|
+
attributes = csbi[8, 2].unpack1('S')
|
329
|
+
cursor = csbi[4, 4].unpack1('L')
|
328
330
|
written = 0.chr * 4
|
329
331
|
@@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
|
330
|
-
@@FillConsoleOutputAttribute.call(@@hConsoleHandle,
|
332
|
+
@@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
|
331
333
|
end
|
332
334
|
|
333
335
|
def self.scroll_down(val)
|
@@ -343,8 +345,8 @@ class Reline::Windows
|
|
343
345
|
def self.clear_screen
|
344
346
|
csbi = 0.chr * 22
|
345
347
|
return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
|
346
|
-
buffer_width = csbi[0, 2].
|
347
|
-
attributes = csbi[8, 2].
|
348
|
+
buffer_width = csbi[0, 2].unpack1('S')
|
349
|
+
attributes = csbi[8, 2].unpack1('S')
|
348
350
|
_window_left, window_top, _window_right, window_bottom = *csbi[10,8].unpack('S*')
|
349
351
|
fill_length = buffer_width * (window_bottom - window_top + 1)
|
350
352
|
screen_topleft = window_top * 65536
|