reline 0.5.12 → 0.6.0

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.
@@ -13,7 +13,6 @@ class Reline::LineEditor
13
13
  attr_accessor :prompt_proc
14
14
  attr_accessor :auto_indent_proc
15
15
  attr_accessor :dig_perfect_match_proc
16
- attr_writer :output
17
16
 
18
17
  VI_MOTIONS = %i{
19
18
  ed_prev_char
@@ -253,7 +252,7 @@ class Reline::LineEditor
253
252
  @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
254
253
  @input_lines = [[[""], 0, 0]]
255
254
  @input_lines_position = 0
256
- @undoing = false
255
+ @restoring = false
257
256
  @prev_action_state = NullActionState
258
257
  @next_action_state = NullActionState
259
258
  reset_line
@@ -414,7 +413,7 @@ class Reline::LineEditor
414
413
  # do nothing
415
414
  elsif level == :blank
416
415
  Reline::IOGate.move_cursor_column base_x
417
- @output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
416
+ Reline::IOGate.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
418
417
  else
419
418
  x, w, content = new_items[level]
420
419
  cover_begin = base_x != 0 && new_levels[base_x - 1] == level
@@ -424,7 +423,7 @@ class Reline::LineEditor
424
423
  content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
425
424
  end
426
425
  Reline::IOGate.move_cursor_column x + pos
427
- @output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
426
+ Reline::IOGate.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
428
427
  end
429
428
  base_x += width
430
429
  end
@@ -437,7 +436,7 @@ class Reline::LineEditor
437
436
  # Calculate cursor position in word wrapped content.
438
437
  def wrapped_cursor_position
439
438
  prompt_width = calculate_width(prompt_list[@line_index], true)
440
- line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
439
+ line_before_cursor = Reline::Unicode.escape_for_print(whole_lines[@line_index].byteslice(0, @byte_pointer))
441
440
  wrapped_line_before_cursor = split_line_by_width(' ' * prompt_width + line_before_cursor, screen_width)
442
441
  wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
443
442
  wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
@@ -460,19 +459,21 @@ class Reline::LineEditor
460
459
  end
461
460
 
462
461
  def render_finished
463
- render_differential([], 0, 0)
464
- lines = @buffer_of_lines.size.times.map do |i|
465
- line = Reline::Unicode.strip_non_printing_start_end(prompt_list[i]) + modified_lines[i]
466
- wrapped_lines = split_line_by_width(line, screen_width)
467
- wrapped_lines.last.empty? ? "#{line} " : line
462
+ Reline::IOGate.buffered_output do
463
+ render_differential([], 0, 0)
464
+ lines = @buffer_of_lines.size.times.map do |i|
465
+ line = Reline::Unicode.strip_non_printing_start_end(prompt_list[i]) + modified_lines[i]
466
+ wrapped_lines = split_line_by_width(line, screen_width)
467
+ wrapped_lines.last.empty? ? "#{line} " : line
468
+ end
469
+ Reline::IOGate.write lines.map { |l| "#{l}\r\n" }.join
468
470
  end
469
- @output.puts lines.map { |l| "#{l}\r\n" }.join
470
471
  end
471
472
 
472
473
  def print_nomultiline_prompt
473
474
  Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
474
475
  # Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
475
- @output.write Reline::Unicode.strip_non_printing_start_end(@prompt) if @prompt && !@is_multiline
476
+ Reline::IOGate.write Reline::Unicode.strip_non_printing_start_end(@prompt) if @prompt && !@is_multiline
476
477
  ensure
477
478
  Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
478
479
  end
@@ -503,7 +504,9 @@ class Reline::LineEditor
503
504
  end
504
505
  end
505
506
 
506
- render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
507
+ Reline::IOGate.buffered_output do
508
+ render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
509
+ end
507
510
  end
508
511
 
509
512
  # Reflects lines to be rendered and new cursor position to the screen
@@ -807,11 +810,11 @@ class Reline::LineEditor
807
810
  target = target.downcase if @config.completion_ignore_case
808
811
  list.select do |item|
809
812
  next unless item
810
-
811
813
  unless Encoding.compatible?(target.encoding, item.encoding)
812
- # Crash with Encoding::CompatibilityError is required by readline-ext/test/readline/test_readline.rb
813
- # TODO: fix the test
814
- raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{item.encoding.name}"
814
+ # Workaround for Readline test
815
+ if defined?(::Readline) && ::Readline == ::Reline
816
+ raise Encoding::CompatibilityError, "incompatible character encodings: #{target.encoding} and #{item.encoding}"
817
+ end
815
818
  end
816
819
 
817
820
  if @config.completion_ignore_case
@@ -970,10 +973,18 @@ class Reline::LineEditor
970
973
  @drop_terminate_spaces = false
971
974
  end
972
975
 
976
+ ARGUMENT_DIGIT_METHODS = %i[ed_digit vi_zero ed_argument_digit]
977
+ VI_WAITING_ACCEPT_METHODS = %i[vi_change_meta vi_delete_meta vi_yank ed_insert ed_argument_digit]
978
+
973
979
  private def process_key(key, method_symbol)
974
- if key.is_a?(Symbol)
975
- cleanup_waiting
976
- elsif @waiting_proc
980
+ if @waiting_proc
981
+ cleanup_waiting unless key.size == 1
982
+ end
983
+ if @vi_waiting_operator
984
+ cleanup_waiting unless VI_WAITING_ACCEPT_METHODS.include?(method_symbol) || VI_MOTIONS.include?(method_symbol)
985
+ end
986
+
987
+ if @waiting_proc
977
988
  old_byte_pointer = @byte_pointer
978
989
  @waiting_proc.call(key)
979
990
  if @vi_waiting_operator
@@ -987,23 +998,14 @@ class Reline::LineEditor
987
998
  return
988
999
  end
989
1000
 
1001
+ # Reject multibyte input (converted to ed_insert) in vi_command mode
1002
+ return if method_symbol == :ed_insert && @config.editing_mode_is?(:vi_command)
1003
+
990
1004
  if method_symbol and respond_to?(method_symbol, true)
991
1005
  method_obj = method(method_symbol)
992
1006
  end
993
- if method_symbol and key.is_a?(Symbol)
994
- if @vi_arg and argumentable?(method_obj)
995
- run_for_operators(key, method_symbol) do |with_operator|
996
- wrap_method_call(method_symbol, method_obj, key, with_operator)
997
- end
998
- else
999
- wrap_method_call(method_symbol, method_obj, key) if method_obj
1000
- end
1001
- @kill_ring.process
1002
- if @vi_arg
1003
- @vi_arg = nil
1004
- end
1005
- elsif @vi_arg
1006
- if key.chr =~ /[0-9]/
1007
+ if @vi_arg
1008
+ if ARGUMENT_DIGIT_METHODS.include?(method_symbol)
1007
1009
  ed_argument_digit(key)
1008
1010
  else
1009
1011
  if argumentable?(method_obj)
@@ -1012,13 +1014,9 @@ class Reline::LineEditor
1012
1014
  end
1013
1015
  elsif method_obj
1014
1016
  wrap_method_call(method_symbol, method_obj, key)
1015
- else
1016
- ed_insert(key) unless @config.editing_mode_is?(:vi_command)
1017
1017
  end
1018
1018
  @kill_ring.process
1019
- if @vi_arg
1020
- @vi_arg = nil
1021
- end
1019
+ @vi_arg = nil
1022
1020
  end
1023
1021
  elsif method_obj
1024
1022
  if method_symbol == :ed_argument_digit
@@ -1029,21 +1027,6 @@ class Reline::LineEditor
1029
1027
  end
1030
1028
  end
1031
1029
  @kill_ring.process
1032
- else
1033
- ed_insert(key) unless @config.editing_mode_is?(:vi_command)
1034
- end
1035
- end
1036
-
1037
- private def normal_char(key)
1038
- if key.char < 0x80
1039
- method_symbol = @config.editing_mode.get_method(key.combined_char)
1040
- process_key(key.combined_char, method_symbol)
1041
- else
1042
- process_key(key.char.chr(encoding), nil)
1043
- end
1044
- if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
1045
- byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
1046
- @byte_pointer -= byte_size
1047
1030
  end
1048
1031
  end
1049
1032
 
@@ -1060,23 +1043,23 @@ class Reline::LineEditor
1060
1043
  def input_key(key)
1061
1044
  save_old_buffer
1062
1045
  @config.reset_oneshot_key_bindings
1063
- @dialogs.each do |dialog|
1064
- if key.char.instance_of?(Symbol) and key.char == dialog.name
1065
- return
1066
- end
1067
- end
1068
1046
  if key.char.nil?
1069
1047
  process_insert(force: true)
1070
1048
  @eof = buffer_empty?
1071
1049
  finish
1072
1050
  return
1073
1051
  end
1052
+ @dialogs.each do |dialog|
1053
+ if key.method_symbol == dialog.name
1054
+ return
1055
+ end
1056
+ end
1074
1057
  @completion_occurs = false
1075
1058
 
1076
- if key.char.is_a?(Symbol)
1077
- process_key(key.char, key.char)
1078
- else
1079
- normal_char(key)
1059
+ process_key(key.char, key.method_symbol)
1060
+ if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
1061
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
1062
+ @byte_pointer -= byte_size
1080
1063
  end
1081
1064
 
1082
1065
  @prev_action_state, @next_action_state = @next_action_state, NullActionState
@@ -1086,8 +1069,8 @@ class Reline::LineEditor
1086
1069
  @completion_journey_state = nil
1087
1070
  end
1088
1071
 
1089
- push_input_lines unless @undoing
1090
- @undoing = false
1072
+ push_input_lines unless @restoring
1073
+ @restoring = false
1091
1074
 
1092
1075
  if @in_pasting
1093
1076
  clear_dialogs
@@ -1201,18 +1184,6 @@ class Reline::LineEditor
1201
1184
  process_auto_indent
1202
1185
  end
1203
1186
 
1204
- def set_current_lines(lines, byte_pointer = nil, line_index = 0)
1205
- cursor = current_byte_pointer_cursor
1206
- @buffer_of_lines = lines
1207
- @line_index = line_index
1208
- if byte_pointer
1209
- @byte_pointer = byte_pointer
1210
- else
1211
- calculate_nearest_cursor(cursor)
1212
- end
1213
- process_auto_indent
1214
- end
1215
-
1216
1187
  def retrieve_completion_block
1217
1188
  quote_characters = Reline.completer_quote_characters
1218
1189
  before = current_line.byteslice(0, @byte_pointer).grapheme_clusters
@@ -1255,7 +1226,6 @@ class Reline::LineEditor
1255
1226
  end
1256
1227
 
1257
1228
  def insert_multiline_text(text)
1258
- save_old_buffer
1259
1229
  pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
1260
1230
  post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
1261
1231
  lines = (pre + Reline::Unicode.safe_encode(text, encoding).gsub(/\r\n?/, "\n") + post).split("\n", -1)
@@ -1263,7 +1233,6 @@ class Reline::LineEditor
1263
1233
  @buffer_of_lines[@line_index, 1] = lines
1264
1234
  @line_index += lines.size - 1
1265
1235
  @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
1266
- push_input_lines
1267
1236
  end
1268
1237
 
1269
1238
  def insert_text(text)
@@ -1429,21 +1398,11 @@ class Reline::LineEditor
1429
1398
  # digit or if the existing argument is already greater than a
1430
1399
  # million.
1431
1400
  # GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
1432
- private def ed_insert(key)
1433
- if key.instance_of?(String)
1434
- begin
1435
- key.encode(Encoding::UTF_8)
1436
- rescue Encoding::UndefinedConversionError
1437
- return
1438
- end
1439
- str = key
1440
- else
1441
- begin
1442
- key.chr.encode(Encoding::UTF_8)
1443
- rescue Encoding::UndefinedConversionError
1444
- return
1445
- end
1446
- str = key.chr
1401
+ private def ed_insert(str)
1402
+ begin
1403
+ str.encode(Encoding::UTF_8)
1404
+ rescue Encoding::UndefinedConversionError
1405
+ return
1447
1406
  end
1448
1407
  if @in_pasting
1449
1408
  @continuous_insertion_buffer << str
@@ -1457,21 +1416,16 @@ class Reline::LineEditor
1457
1416
  alias_method :ed_digit, :ed_insert
1458
1417
  alias_method :self_insert, :ed_insert
1459
1418
 
1460
- private def ed_quoted_insert(str, arg: 1)
1461
- @waiting_proc = proc { |key|
1462
- arg.times do
1463
- if key == "\C-j".ord or key == "\C-m".ord
1464
- key_newline(key)
1465
- elsif key == 0
1466
- # Ignore NUL.
1467
- else
1468
- ed_insert(key)
1469
- end
1419
+ private def insert_raw_char(str, arg: 1)
1420
+ arg.times do
1421
+ if str == "\C-j" or str == "\C-m"
1422
+ key_newline(str)
1423
+ elsif str != "\0"
1424
+ # Ignore NUL.
1425
+ ed_insert(str)
1470
1426
  end
1471
- @waiting_proc = nil
1472
- }
1427
+ end
1473
1428
  end
1474
- alias_method :quoted_insert, :ed_quoted_insert
1475
1429
 
1476
1430
  private def ed_next_char(key, arg: 1)
1477
1431
  byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
@@ -1520,13 +1474,13 @@ class Reline::LineEditor
1520
1474
  lambda do |key|
1521
1475
  search_again = false
1522
1476
  case key
1523
- when "\C-h".ord, "\C-?".ord
1477
+ when "\C-h", "\C-?"
1524
1478
  grapheme_clusters = search_word.grapheme_clusters
1525
1479
  if grapheme_clusters.size > 0
1526
1480
  grapheme_clusters.pop
1527
1481
  search_word = grapheme_clusters.join
1528
1482
  end
1529
- when "\C-r".ord, "\C-s".ord
1483
+ when "\C-r", "\C-s"
1530
1484
  search_again = true if search_key == key
1531
1485
  search_key = key
1532
1486
  else
@@ -1543,10 +1497,10 @@ class Reline::LineEditor
1543
1497
  end
1544
1498
  if @history_pointer
1545
1499
  case search_key
1546
- when "\C-r".ord
1500
+ when "\C-r"
1547
1501
  history_pointer_base = 0
1548
1502
  history = Reline::HISTORY[0..(@history_pointer - 1)]
1549
- when "\C-s".ord
1503
+ when "\C-s"
1550
1504
  history_pointer_base = @history_pointer + 1
1551
1505
  history = Reline::HISTORY[(@history_pointer + 1)..-1]
1552
1506
  end
@@ -1556,10 +1510,10 @@ class Reline::LineEditor
1556
1510
  end
1557
1511
  elsif @history_pointer
1558
1512
  case search_key
1559
- when "\C-r".ord
1513
+ when "\C-r"
1560
1514
  history_pointer_base = 0
1561
1515
  history = Reline::HISTORY[0..@history_pointer]
1562
- when "\C-s".ord
1516
+ when "\C-s"
1563
1517
  history_pointer_base = @history_pointer
1564
1518
  history = Reline::HISTORY[@history_pointer..-1]
1565
1519
  end
@@ -1568,11 +1522,11 @@ class Reline::LineEditor
1568
1522
  history = Reline::HISTORY
1569
1523
  end
1570
1524
  case search_key
1571
- when "\C-r".ord
1525
+ when "\C-r"
1572
1526
  hit_index = history.rindex { |item|
1573
1527
  item.include?(search_word)
1574
1528
  }
1575
- when "\C-s".ord
1529
+ when "\C-s"
1576
1530
  hit_index = history.index { |item|
1577
1531
  item.include?(search_word)
1578
1532
  }
@@ -1583,9 +1537,9 @@ class Reline::LineEditor
1583
1537
  end
1584
1538
  end
1585
1539
  case search_key
1586
- when "\C-r".ord
1540
+ when "\C-r"
1587
1541
  prompt_name = 'reverse-i-search'
1588
- when "\C-s".ord
1542
+ when "\C-s"
1589
1543
  prompt_name = 'i-search'
1590
1544
  end
1591
1545
  prompt_name = "failed #{prompt_name}" unless hit
@@ -1597,16 +1551,15 @@ class Reline::LineEditor
1597
1551
  backup = @buffer_of_lines.dup, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history
1598
1552
  searcher = generate_searcher(key)
1599
1553
  @searching_prompt = "(reverse-i-search)`': "
1600
- termination_keys = ["\C-j".ord]
1601
- termination_keys.concat(@config.isearch_terminators.chars.map(&:ord)) if @config.isearch_terminators
1554
+ termination_keys = ["\C-j"]
1555
+ termination_keys.concat(@config.isearch_terminators.chars) if @config.isearch_terminators
1602
1556
  @waiting_proc = ->(k) {
1603
- chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
1604
- if k == "\C-g".ord
1557
+ if k == "\C-g"
1605
1558
  # cancel search and restore buffer
1606
1559
  @buffer_of_lines, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history = backup
1607
1560
  @searching_prompt = nil
1608
1561
  @waiting_proc = nil
1609
- elsif !termination_keys.include?(k) && (chr.match?(/[[:print:]]/) || k == "\C-h".ord || k == "\C-?".ord || k == "\C-r".ord || k == "\C-s".ord)
1562
+ elsif !termination_keys.include?(k) && (k.match?(/[[:print:]]/) || k == "\C-h" || k == "\C-?" || k == "\C-r" || k == "\C-s")
1610
1563
  search_word, prompt_name, hit_pointer = searcher.call(k)
1611
1564
  Reline.last_incremental_search = search_word
1612
1565
  @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
@@ -1822,7 +1775,7 @@ class Reline::LineEditor
1822
1775
  alias_method :kill_whole_line, :em_kill_line
1823
1776
 
1824
1777
  private def em_delete(key)
1825
- if buffer_empty? and key == "\C-d".ord
1778
+ if buffer_empty? and key == "\C-d"
1826
1779
  @eof = true
1827
1780
  finish
1828
1781
  elsif @byte_pointer < current_line.bytesize
@@ -2240,20 +2193,9 @@ class Reline::LineEditor
2240
2193
  end
2241
2194
 
2242
2195
  private def ed_argument_digit(key)
2243
- if @vi_arg.nil?
2244
- if key.chr.to_i.zero?
2245
- if key.anybits?(0b10000000)
2246
- unescaped_key = key ^ 0b10000000
2247
- unless unescaped_key.chr.to_i.zero?
2248
- @vi_arg = unescaped_key.chr.to_i
2249
- end
2250
- end
2251
- else
2252
- @vi_arg = key.chr.to_i
2253
- end
2254
- else
2255
- @vi_arg = @vi_arg * 10 + key.chr.to_i
2256
- end
2196
+ # key is expected to be `ESC digit` or `digit`
2197
+ num = key[/\d/].to_i
2198
+ @vi_arg = (@vi_arg || 0) * 10 + num
2257
2199
  end
2258
2200
 
2259
2201
  private def vi_to_column(key, arg: 0)
@@ -2272,7 +2214,7 @@ class Reline::LineEditor
2272
2214
  before = current_line.byteslice(0, @byte_pointer)
2273
2215
  remaining_point = @byte_pointer + byte_size
2274
2216
  after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
2275
- set_current_line(before + k.chr + after)
2217
+ set_current_line(before + k + after)
2276
2218
  @waiting_proc = nil
2277
2219
  elsif arg > 1
2278
2220
  byte_size = 0
@@ -2282,7 +2224,7 @@ class Reline::LineEditor
2282
2224
  before = current_line.byteslice(0, @byte_pointer)
2283
2225
  remaining_point = @byte_pointer + byte_size
2284
2226
  after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
2285
- replaced = k.chr * arg
2227
+ replaced = k * arg
2286
2228
  set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
2287
2229
  @waiting_proc = nil
2288
2230
  end
@@ -2298,11 +2240,6 @@ class Reline::LineEditor
2298
2240
  end
2299
2241
 
2300
2242
  private def search_next_char(key, arg, need_prev_char: false, inclusive: false)
2301
- if key.instance_of?(String)
2302
- inputted_char = key
2303
- else
2304
- inputted_char = key.chr
2305
- end
2306
2243
  prev_total = nil
2307
2244
  total = nil
2308
2245
  found = false
@@ -2313,7 +2250,7 @@ class Reline::LineEditor
2313
2250
  width = Reline::Unicode.get_mbchar_width(mbchar)
2314
2251
  total = [mbchar.bytesize, width]
2315
2252
  else
2316
- if inputted_char == mbchar
2253
+ if key == mbchar
2317
2254
  arg -= 1
2318
2255
  if arg.zero?
2319
2256
  found = true
@@ -2350,11 +2287,6 @@ class Reline::LineEditor
2350
2287
  end
2351
2288
 
2352
2289
  private def search_prev_char(key, arg, need_next_char = false)
2353
- if key.instance_of?(String)
2354
- inputted_char = key
2355
- else
2356
- inputted_char = key.chr
2357
- end
2358
2290
  prev_total = nil
2359
2291
  total = nil
2360
2292
  found = false
@@ -2365,7 +2297,7 @@ class Reline::LineEditor
2365
2297
  width = Reline::Unicode.get_mbchar_width(mbchar)
2366
2298
  total = [mbchar.bytesize, width]
2367
2299
  else
2368
- if inputted_char == mbchar
2300
+ if key == mbchar
2369
2301
  arg -= 1
2370
2302
  if arg.zero?
2371
2303
  found = true
@@ -2417,24 +2349,23 @@ class Reline::LineEditor
2417
2349
  @config.editing_mode = :vi_insert
2418
2350
  end
2419
2351
 
2420
- private def undo(_key)
2421
- @undoing = true
2352
+ private def move_undo_redo(direction)
2353
+ @restoring = true
2354
+ return unless (0..@input_lines.size - 1).cover?(@input_lines_position + direction)
2422
2355
 
2423
- return if @input_lines_position <= 0
2356
+ @input_lines_position += direction
2357
+ buffer_of_lines, byte_pointer, line_index = @input_lines[@input_lines_position]
2358
+ @buffer_of_lines = buffer_of_lines.dup
2359
+ @line_index = line_index
2360
+ @byte_pointer = byte_pointer
2361
+ end
2424
2362
 
2425
- @input_lines_position -= 1
2426
- target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
2427
- set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
2363
+ private def undo(_key)
2364
+ move_undo_redo(-1)
2428
2365
  end
2429
2366
 
2430
2367
  private def redo(_key)
2431
- @undoing = true
2432
-
2433
- return if @input_lines_position >= @input_lines.size - 1
2434
-
2435
- @input_lines_position += 1
2436
- target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
2437
- set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
2368
+ move_undo_redo(+1)
2438
2369
  end
2439
2370
 
2440
2371
  private def prev_action_state_value(type)