reline 0.5.8 → 0.5.10

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.
@@ -7,138 +7,99 @@ class Reline::KeyStroke
7
7
  @config = config
8
8
  end
9
9
 
10
- def compress_meta_key(ary)
11
- return ary unless @config.convert_meta
12
- ary.inject([]) { |result, key|
13
- if result.size > 0 and result.last == "\e".ord
14
- result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
15
- else
16
- result << key
17
- end
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 start_with?(me, other)
23
- compressed_me = compress_meta_key(me)
24
- compressed_other = compress_meta_key(other)
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
- def equal?(me, other)
47
- case me
48
- when Array
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
- def match_status(input)
72
- key_mapping.keys.select { |lhs|
73
- start_with?(lhs, input)
74
- }.tap { |it|
75
- return :matched if it.size == 1 && equal?(it[0], input)
76
- return :matching if it.size == 1 && !equal?(it[0], input)
77
- return :matched if it.max_by(&:size)&.size&.< input.size
78
- return :matching if it.size > 1
79
- }
80
- if key_mapping.keys.any? { |lhs| start_with?(input, lhs) }
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
- match_unknown_escape_sequence(input).first
38
+ UNMATCHED
84
39
  end
85
40
  end
86
41
 
87
42
  def expand(input)
88
- lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
89
- unless lhs
90
- status, size = match_unknown_escape_sequence(input)
91
- case status
92
- when :matched
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
- rhs = key_mapping[lhs]
49
+ return [[], []] unless matched_bytes
101
50
 
102
- case rhs
103
- when String
104
- rhs_bytes = rhs.bytes
105
- expand(expand(rhs_bytes) + expand(input.drop(lhs.size)))
106
- when Symbol
107
- [rhs] + expand(input.drop(lhs.size))
108
- when Array
109
- rhs
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 [:unmatched, nil] unless input[idx] == ESC_BYTE
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
- return [:matching, nil]
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
- input[idx + 1] ? [:matched, idx + 2] : [:matching, nil]
89
+ # SS3 sequence `ESC O char`
90
+ idx += 1
134
91
  else
135
- if idx == 1
136
- # `ESC char`, make it :unmatched so that it will be handled correctly in `read_2nd_character_of_key_sequence`
137
- [:unmatched, nil]
138
- else
139
- # `ESC ESC char`
140
- [:matched, idx + 1]
141
- end
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
 
@@ -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
@@ -175,9 +176,8 @@ class Reline::LineEditor
175
176
  scroll_into_view
176
177
  Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
177
178
  @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
178
- @rendered_screen.lines = []
179
- @rendered_screen.cursor_y = 0
180
- render_differential
179
+ clear_rendered_screen_cache
180
+ render
181
181
  end
182
182
 
183
183
  private def handle_interrupted
@@ -185,11 +185,11 @@ class Reline::LineEditor
185
185
 
186
186
  @interrupted = false
187
187
  clear_dialogs
188
- scrolldown = render_differential
189
- Reline::IOGate.scroll_down scrolldown
188
+ render
189
+ cursor_to_bottom_offset = @rendered_screen.lines.size - @rendered_screen.cursor_y
190
+ Reline::IOGate.scroll_down cursor_to_bottom_offset
190
191
  Reline::IOGate.move_cursor_column 0
191
- @rendered_screen.lines = []
192
- @rendered_screen.cursor_y = 0
192
+ clear_rendered_screen_cache
193
193
  case @old_trap
194
194
  when 'DEFAULT', 'SYSTEM_DEFAULT'
195
195
  raise Interrupt
@@ -237,7 +237,6 @@ class Reline::LineEditor
237
237
  @perfect_matched = nil
238
238
  @menu_info = nil
239
239
  @searching_prompt = nil
240
- @first_char = true
241
240
  @just_cursor_moving = false
242
241
  @eof = false
243
242
  @continuous_insertion_buffer = String.new(encoding: @encoding)
@@ -253,6 +252,8 @@ class Reline::LineEditor
253
252
  @input_lines = [[[""], 0, 0]]
254
253
  @input_lines_position = 0
255
254
  @undoing = false
255
+ @prev_action_state = NullActionState
256
+ @next_action_state = NullActionState
256
257
  reset_line
257
258
  end
258
259
 
@@ -412,7 +413,7 @@ class Reline::LineEditor
412
413
  # do nothing
413
414
  elsif level == :blank
414
415
  Reline::IOGate.move_cursor_column base_x
415
- @output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
416
+ @output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
416
417
  else
417
418
  x, w, content = new_items[level]
418
419
  cover_begin = base_x != 0 && new_levels[base_x - 1] == level
@@ -422,7 +423,7 @@ class Reline::LineEditor
422
423
  content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
423
424
  end
424
425
  Reline::IOGate.move_cursor_column x + pos
425
- @output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
426
+ @output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
426
427
  end
427
428
  base_x += width
428
429
  end
@@ -458,28 +459,7 @@ class Reline::LineEditor
458
459
  end
459
460
 
460
461
  def render_finished
461
- clear_rendered_lines
462
- render_full_content
463
- end
464
-
465
- def clear_rendered_lines
466
- Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
467
- Reline::IOGate.move_cursor_column 0
468
-
469
- num_lines = @rendered_screen.lines.size
470
- return unless num_lines && num_lines >= 1
471
-
472
- Reline::IOGate.move_cursor_down num_lines - 1
473
- (num_lines - 1).times do
474
- Reline::IOGate.erase_after_cursor
475
- Reline::IOGate.move_cursor_up 1
476
- end
477
- Reline::IOGate.erase_after_cursor
478
- @rendered_screen.lines = []
479
- @rendered_screen.cursor_y = 0
480
- end
481
-
482
- def render_full_content
462
+ render_differential([], 0, 0)
483
463
  lines = @buffer_of_lines.size.times.map do |i|
484
464
  line = prompt_list[i] + modified_lines[i]
485
465
  wrapped_lines, = split_by_width(line, screen_width)
@@ -488,19 +468,13 @@ class Reline::LineEditor
488
468
  @output.puts lines.map { |l| "#{l}\r\n" }.join
489
469
  end
490
470
 
491
- def print_nomultiline_prompt(prompt)
492
- return unless prompt && !@is_multiline
493
-
471
+ def print_nomultiline_prompt
494
472
  # Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
495
- @rendered_screen.lines = [[[0, Reline::Unicode.calculate_width(prompt, true), prompt]]]
496
- @rendered_screen.cursor_y = 0
497
- @output.write prompt
473
+ @output.write @prompt if @prompt && !@is_multiline
498
474
  end
499
475
 
500
- def render_differential
476
+ def render
501
477
  wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
502
-
503
- rendered_lines = @rendered_screen.lines
504
478
  new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
505
479
  prompt_width = Reline::Unicode.calculate_width(prompt, true)
506
480
  [[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
@@ -518,12 +492,21 @@ class Reline::LineEditor
518
492
  x_range, y_range = dialog_range dialog, wrapped_cursor_y - screen_scroll_top
519
493
  y_range.each do |row|
520
494
  next if row < 0 || row >= screen_height
495
+
521
496
  dialog_rows = new_lines[row] ||= []
522
497
  # index 0 is for prompt, index 1 is for line, index 2.. is for dialog
523
498
  dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
524
499
  end
525
500
  end
526
501
 
502
+ render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
503
+ end
504
+
505
+ # Reflects lines to be rendered and new cursor position to the screen
506
+ # by calculating the difference from the previous render.
507
+
508
+ private def render_differential(new_lines, new_cursor_x, new_cursor_y)
509
+ rendered_lines = @rendered_screen.lines
527
510
  cursor_y = @rendered_screen.cursor_y
528
511
  if new_lines != rendered_lines
529
512
  # Hide cursor while rendering to avoid cursor flickering.
@@ -550,11 +533,14 @@ class Reline::LineEditor
550
533
  @rendered_screen.lines = new_lines
551
534
  Reline::IOGate.show_cursor
552
535
  end
553
- y = wrapped_cursor_y - screen_scroll_top
554
- Reline::IOGate.move_cursor_column wrapped_cursor_x
555
- Reline::IOGate.move_cursor_down y - cursor_y
556
- @rendered_screen.cursor_y = y
557
- new_lines.size - y
536
+ Reline::IOGate.move_cursor_column new_cursor_x
537
+ Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
538
+ @rendered_screen.cursor_y = new_cursor_y
539
+ end
540
+
541
+ private def clear_rendered_screen_cache
542
+ @rendered_screen.lines = []
543
+ @rendered_screen.cursor_y = 0
558
544
  end
559
545
 
560
546
  def upper_space_height(wrapped_cursor_y)
@@ -566,7 +552,7 @@ class Reline::LineEditor
566
552
  end
567
553
 
568
554
  def rerender
569
- render_differential unless @in_pasting
555
+ render unless @in_pasting
570
556
  end
571
557
 
572
558
  class DialogProcScope
@@ -684,10 +670,8 @@ class Reline::LineEditor
684
670
  @trap_key.each do |t|
685
671
  @config.add_oneshot_key_binding(t, @name)
686
672
  end
687
- elsif @trap_key.is_a?(Array)
673
+ else
688
674
  @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
675
  end
692
676
  end
693
677
  dialog_render_info
@@ -1080,17 +1064,7 @@ class Reline::LineEditor
1080
1064
  else # single byte
1081
1065
  return if key.char >= 128 # maybe, first byte of multi byte
1082
1066
  method_symbol = @config.editing_mode.get_method(key.combined_char)
1083
- if key.with_meta and method_symbol == :ed_unassigned
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
1067
+ process_key(key.combined_char, method_symbol)
1094
1068
  @multibyte_buffer.clear
1095
1069
  end
1096
1070
  if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
@@ -1119,13 +1093,10 @@ class Reline::LineEditor
1119
1093
  end
1120
1094
  if key.char.nil?
1121
1095
  process_insert(force: true)
1122
- if @first_char
1123
- @eof = true
1124
- end
1096
+ @eof = buffer_empty?
1125
1097
  finish
1126
1098
  return
1127
1099
  end
1128
- @first_char = false
1129
1100
  @completion_occurs = false
1130
1101
 
1131
1102
  if key.char.is_a?(Symbol)
@@ -1133,6 +1104,9 @@ class Reline::LineEditor
1133
1104
  else
1134
1105
  normal_char(key)
1135
1106
  end
1107
+
1108
+ @prev_action_state, @next_action_state = @next_action_state, NullActionState
1109
+
1136
1110
  unless @completion_occurs
1137
1111
  @completion_state = CompletionState::NORMAL
1138
1112
  @completion_journey_state = nil
@@ -1347,7 +1321,7 @@ class Reline::LineEditor
1347
1321
  @confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
1348
1322
  end
1349
1323
 
1350
- def insert_pasted_text(text)
1324
+ def insert_multiline_text(text)
1351
1325
  save_old_buffer
1352
1326
  pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
1353
1327
  post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
@@ -1415,6 +1389,10 @@ class Reline::LineEditor
1415
1389
  whole_lines.join("\n")
1416
1390
  end
1417
1391
 
1392
+ private def buffer_empty?
1393
+ current_line.empty? and @buffer_of_lines.size == 1
1394
+ end
1395
+
1418
1396
  def finished?
1419
1397
  @finished
1420
1398
  end
@@ -1763,29 +1741,31 @@ class Reline::LineEditor
1763
1741
  end
1764
1742
 
1765
1743
  private def ed_search_prev_history(key, arg: 1)
1766
- substr = current_line.byteslice(0, @byte_pointer)
1744
+ substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
1767
1745
  return if @history_pointer == 0
1768
1746
  return if @history_pointer.nil? && substr.empty? && !current_line.empty?
1769
1747
 
1770
1748
  history_range = 0...(@history_pointer || Reline::HISTORY.size)
1771
1749
  h_pointer, line_index = search_history(substr, history_range.reverse_each)
1772
1750
  return unless h_pointer
1773
- move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
1751
+ move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
1774
1752
  arg -= 1
1753
+ set_next_action_state(:search_history, :empty) if substr.empty?
1775
1754
  ed_search_prev_history(key, arg: arg) if arg > 0
1776
1755
  end
1777
1756
  alias_method :history_search_backward, :ed_search_prev_history
1778
1757
 
1779
1758
  private def ed_search_next_history(key, arg: 1)
1780
- substr = current_line.byteslice(0, @byte_pointer)
1759
+ substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
1781
1760
  return if @history_pointer.nil?
1782
1761
 
1783
1762
  history_range = @history_pointer + 1...Reline::HISTORY.size
1784
1763
  h_pointer, line_index = search_history(substr, history_range)
1785
1764
  return if h_pointer.nil? and not substr.empty?
1786
1765
 
1787
- move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
1766
+ move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
1788
1767
  arg -= 1
1768
+ set_next_action_state(:search_history, :empty) if substr.empty?
1789
1769
  ed_search_next_history(key, arg: arg) if arg > 0
1790
1770
  end
1791
1771
  alias_method :history_search_forward, :ed_search_next_history
@@ -1941,7 +1921,7 @@ class Reline::LineEditor
1941
1921
  alias_method :kill_whole_line, :em_kill_line
1942
1922
 
1943
1923
  private def em_delete(key)
1944
- if current_line.empty? and @buffer_of_lines.size == 1 and key == "\C-d".ord
1924
+ if buffer_empty? and key == "\C-d".ord
1945
1925
  @eof = true
1946
1926
  finish
1947
1927
  elsif @byte_pointer < current_line.bytesize
@@ -1986,9 +1966,8 @@ class Reline::LineEditor
1986
1966
  private def ed_clear_screen(key)
1987
1967
  Reline::IOGate.clear_screen
1988
1968
  @screen_size = Reline::IOGate.get_screen_size
1989
- @rendered_screen.lines = []
1990
1969
  @rendered_screen.base_y = 0
1991
- @rendered_screen.cursor_y = 0
1970
+ clear_rendered_screen_cache
1992
1971
  end
1993
1972
  alias_method :clear_screen, :ed_clear_screen
1994
1973
 
@@ -2263,9 +2242,11 @@ class Reline::LineEditor
2263
2242
  line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
2264
2243
  elsif byte_pointer_diff < 0
2265
2244
  line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2245
+ else
2246
+ return
2266
2247
  end
2267
2248
  copy_for_vi(cut)
2268
- set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
2249
+ set_current_line(line, @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
2269
2250
  end
2270
2251
 
2271
2252
  private def vi_yank(key, arg: nil)
@@ -2284,13 +2265,14 @@ class Reline::LineEditor
2284
2265
  cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
2285
2266
  elsif byte_pointer_diff < 0
2286
2267
  cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
2268
+ else
2269
+ return
2287
2270
  end
2288
2271
  copy_for_vi(cut)
2289
2272
  end
2290
2273
 
2291
2274
  private def vi_list_or_eof(key)
2292
- if current_line.empty? and @buffer_of_lines.size == 1
2293
- set_current_line('', 0)
2275
+ if buffer_empty?
2294
2276
  @eof = true
2295
2277
  finish
2296
2278
  else
@@ -2551,4 +2533,16 @@ class Reline::LineEditor
2551
2533
  target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
2552
2534
  set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
2553
2535
  end
2536
+
2537
+ private def prev_action_state_value(type)
2538
+ @prev_action_state[0] == type ? @prev_action_state[1] : nil
2539
+ end
2540
+
2541
+ private def set_next_action_state(type, value)
2542
+ @next_action_state = [type, value]
2543
+ end
2544
+
2545
+ private def re_read_init_file(_key)
2546
+ @config.reload
2547
+ end
2554
2548
  end
@@ -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
@@ -78,7 +83,7 @@ module Reline::Terminfo
78
83
  end
79
84
 
80
85
  def self.setupterm(term, fildes)
81
- errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
86
+ errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
82
87
  ret = @setupterm.(term, fildes, errret_int)
83
88
  case ret
84
89
  when 0 # OK