reline 0.2.8.pre.7 → 0.2.8.pre.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reline/config.rb +16 -2
- data/lib/reline/key_stroke.rb +56 -4
- data/lib/reline/line_editor.rb +42 -6
- data/lib/reline/line_editor.rb.orig +49 -6
- data/lib/reline/unicode.rb +3 -3
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +53 -24
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f03d46c602265d3a197f00021df365a9686e4fd0b5d0ef2a037a9ad25143b91
|
4
|
+
data.tar.gz: e97bfb610d3c9498e651b25de97e87380e624b56ea970ab7048b25dca7be9488
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be1a180b58930985ea7ba5d63be81b62c8ffb0b960daf33c5ad984652fa6021151519cc1fa41055c240d7675d628c6749ab69ca67c2c2bfa306a9deab8200c56
|
7
|
+
data.tar.gz: 68be299c9815a350c8afec2c5b27aa02905c8fcc04c6fbba331aded2aded1d0dc160d2e8b01be58a91f308b1ad1dd880209e237de770002422910c6014ddc51a
|
data/lib/reline/config.rb
CHANGED
@@ -50,6 +50,7 @@ class Reline::Config
|
|
50
50
|
@additional_key_bindings[:emacs] = {}
|
51
51
|
@additional_key_bindings[:vi_insert] = {}
|
52
52
|
@additional_key_bindings[:vi_command] = {}
|
53
|
+
@oneshot_key_bindings = {}
|
53
54
|
@skip_section = nil
|
54
55
|
@if_stack = nil
|
55
56
|
@editing_mode_label = :emacs
|
@@ -75,6 +76,7 @@ class Reline::Config
|
|
75
76
|
@additional_key_bindings.keys.each do |key|
|
76
77
|
@additional_key_bindings[key].clear
|
77
78
|
end
|
79
|
+
@oneshot_key_bindings.clear
|
78
80
|
reset_default_key_bindings
|
79
81
|
end
|
80
82
|
|
@@ -128,8 +130,12 @@ class Reline::Config
|
|
128
130
|
return home_rc_path
|
129
131
|
end
|
130
132
|
|
133
|
+
private def default_inputrc_path
|
134
|
+
@default_inputrc_path ||= inputrc_path
|
135
|
+
end
|
136
|
+
|
131
137
|
def read(file = nil)
|
132
|
-
file ||=
|
138
|
+
file ||= default_inputrc_path
|
133
139
|
begin
|
134
140
|
if file.respond_to?(:readlines)
|
135
141
|
lines = file.readlines
|
@@ -149,7 +155,15 @@ class Reline::Config
|
|
149
155
|
|
150
156
|
def key_bindings
|
151
157
|
# override @key_actors[@editing_mode_label].default_key_bindings with @additional_key_bindings[@editing_mode_label]
|
152
|
-
@key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label])
|
158
|
+
@key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label]).merge(@oneshot_key_bindings)
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_oneshot_key_binding(keystroke, target)
|
162
|
+
@oneshot_key_bindings[keystroke] = target
|
163
|
+
end
|
164
|
+
|
165
|
+
def reset_oneshot_key_bindings
|
166
|
+
@oneshot_key_bindings.clear
|
153
167
|
end
|
154
168
|
|
155
169
|
def add_default_key_binding_by_keymap(keymap, keystroke, target)
|
data/lib/reline/key_stroke.rb
CHANGED
@@ -1,8 +1,59 @@
|
|
1
1
|
class Reline::KeyStroke
|
2
2
|
using Module.new {
|
3
|
+
refine Integer do
|
4
|
+
def ==(other)
|
5
|
+
if other.is_a?(Reline::Key)
|
6
|
+
if other.combined_char == "\e".ord
|
7
|
+
false
|
8
|
+
else
|
9
|
+
other.combined_char == self
|
10
|
+
end
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
3
17
|
refine Array do
|
4
18
|
def start_with?(other)
|
5
|
-
|
19
|
+
compressed_me = compress_meta_key
|
20
|
+
compressed_other = other.compress_meta_key
|
21
|
+
i = 0
|
22
|
+
loop do
|
23
|
+
my_c = compressed_me[i]
|
24
|
+
other_c = compressed_other[i]
|
25
|
+
other_is_last = (i + 1) == compressed_other.size
|
26
|
+
me_is_last = (i + 1) == compressed_me.size
|
27
|
+
if my_c != other_c
|
28
|
+
if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
|
29
|
+
return true
|
30
|
+
else
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
elsif other_is_last
|
34
|
+
return true
|
35
|
+
elsif me_is_last
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
i += 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def ==(other)
|
43
|
+
compressed_me = compress_meta_key
|
44
|
+
compressed_other = other.compress_meta_key
|
45
|
+
compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| i[0] == i[1] }
|
46
|
+
end
|
47
|
+
|
48
|
+
def compress_meta_key
|
49
|
+
inject([]) { |result, key|
|
50
|
+
if result.size > 0 and result.last == "\e".ord
|
51
|
+
result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
|
52
|
+
else
|
53
|
+
result << key
|
54
|
+
end
|
55
|
+
result
|
56
|
+
}
|
6
57
|
end
|
7
58
|
|
8
59
|
def bytes
|
@@ -19,8 +70,8 @@ class Reline::KeyStroke
|
|
19
70
|
key_mapping.keys.select { |lhs|
|
20
71
|
lhs.start_with? input
|
21
72
|
}.tap { |it|
|
22
|
-
return :matched if it.size == 1 && (it
|
23
|
-
return :matching if it.size == 1 && (it
|
73
|
+
return :matched if it.size == 1 && (it[0] == input)
|
74
|
+
return :matching if it.size == 1 && (it[0] != input)
|
24
75
|
return :matched if it.max_by(&:size)&.size&.< input.size
|
25
76
|
return :matching if it.size > 1
|
26
77
|
}
|
@@ -32,7 +83,8 @@ class Reline::KeyStroke
|
|
32
83
|
end
|
33
84
|
|
34
85
|
def expand(input)
|
35
|
-
|
86
|
+
input = input.compress_meta_key
|
87
|
+
lhs = key_mapping.keys.select { |item| input.start_with? item }.sort_by(&:size).last
|
36
88
|
return input unless lhs
|
37
89
|
rhs = key_mapping[lhs]
|
38
90
|
|
data/lib/reline/line_editor.rb
CHANGED
@@ -550,8 +550,9 @@ class Reline::LineEditor
|
|
550
550
|
attr_reader :name, :contents, :width
|
551
551
|
attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup, :trap_key
|
552
552
|
|
553
|
-
def initialize(name, proc_scope)
|
553
|
+
def initialize(name, config, proc_scope)
|
554
554
|
@name = name
|
555
|
+
@config = config
|
555
556
|
@proc_scope = proc_scope
|
556
557
|
@width = nil
|
557
558
|
@scroll_top = 0
|
@@ -575,13 +576,25 @@ class Reline::LineEditor
|
|
575
576
|
def call(key)
|
576
577
|
@proc_scope.set_dialog(self)
|
577
578
|
@proc_scope.set_key(key)
|
578
|
-
@proc_scope.call
|
579
|
+
dialog_render_info = @proc_scope.call
|
580
|
+
if @trap_key
|
581
|
+
if @trap_key.any?{ |i| i.is_a?(Array) } # multiple trap
|
582
|
+
@trap_key.each do |t|
|
583
|
+
@config.add_oneshot_key_binding(t, @name)
|
584
|
+
end
|
585
|
+
elsif @trap_key.is_a?(Array)
|
586
|
+
@config.add_oneshot_key_binding(@trap_key, @name)
|
587
|
+
elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
|
588
|
+
@config.add_oneshot_key_binding([@trap_key], @name)
|
589
|
+
end
|
590
|
+
end
|
591
|
+
dialog_render_info
|
579
592
|
end
|
580
593
|
end
|
581
594
|
|
582
595
|
def add_dialog_proc(name, p, context = nil)
|
583
596
|
return if @dialogs.any? { |d| d.name == name }
|
584
|
-
@dialogs << Dialog.new(name, DialogProcScope.new(self, @config, p, context))
|
597
|
+
@dialogs << Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context))
|
585
598
|
end
|
586
599
|
|
587
600
|
DIALOG_HEIGHT = 20
|
@@ -661,6 +674,13 @@ class Reline::LineEditor
|
|
661
674
|
reset_dialog(dialog, old_dialog)
|
662
675
|
move_cursor_down(dialog.vertical_offset)
|
663
676
|
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
|
664
684
|
dialog.contents.each_with_index do |item, i|
|
665
685
|
if i == pointer
|
666
686
|
bg_color = '45'
|
@@ -672,10 +692,26 @@ class Reline::LineEditor
|
|
672
692
|
end
|
673
693
|
end
|
674
694
|
str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, dialog.width), dialog.width)
|
675
|
-
@output.write "\e[#{bg_color}m#{str}
|
695
|
+
@output.write "\e[#{bg_color}m#{str}"
|
696
|
+
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
697
|
+
@output.write "\e[37m"
|
698
|
+
if position <= (i * 2) and (i * 2 + 1) < (position + bar_height)
|
699
|
+
@output.write '█'
|
700
|
+
elsif position <= (i * 2) and (i * 2) < (position + bar_height)
|
701
|
+
@output.write '▀'
|
702
|
+
str += ''
|
703
|
+
elsif position <= (i * 2 + 1) and (i * 2) < (position + bar_height)
|
704
|
+
@output.write '▄'
|
705
|
+
else
|
706
|
+
@output.write ' '
|
707
|
+
end
|
708
|
+
@output.write "\e[39m"
|
709
|
+
end
|
710
|
+
@output.write "\e[49m"
|
676
711
|
Reline::IOGate.move_cursor_column(dialog.column)
|
677
712
|
move_cursor_down(1) if i < (dialog.contents.size - 1)
|
678
713
|
end
|
714
|
+
dialog.width += 1 if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
679
715
|
Reline::IOGate.move_cursor_column(cursor_column)
|
680
716
|
move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
|
681
717
|
Reline::IOGate.show_cursor
|
@@ -1478,9 +1514,9 @@ class Reline::LineEditor
|
|
1478
1514
|
|
1479
1515
|
def input_key(key)
|
1480
1516
|
@last_key = key
|
1517
|
+
@config.reset_oneshot_key_bindings
|
1481
1518
|
@dialogs.each do |dialog|
|
1482
|
-
|
1483
|
-
if dialog.trap_key and dialog.trap_key.match?(key)
|
1519
|
+
if key.char.instance_of?(Symbol) and key.char == dialog.name
|
1484
1520
|
return
|
1485
1521
|
end
|
1486
1522
|
end
|
@@ -251,6 +251,7 @@ class Reline::LineEditor
|
|
251
251
|
@in_pasting = false
|
252
252
|
@auto_indent_proc = nil
|
253
253
|
@dialogs = []
|
254
|
+
@last_key = nil
|
254
255
|
reset_line
|
255
256
|
end
|
256
257
|
|
@@ -512,6 +513,14 @@ class Reline::LineEditor
|
|
512
513
|
@cursor_pos.y = row
|
513
514
|
end
|
514
515
|
|
516
|
+
def set_key(key)
|
517
|
+
@key = key
|
518
|
+
end
|
519
|
+
|
520
|
+
def key
|
521
|
+
@key
|
522
|
+
end
|
523
|
+
|
515
524
|
def cursor_pos
|
516
525
|
@cursor_pos
|
517
526
|
end
|
@@ -539,7 +548,7 @@ class Reline::LineEditor
|
|
539
548
|
|
540
549
|
class Dialog
|
541
550
|
attr_reader :name, :contents, :width
|
542
|
-
attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup
|
551
|
+
attr_accessor :scroll_top, :column, :vertical_offset, :lines_backup, :trap_key
|
543
552
|
|
544
553
|
def initialize(name, proc_scope)
|
545
554
|
@name = name
|
@@ -563,8 +572,9 @@ class Reline::LineEditor
|
|
563
572
|
end
|
564
573
|
end
|
565
574
|
|
566
|
-
def call
|
575
|
+
def call(key)
|
567
576
|
@proc_scope.set_dialog(self)
|
577
|
+
@proc_scope.set_key(key)
|
568
578
|
@proc_scope.call
|
569
579
|
end
|
570
580
|
end
|
@@ -588,10 +598,11 @@ class Reline::LineEditor
|
|
588
598
|
private def render_each_dialog(dialog, cursor_column)
|
589
599
|
if @in_pasting
|
590
600
|
dialog.contents = nil
|
601
|
+
dialog.trap_key = nil
|
591
602
|
return
|
592
603
|
end
|
593
604
|
dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
|
594
|
-
dialog_render_info = dialog.call
|
605
|
+
dialog_render_info = dialog.call(@last_key)
|
595
606
|
if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
|
596
607
|
dialog.lines_backup = {
|
597
608
|
lines: modify_lines(whole_lines),
|
@@ -602,13 +613,18 @@ class Reline::LineEditor
|
|
602
613
|
}
|
603
614
|
clear_each_dialog(dialog)
|
604
615
|
dialog.contents = nil
|
616
|
+
dialog.trap_key = nil
|
605
617
|
return
|
606
618
|
end
|
607
619
|
old_dialog = dialog.clone
|
608
|
-
dialog.width = dialog_render_info.width if dialog_render_info.width
|
609
|
-
height = dialog_render_info.height || DIALOG_HEIGHT
|
610
|
-
pointer = dialog_render_info.pointer
|
611
620
|
dialog.contents = dialog_render_info.contents
|
621
|
+
pointer = dialog_render_info.pointer
|
622
|
+
if dialog_render_info.width
|
623
|
+
dialog.width = dialog_render_info.width
|
624
|
+
else
|
625
|
+
dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
|
626
|
+
end
|
627
|
+
height = dialog_render_info.height || DIALOG_HEIGHT
|
612
628
|
height = dialog.contents.size if dialog.contents.size < height
|
613
629
|
if dialog.contents.size > height
|
614
630
|
if dialog_render_info.pointer
|
@@ -645,6 +661,13 @@ class Reline::LineEditor
|
|
645
661
|
reset_dialog(dialog, old_dialog)
|
646
662
|
move_cursor_down(dialog.vertical_offset)
|
647
663
|
Reline::IOGate.move_cursor_column(dialog.column)
|
664
|
+
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
665
|
+
bar_max_height = height * 2
|
666
|
+
moving_distance = (dialog_render_info.contents.size - height) * 2
|
667
|
+
position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
|
668
|
+
bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
|
669
|
+
position = ((bar_max_height - bar_height) * position_ratio).floor.to_i
|
670
|
+
end
|
648
671
|
dialog.contents.each_with_index do |item, i|
|
649
672
|
if i == pointer
|
650
673
|
bg_color = '45'
|
@@ -656,10 +679,22 @@ class Reline::LineEditor
|
|
656
679
|
end
|
657
680
|
end
|
658
681
|
str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, dialog.width), dialog.width)
|
682
|
+
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
683
|
+
if position <= (i * 2) and (i * 2 + 1) < (position + bar_height)
|
684
|
+
str += '█'
|
685
|
+
elsif position <= (i * 2) and (i * 2) < (position + bar_height)
|
686
|
+
str += '▀'
|
687
|
+
elsif position <= (i * 2 + 1) and (i * 2) < (position + bar_height)
|
688
|
+
str += '▄'
|
689
|
+
else
|
690
|
+
str += ' '
|
691
|
+
end
|
692
|
+
end
|
659
693
|
@output.write "\e[#{bg_color}m#{str}\e[49m"
|
660
694
|
Reline::IOGate.move_cursor_column(dialog.column)
|
661
695
|
move_cursor_down(1) if i < (dialog.contents.size - 1)
|
662
696
|
end
|
697
|
+
dialog.width += 1 if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
|
663
698
|
Reline::IOGate.move_cursor_column(cursor_column)
|
664
699
|
move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
|
665
700
|
Reline::IOGate.show_cursor
|
@@ -774,6 +809,7 @@ class Reline::LineEditor
|
|
774
809
|
end
|
775
810
|
|
776
811
|
private def clear_each_dialog(dialog)
|
812
|
+
dialog.trap_key = nil
|
777
813
|
return unless dialog.contents
|
778
814
|
prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
|
779
815
|
visual_lines = []
|
@@ -1460,6 +1496,13 @@ class Reline::LineEditor
|
|
1460
1496
|
end
|
1461
1497
|
|
1462
1498
|
def input_key(key)
|
1499
|
+
@last_key = key
|
1500
|
+
@dialogs.each do |dialog|
|
1501
|
+
# The dialog will intercept the key if trap_key is set.
|
1502
|
+
if dialog.trap_key and dialog.trap_key.match?(key)
|
1503
|
+
return
|
1504
|
+
end
|
1505
|
+
end
|
1463
1506
|
@just_cursor_moving = nil
|
1464
1507
|
if key.char.nil?
|
1465
1508
|
if @first_char
|
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.rb
CHANGED
@@ -18,13 +18,26 @@ module Reline
|
|
18
18
|
|
19
19
|
Key = Struct.new('Key', :char, :combined_char, :with_meta) do
|
20
20
|
def match?(key)
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
if key.instance_of?(Reline::Key)
|
22
|
+
(key.char.nil? or char.nil? or char == key.char) and
|
23
|
+
(key.combined_char.nil? or combined_char.nil? or combined_char == key.combined_char) and
|
24
|
+
(key.with_meta.nil? or with_meta.nil? or with_meta == key.with_meta)
|
25
|
+
elsif key.is_a?(Integer) or key.is_a?(Symbol)
|
26
|
+
if not combined_char.nil? and combined_char == key
|
27
|
+
true
|
28
|
+
elsif combined_char.nil? and not char.nil? and char == key
|
29
|
+
true
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
else
|
34
|
+
false
|
35
|
+
end
|
24
36
|
end
|
37
|
+
alias_method :==, :match?
|
25
38
|
end
|
26
39
|
CursorPos = Struct.new(:x, :y)
|
27
|
-
DialogRenderInfo = Struct.new(:pos, :contents, :pointer, :bg_color, :width, :height, keyword_init: true)
|
40
|
+
DialogRenderInfo = Struct.new(:pos, :contents, :pointer, :bg_color, :width, :height, :scrollbar, keyword_init: true)
|
28
41
|
|
29
42
|
class Core
|
30
43
|
ATTR_READER_NAMES = %i(
|
@@ -228,7 +241,7 @@ module Reline
|
|
228
241
|
context.clear
|
229
242
|
context.push(cursor_pos_to_render, result, pointer, dialog)
|
230
243
|
end
|
231
|
-
DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, pointer: pointer, height: 15)
|
244
|
+
DialogRenderInfo.new(pos: cursor_pos_to_render, contents: result, pointer: pointer, scrollbar: true, height: 15)
|
232
245
|
}
|
233
246
|
Reline::DEFAULT_DIALOG_CONTEXT = Array.new
|
234
247
|
|
@@ -368,25 +381,9 @@ module Reline
|
|
368
381
|
break
|
369
382
|
when :matching
|
370
383
|
if buffer.size == 1
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
succ_c = Reline::IOGate.getc
|
375
|
-
}
|
376
|
-
rescue Timeout::Error # cancel matching only when first byte
|
377
|
-
block.([Reline::Key.new(c, c, false)])
|
378
|
-
break
|
379
|
-
else
|
380
|
-
if key_stroke.match_status(buffer.dup.push(succ_c)) == :unmatched
|
381
|
-
if c == "\e".ord
|
382
|
-
block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
|
383
|
-
else
|
384
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
|
385
|
-
end
|
386
|
-
break
|
387
|
-
else
|
388
|
-
Reline::IOGate.ungetc(succ_c)
|
389
|
-
end
|
384
|
+
case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
|
385
|
+
when :break then break
|
386
|
+
when :next then next
|
390
387
|
end
|
391
388
|
end
|
392
389
|
when :unmatched
|
@@ -403,6 +400,38 @@ module Reline
|
|
403
400
|
end
|
404
401
|
end
|
405
402
|
|
403
|
+
private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
|
404
|
+
begin
|
405
|
+
succ_c = nil
|
406
|
+
Timeout.timeout(keyseq_timeout / 1000.0) {
|
407
|
+
succ_c = Reline::IOGate.getc
|
408
|
+
}
|
409
|
+
rescue Timeout::Error # cancel matching only when first byte
|
410
|
+
block.([Reline::Key.new(c, c, false)])
|
411
|
+
return :break
|
412
|
+
else
|
413
|
+
case key_stroke.match_status(buffer.dup.push(succ_c))
|
414
|
+
when :unmatched
|
415
|
+
if c == "\e".ord
|
416
|
+
block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
|
417
|
+
else
|
418
|
+
block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
|
419
|
+
end
|
420
|
+
return :break
|
421
|
+
when :matching
|
422
|
+
Reline::IOGate.ungetc(succ_c)
|
423
|
+
return :next
|
424
|
+
when :matched
|
425
|
+
buffer << succ_c
|
426
|
+
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
427
|
+
Reline::Key.new(expanded_c, expanded_c, false)
|
428
|
+
}
|
429
|
+
block.(expanded)
|
430
|
+
return :break
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
406
435
|
private def read_escaped_key(keyseq_timeout, c, block)
|
407
436
|
begin
|
408
437
|
escaped_c = nil
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.8.pre.
|
4
|
+
version: 0.2.8.pre.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|