mirror of
https://github.com/gitlabhq/gitlabhq.git
synced 2025-07-25 16:00:50 +00:00
138 lines
3.8 KiB
Ruby
138 lines
3.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module Diff
|
|
class ViewerHunk
|
|
attr_reader :header
|
|
attr_accessor :lines
|
|
|
|
def self.init_from_diff_lines(diff_lines)
|
|
return [] if diff_lines.empty?
|
|
|
|
hunks = []
|
|
current_hunk = nil
|
|
line_count = diff_lines.size
|
|
|
|
diff_lines.each_with_index do |line, index|
|
|
current_line = line
|
|
is_match = current_line.type == 'match'
|
|
|
|
if is_match || current_hunk.nil?
|
|
if is_match
|
|
previous_line_pos = hunks.last&.lines&.last&.old_pos
|
|
|
|
next_line = index < line_count - 1 ? diff_lines[index + 1] : nil
|
|
next_line_pos = next_line&.old_pos
|
|
|
|
current_hunk = new(
|
|
lines: [],
|
|
header: ViewerHunkHeader.new(current_line, previous_line_pos, next_line_pos)
|
|
)
|
|
else
|
|
current_hunk = new(lines: [line])
|
|
end
|
|
|
|
hunks << current_hunk
|
|
else
|
|
current_hunk.lines << line
|
|
end
|
|
end
|
|
|
|
hunks
|
|
end
|
|
|
|
def self.init_from_expanded_lines(diff_lines, bottom, closest_line_number)
|
|
return if diff_lines.empty?
|
|
|
|
match_lines, non_match_lines = diff_lines.partition { |line| line.type == 'match' }
|
|
return if non_match_lines.empty?
|
|
|
|
# this is different from init_from_diff_lines which uses old_pos to determine lines in between
|
|
# frontend always sends closest_line_number as new_pos since that is what is used by UnfoldPresenter#diff_lines
|
|
first_pos = non_match_lines.first.new_pos
|
|
last_pos = non_match_lines.last.new_pos
|
|
|
|
closest_line_number = 0 unless valid_closest_line_number?(bottom, closest_line_number, first_pos, last_pos)
|
|
|
|
header = if match_lines.first
|
|
start_line, end_line = bottom ? [last_pos, closest_line_number] : [closest_line_number, first_pos]
|
|
ViewerHunkHeader.new(match_lines.first, start_line, end_line)
|
|
end
|
|
|
|
create_viewer_hunks(non_match_lines, header, bottom)
|
|
end
|
|
|
|
def self.create_viewer_hunks(non_match_lines, header, bottom)
|
|
if bottom
|
|
[new(lines: non_match_lines), new(lines: nil, header: header)]
|
|
else
|
|
[new(lines: non_match_lines, header: header)]
|
|
end
|
|
end
|
|
private_class_method :create_viewer_hunks
|
|
|
|
def self.valid_closest_line_number?(bottom, closest_line_number, first_pos, last_pos)
|
|
return false if closest_line_number.nil? || closest_line_number < 0
|
|
|
|
closest_line_number == 0 || (
|
|
|
|
if bottom
|
|
last_pos < closest_line_number
|
|
else
|
|
closest_line_number < first_pos
|
|
end
|
|
|
|
)
|
|
end
|
|
private_class_method :valid_closest_line_number?
|
|
|
|
def initialize(lines: [], header: nil)
|
|
@lines = lines
|
|
@header = header
|
|
end
|
|
|
|
def parallel_lines
|
|
::Gitlab::Diff::ParallelDiff.parallelize(lines)
|
|
end
|
|
end
|
|
|
|
class ViewerHunkHeader
|
|
attr_reader :line
|
|
|
|
MAX_EXPANDABLE_LINES = 20
|
|
|
|
def initialize(line, previous_line_pos, next_line_pos)
|
|
@line = line
|
|
@previous_line_pos = previous_line_pos
|
|
@next_line_pos = next_line_pos
|
|
end
|
|
|
|
def text
|
|
@line.text
|
|
end
|
|
|
|
def expand_directions
|
|
return [:both] if (1..MAX_EXPANDABLE_LINES).cover?(line_count_between)
|
|
|
|
directions = []
|
|
directions << :up if @next_line_pos&.positive?
|
|
directions << :down if @previous_line_pos&.positive?
|
|
directions
|
|
end
|
|
|
|
private
|
|
|
|
def line_count_between
|
|
return 0 if invalid_pos?(@previous_line_pos) || invalid_pos?(@next_line_pos)
|
|
|
|
# 1..3 -> lines in between: 1
|
|
@next_line_pos - @previous_line_pos - 1
|
|
end
|
|
|
|
def invalid_pos?(pos)
|
|
pos.nil? || pos == 0
|
|
end
|
|
end
|
|
end
|
|
end
|