reline 0.5.2 → 0.5.3

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