diff options
-rw-r--r-- | lib/banzai/filter/autolink_filter.rb | 10 | ||||
-rw-r--r-- | lib/banzai/pipeline/autolink_pipeline.rb | 12 | ||||
-rw-r--r-- | lib/gitlab/highlight.rb | 20 | ||||
-rw-r--r-- | spec/lib/gitlab/highlight_spec.rb | 65 |
4 files changed, 98 insertions, 9 deletions
diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb index a8ca2757612..15f7da5d934 100644 --- a/lib/banzai/filter/autolink_filter.rb +++ b/lib/banzai/filter/autolink_filter.rb @@ -54,15 +54,13 @@ module Banzai # # `@doc` will be re-parsed with the HTML String from Rinku. def rinku_parse - # Convert the options from a Hash to a String that Rinku expects - options = tag_options(link_options) - # NOTE: We don't parse email links because it will erroneously match # external Commit and CommitRange references. # # The final argument tells Rinku to link short URLs that don't include a # period (e.g., http://localhost:3000/) - rinku = Rinku.auto_link(html, :urls, options, IGNORE_PARENTS.to_a, 1) + mode = context[:autolink_emails] ? :all : :urls + rinku = Rinku.auto_link(html, mode, tag_options(link_options), IGNORE_PARENTS.to_a, 1) return if rinku == html @@ -111,9 +109,9 @@ module Banzai # order to be output literally rather than escaped. match.gsub!(/((?:&[\w#]+;)+)\z/, '') dropped = ($1 || '').html_safe + match = ERB::Util.html_escape_once(match) - options = link_options.merge(href: match) - content_tag(:a, match, options) + dropped + %{<a href="#{match}" #{tag_options(link_options)}>#{match}</a>#{dropped}}.html_safe end def autolink_filter(text) diff --git a/lib/banzai/pipeline/autolink_pipeline.rb b/lib/banzai/pipeline/autolink_pipeline.rb new file mode 100644 index 00000000000..53f2da5c7b5 --- /dev/null +++ b/lib/banzai/pipeline/autolink_pipeline.rb @@ -0,0 +1,12 @@ +module Banzai + module Pipeline + class AutolinkPipeline < BasePipeline + def self.filters + @filters ||= FilterArray[ + Filter::AutolinkFilter, + Filter::ExternalLinkFilter + ] + end + end + end +end diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb index 83bc230df3e..57ae127254b 100644 --- a/lib/gitlab/highlight.rb +++ b/lib/gitlab/highlight.rb @@ -25,7 +25,7 @@ module Gitlab def highlight(text, continue: true, plain: false) highlighted_text = highlight_text(text, continue: continue, plain: plain) highlighted_text = link_dependencies(text, highlighted_text) if blob_name - highlighted_text + autolink_strings(highlighted_text) end def lexer @@ -67,5 +67,23 @@ module Gitlab def link_dependencies(text, highlighted_text) Gitlab::DependencyLinker.link(blob_name, text, highlighted_text) end + + def autolink_strings(highlighted_text) + doc = Nokogiri::HTML::DocumentFragment.parse(highlighted_text) + + # Files without highlighting have all text in `span.line`. + # Files with highlighting have strings and comments in `span`s with a + # `class` starting with `c` or `s`. + doc.xpath('.//span[@class="line" or starts-with(@class, "c") or starts-with(@class, "s")]/text()').each do |node| + content = node.to_html + html = Banzai.render(content, pipeline: :autolink, autolink_emails: true) + + next if html == content + + node.replace(html) + end + + doc.to_html.html_safe + end end end diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index e57b3053871..4a106fc675c 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::Highlight, lib: true do describe '.highlight_lines' do let(:lines) do - Gitlab::Highlight.highlight_lines(project.repository, commit.id, 'files/ruby/popen.rb') + described_class.highlight_lines(project.repository, commit.id, 'files/ruby/popen.rb') end it 'highlights all the lines properly' do @@ -59,7 +59,7 @@ describe Gitlab::Highlight, lib: true do end describe '#highlight' do - subject { described_class.highlight(file_name, file_content, nowrap: false) } + subject { described_class.highlight(file_name, file_content) } it 'links dependencies via DependencyLinker' do expect(Gitlab::DependencyLinker).to receive(:link). @@ -67,5 +67,66 @@ describe Gitlab::Highlight, lib: true do described_class.highlight('file.name', 'Contents') end + + context "plain text file" do + let(:file_name) { "example.txt" } + let(:file_content) do + <<-CONTENT.strip_heredoc + URL: http://www.google.com + Email: hello@example.com + CONTENT + end + + it "links URLs" do + expect(subject).to include(%{<a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a>}) + end + + it "links emails" do + expect(subject).to include(%{<a href="mailto:hello@example.com">hello@example.com</a>}) + end + end + + context "file with highlighting" do + let(:file_name) { "example.rb" } + let(:file_content) do + <<-CONTENT.strip_heredoc + # URL in comment: http://www.google.com + # Email in comment: hello@example.com + + "URL in string: http://www.google.com" + "Email in string: hello@example.com" + + # <http://www.google.com> + # <url>http://www.google.com</url> + CONTENT + end + + context "in a comment" do + it "links URLs" do + expect(subject).to include(%{URL in comment: <a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a>}) + end + + it "links emails" do + expect(subject).to include(%{Email in comment: <a href="mailto:hello@example.com">hello@example.com</a>}) + end + end + + context "in a string" do + it "links URLs" do + expect(subject).to include(%{URL in string: <a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a>}) + end + + it "links emails" do + expect(subject).to include(%{Email in string: <a href="mailto:hello@example.com">hello@example.com</a>}) + end + end + + context 'in HTML/XML tags' do + it "links URLs" do + expect(subject).to include(%{<<a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a>>}) + expect(subject).to include(%{<url><a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a></url>}) + end + end + end end end |