reline 0.5.8 → 0.5.9
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 +21 -19
- data/lib/reline/{ansi.rb → io/ansi.rb} +87 -85
- data/lib/reline/io/dumb.rb +106 -0
- data/lib/reline/{windows.rb → io/windows.rb} +102 -102
- data/lib/reline/io.rb +41 -0
- data/lib/reline/key_actor/base.rb +22 -6
- data/lib/reline/key_actor/composite.rb +17 -0
- data/lib/reline/key_actor/emacs.rb +2 -2
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/key_actor.rb +1 -0
- data/lib/reline/key_stroke.rb +65 -104
- data/lib/reline/line_editor.rb +31 -28
- data/lib/reline/terminfo.rb +5 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +35 -123
- metadata +7 -5
- data/lib/reline/general_io.rb +0 -111
data/lib/reline/key_stroke.rb
CHANGED
@@ -7,138 +7,99 @@ class Reline::KeyStroke
|
|
7
7
|
@config = config
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
result
|
19
|
-
}
|
20
|
-
end
|
10
|
+
# Input exactly matches to a key sequence
|
11
|
+
MATCHING = :matching
|
12
|
+
# Input partially matches to a key sequence
|
13
|
+
MATCHED = :matched
|
14
|
+
# Input matches to a key sequence and the key sequence is a prefix of another key sequence
|
15
|
+
MATCHING_MATCHED = :matching_matched
|
16
|
+
# Input does not match to any key sequence
|
17
|
+
UNMATCHED = :unmatched
|
21
18
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
i = 0
|
26
|
-
loop do
|
27
|
-
my_c = compressed_me[i]
|
28
|
-
other_c = compressed_other[i]
|
29
|
-
other_is_last = (i + 1) == compressed_other.size
|
30
|
-
me_is_last = (i + 1) == compressed_me.size
|
31
|
-
if my_c != other_c
|
32
|
-
if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
|
33
|
-
return true
|
34
|
-
else
|
35
|
-
return false
|
36
|
-
end
|
37
|
-
elsif other_is_last
|
38
|
-
return true
|
39
|
-
elsif me_is_last
|
40
|
-
return false
|
41
|
-
end
|
42
|
-
i += 1
|
43
|
-
end
|
44
|
-
end
|
19
|
+
def match_status(input)
|
20
|
+
matching = key_mapping.matching?(input)
|
21
|
+
matched = key_mapping.get(input)
|
45
22
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
compressed_me = compress_meta_key(me)
|
50
|
-
compressed_other = compress_meta_key(other)
|
51
|
-
compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| equal?(i[0], i[1]) }
|
52
|
-
when Integer
|
53
|
-
if other.is_a?(Reline::Key)
|
54
|
-
if other.combined_char == "\e".ord
|
55
|
-
false
|
56
|
-
else
|
57
|
-
other.combined_char == me
|
58
|
-
end
|
59
|
-
else
|
60
|
-
me == other
|
61
|
-
end
|
62
|
-
when Reline::Key
|
63
|
-
if other.is_a?(Integer)
|
64
|
-
me.combined_char == other
|
65
|
-
else
|
66
|
-
me == other
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
23
|
+
# FIXME: Workaround for single byte. remove this after MAPPING is merged into KeyActor.
|
24
|
+
matched ||= input.size == 1
|
25
|
+
matching ||= input == [ESC_BYTE]
|
70
26
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
:matched
|
27
|
+
if matching && matched
|
28
|
+
MATCHING_MATCHED
|
29
|
+
elsif matching
|
30
|
+
MATCHING
|
31
|
+
elsif matched
|
32
|
+
MATCHED
|
33
|
+
elsif input[0] == ESC_BYTE
|
34
|
+
match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command))
|
35
|
+
elsif input.size == 1
|
36
|
+
MATCHED
|
82
37
|
else
|
83
|
-
|
38
|
+
UNMATCHED
|
84
39
|
end
|
85
40
|
end
|
86
41
|
|
87
42
|
def expand(input)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
return [:ed_unassigned] + expand(input.drop(size))
|
94
|
-
when :matching
|
95
|
-
return [:ed_unassigned]
|
96
|
-
else
|
97
|
-
return input
|
98
|
-
end
|
43
|
+
matched_bytes = nil
|
44
|
+
(1..input.size).each do |i|
|
45
|
+
bytes = input.take(i)
|
46
|
+
status = match_status(bytes)
|
47
|
+
matched_bytes = bytes if status == MATCHED || status == MATCHING_MATCHED
|
99
48
|
end
|
100
|
-
|
49
|
+
return [[], []] unless matched_bytes
|
101
50
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
51
|
+
func = key_mapping.get(matched_bytes)
|
52
|
+
if func.is_a?(Array)
|
53
|
+
keys = func.map { |c| Reline::Key.new(c, c, false) }
|
54
|
+
elsif func
|
55
|
+
keys = [Reline::Key.new(func, func, false)]
|
56
|
+
elsif matched_bytes.size == 1
|
57
|
+
keys = [Reline::Key.new(matched_bytes.first, matched_bytes.first, false)]
|
58
|
+
elsif matched_bytes.size == 2 && matched_bytes[0] == ESC_BYTE
|
59
|
+
keys = [Reline::Key.new(matched_bytes[1], matched_bytes[1] | 0b10000000, true)]
|
60
|
+
else
|
61
|
+
keys = []
|
110
62
|
end
|
63
|
+
|
64
|
+
[keys, input.drop(matched_bytes.size)]
|
111
65
|
end
|
112
66
|
|
113
67
|
private
|
114
68
|
|
115
69
|
# returns match status of CSI/SS3 sequence and matched length
|
116
|
-
def match_unknown_escape_sequence(input)
|
70
|
+
def match_unknown_escape_sequence(input, vi_mode: false)
|
117
71
|
idx = 0
|
118
|
-
return
|
72
|
+
return UNMATCHED unless input[idx] == ESC_BYTE
|
119
73
|
idx += 1
|
120
74
|
idx += 1 if input[idx] == ESC_BYTE
|
121
75
|
|
122
76
|
case input[idx]
|
123
77
|
when nil
|
124
|
-
|
78
|
+
if idx == 1 # `ESC`
|
79
|
+
return MATCHING_MATCHED
|
80
|
+
else # `ESC ESC`
|
81
|
+
return MATCHING
|
82
|
+
end
|
125
83
|
when 91 # == '['.ord
|
126
|
-
# CSI sequence
|
84
|
+
# CSI sequence `ESC [ ... char`
|
127
85
|
idx += 1
|
128
86
|
idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx])
|
129
87
|
idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx])
|
130
|
-
input[idx] ? [:matched, idx + 1] : [:matching, nil]
|
131
88
|
when 79 # == 'O'.ord
|
132
|
-
# SS3 sequence
|
133
|
-
|
89
|
+
# SS3 sequence `ESC O char`
|
90
|
+
idx += 1
|
134
91
|
else
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
92
|
+
# `ESC char` or `ESC ESC char`
|
93
|
+
return UNMATCHED if vi_mode
|
94
|
+
end
|
95
|
+
|
96
|
+
case input.size
|
97
|
+
when idx
|
98
|
+
MATCHING
|
99
|
+
when idx + 1
|
100
|
+
MATCHED
|
101
|
+
else
|
102
|
+
UNMATCHED
|
142
103
|
end
|
143
104
|
end
|
144
105
|
|
data/lib/reline/line_editor.rb
CHANGED
@@ -45,6 +45,7 @@ class Reline::LineEditor
|
|
45
45
|
RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
|
46
46
|
|
47
47
|
CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
|
48
|
+
NullActionState = [nil, nil].freeze
|
48
49
|
|
49
50
|
class MenuInfo
|
50
51
|
attr_reader :list
|
@@ -237,7 +238,6 @@ class Reline::LineEditor
|
|
237
238
|
@perfect_matched = nil
|
238
239
|
@menu_info = nil
|
239
240
|
@searching_prompt = nil
|
240
|
-
@first_char = true
|
241
241
|
@just_cursor_moving = false
|
242
242
|
@eof = false
|
243
243
|
@continuous_insertion_buffer = String.new(encoding: @encoding)
|
@@ -253,6 +253,8 @@ class Reline::LineEditor
|
|
253
253
|
@input_lines = [[[""], 0, 0]]
|
254
254
|
@input_lines_position = 0
|
255
255
|
@undoing = false
|
256
|
+
@prev_action_state = NullActionState
|
257
|
+
@next_action_state = NullActionState
|
256
258
|
reset_line
|
257
259
|
end
|
258
260
|
|
@@ -412,7 +414,7 @@ class Reline::LineEditor
|
|
412
414
|
# do nothing
|
413
415
|
elsif level == :blank
|
414
416
|
Reline::IOGate.move_cursor_column base_x
|
415
|
-
@output.write "#{Reline::IOGate
|
417
|
+
@output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
|
416
418
|
else
|
417
419
|
x, w, content = new_items[level]
|
418
420
|
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
|
@@ -422,7 +424,7 @@ class Reline::LineEditor
|
|
422
424
|
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
423
425
|
end
|
424
426
|
Reline::IOGate.move_cursor_column x + pos
|
425
|
-
@output.write "#{Reline::IOGate
|
427
|
+
@output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
|
426
428
|
end
|
427
429
|
base_x += width
|
428
430
|
end
|
@@ -684,10 +686,8 @@ class Reline::LineEditor
|
|
684
686
|
@trap_key.each do |t|
|
685
687
|
@config.add_oneshot_key_binding(t, @name)
|
686
688
|
end
|
687
|
-
|
689
|
+
else
|
688
690
|
@config.add_oneshot_key_binding(@trap_key, @name)
|
689
|
-
elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
|
690
|
-
@config.add_oneshot_key_binding([@trap_key], @name)
|
691
691
|
end
|
692
692
|
end
|
693
693
|
dialog_render_info
|
@@ -1080,17 +1080,7 @@ class Reline::LineEditor
|
|
1080
1080
|
else # single byte
|
1081
1081
|
return if key.char >= 128 # maybe, first byte of multi byte
|
1082
1082
|
method_symbol = @config.editing_mode.get_method(key.combined_char)
|
1083
|
-
|
1084
|
-
if @config.editing_mode_is?(:vi_command, :vi_insert)
|
1085
|
-
# split ESC + key in vi mode
|
1086
|
-
method_symbol = @config.editing_mode.get_method("\e".ord)
|
1087
|
-
process_key("\e".ord, method_symbol)
|
1088
|
-
method_symbol = @config.editing_mode.get_method(key.char)
|
1089
|
-
process_key(key.char, method_symbol)
|
1090
|
-
end
|
1091
|
-
else
|
1092
|
-
process_key(key.combined_char, method_symbol)
|
1093
|
-
end
|
1083
|
+
process_key(key.combined_char, method_symbol)
|
1094
1084
|
@multibyte_buffer.clear
|
1095
1085
|
end
|
1096
1086
|
if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
|
@@ -1119,13 +1109,10 @@ class Reline::LineEditor
|
|
1119
1109
|
end
|
1120
1110
|
if key.char.nil?
|
1121
1111
|
process_insert(force: true)
|
1122
|
-
|
1123
|
-
@eof = true
|
1124
|
-
end
|
1112
|
+
@eof = buffer_empty?
|
1125
1113
|
finish
|
1126
1114
|
return
|
1127
1115
|
end
|
1128
|
-
@first_char = false
|
1129
1116
|
@completion_occurs = false
|
1130
1117
|
|
1131
1118
|
if key.char.is_a?(Symbol)
|
@@ -1133,6 +1120,9 @@ class Reline::LineEditor
|
|
1133
1120
|
else
|
1134
1121
|
normal_char(key)
|
1135
1122
|
end
|
1123
|
+
|
1124
|
+
@prev_action_state, @next_action_state = @next_action_state, NullActionState
|
1125
|
+
|
1136
1126
|
unless @completion_occurs
|
1137
1127
|
@completion_state = CompletionState::NORMAL
|
1138
1128
|
@completion_journey_state = nil
|
@@ -1415,6 +1405,10 @@ class Reline::LineEditor
|
|
1415
1405
|
whole_lines.join("\n")
|
1416
1406
|
end
|
1417
1407
|
|
1408
|
+
private def buffer_empty?
|
1409
|
+
current_line.empty? and @buffer_of_lines.size == 1
|
1410
|
+
end
|
1411
|
+
|
1418
1412
|
def finished?
|
1419
1413
|
@finished
|
1420
1414
|
end
|
@@ -1763,29 +1757,31 @@ class Reline::LineEditor
|
|
1763
1757
|
end
|
1764
1758
|
|
1765
1759
|
private def ed_search_prev_history(key, arg: 1)
|
1766
|
-
substr = current_line.byteslice(0, @byte_pointer)
|
1760
|
+
substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
|
1767
1761
|
return if @history_pointer == 0
|
1768
1762
|
return if @history_pointer.nil? && substr.empty? && !current_line.empty?
|
1769
1763
|
|
1770
1764
|
history_range = 0...(@history_pointer || Reline::HISTORY.size)
|
1771
1765
|
h_pointer, line_index = search_history(substr, history_range.reverse_each)
|
1772
1766
|
return unless h_pointer
|
1773
|
-
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1767
|
+
move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
|
1774
1768
|
arg -= 1
|
1769
|
+
set_next_action_state(:search_history, :empty) if substr.empty?
|
1775
1770
|
ed_search_prev_history(key, arg: arg) if arg > 0
|
1776
1771
|
end
|
1777
1772
|
alias_method :history_search_backward, :ed_search_prev_history
|
1778
1773
|
|
1779
1774
|
private def ed_search_next_history(key, arg: 1)
|
1780
|
-
substr = current_line.byteslice(0, @byte_pointer)
|
1775
|
+
substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
|
1781
1776
|
return if @history_pointer.nil?
|
1782
1777
|
|
1783
1778
|
history_range = @history_pointer + 1...Reline::HISTORY.size
|
1784
1779
|
h_pointer, line_index = search_history(substr, history_range)
|
1785
1780
|
return if h_pointer.nil? and not substr.empty?
|
1786
1781
|
|
1787
|
-
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1782
|
+
move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
|
1788
1783
|
arg -= 1
|
1784
|
+
set_next_action_state(:search_history, :empty) if substr.empty?
|
1789
1785
|
ed_search_next_history(key, arg: arg) if arg > 0
|
1790
1786
|
end
|
1791
1787
|
alias_method :history_search_forward, :ed_search_next_history
|
@@ -1941,7 +1937,7 @@ class Reline::LineEditor
|
|
1941
1937
|
alias_method :kill_whole_line, :em_kill_line
|
1942
1938
|
|
1943
1939
|
private def em_delete(key)
|
1944
|
-
if
|
1940
|
+
if buffer_empty? and key == "\C-d".ord
|
1945
1941
|
@eof = true
|
1946
1942
|
finish
|
1947
1943
|
elsif @byte_pointer < current_line.bytesize
|
@@ -2289,8 +2285,7 @@ class Reline::LineEditor
|
|
2289
2285
|
end
|
2290
2286
|
|
2291
2287
|
private def vi_list_or_eof(key)
|
2292
|
-
if
|
2293
|
-
set_current_line('', 0)
|
2288
|
+
if buffer_empty?
|
2294
2289
|
@eof = true
|
2295
2290
|
finish
|
2296
2291
|
else
|
@@ -2551,4 +2546,12 @@ class Reline::LineEditor
|
|
2551
2546
|
target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
|
2552
2547
|
set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
|
2553
2548
|
end
|
2549
|
+
|
2550
|
+
private def prev_action_state_value(type)
|
2551
|
+
@prev_action_state[0] == type ? @prev_action_state[1] : nil
|
2552
|
+
end
|
2553
|
+
|
2554
|
+
private def set_next_action_state(type, value)
|
2555
|
+
@next_action_state = [type, value]
|
2556
|
+
end
|
2554
2557
|
end
|
data/lib/reline/terminfo.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
begin
|
2
|
+
# Ignore warning `Add fiddle to your Gemfile or gemspec` in Ruby 3.4.
|
3
|
+
# terminfo.rb and ansi.rb supports fiddle unavailable environment.
|
4
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
2
5
|
require 'fiddle'
|
3
6
|
require 'fiddle/import'
|
4
7
|
rescue LoadError
|
@@ -7,6 +10,8 @@ rescue LoadError
|
|
7
10
|
false
|
8
11
|
end
|
9
12
|
end
|
13
|
+
ensure
|
14
|
+
$VERBOSE = verbose
|
10
15
|
end
|
11
16
|
|
12
17
|
module Reline::Terminfo
|
data/lib/reline/version.rb
CHANGED
data/lib/reline.rb
CHANGED
@@ -7,6 +7,7 @@ require 'reline/key_stroke'
|
|
7
7
|
require 'reline/line_editor'
|
8
8
|
require 'reline/history'
|
9
9
|
require 'reline/terminfo'
|
10
|
+
require 'reline/io'
|
10
11
|
require 'reline/face'
|
11
12
|
require 'rbconfig'
|
12
13
|
|
@@ -18,20 +19,10 @@ module Reline
|
|
18
19
|
class ConfigEncodingConversionError < StandardError; end
|
19
20
|
|
20
21
|
Key = Struct.new(:char, :combined_char, :with_meta) do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
(other.char.nil? or char.nil? or char == other.char) and
|
25
|
-
(other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
|
26
|
-
(other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
|
27
|
-
when Integer, Symbol
|
28
|
-
(combined_char and combined_char == other) or
|
29
|
-
(combined_char.nil? and char and char == other)
|
30
|
-
else
|
31
|
-
false
|
32
|
-
end
|
22
|
+
# For dialog_proc `key.match?(dialog.name)`
|
23
|
+
def match?(sym)
|
24
|
+
combined_char.is_a?(Symbol) && combined_char == sym
|
33
25
|
end
|
34
|
-
alias_method :==, :match?
|
35
26
|
end
|
36
27
|
CursorPos = Struct.new(:x, :y)
|
37
28
|
DialogRenderInfo = Struct.new(
|
@@ -263,7 +254,6 @@ module Reline
|
|
263
254
|
raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
|
264
255
|
end
|
265
256
|
|
266
|
-
Reline.update_iogate
|
267
257
|
io_gate.with_raw_input do
|
268
258
|
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
|
269
259
|
end
|
@@ -286,7 +276,6 @@ module Reline
|
|
286
276
|
|
287
277
|
def readline(prompt = '', add_hist = false)
|
288
278
|
@mutex.synchronize do
|
289
|
-
Reline.update_iogate
|
290
279
|
io_gate.with_raw_input do
|
291
280
|
inner_readline(prompt, add_hist, false)
|
292
281
|
end
|
@@ -336,7 +325,7 @@ module Reline
|
|
336
325
|
line_editor.auto_indent_proc = auto_indent_proc
|
337
326
|
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
|
338
327
|
pre_input_hook&.call
|
339
|
-
unless Reline::IOGate
|
328
|
+
unless Reline::IOGate.dumb?
|
340
329
|
@dialog_proc_list.each_pair do |name_sym, d|
|
341
330
|
line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
|
342
331
|
end
|
@@ -378,92 +367,39 @@ module Reline
|
|
378
367
|
end
|
379
368
|
end
|
380
369
|
|
381
|
-
# GNU Readline
|
382
|
-
#
|
383
|
-
#
|
384
|
-
#
|
385
|
-
#
|
386
|
-
#
|
387
|
-
#
|
388
|
-
# GNU Readline will wait for the 2nd character with "keyseq-timeout"
|
389
|
-
# milli-seconds but wait forever after 3rd characters.
|
370
|
+
# GNU Readline watis for "keyseq-timeout" milliseconds when the input is
|
371
|
+
# ambiguous whether it is matching or matched.
|
372
|
+
# If the next character does not arrive within the specified timeout, input
|
373
|
+
# is considered as matched.
|
374
|
+
# `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
|
375
|
+
# `ESC char` or part of CSI sequence (matching).
|
390
376
|
private def read_io(keyseq_timeout, &block)
|
391
377
|
buffer = []
|
378
|
+
status = KeyStroke::MATCHING
|
392
379
|
loop do
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
403
|
-
Reline::Key.new(expanded_c, expanded_c, false)
|
404
|
-
}
|
405
|
-
block.(expanded)
|
406
|
-
break
|
407
|
-
when :matching
|
408
|
-
if buffer.size == 1
|
409
|
-
case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
|
410
|
-
when :break then break
|
411
|
-
when :next then next
|
412
|
-
end
|
413
|
-
end
|
414
|
-
when :unmatched
|
415
|
-
if buffer.size == 1 and c == "\e".ord
|
416
|
-
read_escaped_key(keyseq_timeout, c, block)
|
380
|
+
timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
|
381
|
+
c = io_gate.getc(timeout)
|
382
|
+
if c.nil? || c == -1
|
383
|
+
if status == KeyStroke::MATCHING_MATCHED
|
384
|
+
status = KeyStroke::MATCHED
|
385
|
+
elsif buffer.empty?
|
386
|
+
# io_gate is closed and reached EOF
|
387
|
+
block.call([Key.new(nil, nil, false)])
|
388
|
+
return
|
417
389
|
else
|
418
|
-
|
419
|
-
Reline::Key.new(expanded_c, expanded_c, false)
|
420
|
-
}
|
421
|
-
block.(expanded)
|
390
|
+
status = KeyStroke::UNMATCHED
|
422
391
|
end
|
423
|
-
|
392
|
+
else
|
393
|
+
buffer << c
|
394
|
+
status = key_stroke.match_status(buffer)
|
424
395
|
end
|
425
|
-
end
|
426
|
-
end
|
427
396
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
if c == "\e".ord
|
434
|
-
block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
|
435
|
-
else
|
436
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
|
437
|
-
end
|
438
|
-
return :break
|
439
|
-
when :matching
|
440
|
-
io_gate.ungetc(succ_c)
|
441
|
-
return :next
|
442
|
-
when :matched
|
443
|
-
buffer << succ_c
|
444
|
-
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
445
|
-
Reline::Key.new(expanded_c, expanded_c, false)
|
446
|
-
}
|
447
|
-
block.(expanded)
|
448
|
-
return :break
|
397
|
+
if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
|
398
|
+
expanded, rest_bytes = key_stroke.expand(buffer)
|
399
|
+
rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
|
400
|
+
block.call(expanded)
|
401
|
+
return
|
449
402
|
end
|
450
|
-
else
|
451
|
-
block.([Reline::Key.new(c, c, false)])
|
452
|
-
return :break
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
private def read_escaped_key(keyseq_timeout, c, block)
|
457
|
-
escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000))
|
458
|
-
|
459
|
-
if escaped_c.nil?
|
460
|
-
block.([Reline::Key.new(c, c, false)])
|
461
|
-
elsif escaped_c >= 128 # maybe, first byte of multi byte
|
462
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
|
463
|
-
elsif escaped_c == "\e".ord # escape twice
|
464
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
|
465
|
-
else
|
466
|
-
block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
|
467
403
|
end
|
468
404
|
end
|
469
405
|
|
@@ -473,7 +409,7 @@ module Reline
|
|
473
409
|
end
|
474
410
|
|
475
411
|
private def may_req_ambiguous_char_width
|
476
|
-
@ambiguous_width = 2 if io_gate
|
412
|
+
@ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
|
477
413
|
return if defined? @ambiguous_width
|
478
414
|
io_gate.move_cursor_column(0)
|
479
415
|
begin
|
@@ -567,37 +503,13 @@ module Reline
|
|
567
503
|
def self.line_editor
|
568
504
|
core.line_editor
|
569
505
|
end
|
506
|
+
end
|
570
507
|
|
571
|
-
def self.update_iogate
|
572
|
-
return if core.config.test_mode
|
573
508
|
|
574
|
-
|
575
|
-
# Example: rails/spring boot the application in non-tty, then run console in tty.
|
576
|
-
if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
|
577
|
-
require 'reline/ansi'
|
578
|
-
remove_const(:IOGate)
|
579
|
-
const_set(:IOGate, Reline::ANSI)
|
580
|
-
end
|
581
|
-
end
|
582
|
-
end
|
509
|
+
Reline::IOGate = Reline::IO.decide_io_gate
|
583
510
|
|
584
|
-
|
585
|
-
|
586
|
-
unless ENV['TERM'] == 'dumb'
|
587
|
-
case RbConfig::CONFIG['host_os']
|
588
|
-
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
589
|
-
require 'reline/windows'
|
590
|
-
tty = (io = Reline::Windows).msys_tty?
|
591
|
-
else
|
592
|
-
tty = $stdout.tty?
|
593
|
-
end
|
594
|
-
end
|
595
|
-
Reline::IOGate = if tty
|
596
|
-
require 'reline/ansi'
|
597
|
-
Reline::ANSI
|
598
|
-
else
|
599
|
-
io
|
600
|
-
end
|
511
|
+
# Deprecated
|
512
|
+
Reline::GeneralIO = Reline::Dumb.new
|
601
513
|
|
602
514
|
Reline::Face.load_initial_configs
|
603
515
|
|
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.5.
|
4
|
+
version: 0.5.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|
@@ -35,13 +35,16 @@ files:
|
|
35
35
|
- COPYING
|
36
36
|
- README.md
|
37
37
|
- lib/reline.rb
|
38
|
-
- lib/reline/ansi.rb
|
39
38
|
- lib/reline/config.rb
|
40
39
|
- lib/reline/face.rb
|
41
|
-
- lib/reline/general_io.rb
|
42
40
|
- lib/reline/history.rb
|
41
|
+
- lib/reline/io.rb
|
42
|
+
- lib/reline/io/ansi.rb
|
43
|
+
- lib/reline/io/dumb.rb
|
44
|
+
- lib/reline/io/windows.rb
|
43
45
|
- lib/reline/key_actor.rb
|
44
46
|
- lib/reline/key_actor/base.rb
|
47
|
+
- lib/reline/key_actor/composite.rb
|
45
48
|
- lib/reline/key_actor/emacs.rb
|
46
49
|
- lib/reline/key_actor/vi_command.rb
|
47
50
|
- lib/reline/key_actor/vi_insert.rb
|
@@ -52,7 +55,6 @@ files:
|
|
52
55
|
- lib/reline/unicode.rb
|
53
56
|
- lib/reline/unicode/east_asian_width.rb
|
54
57
|
- lib/reline/version.rb
|
55
|
-
- lib/reline/windows.rb
|
56
58
|
- license_of_rb-readline
|
57
59
|
homepage: https://github.com/ruby/reline
|
58
60
|
licenses:
|