diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-15 18:09:20 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-15 18:09:20 +0300 |
commit | 9440c17f554424cc77aff8afadc61adbe23524d1 (patch) | |
tree | bc2b4213d845e5fd6d43eb71d21cfce28c81e440 /lib/gitlab/diff | |
parent | 3e0c035fe3a10436be36b4e22a4986479821b8e4 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab/diff')
-rw-r--r-- | lib/gitlab/diff/rendered/notebook/diff_file.rb | 36 | ||||
-rw-r--r-- | lib/gitlab/diff/rendered/notebook/diff_file_helper.rb | 135 |
2 files changed, 94 insertions, 77 deletions
diff --git a/lib/gitlab/diff/rendered/notebook/diff_file.rb b/lib/gitlab/diff/rendered/notebook/diff_file.rb index 99631d90ce6..0795e0acebb 100644 --- a/lib/gitlab/diff/rendered/notebook/diff_file.rb +++ b/lib/gitlab/diff/rendered/notebook/diff_file.rb @@ -50,12 +50,14 @@ module Gitlab end def highlighted_diff_lines - @highlighted_diff_lines ||= begin - removal_line_maps, addition_line_maps = map_diff_block_to_source_line( - source_diff.highlighted_diff_lines, source_diff.new_file?, source_diff.deleted_file?) - Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight.map do |line| - mutate_line(line, addition_line_maps, removal_line_maps) - end + strong_memoize(:highlighted_diff_lines) do + lines = Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight + lines_in_source = lines_in_source_diff( + source_diff.highlighted_diff_lines, source_diff.deleted_file?, source_diff.new_file? + ) + + lines.zip(line_positions_at_source_diff(lines, transformed_blocks)) + .map { |line, positions| mutate_line(line, positions, lines_in_source)} end end @@ -91,6 +93,10 @@ module Gitlab diff end + def transformed_blocks + { from: notebook_diff.from.blocks, to: notebook_diff.to.blocks } + end + def rendered_timeout @rendered_timeout ||= Gitlab::Metrics.counter( :ipynb_semantic_diff_timeouts_total, @@ -108,21 +114,13 @@ module Gitlab nil end - def compute_line_numbers(transformed_old_pos, transformed_new_pos, addition_line_maps, removal_line_maps) - new_pos = map_transformed_line_to_source(transformed_new_pos, notebook_diff.to.blocks) - old_pos = map_transformed_line_to_source(transformed_old_pos, notebook_diff.from.blocks) - - old_pos = addition_line_maps[new_pos] if old_pos == 0 && new_pos != 0 - new_pos = removal_line_maps[old_pos] if new_pos == 0 && old_pos != 0 - - [old_pos, new_pos] - end - - def mutate_line(line, addition_line_maps, removal_line_maps) - line.old_pos, line.new_pos = compute_line_numbers(line.old_pos, line.new_pos, addition_line_maps, removal_line_maps) + def mutate_line(line, mapped_positions, source_diff_lines) + line.old_pos, line.new_pos = mapped_positions # Lines that do not appear on the original diff should not be commentable - line.type = "#{line.type || 'unchanged'}-nomappinginraw" unless addition_line_maps[line.new_pos] || removal_line_maps[line.old_pos] + unless source_diff_lines[:to].include?(line.new_pos) || source_diff_lines[:from].include?(line.old_pos) + line.type = "#{line.type || 'unchanged'}-nomappinginraw" + end line.line_code = line_code(line) diff --git a/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb b/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb index 822b3771276..2e1b5ea301d 100644 --- a/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb +++ b/lib/gitlab/diff/rendered/notebook/diff_file_helper.rb @@ -4,75 +4,94 @@ module Gitlab module Rendered module Notebook module DiffFileHelper + require 'set' + EMBEDDED_IMAGE_PATTERN = ' ![](data:image' def strip_diff_frontmatter(diff_content) diff_content.scan(/.*\n/)[2..]&.join('') if diff_content.present? end - def map_transformed_line_to_source(transformed_line, transformed_blocks) - transformed_blocks.empty? ? 0 : ( transformed_blocks[transformed_line - 1][:source_line] || -1 ) + 1 - end - - # line_codes are used for assigning notes to diffs, and these depend on the line on the new version and the - # line that would have been that one in the previous version. However, since we do a transformation on the - # file, that mapping gets lost. To overcome this, we look at the original source lines and build two maps: - # - For additions, we look at the latest line change for that line and pick the old line for that id - # - For removals, we look at the first line in the old version, and pick the first line on the new version - # - # Note: ipynb files never change the first or last line (open and closure of the - # json object), unless the file is removed or deleted - # - # Example: Additions and removals - # Old: New: - # A A - # B D - # C E - # F F + # line_positions_at_source_diff: given the transformed lines, + # what are the correct values for old_pos and new_pos? # - # Diff: - # 1 A A 1 | line code: 1_1 - # 2 -B | line code: 2_2 -> new line is what it is after been without the removal, 2 - # 3 -C | line code: 3_2 - # + D 2 | line code: 4_2 -> old line is what would have been before the addition, 4 - # + E 3 | line code: 4_3 - # 4 F F 4 | line code: 4_4 + # Example: # - # Example: only additions - # Old: New: - # A A - # F B - # C - # F + # Original + # from | to + # A | A + # B | D + # C | E + # F | F # - # Diff: - # A A | line code: 1_1 - # + B | line code: 2_2 -> old line is the next after the additions, 2 - # + C | line code: 2_3 - # F F | line code: 2_4 + # Original Diff + # A A + # - B + # - C + # + D + # + E + # F F # - # Example: only removals - # Old: New: - # A A - # B F - # C - # F + # Transformed + # from | to + # A | A + # C | D + # B | J + # L | E + # K | K + # F | F # - # Diff: - # A A | line code: 1_1 - # -B | line code: 2_2 -> new line is what it is after been without the removal, 2 - # -C | line code: 3_2 - # F F | line code: 4_2 - def map_diff_block_to_source_line(lines, file_added, file_deleted) - removals = {} - additions = {} - - lines.each do |line| - removals[line.old_pos] = line.new_pos unless file_added - additions[line.new_pos] = line.old_pos unless file_deleted - end - - [removals, additions] + # Transformed diff | transf old, new | OG old_pos, new_pos | + # A A | 1, 1 | 1, 1 | + # -C | 2, 2 | 3, 2 | + # -B | 3, 2 | 2, 2 | + # -L | 4, 2 | 0, 0 | + # + D | 5, 2 | 4, 2 | + # + J | 5, 3 | 0, 0 | + # + E | 5, 4 | 4, 3 | + # K K | 5, 5 | 0, 0 | + # F F | 6, 6 | 4, 4 | + def line_positions_at_source_diff(lines, blocks) + last_mapped_old_pos = 0 + last_mapped_new_pos = 0 + + lines.reverse_each.map do |line| + old_pos = source_line_from_block(line.old_pos, blocks[:from]) + new_pos = source_line_from_block(line.new_pos, blocks[:to]) + + old_has_no_mapping = old_pos == 0 + new_has_no_mapping = new_pos == 0 + + next [0, 0] if old_has_no_mapping && (new_has_no_mapping || line.type == 'old') + next [0, 0] if new_has_no_mapping && line.type == 'new' + + new_pos = last_mapped_new_pos if new_has_no_mapping && line.type == 'old' + old_pos = last_mapped_old_pos if old_has_no_mapping && line.type == 'new' + + last_mapped_old_pos = old_pos + last_mapped_new_pos = new_pos + + [old_pos, new_pos] + end.reverse + end + + def lines_in_source_diff(source_diff_lines, is_deleted_file, is_added_file) + { + from: is_added_file ? Set[] : source_diff_lines.map {|l| l.old_pos}.to_set, + to: is_deleted_file ? Set[] : source_diff_lines.map {|l| l.new_pos}.to_set + } + end + + def source_line_from_block(transformed_line, transformed_blocks) + # Blocks are the lines returned from the library and are a hash with {text:, source_line:} + # Blocks source_line are 0 indexed + return 0 if transformed_blocks.empty? + + line_in_source = transformed_blocks[transformed_line - 1][:source_line] + + return 0 unless line_in_source.present? + + line_in_source + 1 end def image_as_rich_text(line_text) |