reline 0.5.8 → 0.5.9
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/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:
|