summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRubén Dávila <rdavila84@gmail.com>2015-12-30 00:52:50 -0500
committerRubén Dávila <rdavila84@gmail.com>2015-12-30 00:52:50 -0500
commitbb96d631537d3d8181f0d3b762603a012219c3e6 (patch)
tree3520e34f8f99dd1a3a401ee83d1cb067cd9e3e66
parentc031b9d9cd1ea41ab68f46eb5e630efaf901933a (diff)
downloadgitlab-ce-bb96d631537d3d8181f0d3b762603a012219c3e6.tar.gz
New implementation for highlighting diff files. #3945
* It is more performant given now we process all the diff file instead of processing line by line. * Multiline comments are highlighted correctly.
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/helpers/blob_helper.rb15
-rw-r--r--app/helpers/diff_helper.rb6
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml6
-rw-r--r--app/views/projects/diffs/_text_file.html.haml5
-rw-r--r--lib/gitlab/diff/file.rb4
-rw-r--r--lib/gitlab/diff/highlight.rb55
-rw-r--r--lib/gitlab/diff/line.rb1
-rw-r--r--lib/rouge/lexers/gitlab_diff.rb2
-rw-r--r--spec/helpers/blob_helper_spec.rb11
10 files changed, 68 insertions, 43 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index bc4b6ec0327..0b00b9a0702 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -326,10 +326,4 @@ module ApplicationHelper
def truncate_first_line(message, length = 50)
truncate(message.each_line.first.chomp, length: length) if message
end
-
- def unescape_html(content)
- text = CGI.unescapeHTML(content)
- text.gsub!('&nbsp;', ' ')
- text
- end
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index bf18673972c..1230002e69c 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -24,21 +24,6 @@ module BlobHelper
result
end
- def highlight_line(blob_name, content, continue: false)
- if @previous_blob_name != blob_name
- @parent = Rouge::Lexer.guess(filename: blob_name, source: content).new rescue Rouge::Lexers::PlainText.new
- @lexer = Rouge::Lexers::GitlabDiff.new(parent_lexer: @parent)
- @options = Rouge::Lexers::PlainText === @parent ? {} : { continue: continue }
- end
-
- @previous_blob_name = blob_name
- @formatter ||= rouge_formatter(nowrap: true)
-
- content.sub!(/\A((?:\+|-)\s*)/, '') # Don't format '+' or '-' indicators.
-
- "#{$1}#{@formatter.format(@lexer.lex(content, @options))}".html_safe
- end
-
def no_highlight_files
%w(credits changelog news copying copyright license authors)
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 24134310fc5..2ff8c65e5ca 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -54,9 +54,9 @@ module DiffHelper
# right_line_type, right_line_number, right_line_content, right_line_code
# ]
#
- diff_file.diff_lines.each do |line|
+ diff_file.highlighted_diff_lines.each do |line|
- full_line = line.text
+ full_line = line.highlighted_text
type = line.type
line_code = generate_line_code(diff_file.file_path, line)
line_new = line.new_pos
@@ -67,7 +67,7 @@ module DiffHelper
if next_line
next_line_code = generate_line_code(diff_file.file_path, next_line)
next_type = next_line.type
- next_line = next_line.text
+ next_line = next_line.highlighted_text
end
if type == 'match' || type.nil?
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index c6a9d71e789..4ded4d2daad 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -20,8 +20,7 @@
= link_to raw(line_number_left), "##{line_code_left}", id: line_code_left
- if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code_left, 'old')
- %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }<
- = highlight_line(diff_file.new_path, unescape_html(line_content_left))
+ %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw(line_content_left)
- if type_right == 'new'
- new_line_class = 'new'
@@ -34,8 +33,7 @@
= link_to raw(line_number_right), "##{new_line_code}", id: new_line_code
- if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code_right, 'new')
- %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}<
- = highlight_line(diff_file.new_path, unescape_html(line_content_right))
+ %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw(line_content_right)
- if @reply_allowed
- comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right)
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index 78c66a6291e..641e9e5501a 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -6,7 +6,7 @@
%table.text-file.code.js-syntax-highlight{ class: [user_color_scheme, too_big ? 'hide' : ''] }
- last_line = 0
- - diff_file.diff_lines.each_with_index do |line, index|
+ - diff_file.highlighted_diff_lines.each_with_index do |line, index|
- type = line.type
- last_line = line.new_pos
- line_code = generate_line_code(diff_file.file_path, line)
@@ -22,8 +22,7 @@
= link_to_new_diff_note(line_code)
%td.new_line{data: {linenumber: line.new_pos}}
= link_to raw(type == "old" ? "&nbsp;" : line.new_pos) , "##{line_code}", id: line_code
- %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}<
- = highlight_line(diff_file.new_path, unescape_html(diff_line_content(line.text)))
+ %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw(diff_line_content(line.highlighted_text))
- if @reply_allowed
- comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at)
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 79061cd0141..ff8765b8e26 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -15,6 +15,10 @@ module Gitlab
@lines ||= parser.parse(raw_diff.lines)
end
+ def highlighted_diff_lines
+ Gitlab::Diff::Highlight.process_diff_lines(self)
+ end
+
def mode_changed?
!!(diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode)
end
diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb
new file mode 100644
index 00000000000..f10b55eb00b
--- /dev/null
+++ b/lib/gitlab/diff/highlight.rb
@@ -0,0 +1,55 @@
+module Gitlab
+ module Diff
+ class Highlight
+ def self.process_diff_lines(diff_file)
+ processor = new(diff_file)
+ processor.highlight
+ end
+
+ def initialize(diff_file)
+ text_lines = diff_file.diff_lines.map(&:text)
+ @diff_file = diff_file
+ @diff_lines = diff_file.diff_lines
+ @diff_line_prefixes = text_lines.map { |line| line.sub!(/\A((\+|\-)\s*)/, '');$1 }
+ @raw_lines = text_lines.join("\n")
+ end
+
+ def highlight
+ @code = unescape_html(@raw_lines)
+ @highlighted_code = formatter.format(lexer.lex(@code))
+
+ update_diff_lines
+ end
+
+ private
+
+ def update_diff_lines
+ @highlighted_code.lines.each_with_index do |line, i|
+ @diff_lines[i].highlighted_text = "#{@diff_line_prefixes[i]}#{line}"
+ end
+
+ @diff_lines
+ end
+
+ def lexer
+ parent = Rouge::Lexer.guess(filename: @diff_file.new_path, source: @code).new rescue Rouge::Lexers::PlainText.new
+ Rouge::Lexers::GitlabDiff.new(parent_lexer: parent)
+ end
+
+ def unescape_html(content)
+ text = CGI.unescapeHTML(content)
+ text.gsub!('&nbsp;', ' ')
+ text
+ end
+
+ def formatter
+ @formatter ||= Rouge::Formatters::HTMLGitlab.new(
+ nowrap: true,
+ cssclass: 'code highlight',
+ lineanchors: true,
+ lineanchorsid: 'LC'
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
index 0072194606e..c48c69fb344 100644
--- a/lib/gitlab/diff/line.rb
+++ b/lib/gitlab/diff/line.rb
@@ -2,6 +2,7 @@ module Gitlab
module Diff
class Line
attr_reader :type, :text, :index, :old_pos, :new_pos
+ attr_accessor :highlighted_text
def initialize(text, type, index, old_pos, new_pos)
@text, @type, @index = text, type, index
diff --git a/lib/rouge/lexers/gitlab_diff.rb b/lib/rouge/lexers/gitlab_diff.rb
index c7aaeb92608..d91dd6c4245 100644
--- a/lib/rouge/lexers/gitlab_diff.rb
+++ b/lib/rouge/lexers/gitlab_diff.rb
@@ -11,7 +11,7 @@ module Rouge
token InlineDiff, match[1]
end
- rule /(?:(?!<span).)*/ do
+ rule /(?:(?!<span class='idiff').)*/m do
delegate option(:parent_lexer)
end
end
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 74edef3a2b4..b8bba36439a 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -64,15 +64,4 @@ describe BlobHelper do
end
end
end
-
- describe 'highlight_line' do
- let(:expected) do
- %q(<span id="LC1" class="line"><span class="nb">puts</span> <span class="s1">&#39;Hello&#39;</span> <span class="idiff">world</span></span>)
- end
-
- it 'should respect the inline diff markup' do
- result = highlight_line('demo.rb', "puts 'Hello' <span class='idiff'>world</span>")
- expect(result).to eq(expected)
- end
- end
end