reline 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/reline/ansi.rb +12 -6
- data/lib/reline/general_io.rb +1 -0
- data/lib/reline/line_editor.rb +148 -116
- data/lib/reline/terminfo.rb +7 -14
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +1 -1
- data/lib/reline.rb +31 -42
- 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: 47d262bd9b8ab9b3fb314863af068783c217d53177f947372eb979df2ceaf3cf
|
4
|
+
data.tar.gz: 8112b4441c7946a697adf3d16ec79531fc744fac132ea3cca89ef16b9b6518d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22570f23bfa74602ef627bf977982304b0e5849cbc52abb33f321a32b3860348eabb3efd88bfcfa6b46032433a012813a0fa9aa70422438d0f0694a724ca3055
|
7
|
+
data.tar.gz: 6a30e3c69c1a64149a5cd0517e3c46c6dfb9d724532ded4ab4475c6b595bcf5cdf6b6ffd1b9d32156b8a8a447885bb918d35f78be90934a2e2513f87fdf40bb0
|
data/lib/reline/ansi.rb
CHANGED
@@ -151,7 +151,11 @@ class Reline::ANSI
|
|
151
151
|
end
|
152
152
|
|
153
153
|
def self.with_raw_input
|
154
|
-
@@input.
|
154
|
+
if @@input.tty?
|
155
|
+
@@input.raw(intr: true) { yield }
|
156
|
+
else
|
157
|
+
yield
|
158
|
+
end
|
155
159
|
end
|
156
160
|
|
157
161
|
@@buf = []
|
@@ -159,11 +163,13 @@ class Reline::ANSI
|
|
159
163
|
unless @@buf.empty?
|
160
164
|
return @@buf.shift
|
161
165
|
end
|
162
|
-
until
|
163
|
-
timeout_second -= 0.
|
166
|
+
until @@input.wait_readable(0.01)
|
167
|
+
timeout_second -= 0.01
|
164
168
|
return nil if timeout_second <= 0
|
165
|
-
|
169
|
+
|
170
|
+
Reline.core.line_editor.handle_signal
|
166
171
|
end
|
172
|
+
c = @@input.getbyte
|
167
173
|
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
|
168
174
|
rescue Errno::EIO
|
169
175
|
# Maybe the I/O has been closed.
|
@@ -309,7 +315,7 @@ class Reline::ANSI
|
|
309
315
|
end
|
310
316
|
|
311
317
|
def self.hide_cursor
|
312
|
-
if Reline::Terminfo.enabled?
|
318
|
+
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
|
313
319
|
begin
|
314
320
|
@@output.write Reline::Terminfo.tigetstr('civis')
|
315
321
|
rescue Reline::Terminfo::TerminfoError
|
@@ -321,7 +327,7 @@ class Reline::ANSI
|
|
321
327
|
end
|
322
328
|
|
323
329
|
def self.show_cursor
|
324
|
-
if Reline::Terminfo.enabled?
|
330
|
+
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
|
325
331
|
begin
|
326
332
|
@@output.write Reline::Terminfo.tigetstr('cnorm')
|
327
333
|
rescue Reline::Terminfo::TerminfoError
|
data/lib/reline/general_io.rb
CHANGED
data/lib/reline/line_editor.rb
CHANGED
@@ -41,15 +41,36 @@ class Reline::LineEditor
|
|
41
41
|
NORMAL = :normal
|
42
42
|
COMPLETION = :completion
|
43
43
|
MENU = :menu
|
44
|
-
JOURNEY = :journey
|
45
44
|
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
|
46
45
|
PERFECT_MATCH = :perfect_match
|
47
46
|
end
|
48
47
|
|
49
48
|
RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
|
50
49
|
|
51
|
-
|
52
|
-
|
50
|
+
CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
|
51
|
+
|
52
|
+
class MenuInfo
|
53
|
+
attr_reader :list
|
54
|
+
|
55
|
+
def initialize(list)
|
56
|
+
@list = list
|
57
|
+
end
|
58
|
+
|
59
|
+
def lines(screen_width)
|
60
|
+
return [] if @list.empty?
|
61
|
+
|
62
|
+
list = @list.sort
|
63
|
+
sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
|
64
|
+
item_width = sizes.max + 2
|
65
|
+
num_cols = [screen_width / item_width, 1].max
|
66
|
+
num_rows = list.size.fdiv(num_cols).ceil
|
67
|
+
list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
|
68
|
+
aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
|
69
|
+
aligned.map do |row|
|
70
|
+
row.join.rstrip
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
53
74
|
|
54
75
|
MINIMUM_SCROLLBAR_HEIGHT = 1
|
55
76
|
|
@@ -117,9 +138,6 @@ class Reline::LineEditor
|
|
117
138
|
@screen_size = Reline::IOGate.get_screen_size
|
118
139
|
reset_variables(prompt, encoding: encoding)
|
119
140
|
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
|
120
|
-
Reline::IOGate.set_winch_handler do
|
121
|
-
@resized = true
|
122
|
-
end
|
123
141
|
if ENV.key?('RELINE_ALT_SCROLLBAR')
|
124
142
|
@full_block = '::'
|
125
143
|
@upper_half_block = "''"
|
@@ -143,7 +161,12 @@ class Reline::LineEditor
|
|
143
161
|
end
|
144
162
|
end
|
145
163
|
|
146
|
-
def
|
164
|
+
def handle_signal
|
165
|
+
handle_interrupted
|
166
|
+
handle_resized
|
167
|
+
end
|
168
|
+
|
169
|
+
private def handle_resized
|
147
170
|
return unless @resized
|
148
171
|
|
149
172
|
@screen_size = Reline::IOGate.get_screen_size
|
@@ -156,25 +179,35 @@ class Reline::LineEditor
|
|
156
179
|
render_differential
|
157
180
|
end
|
158
181
|
|
182
|
+
private def handle_interrupted
|
183
|
+
return unless @interrupted
|
184
|
+
|
185
|
+
@interrupted = false
|
186
|
+
clear_dialogs
|
187
|
+
scrolldown = render_differential
|
188
|
+
Reline::IOGate.scroll_down scrolldown
|
189
|
+
Reline::IOGate.move_cursor_column 0
|
190
|
+
@rendered_screen.lines = []
|
191
|
+
@rendered_screen.cursor_y = 0
|
192
|
+
case @old_trap
|
193
|
+
when 'DEFAULT', 'SYSTEM_DEFAULT'
|
194
|
+
raise Interrupt
|
195
|
+
when 'IGNORE'
|
196
|
+
# Do nothing
|
197
|
+
when 'EXIT'
|
198
|
+
exit
|
199
|
+
else
|
200
|
+
@old_trap.call if @old_trap.respond_to?(:call)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
159
204
|
def set_signal_handlers
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
@rendered_screen.cursor_y = 0
|
167
|
-
case @old_trap
|
168
|
-
when 'DEFAULT', 'SYSTEM_DEFAULT'
|
169
|
-
raise Interrupt
|
170
|
-
when 'IGNORE'
|
171
|
-
# Do nothing
|
172
|
-
when 'EXIT'
|
173
|
-
exit
|
174
|
-
else
|
175
|
-
@old_trap.call if @old_trap.respond_to?(:call)
|
176
|
-
end
|
177
|
-
}
|
205
|
+
Reline::IOGate.set_winch_handler do
|
206
|
+
@resized = true
|
207
|
+
end
|
208
|
+
@old_trap = Signal.trap('INT') do
|
209
|
+
@interrupted = true
|
210
|
+
end
|
178
211
|
end
|
179
212
|
|
180
213
|
def finalize
|
@@ -191,7 +224,6 @@ class Reline::LineEditor
|
|
191
224
|
@encoding = encoding
|
192
225
|
@is_multiline = false
|
193
226
|
@finished = false
|
194
|
-
@cleared = false
|
195
227
|
@history_pointer = nil
|
196
228
|
@kill_ring ||= Reline::KillRing.new
|
197
229
|
@vi_clipboard = ''
|
@@ -199,7 +231,7 @@ class Reline::LineEditor
|
|
199
231
|
@waiting_proc = nil
|
200
232
|
@waiting_operator_proc = nil
|
201
233
|
@waiting_operator_vi_arg = nil
|
202
|
-
@
|
234
|
+
@completion_journey_state = nil
|
203
235
|
@completion_state = CompletionState::NORMAL
|
204
236
|
@perfect_matched = nil
|
205
237
|
@menu_info = nil
|
@@ -213,6 +245,7 @@ class Reline::LineEditor
|
|
213
245
|
@in_pasting = false
|
214
246
|
@auto_indent_proc = nil
|
215
247
|
@dialogs = []
|
248
|
+
@interrupted = false
|
216
249
|
@resized = false
|
217
250
|
@cache = {}
|
218
251
|
@rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
|
@@ -458,7 +491,7 @@ class Reline::LineEditor
|
|
458
491
|
[[0, Reline::Unicode.calculate_width(l, true), l]]
|
459
492
|
end
|
460
493
|
if @menu_info
|
461
|
-
@menu_info.
|
494
|
+
@menu_info.lines(screen_width).each do |item|
|
462
495
|
new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
|
463
496
|
end
|
464
497
|
@menu_info = nil # TODO: do not change state here
|
@@ -520,23 +553,13 @@ class Reline::LineEditor
|
|
520
553
|
screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
|
521
554
|
end
|
522
555
|
|
523
|
-
def handle_cleared
|
524
|
-
return unless @cleared
|
525
|
-
|
526
|
-
@cleared = false
|
527
|
-
Reline::IOGate.clear_screen
|
528
|
-
@screen_size = Reline::IOGate.get_screen_size
|
529
|
-
@rendered_screen.lines = []
|
530
|
-
@rendered_screen.base_y = 0
|
531
|
-
@rendered_screen.cursor_y = 0
|
532
|
-
end
|
533
|
-
|
534
556
|
def rerender
|
535
|
-
handle_cleared
|
536
557
|
render_differential unless @in_pasting
|
537
558
|
end
|
538
559
|
|
539
560
|
class DialogProcScope
|
561
|
+
CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
|
562
|
+
|
540
563
|
def initialize(line_editor, config, proc_to_exec, context)
|
541
564
|
@line_editor = line_editor
|
542
565
|
@config = config
|
@@ -600,7 +623,7 @@ class Reline::LineEditor
|
|
600
623
|
end
|
601
624
|
|
602
625
|
def completion_journey_data
|
603
|
-
@line_editor.
|
626
|
+
@line_editor.dialog_proc_scope_completion_journey_data
|
604
627
|
end
|
605
628
|
|
606
629
|
def config
|
@@ -771,7 +794,7 @@ class Reline::LineEditor
|
|
771
794
|
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
|
772
795
|
after.lines("\n").map { |l| l.chomp('') }
|
773
796
|
else
|
774
|
-
before
|
797
|
+
before.map { |l| Reline::Unicode.escape_for_print(l) }
|
775
798
|
end
|
776
799
|
end
|
777
800
|
|
@@ -779,8 +802,8 @@ class Reline::LineEditor
|
|
779
802
|
@config.editing_mode
|
780
803
|
end
|
781
804
|
|
782
|
-
private def menu(
|
783
|
-
@menu_info = MenuInfo.new(
|
805
|
+
private def menu(_target, list)
|
806
|
+
@menu_info = MenuInfo.new(list)
|
784
807
|
end
|
785
808
|
|
786
809
|
private def complete_internal_proc(list, is_menu)
|
@@ -829,9 +852,9 @@ class Reline::LineEditor
|
|
829
852
|
[target, preposing, completed, postposing]
|
830
853
|
end
|
831
854
|
|
832
|
-
private def complete(list, just_show_list
|
855
|
+
private def complete(list, just_show_list)
|
833
856
|
case @completion_state
|
834
|
-
when CompletionState::NORMAL
|
857
|
+
when CompletionState::NORMAL
|
835
858
|
@completion_state = CompletionState::COMPLETION
|
836
859
|
when CompletionState::PERFECT_MATCH
|
837
860
|
@dig_perfect_match_proc&.(@perfect_matched)
|
@@ -871,46 +894,44 @@ class Reline::LineEditor
|
|
871
894
|
end
|
872
895
|
end
|
873
896
|
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
@
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
end
|
894
|
-
end
|
895
|
-
@completion_state = CompletionState::JOURNEY
|
896
|
-
else
|
897
|
-
case direction
|
898
|
-
when :up
|
899
|
-
@completion_journey_data.pointer -= 1
|
900
|
-
if @completion_journey_data.pointer < 0
|
901
|
-
@completion_journey_data.pointer = @completion_journey_data.list.size - 1
|
902
|
-
end
|
903
|
-
when :down
|
904
|
-
@completion_journey_data.pointer += 1
|
905
|
-
if @completion_journey_data.pointer >= @completion_journey_data.list.size
|
906
|
-
@completion_journey_data.pointer = 0
|
907
|
-
end
|
908
|
-
end
|
897
|
+
def dialog_proc_scope_completion_journey_data
|
898
|
+
return nil unless @completion_journey_state
|
899
|
+
line_index = @completion_journey_state.line_index
|
900
|
+
pre_lines = @buffer_of_lines[0...line_index].map { |line| line + "\n" }
|
901
|
+
post_lines = @buffer_of_lines[(line_index + 1)..-1].map { |line| line + "\n" }
|
902
|
+
DialogProcScope::CompletionJourneyData.new(
|
903
|
+
pre_lines.join + @completion_journey_state.pre,
|
904
|
+
@completion_journey_state.post + post_lines.join,
|
905
|
+
@completion_journey_state.list,
|
906
|
+
@completion_journey_state.pointer
|
907
|
+
)
|
908
|
+
end
|
909
|
+
|
910
|
+
private def move_completed_list(direction)
|
911
|
+
@completion_journey_state ||= retrieve_completion_journey_state
|
912
|
+
return false unless @completion_journey_state
|
913
|
+
|
914
|
+
if (delta = { up: -1, down: +1 }[direction])
|
915
|
+
@completion_journey_state.pointer = (@completion_journey_state.pointer + delta) % @completion_journey_state.list.size
|
909
916
|
end
|
910
|
-
completed = @
|
911
|
-
|
912
|
-
|
913
|
-
|
917
|
+
completed = @completion_journey_state.list[@completion_journey_state.pointer]
|
918
|
+
set_current_line(@completion_journey_state.pre + completed + @completion_journey_state.post, @completion_journey_state.pre.bytesize + completed.bytesize)
|
919
|
+
true
|
920
|
+
end
|
921
|
+
|
922
|
+
private def retrieve_completion_journey_state
|
923
|
+
preposing, target, postposing = retrieve_completion_block
|
924
|
+
list = call_completion_proc
|
925
|
+
return unless list.is_a?(Array)
|
926
|
+
|
927
|
+
candidates = list.select{ |item| item.start_with?(target) }
|
928
|
+
return if candidates.empty?
|
929
|
+
|
930
|
+
pre = preposing.split("\n", -1).last || ''
|
931
|
+
post = postposing.split("\n", -1).first || ''
|
932
|
+
CompletionJourneyState.new(
|
933
|
+
@line_index, pre, target, post, [target] + candidates, 0
|
934
|
+
)
|
914
935
|
end
|
915
936
|
|
916
937
|
private def run_for_operators(key, method_symbol, &block)
|
@@ -1099,50 +1120,56 @@ class Reline::LineEditor
|
|
1099
1120
|
@first_char = false
|
1100
1121
|
completion_occurs = false
|
1101
1122
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
1102
|
-
|
1103
|
-
|
1104
|
-
if
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1123
|
+
if !@config.disable_completion
|
1124
|
+
process_insert(force: true)
|
1125
|
+
if @config.autocompletion
|
1126
|
+
@completion_state = CompletionState::NORMAL
|
1127
|
+
completion_occurs = move_completed_list(:down)
|
1128
|
+
else
|
1129
|
+
@completion_journey_state = nil
|
1130
|
+
result = call_completion_proc
|
1131
|
+
if result.is_a?(Array)
|
1132
|
+
completion_occurs = true
|
1133
|
+
complete(result, false)
|
1111
1134
|
end
|
1112
1135
|
end
|
1113
1136
|
end
|
1114
1137
|
elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
|
1115
1138
|
if not @config.disable_completion and @config.autocompletion
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
process_insert
|
1120
|
-
move_completed_list(result, :up)
|
1121
|
-
end
|
1139
|
+
process_insert(force: true)
|
1140
|
+
@completion_state = CompletionState::NORMAL
|
1141
|
+
completion_occurs = move_completed_list(:up)
|
1122
1142
|
end
|
1123
|
-
elsif
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
|
1130
|
-
end
|
1143
|
+
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
1144
|
+
# In vi mode, move completed list even if autocompletion is off
|
1145
|
+
if not @config.disable_completion
|
1146
|
+
process_insert(force: true)
|
1147
|
+
@completion_state = CompletionState::NORMAL
|
1148
|
+
completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
|
1131
1149
|
end
|
1132
1150
|
elsif Symbol === key.char and respond_to?(key.char, true)
|
1133
1151
|
process_key(key.char, key.char)
|
1134
1152
|
else
|
1135
1153
|
normal_char(key)
|
1136
1154
|
end
|
1155
|
+
|
1137
1156
|
unless completion_occurs
|
1138
1157
|
@completion_state = CompletionState::NORMAL
|
1139
|
-
@
|
1158
|
+
@completion_journey_state = nil
|
1140
1159
|
end
|
1160
|
+
|
1141
1161
|
if @in_pasting
|
1142
1162
|
clear_dialogs
|
1143
|
-
|
1144
|
-
|
1163
|
+
return
|
1164
|
+
end
|
1165
|
+
|
1166
|
+
modified = old_lines != @buffer_of_lines
|
1167
|
+
if !completion_occurs && modified && !@config.disable_completion && @config.autocompletion
|
1168
|
+
# Auto complete starts only when edited
|
1169
|
+
process_insert(force: true)
|
1170
|
+
@completion_journey_state = retrieve_completion_journey_state
|
1145
1171
|
end
|
1172
|
+
modified
|
1146
1173
|
end
|
1147
1174
|
|
1148
1175
|
def scroll_into_view
|
@@ -1194,10 +1221,11 @@ class Reline::LineEditor
|
|
1194
1221
|
new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
|
1195
1222
|
return unless new_indent
|
1196
1223
|
|
1197
|
-
|
1224
|
+
new_line = ' ' * new_indent + line.lstrip
|
1225
|
+
@buffer_of_lines[line_index] = new_line
|
1198
1226
|
if @line_index == line_index
|
1199
|
-
|
1200
|
-
@byte_pointer = [@byte_pointer +
|
1227
|
+
indent_diff = new_line.bytesize - line.bytesize
|
1228
|
+
@byte_pointer = [@byte_pointer + indent_diff, 0].max
|
1201
1229
|
end
|
1202
1230
|
end
|
1203
1231
|
|
@@ -2020,7 +2048,7 @@ class Reline::LineEditor
|
|
2020
2048
|
private def em_delete_or_list(key)
|
2021
2049
|
if current_line.empty? or @byte_pointer < current_line.bytesize
|
2022
2050
|
em_delete(key)
|
2023
|
-
|
2051
|
+
elsif !@config.autocompletion # show completed list
|
2024
2052
|
result = call_completion_proc
|
2025
2053
|
if result.is_a?(Array)
|
2026
2054
|
complete(result, true)
|
@@ -2046,7 +2074,11 @@ class Reline::LineEditor
|
|
2046
2074
|
alias_method :yank_pop, :em_yank_pop
|
2047
2075
|
|
2048
2076
|
private def ed_clear_screen(key)
|
2049
|
-
|
2077
|
+
Reline::IOGate.clear_screen
|
2078
|
+
@screen_size = Reline::IOGate.get_screen_size
|
2079
|
+
@rendered_screen.lines = []
|
2080
|
+
@rendered_screen.base_y = 0
|
2081
|
+
@rendered_screen.cursor_y = 0
|
2050
2082
|
end
|
2051
2083
|
alias_method :clear_screen, :ed_clear_screen
|
2052
2084
|
|
data/lib/reline/terminfo.rb
CHANGED
@@ -80,23 +80,11 @@ module Reline::Terminfo
|
|
80
80
|
def self.setupterm(term, fildes)
|
81
81
|
errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
|
82
82
|
ret = @setupterm.(term, fildes, errret_int)
|
83
|
-
errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
|
84
83
|
case ret
|
85
84
|
when 0 # OK
|
86
|
-
|
85
|
+
@term_supported = true
|
87
86
|
when -1 # ERR
|
88
|
-
|
89
|
-
when 1
|
90
|
-
raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
|
91
|
-
when 0
|
92
|
-
raise TerminfoError.new('The terminal could not be found, or that it is a generic type, having too little information for curses applications to run.')
|
93
|
-
when -1
|
94
|
-
raise TerminfoError.new('The terminfo database could not be found.')
|
95
|
-
else # unknown
|
96
|
-
-1
|
97
|
-
end
|
98
|
-
else # unknown
|
99
|
-
-2
|
87
|
+
@term_supported = false
|
100
88
|
end
|
101
89
|
end
|
102
90
|
|
@@ -148,9 +136,14 @@ module Reline::Terminfo
|
|
148
136
|
num
|
149
137
|
end
|
150
138
|
|
139
|
+
# NOTE: This means Fiddle and curses are enabled.
|
151
140
|
def self.enabled?
|
152
141
|
true
|
153
142
|
end
|
143
|
+
|
144
|
+
def self.term_supported?
|
145
|
+
@term_supported
|
146
|
+
end
|
154
147
|
end if Reline::Terminfo.curses_dl
|
155
148
|
|
156
149
|
module Reline::Terminfo
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -259,7 +259,7 @@ class Reline::Windows
|
|
259
259
|
def self.check_input_event
|
260
260
|
num_of_events = 0.chr * 8
|
261
261
|
while @@output_buf.empty?
|
262
|
-
Reline.core.line_editor.
|
262
|
+
Reline.core.line_editor.handle_signal
|
263
263
|
if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
|
264
264
|
# prevent for background consolemode change
|
265
265
|
@@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
|
data/lib/reline.rb
CHANGED
@@ -75,6 +75,7 @@ module Reline
|
|
75
75
|
|
76
76
|
def initialize
|
77
77
|
self.output = STDOUT
|
78
|
+
@mutex = Mutex.new
|
78
79
|
@dialog_proc_list = {}
|
79
80
|
yield self
|
80
81
|
@completion_quote_character = nil
|
@@ -219,26 +220,16 @@ module Reline
|
|
219
220
|
|
220
221
|
Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
|
221
222
|
# autocomplete
|
222
|
-
return
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
result = completion_journey_data.list.dup
|
233
|
-
result.shift
|
234
|
-
pointer = completion_journey_data.pointer - 1
|
235
|
-
else
|
236
|
-
result = call_completion_proc_with_checking_args(pre, target, post)
|
237
|
-
pointer = nil
|
238
|
-
end
|
239
|
-
if result and result.size == 1 and result[0] == target and pointer != 0
|
240
|
-
result = nil
|
241
|
-
end
|
223
|
+
return unless config.autocompletion
|
224
|
+
|
225
|
+
journey_data = completion_journey_data
|
226
|
+
return unless journey_data
|
227
|
+
|
228
|
+
target = journey_data.list[journey_data.pointer]
|
229
|
+
result = journey_data.list.drop(1)
|
230
|
+
pointer = journey_data.pointer - 1
|
231
|
+
return if target.empty? || (result == [target] && pointer < 0)
|
232
|
+
|
242
233
|
target_width = Reline::Unicode.calculate_width(target)
|
243
234
|
x = cursor_pos.x - target_width
|
244
235
|
if x < 0
|
@@ -264,12 +255,15 @@ module Reline
|
|
264
255
|
Reline::DEFAULT_DIALOG_CONTEXT = Array.new
|
265
256
|
|
266
257
|
def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
|
267
|
-
|
268
|
-
io_gate.with_raw_input do
|
258
|
+
@mutex.synchronize do
|
269
259
|
unless confirm_multiline_termination
|
270
260
|
raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
|
271
261
|
end
|
272
|
-
|
262
|
+
|
263
|
+
Reline.update_iogate
|
264
|
+
io_gate.with_raw_input do
|
265
|
+
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
|
266
|
+
end
|
273
267
|
|
274
268
|
whole_buffer = line_editor.whole_buffer.dup
|
275
269
|
whole_buffer.taint if RUBY_VERSION < '2.7'
|
@@ -288,17 +282,21 @@ module Reline
|
|
288
282
|
end
|
289
283
|
|
290
284
|
def readline(prompt = '', add_hist = false)
|
291
|
-
|
292
|
-
|
285
|
+
@mutex.synchronize do
|
286
|
+
Reline.update_iogate
|
287
|
+
io_gate.with_raw_input do
|
288
|
+
inner_readline(prompt, add_hist, false)
|
289
|
+
end
|
293
290
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
291
|
+
line = line_editor.line.dup
|
292
|
+
line.taint if RUBY_VERSION < '2.7'
|
293
|
+
if add_hist and line and line.chomp("\n").size > 0
|
294
|
+
Reline::HISTORY << line.chomp("\n")
|
295
|
+
end
|
299
296
|
|
300
|
-
|
301
|
-
|
297
|
+
line_editor.reset_line if line_editor.line.nil?
|
298
|
+
line
|
299
|
+
end
|
302
300
|
end
|
303
301
|
|
304
302
|
private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
|
@@ -365,19 +363,10 @@ module Reline
|
|
365
363
|
io_gate.move_cursor_column(0)
|
366
364
|
rescue Errno::EIO
|
367
365
|
# Maybe the I/O has been closed.
|
368
|
-
|
369
|
-
line_editor.finalize
|
370
|
-
io_gate.deprep(otio)
|
371
|
-
raise e
|
372
|
-
rescue Exception
|
373
|
-
# Including Interrupt
|
366
|
+
ensure
|
374
367
|
line_editor.finalize
|
375
368
|
io_gate.deprep(otio)
|
376
|
-
raise
|
377
369
|
end
|
378
|
-
|
379
|
-
line_editor.finalize
|
380
|
-
io_gate.deprep(otio)
|
381
370
|
end
|
382
371
|
|
383
372
|
# GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
|
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.1
|
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-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|