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 @@
class BlobPresenter < Gitlab::View::Presenter::Delegated
presents :blob
def highlight(plain: nil)
def highlight(since: nil, to: nil, plain: nil)
load_all_blob_data
Gitlab::Highlight.highlight(
blob.path,
blob.data,
limited_blob_data(since: since, to: to),
since: since,
language: blob.language_from_gitattributes,
plain: plain
)
......@@ -23,4 +24,18 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
def load_all_blob_data
blob.load_all_data! if blob.respond_to?(:load_all_data!)
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
......@@ -21,20 +21,19 @@ module Blobs
load_all_blob_data
@subject = blob
@all_lines = blob.data.lines
super(params)
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
# Returns an array of Gitlab::Diff::Line with match line added
def diff_lines
diff_lines = lines.map.with_index do |line, index|
full_line = limited_blob_lines[index].delete("\n")
diff_lines = limited_blob_lines(since, to).map.with_index do |line, index|
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
add_match_line(diff_lines)
......@@ -43,7 +42,7 @@ module Blobs
end
def lines
@lines ||= limit(highlight.lines).map(&:html_safe)
@lines ||= highlight(since: since, to: to).lines.map(&:html_safe)
end
def match_line_text
......@@ -59,7 +58,7 @@ module Blobs
def add_match_line(diff_lines)
return unless unfold?
if bottom? && to < @all_lines.size
if bottom? && to < all_lines.size
old_pos = to - offset
new_pos = to
elsif since != 1
......@@ -73,15 +72,5 @@ module Blobs
bottom? ? diff_lines.push(match_line) : diff_lines.unshift(match_line)
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
---
title: Support selective highlighting of lines
merge_request: 31361
author:
type: performance
......@@ -6,15 +6,16 @@ module Gitlab
TIMEOUT_FOREGROUND = 3.seconds
MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte
def self.highlight(blob_name, blob_content, language: nil, plain: false)
new(blob_name, blob_content, language: language)
def self.highlight(blob_name, blob_content, since: nil, language: nil, plain: false)
new(blob_name, blob_content, since: since, language: language)
.highlight(blob_content, continue: false, plain: plain)
end
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
@since = since
@language = language
@blob_name = blob_name
@blob_content = blob_content
......@@ -53,13 +54,13 @@ module Gitlab
end
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
def highlight_rich(text, continue: true)
tag = lexer.tag
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
Gitlab::Sentry.track_exception(e)
highlight_plain(text)
......
......@@ -8,8 +8,8 @@ module Rouge
# Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance.
#
# [+tag+] The tag (language) of the lexer used to generate the formatted tokens
def initialize(tag: nil)
@line_number = 1
def initialize(tag: nil, since: nil)
@line_number = since || 1
@tag = tag
end
......
......@@ -62,6 +62,14 @@ describe Gitlab::Highlight do
expect(lines[2].text).to eq(' """')
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
let(:file_name) { 'test.diff' }
let(:content) { "+aaa\n+bbb\n- ccc\n ddd\n"}
......
......@@ -28,24 +28,70 @@ describe BlobPresenter, :seed_helper do
subject { described_class.new(blob) }
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
end
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)
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
before do
allow(blob).to receive(:language_from_gitattributes).and_return('ruby')
end
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
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