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.
This commit is contained in:
		
							parent
							
								
									fa216b0e86
								
							
						
					
					
						commit
						46631e1023
					
				|  | @ -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 | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| 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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue