Skip to content

Commit 4426d62

Browse files
committed
Update range subtraction algorithm in dialog rendering
1 parent 4b089c6 commit 4426d62

File tree

2 files changed

+54
-18
lines changed

2 files changed

+54
-18
lines changed

lib/reline/line_editor.rb

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,45 @@ def add_dialog_proc(name, p, context = nil)
659659
render_dialog_changes(changes, cursor_column)
660660
end
661661

662+
private def range_subtract(base_ranges, subtract_ranges)
663+
points = []
664+
base_ranges.each do |range|
665+
points << [range.begin, 1, 1]
666+
points << [range.end, -1, 1]
667+
end
668+
subtract_ranges.each do |range|
669+
points << [range.begin, 1, -1]
670+
points << [range.end, -1, -1]
671+
end
672+
ranges = []
673+
base_count = 0
674+
subtract_count = 0
675+
open = false
676+
points.sort.each do |point, diff, mode|
677+
if mode == 1
678+
base_count += diff
679+
else
680+
subtract_count += diff
681+
end
682+
next if open == (base_count > 0 && subtract_count == 0)
683+
open = !open
684+
if open
685+
if ranges.last&.end === point
686+
ranges[-1] = (ranges.last.begin...)
687+
else
688+
ranges << (point...)
689+
end
690+
else
691+
if ranges.last.begin === point
692+
ranges.pop
693+
else
694+
ranges[-1] = ranges.last.begin...point
695+
end
696+
end
697+
end
698+
ranges
699+
end
700+
662701
private def dialog_range(dialog, dialog_y)
663702
x_range = dialog.column...dialog.column + dialog.width
664703
y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
@@ -687,24 +726,8 @@ def add_dialog_proc(name, p, context = nil)
687726
return if old_dialog_ranges.empty? && new_dialog_ranges.empty?
688727
ranges_to_restore = {}
689728
old_dialog_ranges.each do |y, old_x_ranges|
690-
new_dialog_ranges[y]&.each do |new_x_range|
691-
ranges = []
692-
old_x_ranges.each do |old_x_range|
693-
next if new_x_range.cover? old_x_range
694-
if new_x_range.end <= old_x_range.begin || old_x_range.end <= new_x_range.begin
695-
ranges << old_x_range
696-
elsif new_x_range.begin <= old_x_range.begin
697-
ranges << (new_x_range.end...old_x_range.end)
698-
elsif old_x_range.end <= new_x_range.end
699-
ranges << (old_x_range.begin...new_x_range.begin)
700-
else
701-
ranges << (old_x_range.begin...new_x_range.begin)
702-
ranges << (new_x_range.end...old_x_range.end)
703-
end
704-
end
705-
old_x_ranges = ranges
706-
end
707-
(ranges_to_restore[y] ||= []).push(*old_x_ranges) unless old_x_ranges.empty?
729+
ranges = range_subtract(old_x_ranges, new_dialog_ranges[y] || [])
730+
ranges_to_restore[y] = ranges if ranges.any?
708731
end
709732

710733
if ranges_to_restore.any?

test/reline/test_line_editor.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require_relative 'helper'
2+
require 'reline/line_editor'
3+
4+
class Reline::LineEditor::Test < Reline::TestCase
5+
def test_range_subtract
6+
dummy_config = nil
7+
editor = Reline::LineEditor.new(dummy_config, 'ascii-8bit')
8+
base_ranges = [3...5, 4...10, 6...8, 12...15, 15...20]
9+
subtract_ranges = [5...7, 8...9, 11...13, 17...18, 18...19]
10+
expected_result = [3...5, 7...8, 9...10, 13...17, 19...20]
11+
assert_equal expected_result, editor.send(:range_subtract, base_ranges, subtract_ranges)
12+
end
13+
end

0 commit comments

Comments
 (0)