Add syntax highlighting to diff view. #3945
This commit is contained in:
parent
3a227b5abb
commit
34657b821a
|
@ -326,4 +326,10 @@ module ApplicationHelper
|
||||||
def truncate_first_line(message, length = 50)
|
def truncate_first_line(message, length = 50)
|
||||||
truncate(message.each_line.first.chomp, length: length) if message
|
truncate(message.each_line.first.chomp, length: length) if message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unescape_html(content)
|
||||||
|
text = CGI.unescapeHTML(content)
|
||||||
|
text.gsub!(' ', ' ')
|
||||||
|
text
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
module BlobHelper
|
module BlobHelper
|
||||||
def highlight(blob_name, blob_content, nowrap: false, continue: false)
|
def rouge_formatter(options = {})
|
||||||
@formatter ||= Rouge::Formatters::HTMLGitlab.new(
|
default_options = {
|
||||||
nowrap: nowrap,
|
nowrap: false,
|
||||||
cssclass: 'code highlight',
|
cssclass: 'code highlight',
|
||||||
lineanchors: true,
|
lineanchors: true,
|
||||||
lineanchorsid: 'LC'
|
lineanchorsid: 'LC'
|
||||||
)
|
}
|
||||||
|
|
||||||
|
Rouge::Formatters::HTMLGitlab.new(default_options.merge!(options))
|
||||||
|
end
|
||||||
|
|
||||||
|
def highlight(blob_name, blob_content, nowrap: false, continue: false)
|
||||||
|
@formatter ||= rouge_formatter(nowrap: nowrap)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
@lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
|
@lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
|
||||||
|
@ -18,6 +24,21 @@ module BlobHelper
|
||||||
result
|
result
|
||||||
end
|
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
|
def no_highlight_files
|
||||||
%w(credits changelog news copying copyright license authors)
|
%w(credits changelog news copying copyright license authors)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/ Side-by-side diff view
|
/ Side-by-side diff view
|
||||||
%div.text-file.diff-wrap-lines
|
%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight{ class: user_color_scheme }
|
||||||
%table
|
%table
|
||||||
- parallel_diff(diff_file, index).each do |line|
|
- parallel_diff(diff_file, index).each do |line|
|
||||||
- type_left = line[0]
|
- type_left = line[0]
|
||||||
|
@ -20,7 +20,8 @@
|
||||||
= link_to raw(line_number_left), "##{line_code_left}", id: line_code_left
|
= link_to raw(line_number_left), "##{line_code_left}", id: line_code_left
|
||||||
- if @comments_allowed && can?(current_user, :create_note, @project)
|
- if @comments_allowed && can?(current_user, :create_note, @project)
|
||||||
= link_to_new_diff_note(line_code_left, 'old')
|
= 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 }= raw line_content_left
|
%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))
|
||||||
|
|
||||||
- if type_right == 'new'
|
- if type_right == 'new'
|
||||||
- new_line_class = 'new'
|
- new_line_class = 'new'
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
= link_to raw(line_number_right), "##{new_line_code}", id: new_line_code
|
= link_to raw(line_number_right), "##{new_line_code}", id: new_line_code
|
||||||
- if @comments_allowed && can?(current_user, :create_note, @project)
|
- if @comments_allowed && can?(current_user, :create_note, @project)
|
||||||
= link_to_new_diff_note(line_code_right, 'new')
|
= 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}= raw line_content_right
|
%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))
|
||||||
|
|
||||||
- if @reply_allowed
|
- if @reply_allowed
|
||||||
- comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right)
|
- comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right)
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
.suppressed-container
|
.suppressed-container
|
||||||
%a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
|
%a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
|
||||||
|
|
||||||
%table.text-file{class: "#{'hide' if too_big}"}
|
%table.text-file.code.js-syntax-highlight{ class: [user_color_scheme, too_big ? 'hide' : ''] }
|
||||||
|
|
||||||
- last_line = 0
|
- last_line = 0
|
||||||
- diff_file.diff_lines.each_with_index do |line, index|
|
- diff_file.diff_lines.each_with_index do |line, index|
|
||||||
- type = line.type
|
- type = line.type
|
||||||
|
@ -21,7 +22,8 @@
|
||||||
= link_to_new_diff_note(line_code)
|
= link_to_new_diff_note(line_code)
|
||||||
%td.new_line{data: {linenumber: line.new_pos}}
|
%td.new_line{data: {linenumber: line.new_pos}}
|
||||||
= link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code
|
= link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code
|
||||||
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
|
%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)))
|
||||||
|
|
||||||
- if @reply_allowed
|
- if @reply_allowed
|
||||||
- comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at)
|
- comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at)
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
Rouge::Token::Tokens.token(:InlineDiff, 'idiff')
|
||||||
|
|
||||||
|
module Rouge
|
||||||
|
module Lexers
|
||||||
|
class GitlabDiff < RegexLexer
|
||||||
|
title "GitLab Diff"
|
||||||
|
tag 'gitlab_diff'
|
||||||
|
|
||||||
|
state :root do
|
||||||
|
rule %r{<span class='idiff'>(.*?)</span>} do |match|
|
||||||
|
token InlineDiff, match[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
rule /(?:(?!<span).)*/ do
|
||||||
|
delegate option(:parent_lexer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -64,4 +64,15 @@ describe BlobHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'highlight_line' do
|
||||||
|
let(:expected) do
|
||||||
|
%q(<span id="LC1" class="line"><span class="nb">puts</span> <span class="s1">'Hello'</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
|
end
|
||||||
|
|
Loading…
Reference in New Issue