From 46631e102366bd40bdb449b87fae3f10e992ee68 Mon Sep 17 00:00:00 2001 From: Patrick Bajao Date: Mon, 5 Aug 2019 17:44:13 +0800 Subject: 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. --- app/presenters/blob_presenter.rb | 19 +++++++- app/presenters/blobs/unfold_presenter.rb | 23 +++------- .../unreleased/65152-selective-highlight.yml | 5 +++ lib/gitlab/highlight.rb | 11 ++--- lib/rouge/formatters/html_gitlab.rb | 4 +- spec/lib/gitlab/highlight_spec.rb | 8 ++++ spec/presenters/blob_presenter_spec.rb | 52 ++++++++++++++++++++-- 7 files changed, 93 insertions(+), 29 deletions(-) create mode 100644 changelogs/unreleased/65152-selective-highlight.yml diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb index 2cf3278d240..f85c1a237a6 100644 --- a/app/presenters/blob_presenter.rb +++ b/app/presenters/blob_presenter.rb @@ -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 diff --git a/app/presenters/blobs/unfold_presenter.rb b/app/presenters/blobs/unfold_presenter.rb index 21a1e1309e0..f4672d22fc9 100644 --- a/app/presenters/blobs/unfold_presenter.rb +++ b/app/presenters/blobs/unfold_presenter.rb @@ -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 diff --git a/changelogs/unreleased/65152-selective-highlight.yml b/changelogs/unreleased/65152-selective-highlight.yml new file mode 100644 index 00000000000..371dbbd5924 --- /dev/null +++ b/changelogs/unreleased/65152-selective-highlight.yml @@ -0,0 +1,5 @@ +--- +title: Support selective highlighting of lines +merge_request: 31361 +author: +type: performance diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 381f1dd4e55..1f49a26f0a2 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -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) diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb index e2a7d3ef5ba..0d4ac504428 100644 --- a/lib/rouge/formatters/html_gitlab.rb +++ b/lib/rouge/formatters/html_gitlab.rb @@ -8,8 +8,8 @@ module Rouge # Creates a new Rouge::Formatter::HTMLGitlab 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 diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 4676db6b8d8..a410e4eab45 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -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"} diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb index eacf383be7d..95db2ba6a0d 100644 --- a/spec/presenters/blob_presenter_spec.rb +++ b/spec/presenters/blob_presenter_spec.rb @@ -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 -- cgit v1.2.1