reline 0.5.0 → 0.5.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b325efda8753fa1ecea3b1dabfd685416016ee334876673bf0d965c3a02095d
4
- data.tar.gz: 4b22612ebce12cc96593f98535bfb9223eebbded388931ccbd8bbdb4d13ce1d1
3
+ metadata.gz: 68e79c30bbef8d97090f7126f96c5ee0c32fa95e6dc120a91240a6e9ff3864c6
4
+ data.tar.gz: 857716d3f9ab324efef98d3cb42acf2bba17848012a832c5631ca3e6d2f15733
5
5
  SHA512:
6
- metadata.gz: 29f19adce6163f38399da6119c3605039593d244c7119d601b413279a678cd87a5ad5eba5679f2ea7ccc1bdf7b4743987b2840cf4c0f69fa316c0d2fa84b5f45
7
- data.tar.gz: be0b1ad84d01936ff721b3a18f196d0ee19817da6baf9200e4e6a96681e4b87594c55d1aa71071fcda63f35c4c8d0aefa7aa7a016c62c538d165e19f82e7d3b8
6
+ metadata.gz: b25e6a151ded60963f660ccafceef8c221577b9f2328b9daa10dc381f5ea63c293a9759a786ab02610eb2fb07c52f3a200303fd9ac672210658884cb9a57c88c
7
+ data.tar.gz: 8433437480cf5acf7d87aefc632cc641e9325f163ab1d00d1df9cea5d5f3977f05250b20b366d7fd21ae275edd8f152ddc5879fa88340fbf35990e9b2a7e9725
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.raw { yield }
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 c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
163
- timeout_second -= 0.1
166
+ until @@input.wait_readable(0.01)
167
+ timeout_second -= 0.01
164
168
  return nil if timeout_second <= 0
165
- Reline.core.line_editor.resize
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
@@ -46,6 +46,7 @@ class Reline::GeneralIO
46
46
  end
47
47
  c = nil
48
48
  loop do
49
+ Reline.core.line_editor.handle_signal
49
50
  result = @@input.wait_readable(0.1)
50
51
  next if result.nil?
51
52
  c = @@input.read(1)
@@ -49,13 +49,13 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
49
49
  # 23 ^W
50
50
  :em_kill_region,
51
51
  # 24 ^X
52
- :ed_sequence_lead_in,
52
+ :ed_unassigned,
53
53
  # 25 ^Y
54
54
  :em_yank,
55
55
  # 26 ^Z
56
56
  :ed_ignore,
57
57
  # 27 ^[
58
- :em_meta_next,
58
+ :ed_unassigned,
59
59
  # 28 ^\
60
60
  :ed_ignore,
61
61
  # 29 ^]
@@ -319,9 +319,9 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
319
319
  # 158 M-^^
320
320
  :ed_unassigned,
321
321
  # 159 M-^_
322
- :em_copy_prev_word,
323
- # 160 M-SPACE
324
322
  :ed_unassigned,
323
+ # 160 M-SPACE
324
+ :em_set_mark,
325
325
  # 161 M-!
326
326
  :ed_unassigned,
327
327
  # 162 M-"
@@ -415,7 +415,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
415
415
  # 206 M-N
416
416
  :vi_search_next,
417
417
  # 207 M-O
418
- :ed_sequence_lead_in,
418
+ :ed_unassigned,
419
419
  # 208 M-P
420
420
  :vi_search_prev,
421
421
  # 209 M-Q
@@ -431,15 +431,15 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
431
431
  # 214 M-V
432
432
  :ed_unassigned,
433
433
  # 215 M-W
434
- :em_copy_region,
434
+ :ed_unassigned,
435
435
  # 216 M-X
436
- :ed_command,
437
- # 217 M-Y
438
436
  :ed_unassigned,
437
+ # 217 M-Y
438
+ :em_yank_pop,
439
439
  # 218 M-Z
440
440
  :ed_unassigned,
441
441
  # 219 M-[
442
- :ed_sequence_lead_in,
442
+ :ed_unassigned,
443
443
  # 220 M-\
444
444
  :ed_unassigned,
445
445
  # 221 M-]
@@ -495,9 +495,9 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
495
495
  # 246 M-v
496
496
  :ed_unassigned,
497
497
  # 247 M-w
498
- :em_copy_region,
498
+ :ed_unassigned,
499
499
  # 248 M-x
500
- :ed_command,
500
+ :ed_unassigned,
501
501
  # 249 M-y
502
502
  :ed_unassigned,
503
503
  # 250 M-z
@@ -17,7 +17,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
17
17
  # 7 ^G
18
18
  :ed_unassigned,
19
19
  # 8 ^H
20
- :ed_unassigned,
20
+ :ed_prev_char,
21
21
  # 9 ^I
22
22
  :ed_unassigned,
23
23
  # 10 ^J
@@ -41,7 +41,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
41
41
  # 19 ^S
42
42
  :ed_ignore,
43
43
  # 20 ^T
44
- :ed_unassigned,
44
+ :ed_transpose_chars,
45
45
  # 21 ^U
46
46
  :vi_kill_line_prev,
47
47
  # 22 ^V
@@ -51,7 +51,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
51
51
  # 24 ^X
52
52
  :ed_unassigned,
53
53
  # 25 ^Y
54
- :ed_unassigned,
54
+ :em_yank,
55
55
  # 26 ^Z
56
56
  :ed_unassigned,
57
57
  # 27 ^[
@@ -75,7 +75,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
75
75
  # 36 $
76
76
  :ed_move_to_end,
77
77
  # 37 %
78
- :vi_match,
78
+ :ed_unassigned,
79
79
  # 38 &
80
80
  :ed_unassigned,
81
81
  # 39 '
@@ -89,11 +89,11 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
89
89
  # 43 +
90
90
  :ed_next_history,
91
91
  # 44 ,
92
- :vi_repeat_prev_char,
92
+ :ed_unassigned,
93
93
  # 45 -
94
94
  :ed_prev_history,
95
95
  # 46 .
96
- :vi_redo,
96
+ :ed_unassigned,
97
97
  # 47 /
98
98
  :vi_search_prev,
99
99
  # 48 0
@@ -117,9 +117,9 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
117
117
  # 57 9
118
118
  :ed_argument_digit,
119
119
  # 58 :
120
- :ed_command,
120
+ :ed_unassigned,
121
121
  # 59 ;
122
- :vi_repeat_next_char,
122
+ :ed_unassigned,
123
123
  # 60 <
124
124
  :ed_unassigned,
125
125
  # 61 =
@@ -157,21 +157,21 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
157
157
  # 77 M
158
158
  :ed_unassigned,
159
159
  # 78 N
160
- :vi_repeat_search_prev,
160
+ :ed_unassigned,
161
161
  # 79 O
162
- :ed_sequence_lead_in,
162
+ :ed_unassigned,
163
163
  # 80 P
164
164
  :vi_paste_prev,
165
165
  # 81 Q
166
166
  :ed_unassigned,
167
167
  # 82 R
168
- :vi_replace_mode,
168
+ :ed_unassigned,
169
169
  # 83 S
170
- :vi_substitute_line,
170
+ :ed_unassigned,
171
171
  # 84 T
172
172
  :vi_to_prev_char,
173
173
  # 85 U
174
- :vi_undo_line,
174
+ :ed_unassigned,
175
175
  # 86 V
176
176
  :ed_unassigned,
177
177
  # 87 W
@@ -179,11 +179,11 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
179
179
  # 88 X
180
180
  :ed_delete_prev_char,
181
181
  # 89 Y
182
- :vi_yank_end,
182
+ :ed_unassigned,
183
183
  # 90 Z
184
184
  :ed_unassigned,
185
185
  # 91 [
186
- :ed_sequence_lead_in,
186
+ :ed_unassigned,
187
187
  # 92 \
188
188
  :ed_unassigned,
189
189
  # 93 ]
@@ -191,7 +191,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
191
191
  # 94 ^
192
192
  :vi_first_print,
193
193
  # 95 _
194
- :vi_history_word,
194
+ :ed_unassigned,
195
195
  # 96 `
196
196
  :ed_unassigned,
197
197
  # 97 a
@@ -221,7 +221,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
221
221
  # 109 m
222
222
  :ed_unassigned,
223
223
  # 110 n
224
- :vi_repeat_search_next,
224
+ :ed_unassigned,
225
225
  # 111 o
226
226
  :ed_unassigned,
227
227
  # 112 p
@@ -231,11 +231,11 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
231
231
  # 114 r
232
232
  :vi_replace_char,
233
233
  # 115 s
234
- :vi_substitute_char,
234
+ :ed_unassigned,
235
235
  # 116 t
236
236
  :vi_to_next_char,
237
237
  # 117 u
238
- :vi_undo,
238
+ :ed_unassigned,
239
239
  # 118 v
240
240
  :vi_histedit,
241
241
  # 119 w
@@ -253,9 +253,9 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
253
253
  # 125 }
254
254
  :ed_unassigned,
255
255
  # 126 ~
256
- :vi_change_case,
257
- # 127 ^?
258
256
  :ed_unassigned,
257
+ # 127 ^?
258
+ :em_delete_prev_char,
259
259
  # 128 M-^@
260
260
  :ed_unassigned,
261
261
  # 129 M-^A
@@ -415,7 +415,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
415
415
  # 206 M-N
416
416
  :ed_unassigned,
417
417
  # 207 M-O
418
- :ed_sequence_lead_in,
418
+ :ed_unassigned,
419
419
  # 208 M-P
420
420
  :ed_unassigned,
421
421
  # 209 M-Q
@@ -439,7 +439,7 @@ class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
439
439
  # 218 M-Z
440
440
  :ed_unassigned,
441
441
  # 219 M-[
442
- :ed_sequence_lead_in,
442
+ :ed_unassigned,
443
443
  # 220 M-\
444
444
  :ed_unassigned,
445
445
  # 221 M-]
@@ -41,7 +41,7 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
41
41
  # 19 ^S
42
42
  :vi_search_next,
43
43
  # 20 ^T
44
- :ed_insert,
44
+ :ed_transpose_chars,
45
45
  # 21 ^U
46
46
  :vi_kill_line_prev,
47
47
  # 22 ^V
@@ -51,7 +51,7 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
51
51
  # 24 ^X
52
52
  :ed_insert,
53
53
  # 25 ^Y
54
- :ed_insert,
54
+ :em_yank,
55
55
  # 26 ^Z
56
56
  :ed_insert,
57
57
  # 27 ^[
@@ -33,23 +33,42 @@ class Reline::LineEditor
33
33
  vi_next_big_word
34
34
  vi_prev_big_word
35
35
  vi_end_big_word
36
- vi_repeat_next_char
37
- vi_repeat_prev_char
38
36
  }
39
37
 
40
38
  module CompletionState
41
39
  NORMAL = :normal
42
40
  COMPLETION = :completion
43
41
  MENU = :menu
44
- JOURNEY = :journey
45
42
  MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
46
43
  PERFECT_MATCH = :perfect_match
47
44
  end
48
45
 
49
46
  RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
50
47
 
51
- CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
52
- MenuInfo = Struct.new(:target, :list)
48
+ CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
49
+
50
+ class MenuInfo
51
+ attr_reader :list
52
+
53
+ def initialize(list)
54
+ @list = list
55
+ end
56
+
57
+ def lines(screen_width)
58
+ return [] if @list.empty?
59
+
60
+ list = @list.sort
61
+ sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
62
+ item_width = sizes.max + 2
63
+ num_cols = [screen_width / item_width, 1].max
64
+ num_rows = list.size.fdiv(num_cols).ceil
65
+ list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
66
+ aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
67
+ aligned.map do |row|
68
+ row.join.rstrip
69
+ end
70
+ end
71
+ end
53
72
 
54
73
  MINIMUM_SCROLLBAR_HEIGHT = 1
55
74
 
@@ -117,9 +136,6 @@ class Reline::LineEditor
117
136
  @screen_size = Reline::IOGate.get_screen_size
118
137
  reset_variables(prompt, encoding: encoding)
119
138
  @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
120
- Reline::IOGate.set_winch_handler do
121
- @resized = true
122
- end
123
139
  if ENV.key?('RELINE_ALT_SCROLLBAR')
124
140
  @full_block = '::'
125
141
  @upper_half_block = "''"
@@ -143,7 +159,12 @@ class Reline::LineEditor
143
159
  end
144
160
  end
145
161
 
146
- def resize
162
+ def handle_signal
163
+ handle_interrupted
164
+ handle_resized
165
+ end
166
+
167
+ private def handle_resized
147
168
  return unless @resized
148
169
 
149
170
  @screen_size = Reline::IOGate.get_screen_size
@@ -156,25 +177,35 @@ class Reline::LineEditor
156
177
  render_differential
157
178
  end
158
179
 
180
+ private def handle_interrupted
181
+ return unless @interrupted
182
+
183
+ @interrupted = false
184
+ clear_dialogs
185
+ scrolldown = render_differential
186
+ Reline::IOGate.scroll_down scrolldown
187
+ Reline::IOGate.move_cursor_column 0
188
+ @rendered_screen.lines = []
189
+ @rendered_screen.cursor_y = 0
190
+ case @old_trap
191
+ when 'DEFAULT', 'SYSTEM_DEFAULT'
192
+ raise Interrupt
193
+ when 'IGNORE'
194
+ # Do nothing
195
+ when 'EXIT'
196
+ exit
197
+ else
198
+ @old_trap.call if @old_trap.respond_to?(:call)
199
+ end
200
+ end
201
+
159
202
  def set_signal_handlers
160
- @old_trap = Signal.trap('INT') {
161
- clear_dialogs
162
- scrolldown = render_differential
163
- Reline::IOGate.scroll_down scrolldown
164
- Reline::IOGate.move_cursor_column 0
165
- @rendered_screen.lines = []
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
- }
203
+ Reline::IOGate.set_winch_handler do
204
+ @resized = true
205
+ end
206
+ @old_trap = Signal.trap('INT') do
207
+ @interrupted = true
208
+ end
178
209
  end
179
210
 
180
211
  def finalize
@@ -191,16 +222,16 @@ class Reline::LineEditor
191
222
  @encoding = encoding
192
223
  @is_multiline = false
193
224
  @finished = false
194
- @cleared = false
195
225
  @history_pointer = nil
196
226
  @kill_ring ||= Reline::KillRing.new
197
227
  @vi_clipboard = ''
198
228
  @vi_arg = nil
199
229
  @waiting_proc = nil
200
- @waiting_operator_proc = nil
201
- @waiting_operator_vi_arg = nil
202
- @completion_journey_data = nil
230
+ @vi_waiting_operator = nil
231
+ @vi_waiting_operator_arg = nil
232
+ @completion_journey_state = nil
203
233
  @completion_state = CompletionState::NORMAL
234
+ @completion_occurs = false
204
235
  @perfect_matched = nil
205
236
  @menu_info = nil
206
237
  @searching_prompt = nil
@@ -213,6 +244,7 @@ class Reline::LineEditor
213
244
  @in_pasting = false
214
245
  @auto_indent_proc = nil
215
246
  @dialogs = []
247
+ @interrupted = false
216
248
  @resized = false
217
249
  @cache = {}
218
250
  @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
@@ -458,7 +490,7 @@ class Reline::LineEditor
458
490
  [[0, Reline::Unicode.calculate_width(l, true), l]]
459
491
  end
460
492
  if @menu_info
461
- @menu_info.list.sort!.each do |item|
493
+ @menu_info.lines(screen_width).each do |item|
462
494
  new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
463
495
  end
464
496
  @menu_info = nil # TODO: do not change state here
@@ -508,10 +540,6 @@ class Reline::LineEditor
508
540
  new_lines.size - y
509
541
  end
510
542
 
511
- def current_row
512
- wrapped_lines.flatten[wrapped_cursor_y]
513
- end
514
-
515
543
  def upper_space_height(wrapped_cursor_y)
516
544
  wrapped_cursor_y - screen_scroll_top
517
545
  end
@@ -520,23 +548,13 @@ class Reline::LineEditor
520
548
  screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
521
549
  end
522
550
 
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
551
  def rerender
535
- handle_cleared
536
552
  render_differential unless @in_pasting
537
553
  end
538
554
 
539
555
  class DialogProcScope
556
+ CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
557
+
540
558
  def initialize(line_editor, config, proc_to_exec, context)
541
559
  @line_editor = line_editor
542
560
  @config = config
@@ -600,7 +618,7 @@ class Reline::LineEditor
600
618
  end
601
619
 
602
620
  def completion_journey_data
603
- @line_editor.instance_variable_get(:@completion_journey_data)
621
+ @line_editor.dialog_proc_scope_completion_journey_data
604
622
  end
605
623
 
606
624
  def config
@@ -771,7 +789,7 @@ class Reline::LineEditor
771
789
  if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
772
790
  after.lines("\n").map { |l| l.chomp('') }
773
791
  else
774
- before
792
+ before.map { |l| Reline::Unicode.escape_for_print(l) }
775
793
  end
776
794
  end
777
795
 
@@ -779,8 +797,8 @@ class Reline::LineEditor
779
797
  @config.editing_mode
780
798
  end
781
799
 
782
- private def menu(target, list)
783
- @menu_info = MenuInfo.new(target, list)
800
+ private def menu(_target, list)
801
+ @menu_info = MenuInfo.new(list)
784
802
  end
785
803
 
786
804
  private def complete_internal_proc(list, is_menu)
@@ -829,9 +847,9 @@ class Reline::LineEditor
829
847
  [target, preposing, completed, postposing]
830
848
  end
831
849
 
832
- private def complete(list, just_show_list = false)
850
+ private def complete(list, just_show_list)
833
851
  case @completion_state
834
- when CompletionState::NORMAL, CompletionState::JOURNEY
852
+ when CompletionState::NORMAL
835
853
  @completion_state = CompletionState::COMPLETION
836
854
  when CompletionState::PERFECT_MATCH
837
855
  @dig_perfect_match_proc&.(@perfect_matched)
@@ -871,80 +889,64 @@ class Reline::LineEditor
871
889
  end
872
890
  end
873
891
 
874
- private def move_completed_list(list, direction)
875
- case @completion_state
876
- when CompletionState::NORMAL, CompletionState::COMPLETION,
877
- CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
878
- @completion_state = CompletionState::JOURNEY
879
- result = retrieve_completion_block
880
- return if result.nil?
881
- preposing, target, postposing = result
882
- @completion_journey_data = CompletionJourneyData.new(
883
- preposing, postposing,
884
- [target] + list.select{ |item| item.start_with?(target) }, 0)
885
- if @completion_journey_data.list.size == 1
886
- @completion_journey_data.pointer = 0
887
- else
888
- case direction
889
- when :up
890
- @completion_journey_data.pointer = @completion_journey_data.list.size - 1
891
- when :down
892
- @completion_journey_data.pointer = 1
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
892
+ def dialog_proc_scope_completion_journey_data
893
+ return nil unless @completion_journey_state
894
+ line_index = @completion_journey_state.line_index
895
+ pre_lines = @buffer_of_lines[0...line_index].map { |line| line + "\n" }
896
+ post_lines = @buffer_of_lines[(line_index + 1)..-1].map { |line| line + "\n" }
897
+ DialogProcScope::CompletionJourneyData.new(
898
+ pre_lines.join + @completion_journey_state.pre,
899
+ @completion_journey_state.post + post_lines.join,
900
+ @completion_journey_state.list,
901
+ @completion_journey_state.pointer
902
+ )
903
+ end
904
+
905
+ private def move_completed_list(direction)
906
+ @completion_journey_state ||= retrieve_completion_journey_state
907
+ return false unless @completion_journey_state
908
+
909
+ if (delta = { up: -1, down: +1 }[direction])
910
+ @completion_journey_state.pointer = (@completion_journey_state.pointer + delta) % @completion_journey_state.list.size
909
911
  end
910
- completed = @completion_journey_data.list[@completion_journey_data.pointer]
911
- line_to_pointer = (@completion_journey_data.preposing + completed).split("\n")[@line_index] || String.new(encoding: @encoding)
912
- new_line = line_to_pointer + (@completion_journey_data.postposing.split("\n").first || '')
913
- set_current_line(new_line, line_to_pointer.bytesize)
912
+ completed = @completion_journey_state.list[@completion_journey_state.pointer]
913
+ set_current_line(@completion_journey_state.pre + completed + @completion_journey_state.post, @completion_journey_state.pre.bytesize + completed.bytesize)
914
+ true
915
+ end
916
+
917
+ private def retrieve_completion_journey_state
918
+ preposing, target, postposing = retrieve_completion_block
919
+ list = call_completion_proc
920
+ return unless list.is_a?(Array)
921
+
922
+ candidates = list.select{ |item| item.start_with?(target) }
923
+ return if candidates.empty?
924
+
925
+ pre = preposing.split("\n", -1).last || ''
926
+ post = postposing.split("\n", -1).first || ''
927
+ CompletionJourneyState.new(
928
+ @line_index, pre, target, post, [target] + candidates, 0
929
+ )
914
930
  end
915
931
 
916
932
  private def run_for_operators(key, method_symbol, &block)
917
- if @waiting_operator_proc
933
+ if @vi_waiting_operator
918
934
  if VI_MOTIONS.include?(method_symbol)
919
935
  old_byte_pointer = @byte_pointer
920
- @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
936
+ @vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
921
937
  block.(true)
922
938
  unless @waiting_proc
923
939
  byte_pointer_diff = @byte_pointer - old_byte_pointer
924
940
  @byte_pointer = old_byte_pointer
925
- @waiting_operator_proc.(byte_pointer_diff)
926
- else
927
- old_waiting_proc = @waiting_proc
928
- old_waiting_operator_proc = @waiting_operator_proc
929
- current_waiting_operator_proc = @waiting_operator_proc
930
- @waiting_proc = proc { |k|
931
- old_byte_pointer = @byte_pointer
932
- old_waiting_proc.(k)
933
- byte_pointer_diff = @byte_pointer - old_byte_pointer
934
- @byte_pointer = old_byte_pointer
935
- current_waiting_operator_proc.(byte_pointer_diff)
936
- @waiting_operator_proc = old_waiting_operator_proc
937
- }
941
+ send(@vi_waiting_operator, byte_pointer_diff)
942
+ cleanup_waiting
938
943
  end
939
944
  else
940
945
  # Ignores operator when not motion is given.
941
946
  block.(false)
947
+ cleanup_waiting
942
948
  end
943
- @waiting_operator_proc = nil
944
- @waiting_operator_vi_arg = nil
945
- if @vi_arg
946
- @vi_arg = nil
947
- end
949
+ @vi_arg = nil
948
950
  else
949
951
  block.(false)
950
952
  end
@@ -961,7 +963,7 @@ class Reline::LineEditor
961
963
  end
962
964
 
963
965
  def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
964
- if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil?
966
+ if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
965
967
  not_insertion = method_symbol != :ed_insert
966
968
  process_insert(force: not_insertion)
967
969
  end
@@ -980,11 +982,32 @@ class Reline::LineEditor
980
982
  end
981
983
  end
982
984
 
985
+ private def cleanup_waiting
986
+ @waiting_proc = nil
987
+ @vi_waiting_operator = nil
988
+ @vi_waiting_operator_arg = nil
989
+ @searching_prompt = nil
990
+ @drop_terminate_spaces = false
991
+ end
992
+
983
993
  private def process_key(key, method_symbol)
994
+ if key.is_a?(Symbol)
995
+ cleanup_waiting
996
+ elsif @waiting_proc
997
+ old_byte_pointer = @byte_pointer
998
+ @waiting_proc.call(key)
999
+ if @vi_waiting_operator
1000
+ byte_pointer_diff = @byte_pointer - old_byte_pointer
1001
+ @byte_pointer = old_byte_pointer
1002
+ send(@vi_waiting_operator, byte_pointer_diff)
1003
+ cleanup_waiting
1004
+ end
1005
+ @kill_ring.process
1006
+ return
1007
+ end
1008
+
984
1009
  if method_symbol and respond_to?(method_symbol, true)
985
1010
  method_obj = method(method_symbol)
986
- else
987
- method_obj = nil
988
1011
  end
989
1012
  if method_symbol and key.is_a?(Symbol)
990
1013
  if @vi_arg and argumentable?(method_obj)
@@ -1006,8 +1029,6 @@ class Reline::LineEditor
1006
1029
  run_for_operators(key, method_symbol) do |with_operator|
1007
1030
  wrap_method_call(method_symbol, method_obj, key, with_operator)
1008
1031
  end
1009
- elsif @waiting_proc
1010
- @waiting_proc.(key)
1011
1032
  elsif method_obj
1012
1033
  wrap_method_call(method_symbol, method_obj, key)
1013
1034
  else
@@ -1018,9 +1039,6 @@ class Reline::LineEditor
1018
1039
  @vi_arg = nil
1019
1040
  end
1020
1041
  end
1021
- elsif @waiting_proc
1022
- @waiting_proc.(key)
1023
- @kill_ring.process
1024
1042
  elsif method_obj
1025
1043
  if method_symbol == :ed_argument_digit
1026
1044
  wrap_method_call(method_symbol, method_obj, key)
@@ -1097,52 +1115,51 @@ class Reline::LineEditor
1097
1115
  end
1098
1116
  old_lines = @buffer_of_lines.dup
1099
1117
  @first_char = false
1100
- completion_occurs = false
1118
+ @completion_occurs = false
1101
1119
  if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
1102
- unless @config.disable_completion
1103
- result = call_completion_proc
1104
- if result.is_a?(Array)
1105
- completion_occurs = true
1106
- process_insert
1107
- if @config.autocompletion
1108
- move_completed_list(result, :down)
1109
- else
1110
- complete(result)
1120
+ if !@config.disable_completion
1121
+ process_insert(force: true)
1122
+ if @config.autocompletion
1123
+ @completion_state = CompletionState::NORMAL
1124
+ @completion_occurs = move_completed_list(:down)
1125
+ else
1126
+ @completion_journey_state = nil
1127
+ result = call_completion_proc
1128
+ if result.is_a?(Array)
1129
+ @completion_occurs = true
1130
+ complete(result, false)
1111
1131
  end
1112
1132
  end
1113
1133
  end
1114
- elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
1115
- if not @config.disable_completion and @config.autocompletion
1116
- result = call_completion_proc
1117
- if result.is_a?(Array)
1118
- completion_occurs = true
1119
- process_insert
1120
- move_completed_list(result, :up)
1121
- end
1122
- end
1123
- elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
1124
- unless @config.disable_completion
1125
- result = call_completion_proc
1126
- if result.is_a?(Array)
1127
- completion_occurs = true
1128
- process_insert
1129
- move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
1130
- end
1134
+ elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
1135
+ # In vi mode, move completed list even if autocompletion is off
1136
+ if not @config.disable_completion
1137
+ process_insert(force: true)
1138
+ @completion_state = CompletionState::NORMAL
1139
+ @completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
1131
1140
  end
1132
1141
  elsif Symbol === key.char and respond_to?(key.char, true)
1133
1142
  process_key(key.char, key.char)
1134
1143
  else
1135
1144
  normal_char(key)
1136
1145
  end
1137
- unless completion_occurs
1146
+ unless @completion_occurs
1138
1147
  @completion_state = CompletionState::NORMAL
1139
- @completion_journey_data = nil
1148
+ @completion_journey_state = nil
1140
1149
  end
1150
+
1141
1151
  if @in_pasting
1142
1152
  clear_dialogs
1143
- else
1144
- return old_lines != @buffer_of_lines
1153
+ return
1154
+ end
1155
+
1156
+ modified = old_lines != @buffer_of_lines
1157
+ if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
1158
+ # Auto complete starts only when edited
1159
+ process_insert(force: true)
1160
+ @completion_journey_state = retrieve_completion_journey_state
1145
1161
  end
1162
+ modified
1146
1163
  end
1147
1164
 
1148
1165
  def scroll_into_view
@@ -1194,10 +1211,11 @@ class Reline::LineEditor
1194
1211
  new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
1195
1212
  return unless new_indent
1196
1213
 
1197
- @buffer_of_lines[line_index] = ' ' * new_indent + line.lstrip
1214
+ new_line = ' ' * new_indent + line.lstrip
1215
+ @buffer_of_lines[line_index] = new_line
1198
1216
  if @line_index == line_index
1199
- old_indent = line[/\A */].size
1200
- @byte_pointer = [@byte_pointer + new_indent - old_indent, 0].max
1217
+ indent_diff = new_line.bytesize - line.bytesize
1218
+ @byte_pointer = [@byte_pointer + indent_diff, 0].max
1201
1219
  end
1202
1220
  end
1203
1221
 
@@ -1405,6 +1423,14 @@ class Reline::LineEditor
1405
1423
  end
1406
1424
  end
1407
1425
 
1426
+ private def completion_journey_up(key)
1427
+ if not @config.disable_completion and @config.autocompletion
1428
+ @completion_state = CompletionState::NORMAL
1429
+ @completion_occurs = move_completed_list(:up)
1430
+ end
1431
+ end
1432
+ alias_method :menu_complete_backward, :completion_journey_up
1433
+
1408
1434
  # Editline:: +ed-unassigned+ This editor command always results in an error.
1409
1435
  # GNU Readline:: There is no corresponding macro.
1410
1436
  private def ed_unassigned(key) end # do nothing
@@ -1506,6 +1532,7 @@ class Reline::LineEditor
1506
1532
  @byte_pointer = 0
1507
1533
  end
1508
1534
  alias_method :beginning_of_line, :ed_move_to_beg
1535
+ alias_method :vi_zero, :ed_move_to_beg
1509
1536
 
1510
1537
  private def ed_move_to_end(key)
1511
1538
  @byte_pointer = 0
@@ -2020,7 +2047,7 @@ class Reline::LineEditor
2020
2047
  private def em_delete_or_list(key)
2021
2048
  if current_line.empty? or @byte_pointer < current_line.bytesize
2022
2049
  em_delete(key)
2023
- else # show completed list
2050
+ elsif !@config.autocompletion # show completed list
2024
2051
  result = call_completion_proc
2025
2052
  if result.is_a?(Array)
2026
2053
  complete(result, true)
@@ -2046,7 +2073,11 @@ class Reline::LineEditor
2046
2073
  alias_method :yank_pop, :em_yank_pop
2047
2074
 
2048
2075
  private def ed_clear_screen(key)
2049
- @cleared = true
2076
+ Reline::IOGate.clear_screen
2077
+ @screen_size = Reline::IOGate.get_screen_size
2078
+ @rendered_screen.lines = []
2079
+ @rendered_screen.base_y = 0
2080
+ @rendered_screen.cursor_y = 0
2050
2081
  end
2051
2082
  alias_method :clear_screen, :ed_clear_screen
2052
2083
 
@@ -2287,50 +2318,63 @@ class Reline::LineEditor
2287
2318
  copy_for_vi(deleted)
2288
2319
  end
2289
2320
 
2290
- private def vi_zero(key)
2291
- @byte_pointer = 0
2321
+ private def vi_change_meta(key, arg: nil)
2322
+ if @vi_waiting_operator
2323
+ set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
2324
+ @vi_waiting_operator = nil
2325
+ @vi_waiting_operator_arg = nil
2326
+ else
2327
+ @drop_terminate_spaces = true
2328
+ @vi_waiting_operator = :vi_change_meta_confirm
2329
+ @vi_waiting_operator_arg = arg || 1
2330
+ end
2292
2331
  end
2293
2332
 
2294
- private def vi_change_meta(key, arg: 1)
2295
- @drop_terminate_spaces = true
2296
- @waiting_operator_proc = proc { |byte_pointer_diff|
2297
- if byte_pointer_diff > 0
2298
- line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
2299
- elsif byte_pointer_diff < 0
2300
- line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2301
- end
2302
- set_current_line(line)
2303
- copy_for_vi(cut)
2304
- @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
2305
- @config.editing_mode = :vi_insert
2306
- @drop_terminate_spaces = false
2307
- }
2308
- @waiting_operator_vi_arg = arg
2333
+ private def vi_change_meta_confirm(byte_pointer_diff)
2334
+ vi_delete_meta_confirm(byte_pointer_diff)
2335
+ @config.editing_mode = :vi_insert
2336
+ @drop_terminate_spaces = false
2309
2337
  end
2310
2338
 
2311
- private def vi_delete_meta(key, arg: 1)
2312
- @waiting_operator_proc = proc { |byte_pointer_diff|
2313
- if byte_pointer_diff > 0
2314
- line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
2315
- elsif byte_pointer_diff < 0
2316
- line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2317
- end
2318
- copy_for_vi(cut)
2319
- set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
2320
- }
2321
- @waiting_operator_vi_arg = arg
2339
+ private def vi_delete_meta(key, arg: nil)
2340
+ if @vi_waiting_operator
2341
+ set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
2342
+ @vi_waiting_operator = nil
2343
+ @vi_waiting_operator_arg = nil
2344
+ else
2345
+ @vi_waiting_operator = :vi_delete_meta_confirm
2346
+ @vi_waiting_operator_arg = arg || 1
2347
+ end
2322
2348
  end
2323
2349
 
2324
- private def vi_yank(key, arg: 1)
2325
- @waiting_operator_proc = proc { |byte_pointer_diff|
2326
- if byte_pointer_diff > 0
2327
- cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
2328
- elsif byte_pointer_diff < 0
2329
- cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2330
- end
2331
- copy_for_vi(cut)
2332
- }
2333
- @waiting_operator_vi_arg = arg
2350
+ private def vi_delete_meta_confirm(byte_pointer_diff)
2351
+ if byte_pointer_diff > 0
2352
+ line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
2353
+ elsif byte_pointer_diff < 0
2354
+ line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2355
+ end
2356
+ copy_for_vi(cut)
2357
+ set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
2358
+ end
2359
+
2360
+ private def vi_yank(key, arg: nil)
2361
+ if @vi_waiting_operator
2362
+ copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
2363
+ @vi_waiting_operator = nil
2364
+ @vi_waiting_operator_arg = nil
2365
+ else
2366
+ @vi_waiting_operator = :vi_yank_confirm
2367
+ @vi_waiting_operator_arg = arg || 1
2368
+ end
2369
+ end
2370
+
2371
+ private def vi_yank_confirm(byte_pointer_diff)
2372
+ if byte_pointer_diff > 0
2373
+ cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
2374
+ elsif byte_pointer_diff < 0
2375
+ cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2376
+ end
2377
+ copy_for_vi(cut)
2334
2378
  end
2335
2379
 
2336
2380
  private def vi_list_or_eof(key)
@@ -2435,18 +2479,11 @@ class Reline::LineEditor
2435
2479
  end
2436
2480
 
2437
2481
  private def vi_to_column(key, arg: 0)
2438
- current_row_width = calculate_width(current_row)
2439
- @byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |total, gc|
2440
- # total has [byte_size, cursor]
2482
+ # Implementing behavior of vi, not Readline's vi-mode.
2483
+ @byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |(total_byte_size, total_width), gc|
2441
2484
  mbchar_width = Reline::Unicode.get_mbchar_width(gc)
2442
- if (total.last + mbchar_width) >= arg
2443
- break total
2444
- elsif (total.last + mbchar_width) >= current_row_width
2445
- break total
2446
- else
2447
- total = [total.first + gc.bytesize, total.last + mbchar_width]
2448
- total
2449
- end
2485
+ break [total_byte_size, total_width] if (total_width + mbchar_width) >= arg
2486
+ [total_byte_size + gc.bytesize, total_width + mbchar_width]
2450
2487
  }
2451
2488
  end
2452
2489
 
@@ -2594,6 +2631,11 @@ class Reline::LineEditor
2594
2631
  end
2595
2632
  alias_method :exchange_point_and_mark, :em_exchange_mark
2596
2633
 
2597
- private def em_meta_next(key)
2634
+ private def emacs_editing_mode(key)
2635
+ @config.editing_mode = :emacs
2636
+ end
2637
+
2638
+ private def vi_editing_mode(key)
2639
+ @config.editing_mode = :vi_insert
2598
2640
  end
2599
2641
  end
@@ -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
- 0
85
+ @term_supported = true
87
86
  when -1 # ERR
88
- case errret
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
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.2'
3
3
  end
@@ -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.resize
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 nil unless config.autocompletion
223
- if just_cursor_moving and completion_journey_data.nil?
224
- # Auto complete starts only when edited
225
- return nil
226
- end
227
- pre, target, post = retrieve_completion_block(true)
228
- if target.nil? or target.empty? or (completion_journey_data&.pointer == -1 and target.size <= 3)
229
- return nil
230
- end
231
- if completion_journey_data and completion_journey_data.list
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
- Reline.update_iogate
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
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
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
- Reline.update_iogate
292
- inner_readline(prompt, add_hist, false)
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
- line = line_editor.line.dup
295
- line.taint if RUBY_VERSION < '2.7'
296
- if add_hist and line and line.chomp("\n").size > 0
297
- Reline::HISTORY << line.chomp("\n")
298
- end
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
- line_editor.reset_line if line_editor.line.nil?
301
- line
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
- rescue StandardError => e
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.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-25 00:00:00.000000000 Z
11
+ date: 2024-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console