Skip to content
Snippets Groups Projects
Commit f678137b authored by Douwe Maan's avatar Douwe Maan
Browse files

Autolink URLs and emails in blobs and diffs

parent e82010da
No related branches found
No related tags found
1 merge request!11225WIP: Autolink URLs in blobs and diffs
Loading
Loading
@@ -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
 
Loading
Loading
@@ -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)
Loading
Loading
module Banzai
module Pipeline
class AutolinkPipeline < BasePipeline
def self.filters
@filters ||= FilterArray[
Filter::AutolinkFilter,
Filter::ExternalLinkFilter
]
end
end
end
end
Loading
Loading
@@ -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
Loading
Loading
@@ -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
Loading
Loading
@@ -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
Loading
Loading
@@ -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).
Loading
Loading
@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment