From 65c5fcffcca81fbadb7603b8bc37a3d6746a0413 Mon Sep 17 00:00:00 2001 From: Joe Stein Date: Fri, 13 Feb 2026 16:04:29 -0600 Subject: [PATCH 1/4] Remove unused Pane#{padded,capped_to} At some point in the development of diff elision, it looks like dirty panes might have been padded to preserve context. However, the implementation that was eventually introduced in d18bd142197516fb267f2b8efb8581153e9741c0 ended up essentially cloning the original pane with no padding. This makes #padded, and subsequently #capped_to, unnecessary. --- lib/super_diff/core/tiered_lines_elider.rb | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/lib/super_diff/core/tiered_lines_elider.rb b/lib/super_diff/core/tiered_lines_elider.rb index 148ac6be..1770494a 100644 --- a/lib/super_diff/core/tiered_lines_elider.rb +++ b/lib/super_diff/core/tiered_lines_elider.rb @@ -46,11 +46,7 @@ def panes def padded_dirty_panes @padded_dirty_panes ||= - combine_congruent_panes( - dirty_panes - .map(&:padded) - .map { |pane| pane.capped_to(0, lines.size - 1) } - ) + combine_congruent_panes(dirty_panes) end def dirty_panes @@ -347,19 +343,6 @@ class Pane def extended_to(new_end) self.class.new(type: type, range: range.begin..new_end) end - - def padded - self.class.new(type: type, range: Range.new(range.begin, range.end)) - end - - def capped_to(beginning, ending) - new_beginning = [range.begin, beginning].max - new_ending = [range.end, ending].min - self.class.new( - type: type, - range: Range.new(new_beginning, new_ending) - ) - end end class BuildBoxes From 8afaade08ec0ffa18bbc82ca142d6947e7f3551a Mon Sep 17 00:00:00 2001 From: Joe Stein Date: Fri, 13 Feb 2026 16:10:04 -0600 Subject: [PATCH 2/4] Remove TieredLinesElider#padded_dirty_panes By construction, `dirty_panes` never returns contiguous dirty panes. Since the panes were never really padded, those panes remained untouched until passed into `#combine_congruent_panes`, so that method was essentially a no-op. Removing that method subsequently obviated the need for `#padded_dirty_panes` entirely. --- lib/super_diff/core/tiered_lines_elider.rb | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/super_diff/core/tiered_lines_elider.rb b/lib/super_diff/core/tiered_lines_elider.rb index 1770494a..2738d0c9 100644 --- a/lib/super_diff/core/tiered_lines_elider.rb +++ b/lib/super_diff/core/tiered_lines_elider.rb @@ -41,12 +41,7 @@ def panes_to_consider_for_eliding def panes @panes ||= - BuildPanes.call(dirty_panes: padded_dirty_panes, lines: lines) - end - - def padded_dirty_panes - @padded_dirty_panes ||= - combine_congruent_panes(dirty_panes) + BuildPanes.call(dirty_panes: dirty_panes, lines: lines) end def dirty_panes @@ -174,10 +169,6 @@ def combine_congruent_boxes(boxes) combine(boxes, on: :indentation_level) end - def combine_congruent_panes(panes) - combine(panes, on: :type) - end - def combine(spannables, on:) criterion = on spannables.reduce([]) do |combined_spannables, spannable| From fcdb6c9094f23205e8db42b28e5cd2e3dbf2d009 Mon Sep 17 00:00:00 2001 From: Joe Stein Date: Fri, 13 Feb 2026 16:18:06 -0600 Subject: [PATCH 3/4] Improve #filter_out_boxes_fully_contained_in_others `sorted_boxes` was first sorted, then used in an `#any?` check. In worst-case time complexity, this is just as (in)efficient as checking against the unsorted boxes. We can do better by sorting boxes by beginning ascending and ending descending. Algorithm explanation in comments. --- lib/super_diff/core/tiered_lines_elider.rb | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/super_diff/core/tiered_lines_elider.rb b/lib/super_diff/core/tiered_lines_elider.rb index 2738d0c9..cdb12c66 100644 --- a/lib/super_diff/core/tiered_lines_elider.rb +++ b/lib/super_diff/core/tiered_lines_elider.rb @@ -153,15 +153,22 @@ def box_groups_at_decreasing_indentation_levels_within(pane) end def filter_out_boxes_fully_contained_in_others(boxes) - sorted_boxes = - boxes.sort_by do |box| - [box.indentation_level, box.range.begin, box.range.end] - end - - boxes.reject do |box2| - sorted_boxes.any? do |box1| - !box1.equal?(box2) && box1.fully_contains?(box2) - end + # First, sorts boxes by beginning ascending, range descending. (Boxes may + # never share beginnings, so the latter may be useless, but this is at least + # sufficient if unnecessary.) + # + # Then, iterate through each box, keeping track of the farthest "end" of any + # box seen so far. If the current box we are on ends before (or on) that farthest + # end, we know there is some box earlier in the sequence that begins <= this one + # (because of the prior sorting), and ends >= this one; that is, the current box + # is fully contained, and we can filter it out. + sorted = boxes.sort_by { |box| [box.range.begin, -box.range.end] } + max_end = -1 + + sorted.reject do |box| + contained = box.range.end <= max_end + max_end = box.range.end if box.range.end > max_end + contained end end From 0af0fa4a8678e677dfb7b98dda60fd5d0f7a2798 Mon Sep 17 00:00:00 2001 From: Joe Stein Date: Fri, 13 Feb 2026 16:42:59 -0600 Subject: [PATCH 4/4] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54626310..537596fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Add max major version constraints to dependencies. [#296](https://github.com/splitwise/super_diff/pull/296) - Remove unused `syntax_tree` gems from development. [#297](https://github.com/splitwise/super_diff/pull/297) +- Simplify tiered lines elider. [#302](https://github.com/splitwise/super_diff/pull/302) ## 0.18.0 - 2025-12-05