summaryrefslogtreecommitdiff
path: root/lib/gitlab/diff/lines_unfolder.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/diff/lines_unfolder.rb')
-rw-r--r--lib/gitlab/diff/lines_unfolder.rb235
1 files changed, 0 insertions, 235 deletions
diff --git a/lib/gitlab/diff/lines_unfolder.rb b/lib/gitlab/diff/lines_unfolder.rb
deleted file mode 100644
index 9306b7e16a2..00000000000
--- a/lib/gitlab/diff/lines_unfolder.rb
+++ /dev/null
@@ -1,235 +0,0 @@
-# frozen_string_literal: true
-
-# Given a position, calculates which Blob lines should be extracted, treated and
-# injected in the current diff file lines in order to present a "unfolded" diff.
-module Gitlab
- module Diff
- class LinesUnfolder
- include Gitlab::Utils::StrongMemoize
-
- UNFOLD_CONTEXT_SIZE = 3
-
- def initialize(diff_file, position)
- @diff_file = diff_file
- @blob = diff_file.old_blob
- @position = position
- @generate_top_match_line = true
- @generate_bottom_match_line = true
-
- # These methods update `@generate_top_match_line` and
- # `@generate_bottom_match_line`.
- @from_blob_line = calculate_from_blob_line!
- @to_blob_line = calculate_to_blob_line!
- end
-
- # Returns merged diff lines with required blob lines with correct
- # positions.
- def unfolded_diff_lines
- strong_memoize(:unfolded_diff_lines) do
- next unless unfold_required?
-
- merged_diff_with_blob_lines
- end
- end
-
- # Returns the extracted lines from the old blob which should be merged
- # with the current diff lines.
- def blob_lines
- strong_memoize(:blob_lines) do
- # Blob lines, unlike diffs, doesn't start with an empty space for
- # unchanged line, so the parsing and highlighting step can get fuzzy
- # without the following change.
- line_prefix = ' '
- blob_as_diff_lines = @blob.data.each_line.map { |line| "#{line_prefix}#{line}" }
-
- lines = Gitlab::Diff::Parser.new.parse(blob_as_diff_lines, diff_file: @diff_file).to_a
-
- from = from_blob_line - 1
- to = to_blob_line - 1
-
- lines[from..to]
- end
- end
-
- def unfold_required?
- strong_memoize(:unfold_required) do
- next false unless @diff_file.text?
- next false unless @position.unchanged?
- next false if @diff_file.new_file? || @diff_file.deleted_file?
- next false unless @position.old_line
- # Invalid position (MR import scenario)
- next false if @position.old_line > @blob.lines.size
- next false if @diff_file.diff_lines.empty?
- next false if @diff_file.line_for_position(@position)
- next false unless unfold_line
-
- true
- end
- end
-
- private
-
- attr_reader :from_blob_line, :to_blob_line
-
- def merged_diff_with_blob_lines
- lines = @diff_file.diff_lines
- match_line = unfold_line
- insert_index = bottom? ? -1 : match_line.index
-
- lines -= [match_line] unless bottom?
-
- lines.insert(insert_index, *blob_lines_with_matches)
-
- # The inserted blob lines have invalid indexes, so we need
- # to reindex them.
- reindex(lines)
-
- lines
- end
-
- # Returns 'unchanged' blob lines with recalculated `old_pos` and
- # `new_pos` and the recalculated new match line (needed if we for instance
- # we unfolded once, but there are still folded lines).
- def blob_lines_with_matches
- old_pos = from_blob_line
- new_pos = from_blob_line + offset
-
- new_blob_lines = []
-
- new_blob_lines.push(top_blob_match_line) if top_blob_match_line
-
- blob_lines.each do |line|
- new_blob_lines << Gitlab::Diff::Line.new(line.text, line.type, nil, old_pos, new_pos,
- parent_file: @diff_file)
-
- old_pos += 1
- new_pos += 1
- end
-
- new_blob_lines.push(bottom_blob_match_line) if bottom_blob_match_line
-
- new_blob_lines
- end
-
- def reindex(lines)
- lines.each_with_index { |line, i| line.index = i }
- end
-
- def top_blob_match_line
- strong_memoize(:top_blob_match_line) do
- next unless @generate_top_match_line
-
- old_pos = from_blob_line
- new_pos = from_blob_line + offset
-
- build_match_line(old_pos, new_pos)
- end
- end
-
- def bottom_blob_match_line
- strong_memoize(:bottom_blob_match_line) do
- # The bottom line match addition is already handled on
- # Diff::File#diff_lines_for_serializer
- next if bottom?
- next unless @generate_bottom_match_line
-
- position = line_after_unfold_position.old_pos
-
- old_pos = position
- new_pos = position + offset
-
- build_match_line(old_pos, new_pos)
- end
- end
-
- def build_match_line(old_pos, new_pos)
- blob_lines_length = blob_lines.length
- old_line_ref = [old_pos, blob_lines_length].join(',')
- new_line_ref = [new_pos, blob_lines_length].join(',')
- new_match_line_str = "@@ -#{old_line_ref}+#{new_line_ref} @@"
-
- Gitlab::Diff::Line.new(new_match_line_str, 'match', nil, old_pos, new_pos)
- end
-
- # Returns the first line position that should be extracted
- # from `blob_lines`.
- def calculate_from_blob_line!
- return unless unfold_required?
-
- from = comment_position - UNFOLD_CONTEXT_SIZE
-
- # There's no line before the match if it's in the top-most
- # position.
- prev_line_number = line_before_unfold_position&.old_pos || 0
-
- if from <= prev_line_number + 1
- @generate_top_match_line = false
- from = prev_line_number + 1
- end
-
- from
- end
-
- # Returns the last line position that should be extracted
- # from `blob_lines`.
- def calculate_to_blob_line!
- return unless unfold_required?
-
- to = comment_position + UNFOLD_CONTEXT_SIZE
-
- return to if bottom?
-
- next_line_number = line_after_unfold_position.old_pos
-
- if to >= next_line_number - 1
- @generate_bottom_match_line = false
- to = next_line_number - 1
- end
-
- to
- end
-
- def offset
- unfold_line.new_pos - unfold_line.old_pos
- end
-
- def line_before_unfold_position
- return unless index = unfold_line&.index
-
- @diff_file.diff_lines[index - 1] if index > 0
- end
-
- def line_after_unfold_position
- return unless index = unfold_line&.index
-
- @diff_file.diff_lines[index + 1] if index >= 0
- end
-
- def bottom?
- strong_memoize(:bottom) do
- @position.old_line > last_line.old_pos
- end
- end
-
- # Returns the line which needed to be expanded in order to send a comment
- # in `@position`.
- def unfold_line
- strong_memoize(:unfold_line) do
- next last_line if bottom?
-
- @diff_file.diff_lines.find do |line|
- line.old_pos > comment_position && line.type == 'match'
- end
- end
- end
-
- def comment_position
- @position.old_line
- end
-
- def last_line
- @diff_file.diff_lines.last
- end
- end
- end
-end