diff --git a/lib/super_diff/core/tiered_lines_elider.rb b/lib/super_diff/core/tiered_lines_elider.rb index 148ac6be..98e320bb 100644 --- a/lib/super_diff/core/tiered_lines_elider.rb +++ b/lib/super_diff/core/tiered_lines_elider.rb @@ -108,10 +108,8 @@ def one_dimensional_line_tree? end def all_indentation_levels - lines - .map(&:indentation_level) - .select(&:positive?) - .uniq + levels = lines.map(&:indentation_level).uniq + normalized_indentation_levels(levels) end def find_boxes_to_elide_within(pane) @@ -146,13 +144,10 @@ def normalized_box_groups_at_decreasing_indentation_levels_within(pane) def box_groups_at_decreasing_indentation_levels_within(pane) boxes_within_pane = boxes.select { |box| box.fits_fully_within?(pane) } + levels = boxes_within_pane.map(&:indentation_level).uniq + possible_indentation_levels = - boxes_within_pane - .map(&:indentation_level) - .select(&:positive?) - .uniq - .sort - .reverse + normalized_indentation_levels(levels).sort.reverse possible_indentation_levels.map do |indentation_level| boxes_within_pane.select do |box| @@ -174,6 +169,14 @@ def filter_out_boxes_fully_contained_in_others(boxes) end end + def normalized_indentation_levels(levels) + # For flat structures (strings), include level 0 + return levels if levels.all?(&:zero?) + + # For nested structures (arrays, hashes), exclude level 0 (brackets) + levels.select(&:positive?) + end + def combine_congruent_boxes(boxes) combine(boxes, on: :indentation_level) end diff --git a/spec/unit/core/tiered_lines_elider_spec.rb b/spec/unit/core/tiered_lines_elider_spec.rb index 87c369f0..f5da95e4 100644 --- a/spec/unit/core/tiered_lines_elider_spec.rb +++ b/spec/unit/core/tiered_lines_elider_spec.rb @@ -311,6 +311,94 @@ end context 'and the line tree contains non-noops in addition to noops' do + context 'and the line tree is flat (indentation level 0)' do + it 'elides the beginning of the noop so as to put it at the maximum' do + # Diff: + # + # "one" + # "two" + # "three" + # - "four" + # + "FOUR" + + lines = [ + an_actual_line( + type: :noop, + indentation_level: 0, + value: %("one") + ), + an_actual_line( + type: :noop, + indentation_level: 0, + value: %("two") + ), + an_actual_line( + type: :noop, + indentation_level: 0, + value: %("three") + ), + an_actual_line( + type: :delete, + indentation_level: 0, + value: %("four") + ), + an_actual_line( + type: :insert, + indentation_level: 0, + value: %("FOUR") + ) + ] + + line_tree_with_elisions = + with_configuration( + diff_elision_enabled: true, + diff_elision_maximum: 2 + ) { described_class.call(lines) } + + # Result: + # + # # ... + # "three" + # - "four" + # + "FOUR" + + expect(line_tree_with_elisions).to match( + [ + an_expected_elision( + indentation_level: 0, + children: [ + an_expected_line( + type: :noop, + indentation_level: 0, + value: %("one") + ), + an_expected_line( + type: :noop, + indentation_level: 0, + value: %("two") + ) + ] + ), + an_expected_line( + type: :noop, + indentation_level: 0, + value: %("three") + ), + an_expected_line( + type: :delete, + indentation_level: 0, + value: %("four") + ), + an_expected_line( + type: :insert, + indentation_level: 0, + value: %("FOUR") + ) + ] + ) + end + end + context 'and the only noops that exist are above the only non-noops that exist' do it 'elides the beginning of the noop so as to put it at the maximum' do # Diff: @@ -449,6 +537,7 @@ ] ) end + end context 'and the only noops that exist are below the only non-noops that exist' do