class SuperDiff::TieredLinesElider

Constants

SIZE_OF_ELISION

Public Instance Methods

call() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 10
def call
  if all_lines_are_changed_or_unchanged?
    lines
  else
    elided_lines
  end
end

Private Instance Methods

all_indentation_levels() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 108
def all_indentation_levels
  lines.
    map(&:indentation_level).
    select { |indentation_level| indentation_level > 0 }.
    uniq
end
all_lines_are_changed_or_unchanged?() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 20
def all_lines_are_changed_or_unchanged?
  panes.size == 1 && panes.first.range == Range.new(0, lines.length - 1)
end
box_groups_at_decreasing_indentation_levels_within(pane) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 145
def box_groups_at_decreasing_indentation_levels_within(pane)
  boxes_within_pane = boxes.select do |box|
    box.fits_fully_within?(pane)
  end

  possible_indentation_levels = boxes_within_pane.
    map(&:indentation_level).
    select { |indentation_level| indentation_level > 0 }.
    uniq.
    sort.
    reverse

  possible_indentation_levels.map do |indentation_level|
    boxes_within_pane.select do |box|
      box.indentation_level >= indentation_level
    end
  end
end
boxes() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 202
def boxes
  @_boxes ||= BuildBoxes.call(lines)
end
boxes_to_elide() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 30
def boxes_to_elide
  @_boxes_to_elide ||=
    panes_to_consider_for_eliding.reduce([]) do |array, pane|
      array + (find_boxes_to_elide_within(pane) || [])
    end
end
combine(spannables, on:) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 184
def combine(spannables, on:)
  criterion = on
  spannables.reduce([]) do |combined_spannables, spannable|
    if (
      !combined_spannables.empty? &&
      spannable.range.begin <= combined_spannables.last.range.end + 1 &&
      spannable.public_send(criterion) ==
        combined_spannables.last.public_send(criterion)
    )
      combined_spannables[0..-2] + [
        combined_spannables[-1].extended_to(spannable.range.end),
      ]
    else
      combined_spannables + [spannable]
    end
  end
end
combine_congruent_boxes(boxes) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 176
def combine_congruent_boxes(boxes)
  combine(boxes, on: :indentation_level)
end
combine_congruent_panes(panes) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 180
def combine_congruent_panes(panes)
  combine(panes, on: :type)
end
dirty_panes() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 55
def dirty_panes
  @_dirty_panes ||= lines.
    each_with_index.
    select { |line, index| line.type != :noop }.
    reduce([]) do |panes, (_, index)|
      if !panes.empty? && panes.last.range.end == index - 1
        panes[0..-2] + [panes[-1].extended_to(index)]
      else
        panes + [Pane.new(type: :dirty, range: index..index)]
      end
    end
end
elided_lines() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 24
def elided_lines
  boxes_to_elide.reverse.reduce(lines) do |lines_with_elisions, box|
    with_box_elided(box, lines_with_elisions)
  end
end
filter_out_boxes_fully_contained_in_others(boxes) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 164
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
  end
end
find_boxes_to_elide_within(pane) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 115
def find_boxes_to_elide_within(pane)
  set_of_boxes =
    normalized_box_groups_at_decreasing_indentation_levels_within(pane)

  total_size_before_eliding = lines[pane.range].
    reject(&:complete_bookend?).
    size

  if total_size_before_eliding > maximum
    if maximum > 0
      set_of_boxes.find do |boxes|
        total_size_after_eliding =
          total_size_before_eliding -
          boxes.sum { |box| box.range.size - SIZE_OF_ELISION }
        total_size_after_eliding <= maximum
      end
    else
      set_of_boxes[-1]
    end
  else
    []
  end
end
maximum() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 278
def maximum
  SuperDiff.configuration.diff_elision_maximum || 0
end
normalized_box_groups_at_decreasing_indentation_levels_within(pane) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 139
def normalized_box_groups_at_decreasing_indentation_levels_within(pane)
  box_groups_at_decreasing_indentation_levels_within(pane).
    map(&method(:filter_out_boxes_fully_contained_in_others)).
    map(&method(:combine_congruent_boxes))
end
one_dimensional_line_tree?() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 104
def one_dimensional_line_tree?
  all_indentation_levels.size == 1
end
outermost_box?(box) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 100
def outermost_box?(box)
  box.indentation_level == all_indentation_levels.min
end
padded_dirty_panes() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 47
def padded_dirty_panes
  @_padded_dirty_panes ||= combine_congruent_panes(
    dirty_panes.
    map(&:padded).
    map { |pane| pane.capped_to(0, lines.size - 1) }
  )
end
panes() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 43
def panes
  @_panes ||= BuildPanes.call(dirty_panes: padded_dirty_panes, lines: lines)
end
panes_to_consider_for_eliding() click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 37
def panes_to_consider_for_eliding
  panes.select do |pane|
    pane.type == :clean && pane.range.size > maximum
  end
end
with_box_elided(box, lines) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 68
def with_box_elided(box, lines)
  box_at_start_of_lines =
    if lines.first.complete_bookend?
      box.range.begin == 1
    else
      box.range.begin == 0
    end

  box_at_end_of_lines =
    if lines.last.complete_bookend?
      box.range.end == lines.size - 2
    else
      box.range.end == lines.size - 1
    end

  if one_dimensional_line_tree? && outermost_box?(box)
    if box_at_start_of_lines
      with_start_of_box_elided(box, lines)
    elsif box_at_end_of_lines
      with_end_of_box_elided(box, lines)
    else
      with_middle_of_box_elided(box, lines)
    end
  else
    with_subset_of_lines_elided(
      lines,
      range: box.range,
      indentation_level: box.indentation_level,
    )
  end
end
with_end_of_box_elided(box, lines) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 224
def with_end_of_box_elided(box, lines)
  amount_to_elide =
    if maximum > 0
      box.range.size - maximum + SIZE_OF_ELISION
    else
      box.range.size
    end

  range =
    if amount_to_elide > 0
      Range.new(box.range.end - amount_to_elide + 1, box.range.end)
    else
      box.range
    end

  with_subset_of_lines_elided(
    lines,
    range: range,
    indentation_level: box.indentation_level
  )
end
with_middle_of_box_elided(box, lines) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 246
def with_middle_of_box_elided(box, lines)
  half_of_maximum, remainder =
    if maximum > 0
      (maximum - SIZE_OF_ELISION).divmod(2)
    else
      [0, 0]
    end

  opening_length, closing_length =
    half_of_maximum, half_of_maximum + remainder

  with_subset_of_lines_elided(
    lines,
    range: Range.new(
      box.range.begin + opening_length,
      box.range.end - closing_length,
    ),
    indentation_level: box.indentation_level
  )
end
with_start_of_box_elided(box, lines) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 206
def with_start_of_box_elided(box, lines)
  amount_to_elide =
    if maximum > 0
      box.range.size - maximum + SIZE_OF_ELISION
    else
      box.range.size
    end

  with_subset_of_lines_elided(
    lines,
    range: Range.new(
      box.range.begin,
      box.range.begin + amount_to_elide - 1,
    ),
    indentation_level: box.indentation_level
  )
end
with_subset_of_lines_elided(lines, range:, indentation_level:) click to toggle source
# File lib/super_diff/tiered_lines_elider.rb, line 267
def with_subset_of_lines_elided(lines, range:, indentation_level:)
  with_slice_of_array_replaced(
    lines,
    range,
    Elision.new(
      indentation_level: indentation_level,
      children: lines[range].map(&:as_elided),
    ),
  )
end