diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index bc4b6ec0327f3d7da56df725173a89789f883b08..0b00b9a07027e3c1fa1c553cb152d7b208f682ca 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!(' ', ' ')
-    text
-  end
 end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index bf18673972c00192b574afbd4d61a30c16eecaa7..1230002e69c51acf63d877d14385bc63136023c5 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 24134310fc5d084b4cfa15f1e1c6009b9c51f476..2ff8c65e5cab6d983d26cdb0fa35b163f5f317ec 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 c6a9d71e78929164beadf040663d002d6755931f..4ded4d2daad4a52dd0ac7ca64be45019f2f27c57 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 78c66a6291ece1c5bfddf22c96ac9e4852add8cf..641e9e5501af74210a7c5c6049b3d7534cd97604 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 79061cd014181d0375b622431ae41c5379f493c6..ff8765b8e269be09d138526a2002ad28676f37c2 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 0000000000000000000000000000000000000000..f10b55eb00b6639782f0de99a4d02a9e528a488e
--- /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 0072194606e69b5c9da9f086c80bd7fa2a630e16..c48c69fb3444938fcfe86591d1cb06c0dbcc77cb 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 c7aaeb9260820a37ca81f96fce7efa7bb89399d1..d91dd6c424513c1899088603d367fe9a1ad3f042 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 74edef3a2b41feb68a8960bba64d7ebc18b11c3b..b8bba36439aecd580b94471d884e7b5e412094bd 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