diff options
author | Oswaldo Ferreira <oswaldo@gitlab.com> | 2019-03-15 14:35:34 -0300 |
---|---|---|
committer | Oswaldo Ferreira <oswaldo@gitlab.com> | 2019-03-27 12:26:53 -0300 |
commit | 03e0604d5ded6402c7fddc4001ab23d9712c98de (patch) | |
tree | 33cf57e25d71e9a9c0ab39149cbcb285f0f05a31 /lib/gitlab/diff | |
parent | 1db3926dd2a5de719859ea962d4e1360b375d87b (diff) | |
download | gitlab-ce-03e0604d5ded6402c7fddc4001ab23d9712c98de.tar.gz |
Prepare suggestion implementation for multi-line
Adds the groundwork needed in order to persist multi-line suggestions,
while providing the parsing strategy which will be reused for the
**Preview** as well.
Diffstat (limited to 'lib/gitlab/diff')
-rw-r--r-- | lib/gitlab/diff/suggestion.rb | 52 | ||||
-rw-r--r-- | lib/gitlab/diff/suggestions_parser.rb | 41 |
2 files changed, 93 insertions, 0 deletions
diff --git a/lib/gitlab/diff/suggestion.rb b/lib/gitlab/diff/suggestion.rb new file mode 100644 index 00000000000..027c7a31bcf --- /dev/null +++ b/lib/gitlab/diff/suggestion.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Gitlab + module Diff + class Suggestion + include Suggestible + include Gitlab::Utils::StrongMemoize + + attr_reader :diff_file, :lines_above, :lines_below, + :target_line + + def initialize(text, line:, above:, below:, diff_file:) + @text = text + @target_line = line + @lines_above = above.to_i + @lines_below = below.to_i + @diff_file = diff_file + end + + def to_hash + { + from_content: from_content, + to_content: to_content, + lines_above: @lines_above, + lines_below: @lines_below + } + end + + def from_content + strong_memoize(:from_content) do + fetch_from_content + end + end + + def to_content + # The parsed suggestion doesn't have information about the correct + # ending characters (we may have a line break, or not), so we take + # this information from the last line being changed (last + # characters). + endline_chars = line_break_chars(from_content.lines.last) + "#{@text}#{endline_chars}" + end + + private + + def line_break_chars(line) + match = /\r\n|\r|\n/.match(line) + match[0] if match + end + end + end +end diff --git a/lib/gitlab/diff/suggestions_parser.rb b/lib/gitlab/diff/suggestions_parser.rb index 043bd9a4bcb..c8c03d5d001 100644 --- a/lib/gitlab/diff/suggestions_parser.rb +++ b/lib/gitlab/diff/suggestions_parser.rb @@ -5,6 +5,47 @@ module Gitlab class SuggestionsParser # Matches for instance "-1", "+1" or "-1+2". SUGGESTION_CONTEXT = /^(\-(?<above>\d+))?(\+(?<below>\d+))?$/.freeze + + class << self + # Returns an array of Gitlab::Diff::Suggestion which represents each + # suggestion in the given text. + # + def parse(text, position:, project:) + return [] unless position.complete? + + html = Banzai.render(text, project: nil, no_original_data: true) + doc = Nokogiri::HTML(html) + suggestion_nodes = doc.search('pre.suggestion') + + return [] if suggestion_nodes.empty? + + diff_file = position.diff_file(project.repository) + + suggestion_nodes.map do |node| + lang_param = node['data-lang-params'] + + lines_above, lines_below = nil + + if lang_param && suggestion_params = fetch_suggestion_params(lang_param) + lines_above, lines_below = + suggestion_params[:above], + suggestion_params[:below] + end + + Gitlab::Diff::Suggestion.new(node.text, + line: position.new_line, + above: lines_above.to_i, + below: lines_below.to_i, + diff_file: diff_file) + end + end + + private + + def fetch_suggestion_params(lang_param) + lang_param.match(SUGGESTION_CONTEXT) + end + end end end end |