reline 0.5.12 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)