Commit 46631e10 authored by Patrick Bajao's avatar Patrick Bajao

Support selective highlighting of lines

Instead of highlighting all lines when not all of them are
needed, only highlight specific lines.

The `BlobPresenter#highlight` method has been updated to
support `since` and `to` params. These params will be used to
limit the content to be highlighted.

Modify `Gitlab::Highlight` to support `since` param which will
then be used to determine the starting line number.
parent fa216b0e
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
class BlobPresenter < Gitlab::View::Presenter::Delegated class BlobPresenter < Gitlab::View::Presenter::Delegated
presents :blob presents :blob
def highlight(plain: nil) def highlight(since: nil, to: nil, plain: nil)
load_all_blob_data load_all_blob_data
Gitlab::Highlight.highlight( Gitlab::Highlight.highlight(
blob.path, blob.path,
blob.data, limited_blob_data(since: since, to: to),
since: since,
language: blob.language_from_gitattributes, language: blob.language_from_gitattributes,
plain: plain plain: plain
) )
...@@ -23,4 +24,18 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated ...@@ -23,4 +24,18 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
def load_all_blob_data def load_all_blob_data
blob.load_all_data! if blob.respond_to?(:load_all_data!) blob.load_all_data! if blob.respond_to?(:load_all_data!)
end end
def limited_blob_data(since: nil, to: nil)
return blob.data if since.blank? || to.blank?
limited_blob_lines(since, to).join
end
def limited_blob_lines(since, to)
all_lines[since - 1..to - 1]
end
def all_lines
@all_lines ||= blob.data.lines
end
end end
...@@ -21,20 +21,19 @@ module Blobs ...@@ -21,20 +21,19 @@ module Blobs
load_all_blob_data load_all_blob_data
@subject = blob @subject = blob
@all_lines = blob.data.lines
super(params) super(params)
if full? if full?
self.attributes = { since: 1, to: @all_lines.size, bottom: false, unfold: false, offset: 0, indent: 0 } self.attributes = { since: 1, to: all_lines.size, bottom: false, unfold: false, offset: 0, indent: 0 }
end end
end end
# Returns an array of Gitlab::Diff::Line with match line added # Returns an array of Gitlab::Diff::Line with match line added
def diff_lines def diff_lines
diff_lines = lines.map.with_index do |line, index| diff_lines = limited_blob_lines(since, to).map.with_index do |line, index|
full_line = limited_blob_lines[index].delete("\n") full_line = line.delete("\n")
Gitlab::Diff::Line.new(full_line, nil, nil, nil, nil, rich_text: line) Gitlab::Diff::Line.new(full_line, nil, nil, nil, nil, rich_text: lines[index])
end end
add_match_line(diff_lines) add_match_line(diff_lines)
...@@ -43,7 +42,7 @@ module Blobs ...@@ -43,7 +42,7 @@ module Blobs
end end
def lines def lines
@lines ||= limit(highlight.lines).map(&:html_safe) @lines ||= highlight(since: since, to: to).lines.map(&:html_safe)
end end
def match_line_text def match_line_text
...@@ -59,7 +58,7 @@ module Blobs ...@@ -59,7 +58,7 @@ module Blobs
def add_match_line(diff_lines) def add_match_line(diff_lines)
return unless unfold? return unless unfold?
if bottom? && to < @all_lines.size if bottom? && to < all_lines.size
old_pos = to - offset old_pos = to - offset
new_pos = to new_pos = to
elsif since != 1 elsif since != 1
...@@ -73,15 +72,5 @@ module Blobs ...@@ -73,15 +72,5 @@ module Blobs
bottom? ? diff_lines.push(match_line) : diff_lines.unshift(match_line) bottom? ? diff_lines.push(match_line) : diff_lines.unshift(match_line)
end end
def limited_blob_lines
@limited_blob_lines ||= limit(@all_lines)
end
def limit(lines)
return lines if full?
lines[since - 1..to - 1]
end
end end
end end
---
title: Support selective highlighting of lines
merge_request: 31361
author:
type: performance
...@@ -6,15 +6,16 @@ module Gitlab ...@@ -6,15 +6,16 @@ module Gitlab
TIMEOUT_FOREGROUND = 3.seconds TIMEOUT_FOREGROUND = 3.seconds
MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte
def self.highlight(blob_name, blob_content, language: nil, plain: false) def self.highlight(blob_name, blob_content, since: nil, language: nil, plain: false)
new(blob_name, blob_content, language: language) new(blob_name, blob_content, since: since, language: language)
.highlight(blob_content, continue: false, plain: plain) .highlight(blob_content, continue: false, plain: plain)
end end
attr_reader :blob_name attr_reader :blob_name
def initialize(blob_name, blob_content, language: nil) def initialize(blob_name, blob_content, since: nil, language: nil)
@formatter = Rouge::Formatters::HTMLGitlab @formatter = Rouge::Formatters::HTMLGitlab
@since = since
@language = language @language = language
@blob_name = blob_name @blob_name = blob_name
@blob_content = blob_content @blob_content = blob_content
...@@ -53,13 +54,13 @@ module Gitlab ...@@ -53,13 +54,13 @@ module Gitlab
end end
def highlight_plain(text) def highlight_plain(text)
@formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe @formatter.format(Rouge::Lexers::PlainText.lex(text), since: @since).html_safe
end end
def highlight_rich(text, continue: true) def highlight_rich(text, continue: true)
tag = lexer.tag tag = lexer.tag
tokens = lexer.lex(text, continue: continue) tokens = lexer.lex(text, continue: continue)
Timeout.timeout(timeout_time) { @formatter.format(tokens, tag: tag).html_safe } Timeout.timeout(timeout_time) { @formatter.format(tokens, tag: tag, since: @since).html_safe }
rescue Timeout::Error => e rescue Timeout::Error => e
Gitlab::Sentry.track_exception(e) Gitlab::Sentry.track_exception(e)
highlight_plain(text) highlight_plain(text)
......
...@@ -8,8 +8,8 @@ module Rouge ...@@ -8,8 +8,8 @@ module Rouge
# Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance. # Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance.
# #
# [+tag+] The tag (language) of the lexer used to generate the formatted tokens # [+tag+] The tag (language) of the lexer used to generate the formatted tokens
def initialize(tag: nil) def initialize(tag: nil, since: nil)
@line_number = 1 @line_number = since || 1
@tag = tag @tag = tag
end end
......
...@@ -62,6 +62,14 @@ describe Gitlab::Highlight do ...@@ -62,6 +62,14 @@ describe Gitlab::Highlight do
expect(lines[2].text).to eq(' """') expect(lines[2].text).to eq(' """')
end end
context 'since param is present' do
it 'highlights with the LC starting from "since" param' do
lines = described_class.highlight(file_name, content, since: 2).lines
expect(lines[0]).to include('LC2')
end
end
context 'diff highlighting' do context 'diff highlighting' do
let(:file_name) { 'test.diff' } let(:file_name) { 'test.diff' }
let(:content) { "+aaa\n+bbb\n- ccc\n ddd\n"} let(:content) { "+aaa\n+bbb\n- ccc\n ddd\n"}
......
...@@ -28,24 +28,70 @@ describe BlobPresenter, :seed_helper do ...@@ -28,24 +28,70 @@ describe BlobPresenter, :seed_helper do
subject { described_class.new(blob) } subject { described_class.new(blob) }
it 'returns highlighted content' do it 'returns highlighted content' do
expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', git_blob.data, plain: nil, language: nil) expect(Gitlab::Highlight)
.to receive(:highlight)
.with(
'files/ruby/regex.rb',
git_blob.data,
since: nil,
plain: nil,
language: nil
)
subject.highlight subject.highlight
end end
it 'returns plain content when :plain is true' do it 'returns plain content when :plain is true' do
expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', git_blob.data, plain: true, language: nil) expect(Gitlab::Highlight)
.to receive(:highlight)
.with(
'files/ruby/regex.rb',
git_blob.data,
since: nil,
plain: true,
language: nil
)
subject.highlight(plain: true) subject.highlight(plain: true)
end end
context '"since" and "to" are present' do
before do
allow(git_blob)
.to receive(:data)
.and_return("line one\nline two\nline 3\nline 4")
end
it 'returns limited highlighted content' do
expect(Gitlab::Highlight)
.to receive(:highlight)
.with(
'files/ruby/regex.rb',
"line two\nline 3\n",
since: 2,
language: nil,
plain: nil
)
subject.highlight(since: 2, to: 3)
end
end
context 'gitlab-language contains a match' do context 'gitlab-language contains a match' do
before do before do
allow(blob).to receive(:language_from_gitattributes).and_return('ruby') allow(blob).to receive(:language_from_gitattributes).and_return('ruby')
end end
it 'passes language to inner call' do it 'passes language to inner call' do
expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', git_blob.data, plain: nil, language: 'ruby') expect(Gitlab::Highlight)
.to receive(:highlight)
.with(
'files/ruby/regex.rb',
git_blob.data,
since: nil,
plain: nil,
language: 'ruby'
)
subject.highlight subject.highlight
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment