Skip to content

Commit 060d503

Browse files
authored
Simplify tiered lines elider (#302)
While reviewing #300, I noticed some unrelated clean-up opportunities in `TieredLinesElider`. Most importantly, `Pane#padded` was essentially a no-op. This PR gets rid of it, and simplifies up the call stack through `TieredLinesElider#panes`. Less importantly, and more for my own satisfaction, `#filter_out_boxes_fully_contained_in_others` was $O(n^2)$; assuming sorting is sub-quadratic, it's also now sub-quadratic.
1 parent 2e6d280 commit 060d503

2 files changed

Lines changed: 18 additions & 36 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Add max major version constraints to dependencies. [#296](https://github.com/splitwise/super_diff/pull/296)
88
- Remove unused `syntax_tree` gems from development. [#297](https://github.com/splitwise/super_diff/pull/297)
9+
- Simplify tiered lines elider. [#302](https://github.com/splitwise/super_diff/pull/302)
910

1011
## 0.18.0 - 2025-12-05
1112

lib/super_diff/core/tiered_lines_elider.rb

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,7 @@ def panes_to_consider_for_eliding
4141

4242
def panes
4343
@panes ||=
44-
BuildPanes.call(dirty_panes: padded_dirty_panes, lines: lines)
45-
end
46-
47-
def padded_dirty_panes
48-
@padded_dirty_panes ||=
49-
combine_congruent_panes(
50-
dirty_panes
51-
.map(&:padded)
52-
.map { |pane| pane.capped_to(0, lines.size - 1) }
53-
)
44+
BuildPanes.call(dirty_panes: dirty_panes, lines: lines)
5445
end
5546

5647
def dirty_panes
@@ -162,26 +153,29 @@ def box_groups_at_decreasing_indentation_levels_within(pane)
162153
end
163154

164155
def filter_out_boxes_fully_contained_in_others(boxes)
165-
sorted_boxes =
166-
boxes.sort_by do |box|
167-
[box.indentation_level, box.range.begin, box.range.end]
168-
end
169-
170-
boxes.reject do |box2|
171-
sorted_boxes.any? do |box1|
172-
!box1.equal?(box2) && box1.fully_contains?(box2)
173-
end
156+
# First, sorts boxes by beginning ascending, range descending. (Boxes may
157+
# never share beginnings, so the latter may be useless, but this is at least
158+
# sufficient if unnecessary.)
159+
#
160+
# Then, iterate through each box, keeping track of the farthest "end" of any
161+
# box seen so far. If the current box we are on ends before (or on) that farthest
162+
# end, we know there is some box earlier in the sequence that begins <= this one
163+
# (because of the prior sorting), and ends >= this one; that is, the current box
164+
# is fully contained, and we can filter it out.
165+
sorted = boxes.sort_by { |box| [box.range.begin, -box.range.end] }
166+
max_end = -1
167+
168+
sorted.reject do |box|
169+
contained = box.range.end <= max_end
170+
max_end = box.range.end if box.range.end > max_end
171+
contained
174172
end
175173
end
176174

177175
def combine_congruent_boxes(boxes)
178176
combine(boxes, on: :indentation_level)
179177
end
180178

181-
def combine_congruent_panes(panes)
182-
combine(panes, on: :type)
183-
end
184-
185179
def combine(spannables, on:)
186180
criterion = on
187181
spannables.reduce([]) do |combined_spannables, spannable|
@@ -347,19 +341,6 @@ class Pane
347341
def extended_to(new_end)
348342
self.class.new(type: type, range: range.begin..new_end)
349343
end
350-
351-
def padded
352-
self.class.new(type: type, range: Range.new(range.begin, range.end))
353-
end
354-
355-
def capped_to(beginning, ending)
356-
new_beginning = [range.begin, beginning].max
357-
new_ending = [range.end, ending].min
358-
self.class.new(
359-
type: type,
360-
range: Range.new(new_beginning, new_ending)
361-
)
362-
end
363344
end
364345

365346
class BuildBoxes

0 commit comments

Comments
 (0)