reline 0.5.2 → 0.5.3

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: 68e79c30bbef8d97090f7126f96c5ee0c32fa95e6dc120a91240a6e9ff3864c6
4
- data.tar.gz: 857716d3f9ab324efef98d3cb42acf2bba17848012a832c5631ca3e6d2f15733
3
+ metadata.gz: 77e916d771c2f7219d8cba4be2e3b5e6102dddcb505b342375b8717e069caab1
4
+ data.tar.gz: ec4262c712ed77b4807255d12887542b37e74cf0e1ccf1dfef78d803d886ba17
5
5
  SHA512:
6
- metadata.gz: b25e6a151ded60963f660ccafceef8c221577b9f2328b9daa10dc381f5ea63c293a9759a786ab02610eb2fb07c52f3a200303fd9ac672210658884cb9a57c88c
7
- data.tar.gz: 8433437480cf5acf7d87aefc632cc641e9325f163ab1d00d1df9cea5d5f3977f05250b20b366d7fd21ae275edd8f152ddc5879fa88340fbf35990e9b2a7e9725
6
+ metadata.gz: b0b88eb00ce703b01f691c2fc780a7f9ff43fefdcc9d42d22122bba742ddc03b20db19ecca2c21082081f66d4993f70a3a4cb53ea50ed5a0255728635360c45c
7
+ data.tar.gz: eb4b51fb15f94e2c349fe4cf19c2d6426f7fdf0800320b89a14d66e6f18ea72f327d7792a8edb6d6034df708bb7c25fbffb625fe7cc03271efdb6662d9c90deb
@@ -112,7 +112,11 @@ class Reline::LineEditor
112
112
  else
113
113
  prompt = @prompt
114
114
  end
115
- if @prompt_proc
115
+ if !@is_multiline
116
+ mode_string = check_mode_string
117
+ prompt = mode_string + prompt if mode_string
118
+ [prompt] + [''] * (buffer.size - 1)
119
+ elsif @prompt_proc
116
120
  prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
117
121
  prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
118
122
  prompt_list = [prompt] if prompt_list.empty?
@@ -291,8 +295,8 @@ class Reline::LineEditor
291
295
  end
292
296
  end
293
297
 
294
- private def split_by_width(str, max_width)
295
- Reline::Unicode.split_by_width(str, max_width, @encoding)
298
+ private def split_by_width(str, max_width, offset: 0)
299
+ Reline::Unicode.split_by_width(str, max_width, @encoding, offset: offset)
296
300
  end
297
301
 
298
302
  def current_byte_pointer_cursor
@@ -366,7 +370,7 @@ class Reline::LineEditor
366
370
  @scroll_partial_screen
367
371
  end
368
372
 
369
- def wrapped_lines
373
+ def wrapped_prompt_and_input_lines
370
374
  with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
371
375
  prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
372
376
  cached_wraps = {}
@@ -377,9 +381,14 @@ class Reline::LineEditor
377
381
  end
378
382
 
379
383
  n.times.map do |i|
380
- prompt = prompts[i]
381
- line = lines[i]
382
- cached_wraps[[prompt, line]] || split_by_width("#{prompt}#{line}", width).first.compact
384
+ prompt = prompts[i] || ''
385
+ line = lines[i] || ''
386
+ if (cached = cached_wraps[[prompt, line]])
387
+ next cached
388
+ end
389
+ *wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
390
+ wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt)).first.compact
391
+ wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
383
392
  end
384
393
  end
385
394
  end
@@ -422,7 +431,7 @@ class Reline::LineEditor
422
431
  prompt_width = calculate_width(prompt_list[@line_index], true)
423
432
  line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
424
433
  wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
425
- wrapped_cursor_y = wrapped_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
434
+ wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
426
435
  wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
427
436
  [wrapped_cursor_x, wrapped_cursor_y]
428
437
  end
@@ -486,8 +495,9 @@ class Reline::LineEditor
486
495
  wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
487
496
 
488
497
  rendered_lines = @rendered_screen.lines
489
- new_lines = wrapped_lines.flatten[screen_scroll_top, screen_height].map do |l|
490
- [[0, Reline::Unicode.calculate_width(l, true), l]]
498
+ new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
499
+ prompt_width = Reline::Unicode.calculate_width(prompt, true)
500
+ [[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
491
501
  end
492
502
  if @menu_info
493
503
  @menu_info.lines(screen_width).each do |item|
@@ -503,7 +513,8 @@ class Reline::LineEditor
503
513
  y_range.each do |row|
504
514
  next if row < 0 || row >= screen_height
505
515
  dialog_rows = new_lines[row] ||= []
506
- dialog_rows[index + 1] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
516
+ # index 0 is for prompt, index 1 is for line, index 2.. is for dialog
517
+ dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
507
518
  end
508
519
  end
509
520
 
@@ -876,10 +887,12 @@ class Reline::LineEditor
876
887
  @completion_state = CompletionState::PERFECT_MATCH
877
888
  else
878
889
  @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
890
+ complete(list, true) if @config.show_all_if_ambiguous
879
891
  end
880
892
  @perfect_matched = completed
881
893
  else
882
894
  @completion_state = CompletionState::MENU
895
+ complete(list, true) if @config.show_all_if_ambiguous
883
896
  end
884
897
  if not just_show_list and target < completed
885
898
  @buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
@@ -1220,7 +1233,7 @@ class Reline::LineEditor
1220
1233
  end
1221
1234
 
1222
1235
  def line()
1223
- current_line unless eof?
1236
+ @buffer_of_lines.join("\n") unless eof?
1224
1237
  end
1225
1238
 
1226
1239
  def current_line
@@ -1304,14 +1317,12 @@ class Reline::LineEditor
1304
1317
  end
1305
1318
  target = before
1306
1319
  end
1307
- if @is_multiline
1308
- lines = whole_lines
1309
- if @line_index > 0
1310
- preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
1311
- end
1312
- if (lines.size - 1) > @line_index
1313
- postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
1314
- end
1320
+ lines = whole_lines
1321
+ if @line_index > 0
1322
+ preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
1323
+ end
1324
+ if (lines.size - 1) > @line_index
1325
+ postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
1315
1326
  end
1316
1327
  [preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
1317
1328
  end
@@ -1333,20 +1344,16 @@ class Reline::LineEditor
1333
1344
 
1334
1345
  def delete_text(start = nil, length = nil)
1335
1346
  if start.nil? and length.nil?
1336
- if @is_multiline
1337
- if @buffer_of_lines.size == 1
1338
- @buffer_of_lines[@line_index] = ''
1339
- @byte_pointer = 0
1340
- elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
1341
- @buffer_of_lines.pop
1342
- @line_index -= 1
1343
- @byte_pointer = 0
1344
- elsif @line_index < (@buffer_of_lines.size - 1)
1345
- @buffer_of_lines.delete_at(@line_index)
1346
- @byte_pointer = 0
1347
- end
1348
- else
1349
- set_current_line('', 0)
1347
+ if @buffer_of_lines.size == 1
1348
+ @buffer_of_lines[@line_index] = ''
1349
+ @byte_pointer = 0
1350
+ elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
1351
+ @buffer_of_lines.pop
1352
+ @line_index -= 1
1353
+ @byte_pointer = 0
1354
+ elsif @line_index < (@buffer_of_lines.size - 1)
1355
+ @buffer_of_lines.delete_at(@line_index)
1356
+ @byte_pointer = 0
1350
1357
  end
1351
1358
  elsif not start.nil? and not length.nil?
1352
1359
  if current_line
@@ -1502,7 +1509,7 @@ class Reline::LineEditor
1502
1509
  byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
1503
1510
  if (@byte_pointer < current_line.bytesize)
1504
1511
  @byte_pointer += byte_size
1505
- elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
1512
+ elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
1506
1513
  @byte_pointer = 0
1507
1514
  @line_index += 1
1508
1515
  end
@@ -1515,7 +1522,7 @@ class Reline::LineEditor
1515
1522
  if @byte_pointer > 0
1516
1523
  byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
1517
1524
  @byte_pointer -= byte_size
1518
- elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
1525
+ elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
1519
1526
  @line_index -= 1
1520
1527
  @byte_pointer = current_line.bytesize
1521
1528
  end
@@ -1543,131 +1550,95 @@ class Reline::LineEditor
1543
1550
  end
1544
1551
  alias_method :end_of_line, :ed_move_to_end
1545
1552
 
1546
- private def generate_searcher
1547
- Fiber.new do |first_key|
1548
- prev_search_key = first_key
1549
- search_word = String.new(encoding: @encoding)
1550
- multibyte_buf = String.new(encoding: 'ASCII-8BIT')
1551
- last_hit = nil
1552
- case first_key
1553
- when "\C-r".ord
1554
- prompt_name = 'reverse-i-search'
1555
- when "\C-s".ord
1556
- prompt_name = 'i-search'
1553
+ private def generate_searcher(search_key)
1554
+ search_word = String.new(encoding: @encoding)
1555
+ multibyte_buf = String.new(encoding: 'ASCII-8BIT')
1556
+ hit_pointer = nil
1557
+ lambda do |key|
1558
+ search_again = false
1559
+ case key
1560
+ when "\C-h".ord, "\C-?".ord
1561
+ grapheme_clusters = search_word.grapheme_clusters
1562
+ if grapheme_clusters.size > 0
1563
+ grapheme_clusters.pop
1564
+ search_word = grapheme_clusters.join
1565
+ end
1566
+ when "\C-r".ord, "\C-s".ord
1567
+ search_again = true if search_key == key
1568
+ search_key = key
1569
+ else
1570
+ multibyte_buf << key
1571
+ if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
1572
+ search_word << multibyte_buf.dup.force_encoding(@encoding)
1573
+ multibyte_buf.clear
1574
+ end
1557
1575
  end
1558
- loop do
1559
- key = Fiber.yield(search_word)
1560
- search_again = false
1561
- case key
1562
- when -1 # determined
1563
- Reline.last_incremental_search = search_word
1564
- break
1565
- when "\C-h".ord, "\C-?".ord
1566
- grapheme_clusters = search_word.grapheme_clusters
1567
- if grapheme_clusters.size > 0
1568
- grapheme_clusters.pop
1569
- search_word = grapheme_clusters.join
1570
- end
1571
- when "\C-r".ord, "\C-s".ord
1572
- search_again = true if prev_search_key == key
1573
- prev_search_key = key
1574
- else
1575
- multibyte_buf << key
1576
- if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
1577
- search_word << multibyte_buf.dup.force_encoding(@encoding)
1578
- multibyte_buf.clear
1576
+ hit = nil
1577
+ if not search_word.empty? and @line_backup_in_history&.include?(search_word)
1578
+ hit_pointer = Reline::HISTORY.size
1579
+ hit = @line_backup_in_history
1580
+ else
1581
+ if search_again
1582
+ if search_word.empty? and Reline.last_incremental_search
1583
+ search_word = Reline.last_incremental_search
1579
1584
  end
1580
- end
1581
- hit = nil
1582
- if not search_word.empty? and @line_backup_in_history&.include?(search_word)
1583
- @history_pointer = nil
1584
- hit = @line_backup_in_history
1585
- else
1586
- if search_again
1587
- if search_word.empty? and Reline.last_incremental_search
1588
- search_word = Reline.last_incremental_search
1589
- end
1590
- if @history_pointer
1591
- case prev_search_key
1592
- when "\C-r".ord
1593
- history_pointer_base = 0
1594
- history = Reline::HISTORY[0..(@history_pointer - 1)]
1595
- when "\C-s".ord
1596
- history_pointer_base = @history_pointer + 1
1597
- history = Reline::HISTORY[(@history_pointer + 1)..-1]
1598
- end
1599
- else
1600
- history_pointer_base = 0
1601
- history = Reline::HISTORY
1602
- end
1603
- elsif @history_pointer
1604
- case prev_search_key
1585
+ if @history_pointer
1586
+ case search_key
1605
1587
  when "\C-r".ord
1606
1588
  history_pointer_base = 0
1607
- history = Reline::HISTORY[0..@history_pointer]
1589
+ history = Reline::HISTORY[0..(@history_pointer - 1)]
1608
1590
  when "\C-s".ord
1609
- history_pointer_base = @history_pointer
1610
- history = Reline::HISTORY[@history_pointer..-1]
1591
+ history_pointer_base = @history_pointer + 1
1592
+ history = Reline::HISTORY[(@history_pointer + 1)..-1]
1611
1593
  end
1612
1594
  else
1613
1595
  history_pointer_base = 0
1614
1596
  history = Reline::HISTORY
1615
1597
  end
1616
- case prev_search_key
1598
+ elsif @history_pointer
1599
+ case search_key
1617
1600
  when "\C-r".ord
1618
- hit_index = history.rindex { |item|
1619
- item.include?(search_word)
1620
- }
1601
+ history_pointer_base = 0
1602
+ history = Reline::HISTORY[0..@history_pointer]
1621
1603
  when "\C-s".ord
1622
- hit_index = history.index { |item|
1623
- item.include?(search_word)
1624
- }
1625
- end
1626
- if hit_index
1627
- @history_pointer = history_pointer_base + hit_index
1628
- hit = Reline::HISTORY[@history_pointer]
1604
+ history_pointer_base = @history_pointer
1605
+ history = Reline::HISTORY[@history_pointer..-1]
1629
1606
  end
1607
+ else
1608
+ history_pointer_base = 0
1609
+ history = Reline::HISTORY
1630
1610
  end
1631
- case prev_search_key
1611
+ case search_key
1632
1612
  when "\C-r".ord
1633
- prompt_name = 'reverse-i-search'
1613
+ hit_index = history.rindex { |item|
1614
+ item.include?(search_word)
1615
+ }
1634
1616
  when "\C-s".ord
1635
- prompt_name = 'i-search'
1617
+ hit_index = history.index { |item|
1618
+ item.include?(search_word)
1619
+ }
1636
1620
  end
1637
- if hit
1638
- if @is_multiline
1639
- @buffer_of_lines = hit.split("\n")
1640
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1641
- @line_index = @buffer_of_lines.size - 1
1642
- @byte_pointer = current_line.bytesize
1643
- @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
1644
- else
1645
- @buffer_of_lines = [hit]
1646
- @byte_pointer = hit.bytesize
1647
- @searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
1648
- end
1649
- last_hit = hit
1650
- else
1651
- if @is_multiline
1652
- @searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
1653
- else
1654
- @searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
1655
- end
1621
+ if hit_index
1622
+ hit_pointer = history_pointer_base + hit_index
1623
+ hit = Reline::HISTORY[hit_pointer]
1656
1624
  end
1657
1625
  end
1626
+ case search_key
1627
+ when "\C-r".ord
1628
+ prompt_name = 'reverse-i-search'
1629
+ when "\C-s".ord
1630
+ prompt_name = 'i-search'
1631
+ end
1632
+ prompt_name = "failed #{prompt_name}" unless hit
1633
+ [search_word, prompt_name, hit_pointer]
1658
1634
  end
1659
1635
  end
1660
1636
 
1661
1637
  private def incremental_search_history(key)
1662
1638
  unless @history_pointer
1663
- if @is_multiline
1664
- @line_backup_in_history = whole_buffer
1665
- else
1666
- @line_backup_in_history = current_line
1667
- end
1639
+ @line_backup_in_history = whole_buffer
1668
1640
  end
1669
- searcher = generate_searcher
1670
- searcher.resume(key)
1641
+ searcher = generate_searcher(key)
1671
1642
  @searching_prompt = "(reverse-i-search)`': "
1672
1643
  termination_keys = ["\C-j".ord]
1673
1644
  termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
@@ -1679,53 +1650,41 @@ class Reline::LineEditor
1679
1650
  else
1680
1651
  buffer = @line_backup_in_history
1681
1652
  end
1682
- if @is_multiline
1683
- @buffer_of_lines = buffer.split("\n")
1684
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1685
- @line_index = @buffer_of_lines.size - 1
1686
- else
1687
- @buffer_of_lines = [buffer]
1688
- end
1653
+ @buffer_of_lines = buffer.split("\n")
1654
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1655
+ @line_index = @buffer_of_lines.size - 1
1689
1656
  @searching_prompt = nil
1690
1657
  @waiting_proc = nil
1691
1658
  @byte_pointer = 0
1692
- searcher.resume(-1)
1693
1659
  when "\C-g".ord
1694
- if @is_multiline
1695
- @buffer_of_lines = @line_backup_in_history.split("\n")
1696
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1697
- @line_index = @buffer_of_lines.size - 1
1698
- else
1699
- @buffer_of_lines = [@line_backup_in_history]
1700
- end
1701
- @history_pointer = nil
1660
+ @buffer_of_lines = @line_backup_in_history.split("\n")
1661
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1662
+ @line_index = @buffer_of_lines.size - 1
1663
+ move_history(nil, line: :end, cursor: :end, save_buffer: false)
1702
1664
  @searching_prompt = nil
1703
1665
  @waiting_proc = nil
1704
- @line_backup_in_history = nil
1705
1666
  @byte_pointer = 0
1706
1667
  else
1707
1668
  chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
1708
1669
  if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
1709
- searcher.resume(k)
1670
+ search_word, prompt_name, hit_pointer = searcher.call(k)
1671
+ Reline.last_incremental_search = search_word
1672
+ @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
1673
+ @searching_prompt += ': ' unless @is_multiline
1674
+ move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
1710
1675
  else
1711
1676
  if @history_pointer
1712
1677
  line = Reline::HISTORY[@history_pointer]
1713
1678
  else
1714
1679
  line = @line_backup_in_history
1715
1680
  end
1716
- if @is_multiline
1717
- @line_backup_in_history = whole_buffer
1718
- @buffer_of_lines = line.split("\n")
1719
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1720
- @line_index = @buffer_of_lines.size - 1
1721
- else
1722
- @line_backup_in_history = current_line
1723
- @buffer_of_lines = [line]
1724
- end
1681
+ @line_backup_in_history = whole_buffer
1682
+ @buffer_of_lines = line.split("\n")
1683
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1684
+ @line_index = @buffer_of_lines.size - 1
1725
1685
  @searching_prompt = nil
1726
1686
  @waiting_proc = nil
1727
1687
  @byte_pointer = 0
1728
- searcher.resume(-1)
1729
1688
  end
1730
1689
  end
1731
1690
  }
@@ -1741,191 +1700,95 @@ class Reline::LineEditor
1741
1700
  end
1742
1701
  alias_method :forward_search_history, :vi_search_next
1743
1702
 
1744
- private def ed_search_prev_history(key, arg: 1)
1745
- history = nil
1746
- h_pointer = nil
1747
- line_no = nil
1748
- substr = current_line.slice(0, @byte_pointer)
1749
- if @history_pointer.nil?
1750
- return if not current_line.empty? and substr.empty?
1751
- history = Reline::HISTORY
1752
- elsif @history_pointer.zero?
1753
- history = nil
1754
- h_pointer = nil
1755
- else
1756
- history = Reline::HISTORY.slice(0, @history_pointer)
1757
- end
1758
- return if history.nil?
1759
- if @is_multiline
1760
- h_pointer = history.rindex { |h|
1761
- h.split("\n").each_with_index { |l, i|
1762
- if l.start_with?(substr)
1763
- line_no = i
1764
- break
1765
- end
1766
- }
1767
- not line_no.nil?
1768
- }
1769
- else
1770
- h_pointer = history.rindex { |l|
1771
- l.start_with?(substr)
1772
- }
1773
- end
1774
- return if h_pointer.nil?
1775
- @history_pointer = h_pointer
1776
- cursor = current_byte_pointer_cursor
1777
- if @is_multiline
1778
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
1779
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1780
- @line_index = line_no
1781
- calculate_nearest_cursor(cursor)
1782
- else
1783
- @buffer_of_lines = [Reline::HISTORY[@history_pointer]]
1784
- calculate_nearest_cursor(cursor)
1703
+ private def search_history(prefix, pointer_range)
1704
+ pointer_range.each do |pointer|
1705
+ lines = Reline::HISTORY[pointer].split("\n")
1706
+ lines.each_with_index do |line, index|
1707
+ return [pointer, index] if line.start_with?(prefix)
1708
+ end
1785
1709
  end
1710
+ nil
1711
+ end
1712
+
1713
+ private def ed_search_prev_history(key, arg: 1)
1714
+ substr = current_line.byteslice(0, @byte_pointer)
1715
+ return if @history_pointer == 0
1716
+ return if @history_pointer.nil? && substr.empty? && !current_line.empty?
1717
+
1718
+ history_range = 0...(@history_pointer || Reline::HISTORY.size)
1719
+ h_pointer, line_index = search_history(substr, history_range.reverse_each)
1720
+ return unless h_pointer
1721
+ move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
1786
1722
  arg -= 1
1787
1723
  ed_search_prev_history(key, arg: arg) if arg > 0
1788
1724
  end
1789
1725
  alias_method :history_search_backward, :ed_search_prev_history
1790
1726
 
1791
1727
  private def ed_search_next_history(key, arg: 1)
1792
- substr = current_line.slice(0, @byte_pointer)
1793
- if @history_pointer.nil?
1794
- return
1795
- elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty?
1796
- return
1797
- end
1798
- history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
1799
- h_pointer = nil
1800
- line_no = nil
1801
- if @is_multiline
1802
- h_pointer = history.index { |h|
1803
- h.split("\n").each_with_index { |l, i|
1804
- if l.start_with?(substr)
1805
- line_no = i
1806
- break
1807
- end
1808
- }
1809
- not line_no.nil?
1810
- }
1811
- else
1812
- h_pointer = history.index { |l|
1813
- l.start_with?(substr)
1814
- }
1815
- end
1816
- h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
1728
+ substr = current_line.byteslice(0, @byte_pointer)
1729
+ return if @history_pointer.nil?
1730
+
1731
+ history_range = @history_pointer + 1...Reline::HISTORY.size
1732
+ h_pointer, line_index = search_history(substr, history_range)
1817
1733
  return if h_pointer.nil? and not substr.empty?
1818
- @history_pointer = h_pointer
1819
- if @is_multiline
1820
- if @history_pointer.nil? and substr.empty?
1821
- @buffer_of_lines = []
1822
- @line_index = 0
1823
- @byte_pointer = 0
1824
- else
1825
- cursor = current_byte_pointer_cursor
1826
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
1827
- @line_index = line_no
1828
- calculate_nearest_cursor(cursor)
1829
- end
1830
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1831
- else
1832
- if @history_pointer.nil? and substr.empty?
1833
- set_current_line('', 0)
1834
- else
1835
- set_current_line(Reline::HISTORY[@history_pointer])
1836
- end
1837
- end
1734
+
1735
+ move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
1838
1736
  arg -= 1
1839
1737
  ed_search_next_history(key, arg: arg) if arg > 0
1840
1738
  end
1841
1739
  alias_method :history_search_forward, :ed_search_next_history
1842
1740
 
1741
+ private def move_history(history_pointer, line:, cursor:, save_buffer: true)
1742
+ history_pointer ||= Reline::HISTORY.size
1743
+ return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
1744
+ old_history_pointer = @history_pointer || Reline::HISTORY.size
1745
+ if old_history_pointer == Reline::HISTORY.size
1746
+ @line_backup_in_history = save_buffer ? whole_buffer : ''
1747
+ else
1748
+ Reline::HISTORY[old_history_pointer] = whole_buffer if save_buffer
1749
+ end
1750
+ if history_pointer == Reline::HISTORY.size
1751
+ buf = @line_backup_in_history
1752
+ @history_pointer = @line_backup_in_history = nil
1753
+ else
1754
+ buf = Reline::HISTORY[history_pointer]
1755
+ @history_pointer = history_pointer
1756
+ end
1757
+ @buffer_of_lines = buf.split("\n")
1758
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1759
+ @line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
1760
+ @byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
1761
+ end
1762
+
1843
1763
  private def ed_prev_history(key, arg: 1)
1844
- if @is_multiline and @line_index > 0
1764
+ if @line_index > 0
1845
1765
  cursor = current_byte_pointer_cursor
1846
1766
  @line_index -= 1
1847
1767
  calculate_nearest_cursor(cursor)
1848
1768
  return
1849
1769
  end
1850
- if Reline::HISTORY.empty?
1851
- return
1852
- end
1853
- if @history_pointer.nil?
1854
- @history_pointer = Reline::HISTORY.size - 1
1855
- cursor = current_byte_pointer_cursor
1856
- if @is_multiline
1857
- @line_backup_in_history = whole_buffer
1858
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
1859
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1860
- @line_index = @buffer_of_lines.size - 1
1861
- calculate_nearest_cursor(cursor)
1862
- else
1863
- @line_backup_in_history = whole_buffer
1864
- @buffer_of_lines = [Reline::HISTORY[@history_pointer]]
1865
- calculate_nearest_cursor(cursor)
1866
- end
1867
- elsif @history_pointer.zero?
1868
- return
1869
- else
1870
- if @is_multiline
1871
- Reline::HISTORY[@history_pointer] = whole_buffer
1872
- @history_pointer -= 1
1873
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
1874
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1875
- @line_index = @buffer_of_lines.size - 1
1876
- else
1877
- Reline::HISTORY[@history_pointer] = whole_buffer
1878
- @history_pointer -= 1
1879
- @buffer_of_lines = [Reline::HISTORY[@history_pointer]]
1880
- end
1881
- end
1882
- if @config.editing_mode_is?(:emacs, :vi_insert)
1883
- @byte_pointer = current_line.bytesize
1884
- elsif @config.editing_mode_is?(:vi_command)
1885
- @byte_pointer = 0
1886
- end
1770
+ move_history(
1771
+ (@history_pointer || Reline::HISTORY.size) - 1,
1772
+ line: :end,
1773
+ cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
1774
+ )
1887
1775
  arg -= 1
1888
1776
  ed_prev_history(key, arg: arg) if arg > 0
1889
1777
  end
1890
1778
  alias_method :previous_history, :ed_prev_history
1891
1779
 
1892
1780
  private def ed_next_history(key, arg: 1)
1893
- if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
1781
+ if @line_index < (@buffer_of_lines.size - 1)
1894
1782
  cursor = current_byte_pointer_cursor
1895
1783
  @line_index += 1
1896
1784
  calculate_nearest_cursor(cursor)
1897
1785
  return
1898
1786
  end
1899
- if @history_pointer.nil?
1900
- return
1901
- elsif @history_pointer == (Reline::HISTORY.size - 1)
1902
- if @is_multiline
1903
- @history_pointer = nil
1904
- @buffer_of_lines = @line_backup_in_history.split("\n")
1905
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1906
- @line_index = 0
1907
- else
1908
- @history_pointer = nil
1909
- @buffer_of_lines = [@line_backup_in_history]
1910
- end
1911
- else
1912
- if @is_multiline
1913
- Reline::HISTORY[@history_pointer] = whole_buffer
1914
- @history_pointer += 1
1915
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
1916
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
1917
- @line_index = 0
1918
- else
1919
- Reline::HISTORY[@history_pointer] = whole_buffer
1920
- @history_pointer += 1
1921
- @buffer_of_lines = [Reline::HISTORY[@history_pointer]]
1922
- end
1923
- end
1924
- if @config.editing_mode_is?(:emacs, :vi_insert)
1925
- @byte_pointer = current_line.bytesize
1926
- elsif @config.editing_mode_is?(:vi_command)
1927
- @byte_pointer = 0
1928
- end
1787
+ move_history(
1788
+ (@history_pointer || Reline::HISTORY.size) + 1,
1789
+ line: :start,
1790
+ cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
1791
+ )
1929
1792
  arg -= 1
1930
1793
  ed_next_history(key, arg: arg) if arg > 0
1931
1794
  end
@@ -1956,17 +1819,13 @@ class Reline::LineEditor
1956
1819
  end
1957
1820
  end
1958
1821
  else
1959
- if @history_pointer
1960
- Reline::HISTORY[@history_pointer] = whole_buffer
1961
- @history_pointer = nil
1962
- end
1963
1822
  finish
1964
1823
  end
1965
1824
  end
1966
1825
 
1967
1826
  private def em_delete_prev_char(key, arg: 1)
1968
1827
  arg.times do
1969
- if @is_multiline and @byte_pointer == 0 and @line_index > 0
1828
+ if @byte_pointer == 0 and @line_index > 0
1970
1829
  @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
1971
1830
  @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
1972
1831
  @line_index -= 1
@@ -1990,7 +1849,7 @@ class Reline::LineEditor
1990
1849
  line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
1991
1850
  set_current_line(line, line.bytesize)
1992
1851
  @kill_ring.append(deleted)
1993
- elsif @is_multiline and @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
1852
+ elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
1994
1853
  set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
1995
1854
  end
1996
1855
  end
@@ -2030,7 +1889,7 @@ class Reline::LineEditor
2030
1889
  alias_method :kill_whole_line, :em_kill_line
2031
1890
 
2032
1891
  private def em_delete(key)
2033
- if current_line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == "\C-d".ord
1892
+ if current_line.empty? and @buffer_of_lines.size == 1 and key == "\C-d".ord
2034
1893
  @eof = true
2035
1894
  finish
2036
1895
  elsif @byte_pointer < current_line.bytesize
@@ -2038,7 +1897,7 @@ class Reline::LineEditor
2038
1897
  mbchar = splitted_last.grapheme_clusters.first
2039
1898
  line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
2040
1899
  set_current_line(line)
2041
- elsif @is_multiline and @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
1900
+ elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
2042
1901
  set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
2043
1902
  end
2044
1903
  end
@@ -2281,7 +2140,7 @@ class Reline::LineEditor
2281
2140
  end
2282
2141
 
2283
2142
  private def vi_delete_prev_char(key)
2284
- if @is_multiline and @byte_pointer == 0 and @line_index > 0
2143
+ if @byte_pointer == 0 and @line_index > 0
2285
2144
  @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
2286
2145
  @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
2287
2146
  @line_index -= 1
@@ -2378,7 +2237,7 @@ class Reline::LineEditor
2378
2237
  end
2379
2238
 
2380
2239
  private def vi_list_or_eof(key)
2381
- if (not @is_multiline and current_line.empty?) or (@is_multiline and current_line.empty? and @buffer_of_lines.size == 1)
2240
+ if current_line.empty? and @buffer_of_lines.size == 1
2382
2241
  set_current_line('', 0)
2383
2242
  @eof = true
2384
2243
  finish
@@ -2409,36 +2268,18 @@ class Reline::LineEditor
2409
2268
  if Reline::HISTORY.empty?
2410
2269
  return
2411
2270
  end
2412
- if @history_pointer.nil?
2413
- @history_pointer = 0
2414
- @line_backup_in_history = current_line
2415
- set_current_line(Reline::HISTORY[@history_pointer], 0)
2416
- elsif @history_pointer.zero?
2417
- return
2418
- else
2419
- Reline::HISTORY[@history_pointer] = current_line
2420
- @history_pointer = 0
2421
- set_current_line(Reline::HISTORY[@history_pointer], 0)
2422
- end
2271
+ move_history(0, line: :start, cursor: :start)
2423
2272
  end
2424
2273
 
2425
2274
  private def vi_histedit(key)
2426
2275
  path = Tempfile.open { |fp|
2427
- if @is_multiline
2428
- fp.write whole_lines.join("\n")
2429
- else
2430
- fp.write current_line
2431
- end
2276
+ fp.write whole_lines.join("\n")
2432
2277
  fp.path
2433
2278
  }
2434
2279
  system("#{ENV['EDITOR']} #{path}")
2435
- if @is_multiline
2436
- @buffer_of_lines = File.read(path).split("\n")
2437
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
2438
- @line_index = 0
2439
- else
2440
- @buffer_of_lines = File.read(path).split("\n")
2441
- end
2280
+ @buffer_of_lines = File.read(path).split("\n")
2281
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
2282
+ @line_index = 0
2442
2283
  finish
2443
2284
  end
2444
2285
 
@@ -2610,7 +2451,7 @@ class Reline::LineEditor
2610
2451
  end
2611
2452
 
2612
2453
  private def vi_join_lines(key, arg: 1)
2613
- if @is_multiline and @buffer_of_lines.size > @line_index + 1
2454
+ if @buffer_of_lines.size > @line_index + 1
2614
2455
  next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
2615
2456
  set_current_line(current_line + ' ' + next_line, current_line.bytesize)
2616
2457
  end
@@ -128,10 +128,10 @@ class Reline::Unicode
128
128
  end
129
129
  end
130
130
 
131
- def self.split_by_width(str, max_width, encoding = str.encoding)
131
+ def self.split_by_width(str, max_width, encoding = str.encoding, offset: 0)
132
132
  lines = [String.new(encoding: encoding)]
133
133
  height = 1
134
- width = 0
134
+ width = offset
135
135
  rest = str.encode(Encoding::UTF_8)
136
136
  in_zero_width = false
137
137
  seq = String.new(encoding: encoding)
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.5.2'
2
+ VERSION = '0.5.3'
3
3
  end
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.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-16 00:00:00.000000000 Z
11
+ date: 2024-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console