summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/banzai/filter/autolink_filter.rb10
-rw-r--r--lib/banzai/pipeline/autolink_pipeline.rb12
-rw-r--r--lib/gitlab/highlight.rb20
-rw-r--r--spec/lib/gitlab/highlight_spec.rb65
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(%{&lt;<a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a>&gt;})
+ expect(subject).to include(%{&lt;url&gt;<a href="http://www.google.com" rel="nofollow noreferrer" target="_blank">http://www.google.com</a>&lt;/url&gt;})
+ end
+ end
+ end
end
end