diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 09951fe3d3e38bb649087a2f1c67790142606cf0..6e3829d994fe8d5e9410d0fd5bd821222512c3e2 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -185,6 +185,11 @@ $dark-il: #de935f;
     color: $dark-highlight-color !important;
   }
 
+  // Links to URLs, emails, or dependencies
+  .line a {
+    color: $dark-na;
+  }
+
   .hll { background-color: $dark-hll-bg; }
   .c { color: $dark-c; } /* Comment */
   .err { color: $dark-err; } /* Error */
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index b6a6d298adf592b2af502ceb063c9b2e699f5fd3..68eb0c7720f3737101760a8c7c1684584bb762d5 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -185,6 +185,11 @@ $monokai-gi: #a6e22e;
     color: $black !important;
   }
 
+  // Links to URLs, emails, or dependencies
+  .line a {
+    color: $monokai-k;
+  }
+
   .hll { background-color: $monokai-hll; }
   .c { color: $monokai-c; } /* Comment */
   .err { color: $monokai-err-color; background-color: $monokai-err-bg; } /* Error */
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 4f7a50dcb4fdf3888c772c8594ec2f69e4d1b922..2cc968c32f2b3ef9e1f02e6bc55d006aac795a77 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -188,6 +188,11 @@ $solarized-dark-il: #2aa198;
     background-color: $solarized-dark-highlight !important;
   }
 
+  // Links to URLs, emails, or dependencies
+  .line a {
+    color: $solarized-dark-kd;
+  }
+
   /* Solarized Dark
 
   For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 6463fe96c1b8ddb0b8a99aacb17b12aaec1b4c6f..b61b85a2cd13b60d3254c34e30ca5e96097b9306 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -196,6 +196,11 @@ $solarized-light-il: #2aa198;
     background-color: $solarized-light-highlight !important;
   }
 
+  // Links to URLs, emails, or dependencies
+  .line a {
+    color: $solarized-light-kd;
+  }
+
   /* Solarized Light
 
   For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index ab2018bfbca795df7b7182b51e453bdc3ef3cb15..1daa10aef24912a98fc23666a4ca39f4bb921688 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -203,6 +203,11 @@ $white-gc-bg: #eaf2f5;
     background-color: $white-highlight !important;
   }
 
+  // Links to URLs, emails, or dependencies
+  .line a {
+    color: $white-nb;
+  }
+
   .hll { background-color: $white-hll-bg; }
   .c { color: $white-c; font-style: italic; }
   .err { color: $white-err; background-color: $white-err-bg; }
diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb
index b8d2673c1a67f7739adb81c35368ec1660d0a638..15f7da5d934aadb75663b6978a7d63788a46d442 100644
--- a/lib/banzai/filter/autolink_filter.rb
+++ b/lib/banzai/filter/autolink_filter.rb
@@ -26,7 +26,7 @@ module Banzai
       # in the generated link.
       #
       # Rubular: http://rubular.com/r/cxjPyZc7Sb
-      LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?<!,|\.)}
+      LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?<![,."':?!&)<>])}
 
       # Text matching LINK_PATTERN inside these elements will not be linked
       IGNORE_PARENTS = %w(a code kbd pre script style).to_set
@@ -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 0000000000000000000000000000000000000000..53f2da5c7b5861e318cc7bbbd3110b8c8e29c001
--- /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/dependency_linker.rb b/lib/gitlab/dependency_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..57fc3c6e0e5df9f54b9e3847fb664e5d06a8253e
--- /dev/null
+++ b/lib/gitlab/dependency_linker.rb
@@ -0,0 +1,29 @@
+module Gitlab
+  module DependencyLinker
+    LINKERS = [
+      GemfileLinker,
+      GemspecLinker,
+      PackageJsonLinker,
+      ComposerJsonLinker,
+      PodfileLinker,
+      PodspecLinker,
+      PodspecJsonLinker,
+      CartfileLinker,
+      GodepsJsonLinker,
+      RequirementsTxtLinker
+    ]
+
+    def self.link(blob_name, plain_text, highlighted_text)
+      linker = linker(blob_name)
+      return highlighted_text unless linker
+
+      linker.link(plain_text, highlighted_text)
+    end
+
+    private
+
+    def self.linker(blob_name)
+      LINKERS.find { |linker| linker.support?(blob_name) }
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/base_linker.rb b/lib/gitlab/dependency_linker/base_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d5449eafc40a4cae0f7ff8f58bf42b151d372220
--- /dev/null
+++ b/lib/gitlab/dependency_linker/base_linker.rb
@@ -0,0 +1,144 @@
+module Gitlab
+  module DependencyLinker
+    class BaseLinker
+      def self.link(plain_text, highlighted_text)
+        new(plain_text, highlighted_text).link
+      end
+
+      attr_accessor :plain_text, :highlighted_text
+
+      def initialize(plain_text, highlighted_text)
+        @plain_text = plain_text
+        @highlighted_text = highlighted_text
+      end
+
+      def link
+        link_dependencies
+
+        highlighted_lines.join.html_safe
+      end
+
+      private
+
+      def package_url(name)
+        raise NotImplementedError
+      end
+
+      def link_dependencies
+        raise NotImplementedError
+      end
+
+      def license_url(name)
+        "http://spdx.org/licenses/#{name}.html" if name =~ /[A-Za-z0-9.-]+/
+      end
+
+      def package_link(name, url = package_url(name))
+        return name unless url
+
+        %{<a href="#{ERB::Util.html_escape_once(url)}">#{ERB::Util.html_escape_once(name)}</a>}
+      end
+
+      # Links package names in a method call or assignment string argument.
+      #
+      # Example:
+      #   link_method_call("gem")
+      #   # Will link `package` in `gem "package"`, `gem("package")` and `gem = "package"`
+      #
+      #   link_method_call("gem", "specific_package")
+      #   # Will link `specific_package` in `gem "specific_package"`
+      #
+      #   link_method_call("github", /[^\/"]+\/[^\/"]+/)
+      #   # Will link `user/repo` in `github "user/repo"`, but not `github "package"`
+      #
+      #   link_method_call(%w[add_dependency add_development_dependency])
+      #   # Will link `spec.add_dependency "package"` and `spec.add_development_dependency "package"`
+      #
+      #   link_method_call("name")
+      #   # Will link `package` in `self.name = "package"`
+      def link_method_call(method_names, value = nil, &url_proc)
+        value =
+          case value
+          when String
+            Regexp.escape(value)
+          when nil
+            %{[^'"]+}
+          else
+            value
+          end
+
+        method_names = Array(method_names).map { |name| Regexp.escape(name) }
+        link_regex(/#{Regexp.union(method_names)}\s*[(=]?\s*['"](?<name>#{value})['"]/, &url_proc)
+      end
+
+      # Links package names in a JSON key or values.
+      #
+      # Example:
+      #   link_json("name")
+      #   # Will link `package` in `"name": "package"`
+      #
+      #   link_json("name", "specific_package")
+      #   # Will link `specific_package` in `"name": "specific_package"`
+      #
+      #   link_json("name", /[^\/]+\/[^\/]+/)
+      #   # Will link `user/repo` in `"name": "user/repo"`, but not `"name": "package"`
+      #
+      #   link_json("specific_package", "1.0.1", package: :key)
+      #   # Will link `specific_package` in `"specific_package": "1.0.1"`
+      def link_json(key, value = nil, package: :value, &url_proc)
+        key =
+          case key
+          when String
+            Regexp.escape(key)
+          when nil
+            '[^"]+'
+          else
+            key
+          end
+
+        value =
+          case value
+          when String
+            Regexp.escape(value)
+          when nil
+            '[^"]+'
+          else
+            value
+          end
+
+        if package == :value
+          value = "(?<name>#{value})"
+        else
+          key = "(?<name>#{key})"
+        end
+
+        link_regex(/"#{key}":\s*"#{value}"/, &url_proc)
+      end
+
+      # Links package names based on regex.
+      #
+      # Example:
+      #   link_regex(/(github:|:github =>)\s*['"](?<name>[^'"]+)['"]/)
+      #   # Will link `user/repo` in `github: "user/repo"` or `:github => "user/repo"`
+      def link_regex(regex)
+        highlighted_lines.map!.with_index do |rich_line, i|
+          marker = StringRegexMarker.new(plain_lines[i], rich_line.html_safe)
+
+          marked_line = marker.mark(regex, group: :name) do |text, left:, right:|
+            url = block_given? ? yield(text) : package_url(text)
+            package_link(text, url)
+          end
+
+          marked_line
+        end
+      end
+
+      def plain_lines
+        @plain_lines ||= plain_text.lines
+      end
+
+      def highlighted_lines
+        @highlighted_lines ||= highlighted_text.lines
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/cartfile_linker.rb b/lib/gitlab/dependency_linker/cartfile_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9f7d10b59740f7e3e629915d2da13a29cb00218a
--- /dev/null
+++ b/lib/gitlab/dependency_linker/cartfile_linker.rb
@@ -0,0 +1,19 @@
+module Gitlab
+  module DependencyLinker
+    class CartfileLinker < BaseLinker
+      def self.support?(blob_name)
+        blob_name.start_with?('Cartfile')
+      end
+
+      private
+
+      def link_dependencies
+        link_method_call("github", /[^\/"]+\/[^\/"]+/)
+      end
+
+      def package_url(name)
+        "https://github.com/#{name}"
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/composer_json_linker.rb b/lib/gitlab/dependency_linker/composer_json_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4c8a80a29cab89b15c7432819bf8395176ca4aee
--- /dev/null
+++ b/lib/gitlab/dependency_linker/composer_json_linker.rb
@@ -0,0 +1,23 @@
+module Gitlab
+  module DependencyLinker
+    class ComposerJsonLinker < PackageJsonLinker
+      def self.support?(blob_name)
+        blob_name == 'composer.json'
+      end
+
+      private
+
+      def link_dependencies
+        link_json("name", json["name"])
+        link_json("license", &method(:license_url))
+
+        link_dependencies_at_key("require")
+        link_dependencies_at_key("require-dev")
+      end
+
+      def package_url(name)
+        "https://packagist.org/packages/#{name}" if name =~ /\A[^\/]+\/[^\/]+\z/
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/gemfile_linker.rb b/lib/gitlab/dependency_linker/gemfile_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1e0d08f22914ee1256f67b1ea2b0a4b9d484792c
--- /dev/null
+++ b/lib/gitlab/dependency_linker/gemfile_linker.rb
@@ -0,0 +1,25 @@
+module Gitlab
+  module DependencyLinker
+    class GemfileLinker < BaseLinker
+      def self.support?(blob_name)
+        blob_name == 'Gemfile' || blob_name == 'gems.rb'
+      end
+
+      private
+
+      def link_dependencies
+        # Link `gem "package_name"` to https://rubygems.org/gems/package_name
+        link_method_call("gem")
+
+        # Link `github: "user/repo"` to https://github.com/user/repo
+        link_regex(/(github:|:github\s*=>)\s*['"](?<name>[^'"]+)['"]/) do |name|
+          "https://github.com/#{name}"
+        end
+      end
+
+      def package_url(name)
+        "https://rubygems.org/gems/#{name}"
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/gemspec_linker.rb b/lib/gitlab/dependency_linker/gemspec_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cf8acc5b004f715eb920d6a6ff7469b74593ef60
--- /dev/null
+++ b/lib/gitlab/dependency_linker/gemspec_linker.rb
@@ -0,0 +1,16 @@
+module Gitlab
+  module DependencyLinker
+    class GemspecLinker < GemfileLinker
+      def self.support?(blob_name)
+        blob_name.end_with?('.gemspec')
+      end
+
+      private
+
+      def link_dependencies
+        link_method_call(%w[name add_dependency add_runtime_dependency add_development_dependency])
+        link_method_call("license", &method(:license_url))
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/godeps_json_linker.rb b/lib/gitlab/dependency_linker/godeps_json_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..227f7439fa0c36ed5c4d98478f1287a25dacb5f7
--- /dev/null
+++ b/lib/gitlab/dependency_linker/godeps_json_linker.rb
@@ -0,0 +1,23 @@
+module Gitlab
+  module DependencyLinker
+    class GodepsJsonLinker < BaseLinker
+      def self.support?(blob_name)
+        blob_name == 'Godeps.json'
+      end
+
+      private
+
+      def link_dependencies
+        link_json("ImportPath")
+      end
+
+      def package_url(name)
+        if name =~ /\A(?<repo>git(lab|hub)\.com\/[^\/]+\/[^\/]+)\/(?<path>.+)\z/
+          "http://#{$~[:repo]}/tree/master/#{$~[:path]}"
+        else
+          "http://#{name}"
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/json_linker.rb b/lib/gitlab/dependency_linker/json_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4225cfe4126dd35c8b47a6244e70f6f870fe3e9b
--- /dev/null
+++ b/lib/gitlab/dependency_linker/json_linker.rb
@@ -0,0 +1,17 @@
+module Gitlab
+  module DependencyLinker
+    class JsonLinker < BaseLinker
+      def link
+        return highlighted_text unless json
+
+        super
+      end
+
+      private
+
+      def json
+        @json ||= JSON.parse(plain_text) rescue nil
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/package_json_linker.rb b/lib/gitlab/dependency_linker/package_json_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7c5f3b97d88e65c85227a8dc0b05fb2fb4f49495
--- /dev/null
+++ b/lib/gitlab/dependency_linker/package_json_linker.rb
@@ -0,0 +1,35 @@
+module Gitlab
+  module DependencyLinker
+    class PackageJsonLinker < JsonLinker
+      def self.support?(blob_name)
+        blob_name == 'package.json'
+      end
+
+      private
+
+      def link_dependencies
+        link_json("name", json["name"])
+        link_json("license", &method(:license_url))
+
+        link_dependencies_at_key("dependencies")
+        link_dependencies_at_key("devDependencies")
+      end
+
+      def link_dependencies_at_key(key)
+        dependencies = json[key]
+        return unless dependencies
+
+        dependencies.each do |name, version|
+          link_json(name, version, package: :key)
+          link_json(name, /[^\/"]+\/[^\/"]+/) do |name|
+            "https://github.com/#{name}"
+          end
+        end
+      end
+
+      def package_url(name)
+        "https://npmjs.com/package/#{name}"
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/podfile_linker.rb b/lib/gitlab/dependency_linker/podfile_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6716d5bdfd4f05280f93a18d8dc2369b9e85b48d
--- /dev/null
+++ b/lib/gitlab/dependency_linker/podfile_linker.rb
@@ -0,0 +1,20 @@
+module Gitlab
+  module DependencyLinker
+    class PodfileLinker < BaseLinker
+      def self.support?(blob_name)
+        blob_name == 'Podfile'
+      end
+
+      private
+
+      def link_dependencies
+        link_method_call("pod")
+      end
+
+      def package_url(name)
+        package = name.split("/", 2).first
+        "https://cocoapods.org/pods/#{package}"
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/podspec_json_linker.rb b/lib/gitlab/dependency_linker/podspec_json_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..825c548c1712ccad11a4ecdb4a1bef537d0df65c
--- /dev/null
+++ b/lib/gitlab/dependency_linker/podspec_json_linker.rb
@@ -0,0 +1,39 @@
+module Gitlab
+  module DependencyLinker
+    class PodspecJsonLinker < JsonLinker
+      def self.support?(blob_name)
+        blob_name.end_with?('.podspec.json')
+      end
+
+      private
+
+      def link_dependencies
+        link_json("name", json["name"])
+        link_json("license", &method(:license_url))
+
+        link_dependencies_at_key("dependencies")
+
+        subspecs = json["subspecs"]
+        if subspecs
+          subspecs.each do |subspec|
+            link_dependencies_at_key("dependencies", subspec)
+          end
+        end
+      end
+
+      def link_dependencies_at_key(key, root = json)
+        dependencies = root[key]
+        return unless dependencies
+
+        dependencies.each do |name, _|
+          link_regex(/"(?<name>#{Regexp.escape(name)})":\s*\[/)
+        end
+      end
+
+      def package_url(name)
+        package = name.split("/", 2).first
+        "https://cocoapods.org/pods/#{package}"
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/podspec_linker.rb b/lib/gitlab/dependency_linker/podspec_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fd4b17e39bbb9cb8b18b8d9e0d4a0382a3b5cfd0
--- /dev/null
+++ b/lib/gitlab/dependency_linker/podspec_linker.rb
@@ -0,0 +1,33 @@
+module Gitlab
+  module DependencyLinker
+    class PodspecLinker < PodfileLinker
+      def self.support?(blob_name)
+        blob_name.end_with?('.podspec')
+      end
+
+      private
+
+      def link_dependencies
+        link_method_call(%w[name dependency])
+
+        license_regex = %r{
+          license
+          \s*
+          =
+          \s*
+          (?:
+              # spec.license = 'MIT'
+              ['"](?<name>[^'"]+)['"]
+            |
+              # spec.license = { :type => 'MIT' }
+              \{\s*:type\s*=>\s*['"](?<name>[^'"]+)['"]
+            |
+              # spec.license = { type: 'MIT' }
+              \{\s*type:\s*['"](?<name>[^'"]+)['"]
+          )
+        }x
+        link_regex(license_regex, &method(:license_url))
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/dependency_linker/requirements_txt_linker.rb b/lib/gitlab/dependency_linker/requirements_txt_linker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..92fcb8177ea6fc7a2c4d6333b12629962fa37c0a
--- /dev/null
+++ b/lib/gitlab/dependency_linker/requirements_txt_linker.rb
@@ -0,0 +1,19 @@
+module Gitlab
+  module DependencyLinker
+    class RequirementsTxtLinker < BaseLinker
+      def self.support?(blob_name)
+        blob_name.end_with?('requirements.txt')
+      end
+
+      private
+
+      def link_dependencies
+        link_regex(/(?<name>^(?![a-z+]+:)[^#.-][^ ><=;\[]+)/)
+      end
+
+      def package_url(name)
+        "https://pypi.python.org/pypi/#{name}"
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/diff/inline_diff_marker.rb b/lib/gitlab/diff/inline_diff_marker.rb
index 736933b1c4b0a6cdbc33cd3a04005f0d0dec9087..96f5ca31e5c019223c3862b62902e8b832063c8a 100644
--- a/lib/gitlab/diff/inline_diff_marker.rb
+++ b/lib/gitlab/diff/inline_diff_marker.rb
@@ -1,38 +1,18 @@
 module Gitlab
   module Diff
-    class InlineDiffMarker
+    class InlineDiffMarker < Gitlab::StringRangeMarker
       MARKDOWN_SYMBOLS = {
         addition: "+",
         deletion: "-"
       }.freeze
 
-      attr_accessor :raw_line, :rich_line
-
-      def initialize(raw_line, rich_line = raw_line)
-        @raw_line = raw_line
-        @rich_line = ERB::Util.html_escape(rich_line)
-      end
-
       def mark(line_inline_diffs, mode: nil, markdown: false)
-        return rich_line unless line_inline_diffs
-
-        marker_ranges = []
-        line_inline_diffs.each do |inline_diff_range|
-          # Map the inline-diff range based on the raw line to character positions in the rich line
-          inline_diff_positions = position_mapping[inline_diff_range].flatten
-          # Turn the array of character positions into ranges
-          marker_ranges.concat(collapse_ranges(inline_diff_positions))
-        end
-
-        offset = 0
-
-        # Mark each range
-        marker_ranges.each_with_index do |range, index|
+        super(line_inline_diffs) do |text, left:, right:|
           before_content =
             if markdown
               "{#{MARKDOWN_SYMBOLS[mode]}"
             else
-              "<span class='#{html_class_names(marker_ranges, mode, index)}'>"
+              "<span class='#{html_class_names(left, right, mode)}'>"
             end
           after_content =
             if markdown
@@ -40,98 +20,20 @@ module Gitlab
             else
               "</span>"
             end
-          offset = insert_around_range(rich_line, range, before_content, after_content, offset)
-        end
 
-        rich_line.html_safe
+          "#{before_content}#{text}#{after_content}"
+        end
       end
 
       private
 
-      def html_class_names(marker_ranges, mode, index)
+      def html_class_names(left, right, mode)
         class_names = ["idiff"]
-        class_names << "left"  if index == 0
-        class_names << "right" if index == marker_ranges.length - 1
+        class_names << "left"  if left
+        class_names << "right" if right
         class_names << mode if mode
         class_names.join(" ")
       end
-
-      # Mapping of character positions in the raw line, to the rich (highlighted) line
-      def position_mapping
-        @position_mapping ||= begin
-          mapping = []
-          rich_pos = 0
-          (0..raw_line.length).each do |raw_pos|
-            rich_char = rich_line[rich_pos]
-
-            # The raw and rich lines are the same except for HTML tags,
-            # so skip over any `<...>` segment
-            while rich_char == '<'
-              until rich_char == '>'
-                rich_pos += 1
-                rich_char = rich_line[rich_pos]
-              end
-
-              rich_pos += 1
-              rich_char = rich_line[rich_pos]
-            end
-
-            # multi-char HTML entities in the rich line correspond to a single character in the raw line
-            if rich_char == '&'
-              multichar_mapping = [rich_pos]
-              until rich_char == ';'
-                rich_pos += 1
-                multichar_mapping << rich_pos
-                rich_char = rich_line[rich_pos]
-              end
-
-              mapping[raw_pos] = multichar_mapping
-            else
-              mapping[raw_pos] = rich_pos
-            end
-
-            rich_pos += 1
-          end
-
-          mapping
-        end
-      end
-
-      # Takes an array of integers, and returns an array of ranges covering the same integers
-      def collapse_ranges(positions)
-        return [] if positions.empty?
-        ranges = []
-
-        start = prev = positions[0]
-        range = start..prev
-        positions[1..-1].each do |pos|
-          if pos == prev + 1
-            range = start..pos
-            prev = pos
-          else
-            ranges << range
-            start = prev = pos
-            range = start..prev
-          end
-        end
-        ranges << range
-
-        ranges
-      end
-
-      # Inserts tags around the characters identified by the given range
-      def insert_around_range(text, range, before, after, offset = 0)
-        # Just to be sure
-        return offset if offset + range.end + 1 > text.length
-
-        text.insert(offset + range.begin, before)
-        offset += before.length
-
-        text.insert(offset + range.end + 1, after)
-        offset += after.length
-
-        offset
-      end
     end
   end
 end
diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb
index d787d5db4a0bd80013097d1dbe08d5d9eeedebfc..0d5c7a925409b2cf4c924b3dbb815008302031bd 100644
--- a/lib/gitlab/highlight.rb
+++ b/lib/gitlab/highlight.rb
@@ -1,8 +1,8 @@
 module Gitlab
   class Highlight
-    def self.highlight(blob_name, blob_content, repository: nil, plain: false)
+    def self.highlight(blob_name, blob_content, repository: nil, plain: false, link_deps: true, autolink: true)
       new(blob_name, blob_content, repository: repository).
-        highlight(blob_content, continue: false, plain: plain)
+        highlight(blob_content, continue: false, plain: plain, link_deps: link_deps, autolink: autolink)
     end
 
     def self.highlight_lines(repository, ref, file_name)
@@ -13,6 +13,8 @@ module Gitlab
       highlight(file_name, blob.data, repository: repository).lines.map!(&:html_safe)
     end
 
+    attr_reader :blob_name
+
     def initialize(blob_name, blob_content, repository: nil)
       @formatter = Rouge::Formatters::HTMLGitlab
       @repository = repository
@@ -20,17 +22,11 @@ module Gitlab
       @blob_content = blob_content
     end
 
-    def highlight(text, continue: true, plain: false)
-      if plain
-        hl_lexer = Rouge::Lexers::PlainText
-        continue = false
-      else
-        hl_lexer = self.lexer
-      end
-
-      @formatter.format(hl_lexer.lex(text, continue: continue), tag: hl_lexer.tag).html_safe
-    rescue
-      @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
+    def highlight(text, continue: true, plain: false, link_deps: true, autolink: true)
+      highlighted_text = highlight_text(text, continue: continue, plain: plain)
+      highlighted_text = link_dependencies(text, highlighted_text) if blob_name && link_deps
+      highlighted_text = autolink_strings(text, highlighted_text) if autolink
+      highlighted_text
     end
 
     def lexer
@@ -50,5 +46,65 @@ module Gitlab
 
       Rouge::Lexer.find_fancy(language_name)
     end
+
+    def highlight_text(text, continue: true, plain: false)
+      if plain
+        highlight_plain(text)
+      else
+        highlight_rich(text, continue: continue)
+      end
+    end
+
+    def highlight_plain(text)
+      @formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
+    end
+
+    def highlight_rich(text, continue: true)
+      @formatter.format(lexer.lex(text, continue: continue), tag: lexer.tag).html_safe
+    rescue
+      highlight_plain(text)
+    end
+
+    def link_dependencies(text, highlighted_text)
+      Gitlab::DependencyLinker.link(blob_name, text, highlighted_text)
+    end
+
+    def autolink_strings(text, highlighted_text)
+      raw_lines = text.lines
+
+      # TODO: Don't run pre-processing pipeline, because this may break the highlighting
+      linked_text = Banzai.render(
+        ERB::Util.html_escape(text),
+        pipeline: :autolink,
+        autolink_emails: true
+      ).html_safe
+
+      linked_lines = linked_text.lines
+
+      highlighted_lines = highlighted_text.lines
+
+      highlighted_lines.map!.with_index do |rich_line, i|
+        matches = []
+        linked_lines[i].scan(/(?<start><a[^>]+>)(?<content>[^<]+)(?<end><\/a>)/) { matches << Regexp.last_match }
+        next rich_line if matches.empty?
+
+        raw_line = raw_lines[i]
+        marked_line = rich_line.html_safe
+
+        matches.each do |match|
+          marker = StringRegexMarker.new(raw_line, marked_line)
+
+          regex = /#{Regexp.escape(match[:content])}/
+
+          marked_line = marker.mark(regex) do |text, left:, right:|
+            "#{match[:start]}#{text}#{match[:end]}"
+          end
+        end
+
+        marked_line
+      end
+
+      highlighted_lines.join.html_safe
+    end
   end
 end
diff --git a/lib/gitlab/string_range_marker.rb b/lib/gitlab/string_range_marker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..94fba0a221a181346c96048914b4f578dab1bf48
--- /dev/null
+++ b/lib/gitlab/string_range_marker.rb
@@ -0,0 +1,102 @@
+module Gitlab
+  class StringRangeMarker
+    attr_accessor :raw_line, :rich_line
+
+    def initialize(raw_line, rich_line = raw_line)
+      @raw_line = raw_line
+      @rich_line = ERB::Util.html_escape(rich_line)
+    end
+
+    def mark(marker_ranges)
+      return rich_line unless marker_ranges
+
+      rich_marker_ranges = []
+      marker_ranges.each do |range|
+        # Map the inline-diff range based on the raw line to character positions in the rich line
+        rich_positions = position_mapping[range].flatten
+        # Turn the array of character positions into ranges
+        rich_marker_ranges.concat(collapse_ranges(rich_positions))
+      end
+
+      offset = 0
+      # Mark each range
+      rich_marker_ranges.each_with_index do |range, i|
+        offset_range = (range.begin + offset)..(range.end + offset)
+        original_text = rich_line[offset_range]
+
+        text = yield(original_text, left: i == 0, right: i == rich_marker_ranges.length - 1)
+
+        rich_line[offset_range] = text
+
+        offset += text.length - original_text.length
+      end
+
+      rich_line.html_safe
+    end
+
+    private
+
+    # Mapping of character positions in the raw line, to the rich (highlighted) line
+    def position_mapping
+      @position_mapping ||= begin
+        mapping = []
+        rich_pos = 0
+        (0..raw_line.length).each do |raw_pos|
+          rich_char = rich_line[rich_pos]
+
+          # The raw and rich lines are the same except for HTML tags,
+          # so skip over any `<...>` segment
+          while rich_char == '<'
+            until rich_char == '>'
+              rich_pos += 1
+              rich_char = rich_line[rich_pos]
+            end
+
+            rich_pos += 1
+            rich_char = rich_line[rich_pos]
+          end
+
+          # multi-char HTML entities in the rich line correspond to a single character in the raw line
+          if rich_char == '&'
+            multichar_mapping = [rich_pos]
+            until rich_char == ';'
+              rich_pos += 1
+              multichar_mapping << rich_pos
+              rich_char = rich_line[rich_pos]
+            end
+
+            mapping[raw_pos] = multichar_mapping
+          else
+            mapping[raw_pos] = rich_pos
+          end
+
+          rich_pos += 1
+        end
+
+        mapping
+      end
+    end
+
+    # Takes an array of integers, and returns an array of ranges covering the same integers
+    def collapse_ranges(positions)
+      return [] if positions.empty?
+      ranges = []
+
+      start = prev = positions[0]
+      range = start..prev
+      positions[1..-1].each do |pos|
+        if pos == prev + 1
+          range = start..pos
+          prev = pos
+        else
+          ranges << range
+          start = prev = pos
+          range = start..prev
+        end
+      end
+      ranges << range
+
+      ranges
+    end
+  end
+end
diff --git a/lib/gitlab/string_regex_marker.rb b/lib/gitlab/string_regex_marker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7ebf1c0428ca2786435c73e98b0489a56b7f71e3
--- /dev/null
+++ b/lib/gitlab/string_regex_marker.rb
@@ -0,0 +1,13 @@
+module Gitlab
+  class StringRegexMarker < StringRangeMarker
+    def mark(regex, group: 0, &block)
+      regex_match = raw_line.match(regex)
+      return rich_line unless regex_match
+
+      begin_index, end_index = regex_match.offset(group)
+      name_range = begin_index..(end_index - 1)
+
+      super([name_range], &block)
+    end
+  end
+end
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index a6d2ea11fcc697c2e619e55692f74fdbc0e04563..7fdcd1148aa2d9a387242c724e3fcf45064bec27 100644
--- a/spec/lib/banzai/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -130,6 +130,15 @@ describe Banzai::Filter::AutolinkFilter, lib: true do
 
       doc = filter("See #{link}...")
       expect(doc.at_css('a').text).to eq link
+
+      doc = filter("See #{link}\"")
+      expect(doc.at_css('a').text).to eq link
+
+      doc = filter("See #{link}'")
+      expect(doc.at_css('a').text).to eq link
+
+      doc = filter("See #{link})")
+      expect(doc.at_css('a').text).to eq link
     end
 
     it 'does not include trailing HTML entities' do
diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d562f81fab83d8502e36e566ad88ba05d5ade441
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
@@ -0,0 +1,62 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::CartfileLinker, lib: true do
+  describe '.support?' do
+    it 'supports Cartfile' do
+      expect(described_class.support?('Cartfile')).to be_truthy
+    end
+
+    it 'supports Cartfile.private' do
+      expect(described_class.support?('Cartfile.private')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('test.Cartfile')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "Cartfile" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        # Require version 2.3.1 or later
+        github "ReactiveCocoa/ReactiveCocoa" >= 2.3.1
+
+        # Require version 1.x
+        github "Mantle/Mantle" ~> 1.0    # (1.0 or later, but less than 2.0)
+
+        # Require exactly version 0.4.1
+        github "jspahrsummers/libextobjc" == 0.4.1
+
+        # Use the latest version
+        github "jspahrsummers/xcconfigs"
+
+        # Use the branch
+        github "jspahrsummers/xcconfigs" "branch"
+
+        # Use a project from GitHub Enterprise
+        github "https://enterprise.local/ghe/desktop/git-error-translations"
+
+        # Use a project from any arbitrary server, on the "development" branch
+        git "https://enterprise.local/desktop/git-error-translations2.git" "development"
+
+        # Use a local project
+        git "file:///directory/to/project" "branch"
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("ReactiveCocoa/ReactiveCocoa", "https://github.com/ReactiveCocoa/ReactiveCocoa"))
+      expect(subject).to include(link("Mantle/Mantle", "https://github.com/Mantle/Mantle"))
+      expect(subject).to include(link("jspahrsummers/libextobjc", "https://github.com/jspahrsummers/libextobjc"))
+      expect(subject).to include(link("jspahrsummers/xcconfigs", "https://github.com/jspahrsummers/xcconfigs"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..92bdf0fb37092d64f6f06315cf22bad7b84d5dfe
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
@@ -0,0 +1,67 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::ComposerJsonLinker, lib: true do
+  describe '.support?' do
+    it 'supports composer.json' do
+      expect(described_class.support?('composer.json')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('composer.json.example')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "composer.json" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        {
+            "name": "laravel/laravel",
+            "description": "The Laravel Framework.",
+            "keywords": ["framework", "laravel"],
+            "license": "MIT",
+            "type": "project",
+            "require": {
+                "php": ">=5.5.9",
+                "laravel/framework": "5.2.*"
+            },
+            "require-dev": {
+                "fzaninotto/faker": "~1.4",
+                "mockery/mockery": "0.9.*",
+                "phpunit/phpunit": "~4.0",
+                "symfony/css-selector": "2.8.*|3.0.*",
+                "symfony/dom-crawler": "2.8.*|3.0.*"
+            }
+        }
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links the module name" do
+      expect(subject).to include(link("laravel/laravel", "https://packagist.org/packages/laravel/laravel"))
+    end
+
+    it "links the license" do
+      expect(subject).to include(link("MIT", "http://spdx.org/licenses/MIT.html"))
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("laravel/framework", "https://packagist.org/packages/laravel/framework"))
+      expect(subject).to include(link("fzaninotto/faker", "https://packagist.org/packages/fzaninotto/faker"))
+      expect(subject).to include(link("mockery/mockery", "https://packagist.org/packages/mockery/mockery"))
+      expect(subject).to include(link("phpunit/phpunit", "https://packagist.org/packages/phpunit/phpunit"))
+      expect(subject).to include(link("symfony/css-selector", "https://packagist.org/packages/symfony/css-selector"))
+      expect(subject).to include(link("symfony/dom-crawler", "https://packagist.org/packages/symfony/dom-crawler"))
+    end
+
+    it "doesn't link core dependencies" do
+      expect(subject).not_to include(link("php", "https://packagist.org/packages/php"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8f9d995fef603ea1e7c9e144b4b9a476282e051c
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
@@ -0,0 +1,59 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::GemfileLinker, lib: true do
+  describe '.support?' do
+    it 'supports Gemfile' do
+      expect(described_class.support?('Gemfile')).to be_truthy
+    end
+
+    it 'supports gems.rb' do
+      expect(described_class.support?('gems.rb')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('Gemfile.lock')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "Gemfile" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        source 'https://rubygems.org'
+
+        gem "rails", '4.2.6', github: "rails/rails"
+        gem 'rails-deprecated_sanitizer', '~> 1.0.3'
+
+        # Responders respond_to and respond_with
+        gem 'responders', '~> 2.0', :github => 'rails/responders'
+
+        # Specify a sprockets version due to increased performance
+        # See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069
+        gem 'sprockets', '~> 3.6.0'
+
+        # Default values for AR models
+        gem 'default_value_for', '~> 3.0.0'
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("rails", "https://rubygems.org/gems/rails"))
+      expect(subject).to include(link("rails-deprecated_sanitizer", "https://rubygems.org/gems/rails-deprecated_sanitizer"))
+      expect(subject).to include(link("responders", "https://rubygems.org/gems/responders"))
+      expect(subject).to include(link("sprockets", "https://rubygems.org/gems/sprockets"))
+      expect(subject).to include(link("default_value_for", "https://rubygems.org/gems/default_value_for"))
+    end
+
+    it "links GitHub repos" do
+      expect(subject).to include(link("rails/rails", "https://github.com/rails/rails"))
+      expect(subject).to include(link("rails/responders", "https://github.com/rails/responders"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a60fda533d3e2126ece858762381516bf8b75918
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::GemspecLinker, lib: true do
+  describe '.support?' do
+    it 'supports *.gemspec' do
+      expect(described_class.support?('gitlab_git.gemspec')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('.gemspec.example')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "gitlab_git.gemspec" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        Gem::Specification.new do |s|
+          s.name        = 'gitlab_git'
+          s.version     = `cat VERSION`
+          s.date        = Time.now.strftime("%Y-%m-%d")
+          s.summary     = "Gitlab::Git library"
+          s.description = "GitLab wrapper around git objects"
+          s.authors     = ["Dmitriy Zaporozhets"]
+          s.email       = 'dmitriy.zaporozhets@gmail.com'
+          s.license     = 'MIT'
+          s.files       = `git ls-files lib/`.split("\n") << 'VERSION'
+          s.homepage    =
+            'https://gitlab.com/gitlab-org/gitlab_git'
+
+          s.add_dependency("github-linguist", "~> 4.7.0")
+          s.add_dependency("activesupport", "~> 4.0")
+          s.add_dependency("rugged", "~> 0.24.0")
+          s.add_runtime_dependency("charlock_holmes", "~> 0.7.3")
+          s.add_development_dependency("listen", "~> 3.0.6")
+        end
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links the gem name" do
+      expect(subject).to include(link("gitlab_git", "https://rubygems.org/gems/gitlab_git"))
+    end
+
+    it "links the license" do
+      expect(subject).to include(link("MIT", "http://spdx.org/licenses/MIT.html"))
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("github-linguist", "https://rubygems.org/gems/github-linguist"))
+      expect(subject).to include(link("activesupport", "https://rubygems.org/gems/activesupport"))
+      expect(subject).to include(link("rugged", "https://rubygems.org/gems/rugged"))
+      expect(subject).to include(link("charlock_holmes", "https://rubygems.org/gems/charlock_holmes"))
+      expect(subject).to include(link("listen", "https://rubygems.org/gems/listen"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a9ae721f05e3710e5585869405cd367361d3fa6a
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
@@ -0,0 +1,67 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::GodepsJsonLinker, lib: true do
+  describe '.support?' do
+    it 'supports Godeps.json' do
+      expect(described_class.support?('Godeps.json')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('Godeps.json.example')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "Godeps.json" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        {
+        	"ImportPath": "gitlab.com/gitlab-org/gitlab-pages",
+        	"GoVersion": "go1.5",
+        	"Packages": [
+        		"./..."
+        	],
+        	"Deps": [
+        		{
+        			"ImportPath": "github.com/kardianos/osext",
+        			"Rev": "efacde03154693404c65e7aa7d461ac9014acd0c"
+        		},
+        		{
+        			"ImportPath": "github.com/stretchr/testify/assert",
+        			"Rev": "1297dc01ed0a819ff634c89707081a4df43baf6b"
+        		},
+        		{
+        			"ImportPath": "github.com/stretchr/testify/require",
+        			"Rev": "1297dc01ed0a819ff634c89707081a4df43baf6b"
+        		},
+        		{
+        			"ImportPath": "golang.org/x/crypto/ssh/terminal",
+        			"Rev": "1351f936d976c60a0a48d728281922cf63eafb8d"
+        		},
+        		{
+        			"ImportPath": "golang.org/x/net/http2",
+        			"Rev": "b4e17d61b15679caf2335da776c614169a1b4643"
+        		}
+        	]
+        }
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links the package name" do
+      expect(subject).to include(link("gitlab.com/gitlab-org/gitlab-pages", "http://gitlab.com/gitlab-org/gitlab-pages"))
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("github.com/kardianos/osext", "http://github.com/kardianos/osext"))
+      expect(subject).to include(link("github.com/stretchr/testify/assert", "http://github.com/stretchr/testify/tree/master/assert"))
+      expect(subject).to include(link("github.com/stretchr/testify/require", "http://github.com/stretchr/testify/tree/master/require"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..49d917ff80ba60a375409c0648e19335f2c01801
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
@@ -0,0 +1,70 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::PackageJsonLinker, lib: true do
+  describe '.support?' do
+    it 'supports package.json' do
+      expect(described_class.support?('package.json')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('package.json.example')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "package.json" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        {
+          "name": "module-name",
+          "version": "10.3.1",
+          "dependencies": {
+            "primus": "*",
+            "async": "~0.8.0",
+            "express": "4.2.x",
+            "winston": "git://github.com/flatiron/winston#master",
+            "bigpipe": "bigpipe/pagelet",
+            "plates": "https://github.com/flatiron/plates/tarball/master"
+          },
+          "devDependencies": {
+            "vows": "^0.7.0",
+            "assume": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
+            "pre-commit": "*"
+          },
+          "license": "MIT"
+        }
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links the module name" do
+      expect(subject).to include(link("module-name", "https://npmjs.com/package/module-name"))
+    end
+
+    it "links the license" do
+      expect(subject).to include(link("MIT", "http://spdx.org/licenses/MIT.html"))
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("primus", "https://npmjs.com/package/primus"))
+      expect(subject).to include(link("async", "https://npmjs.com/package/async"))
+      expect(subject).to include(link("express", "https://npmjs.com/package/express"))
+      expect(subject).to include(link("winston", "https://npmjs.com/package/winston"))
+      expect(subject).to include(link("bigpipe", "https://npmjs.com/package/bigpipe"))
+      expect(subject).to include(link("plates", "https://npmjs.com/package/plates"))
+      expect(subject).to include(link("vows", "https://npmjs.com/package/vows"))
+      expect(subject).to include(link("assume", "https://npmjs.com/package/assume"))
+      expect(subject).to include(link("pre-commit", "https://npmjs.com/package/pre-commit"))
+    end
+
+    it "links GitHub repos" do
+      expect(subject).to include(link("bigpipe/pagelet", "https://github.com/bigpipe/pagelet"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..049306f9bd91e8a228541af3f2deef5da8557c2e
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
@@ -0,0 +1,36 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::PodfileLinker, lib: true do
+  describe '.support?' do
+    it 'supports Podfile' do
+      expect(described_class.support?('Podfile')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('Podfile.lock')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "Podfile" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        target 'MyApp'
+        pod 'AFNetworking', '~> 1.0'
+        pod "RestKit/CoreData"
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("AFNetworking", "https://cocoapods.org/pods/AFNetworking"))
+      expect(subject).to include(link("RestKit/CoreData", "https://cocoapods.org/pods/RestKit"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a508def683f0e18a130da7def59626333c1a85ae
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
@@ -0,0 +1,88 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::PodspecJsonLinker, lib: true do
+  describe '.support?' do
+    it 'supports *.podspec.json' do
+      expect(described_class.support?('Reachability.podspec.json')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('.podspec.json.example')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "AFNetworking.podspec.json" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        {
+          "name": "AFNetworking",
+          "version": "2.0.0",
+          "license": "MIT",
+          "summary": "A delightful iOS and OS X networking framework.",
+          "homepage": "https://github.com/AFNetworking/AFNetworking",
+          "authors": {
+            "Mattt Thompson": "m@mattt.me"
+          },
+          "source": {
+            "git": "https://github.com/AFNetworking/AFNetworking.git",
+            "tag": "2.0.0",
+            "submodules": true
+          },
+          "requires_arc": true,
+          "platforms": {
+            "ios": "6.0",
+            "osx": "10.8"
+          },
+          "public_header_files": "AFNetworking/*.h",
+          "subspecs": [
+            {
+              "name": "NSURLConnection",
+              "dependencies": {
+                "AFNetworking/Serialization": [
+
+                ],
+                "AFNetworking/Reachability": [
+
+                ],
+                "AFNetworking/Security": [
+
+                ]
+              },
+              "source_files": [
+                "AFNetworking/AFURLConnectionOperation.{h,m}",
+                "AFNetworking/AFHTTPRequestOperation.{h,m}",
+                "AFNetworking/AFHTTPRequestOperationManager.{h,m}"
+              ]
+            }
+          ]
+        }
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links the gem name" do
+      expect(subject).to include(link("AFNetworking", "https://cocoapods.org/pods/AFNetworking"))
+    end
+
+    it "links the license" do
+      expect(subject).to include(link("MIT", "http://spdx.org/licenses/MIT.html"))
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("AFNetworking/Serialization", "https://cocoapods.org/pods/AFNetworking"))
+      expect(subject).to include(link("AFNetworking/Reachability", "https://cocoapods.org/pods/AFNetworking"))
+      expect(subject).to include(link("AFNetworking/Security", "https://cocoapods.org/pods/AFNetworking"))
+    end
+
+    it "doesn't link subspec names" do
+      expect(subject).not_to include(link("NSURLConnection", "https://cocoapods.org/pods/NSURLConnection"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..597a6393c18c306a2300cdf30fbe345cce618e54
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
@@ -0,0 +1,61 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::PodspecLinker, lib: true do
+  describe '.support?' do
+    it 'supports *.podspec' do
+      expect(described_class.support?('Reachability.podspec')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('.podspec.example')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "Reachability.podspec" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        Pod::Spec.new do |spec|
+          spec.name         = 'Reachability'
+          spec.version      = '3.1.0'
+          spec.license      = { :type => 'BSD' }
+          spec.license      = "MIT"
+          spec.license      = { type: 'Apache-1.0' }
+          spec.homepage     = 'https://github.com/tonymillion/Reachability'
+          spec.authors      = { 'Tony Million' => 'tonymillion@gmail.com' }
+          spec.summary      = 'ARC and GCD Compatible Reachability Class for iOS and OS X.'
+          spec.source       = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' }
+          spec.source_files = 'Reachability.{h,m}'
+          spec.framework    = 'SystemConfiguration'
+
+          spec.dependency 'AFNetworking', '~> 1.0'
+          spec.dependency 'RestKit/CoreData', '~> 0.20.0'
+          spec.ios.dependency 'MBProgressHUD', '~> 0.5'
+        end
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links the gem name" do
+      expect(subject).to include(link("Reachability", "https://cocoapods.org/pods/Reachability"))
+    end
+
+    it "links the license" do
+      expect(subject).to include(link("BSD", "http://spdx.org/licenses/BSD.html"))
+      expect(subject).to include(link("MIT", "http://spdx.org/licenses/MIT.html"))
+      expect(subject).to include(link("Apache-1.0", "http://spdx.org/licenses/Apache-1.0.html"))
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("AFNetworking", "https://cocoapods.org/pods/AFNetworking"))
+      expect(subject).to include(link("RestKit/CoreData", "https://cocoapods.org/pods/RestKit"))
+      expect(subject).to include(link("MBProgressHUD", "https://cocoapods.org/pods/MBProgressHUD"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a334bb38db149f878f6e3143e86be171603d0e9f
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
@@ -0,0 +1,83 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
+  describe '.support?' do
+    it 'supports requirements.txt' do
+      expect(described_class.support?('requirements.txt')).to be_truthy
+    end
+
+    it 'supports doc-requirements.txt' do
+      expect(described_class.support?('doc-requirements.txt')).to be_truthy
+    end
+
+    it 'does not support other files' do
+      expect(described_class.support?('requirements')).to be_falsey
+    end
+  end
+
+  describe '#link' do
+    let(:file_name) { "requirements.txt" }
+
+    let(:file_content) do
+      <<-CONTENT.strip_heredoc
+        #
+        ####### example-requirements.txt #######
+        #
+        ###### Requirements without Version Specifiers ######
+        nose
+        nose-cov
+        beautifulsoup4
+        #
+        ###### Requirements with Version Specifiers ######
+        #   See https://www.python.org/dev/peps/pep-0440/#version-specifiers
+        docopt == 0.6.1             # Version Matching. Must be version 0.6.1
+        keyring >= 4.1.1            # Minimum version 4.1.1
+        coverage != 3.5             # Version Exclusion. Anything except version 3.5
+        Mopidy-Dirble ~= 1.1        # Compatible release. Same as >= 1.1, == 1.*
+        #
+        ###### Refer to other requirements files ######
+        -r other-requirements.txt
+        #
+        #
+        ###### A particular file ######
+        ./downloads/numpy-1.9.2-cp34-none-win32.whl
+        http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl
+        #
+        ###### Additional Requirements without Version Specifiers ######
+        #   Same as 1st section, just here to show that you can put things in any order.
+        rejected
+        green
+        #
+
+        Jinja2>=2.3
+        Pygments>=1.2
+        Sphinx>=1.3
+        docutils>=0.7
+        markupsafe
+      CONTENT
+    end
+
+    subject { Gitlab::Highlight.highlight(file_name, file_content, nowrap: false) }
+
+    def link(name, url)
+      %{<a href="#{url}" rel="nofollow noreferrer" target="_blank">#{name}</a>}
+    end
+
+    it "links dependencies" do
+      expect(subject).to include(link("nose", "https://pypi.python.org/pypi/nose"))
+      expect(subject).to include(link("nose-cov", "https://pypi.python.org/pypi/nose-cov"))
+      expect(subject).to include(link("beautifulsoup4", "https://pypi.python.org/pypi/beautifulsoup4"))
+      expect(subject).to include(link("docopt", "https://pypi.python.org/pypi/docopt"))
+      expect(subject).to include(link("keyring", "https://pypi.python.org/pypi/keyring"))
+      expect(subject).to include(link("coverage", "https://pypi.python.org/pypi/coverage"))
+      expect(subject).to include(link("Mopidy-Dirble", "https://pypi.python.org/pypi/Mopidy-Dirble"))
+      expect(subject).to include(link("rejected", "https://pypi.python.org/pypi/rejected"))
+      expect(subject).to include(link("green", "https://pypi.python.org/pypi/green"))
+      expect(subject).to include(link("Jinja2", "https://pypi.python.org/pypi/Jinja2"))
+      expect(subject).to include(link("Pygments", "https://pypi.python.org/pypi/Pygments"))
+      expect(subject).to include(link("Sphinx", "https://pypi.python.org/pypi/Sphinx"))
+      expect(subject).to include(link("docutils", "https://pypi.python.org/pypi/docutils"))
+      expect(subject).to include(link("markupsafe", "https://pypi.python.org/pypi/markupsafe"))
+    end
+  end
+end
diff --git a/spec/lib/gitlab/dependency_linker_spec.rb b/spec/lib/gitlab/dependency_linker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3d1cfbcfbf710082817d5f28750b420ec6aad08e
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker_spec.rb
@@ -0,0 +1,85 @@
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker, lib: true do
+  describe '.link' do
+    it 'links using GemfileLinker' do
+      blob_name = 'Gemfile'
+
+      expect(described_class::GemfileLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using GemspecLinker' do
+      blob_name = 'gitlab_git.gemspec'
+
+      expect(described_class::GemspecLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using PackageJsonLinker' do
+      blob_name = 'package.json'
+
+      expect(described_class::PackageJsonLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using ComposerJsonLinker' do
+      blob_name = 'composer.json'
+
+      expect(described_class::ComposerJsonLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using PodfileLinker' do
+      blob_name = 'Podfile'
+
+      expect(described_class::PodfileLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using PodspecLinker' do
+      blob_name = 'Reachability.podspec'
+
+      expect(described_class::PodspecLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using PodspecJsonLinker' do
+      blob_name = 'AFNetworking.podspec.json'
+
+      expect(described_class::PodspecJsonLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using CartfileLinker' do
+      blob_name = 'Cartfile'
+
+      expect(described_class::CartfileLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using GodepsJsonLinker' do
+      blob_name = 'Godeps.json'
+
+      expect(described_class::GodepsJsonLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+
+    it 'links using RequirementsTxtLinker' do
+      blob_name = 'requirements.txt'
+
+      expect(described_class::RequirementsTxtLinker).to receive(:link)
+
+      described_class.link(blob_name, nil, nil)
+    end
+  end
+end
diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
index 198ff977f2418f7729f35846ed5e4bea5dda9503..418521ae65061022cb1f821fa09fc958c271d4fa 100644
--- a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
+++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
@@ -1,26 +1,26 @@
 require 'spec_helper'
 
 describe Gitlab::Diff::InlineDiffMarker, lib: true do
-  describe '#inline_diffs' do
+  describe '#mark' do
     context "when the rich text is html safe" do
-      let(:raw)  { "abc 'def'" }
-      let(:rich) { %{<span class="abc">abc</span><span class="space"> </span><span class="def">&#39;def&#39;</span>}.html_safe }
+      let(:raw)  { "abc <def>" }
+      let(:rich) { %{<span class="abc">abc</span><span class="space"> </span><span class="def">&lt;def&gt;</span>}.html_safe }
       let(:inline_diffs) { [2..5] }
-      let(:subject) { Gitlab::Diff::InlineDiffMarker.new(raw, rich).mark(inline_diffs) }
+      let(:subject) { described_class.new(raw, rich).mark(inline_diffs) }
 
       it 'marks the inline diffs' do
-        expect(subject).to eq(%{<span class="abc">ab<span class='idiff left'>c</span></span><span class="space"><span class='idiff'> </span></span><span class="def"><span class='idiff right'>&#39;d</span>ef&#39;</span>})
+        expect(subject).to eq(%{<span class="abc">ab<span class='idiff left'>c</span></span><span class="space"><span class='idiff'> </span></span><span class="def"><span class='idiff right'>&lt;d</span>ef&gt;</span>})
         expect(subject).to be_html_safe
       end
     end
 
-    context "when the text text is not html safe" do
-      let(:raw)  { "abc 'def'" }
+    context "when the text is not html safe" do
+      let(:raw)  { "abc <def>" }
       let(:inline_diffs) { [2..5] }
-      let(:subject) { Gitlab::Diff::InlineDiffMarker.new(raw).mark(inline_diffs) }
+      let(:subject) { described_class.new(raw).mark(inline_diffs) }
 
       it 'marks the inline diffs' do
-        expect(subject).to eq(%{ab<span class='idiff left right'>c &#39;d</span>ef&#39;})
+        expect(subject).to eq(%{ab<span class='idiff left right'>c &lt;d</span>ef&gt;})
         expect(subject).to be_html_safe
       end
     end
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index e49799ad10502bcd8d926db39d7c6f7cf63bdd88..4f6ae157d6e50d6e4bffa866ace0ba229c17df3d 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
@@ -57,4 +57,76 @@ describe Gitlab::Highlight, lib: true do
       end
     end
   end
+
+  describe '#highlight' do
+    subject { described_class.highlight(file_name, file_content) }
+
+    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
+
+    it 'links dependencies via DependencyLinker' do
+      expect(Gitlab::DependencyLinker).to receive(:link).
+        with('file.name', 'Contents', anything).and_call_original
+
+      described_class.highlight('file.name', 'Contents')
+    end
+  end
 end
diff --git a/spec/lib/gitlab/string_range_marker_spec.rb b/spec/lib/gitlab/string_range_marker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7c77772b3f6e80b54724f94a33a76db467310bb1
--- /dev/null
+++ b/spec/lib/gitlab/string_range_marker_spec.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+
+describe Gitlab::StringRangeMarker, lib: true do
+  describe '#mark' do
+    context "when the rich text is html safe" do
+      let(:raw)  { "abc <def>" }
+      let(:rich) { %{<span class="abc">abc</span><span class="space"> </span><span class="def">&lt;def&gt;</span>}.html_safe }
+      let(:inline_diffs) { [2..5] }
+      subject do
+        described_class.new(raw, rich).mark(inline_diffs) do |text, left:, right:|
+          "LEFT#{text}RIGHT"
+        end
+      end
+
+      it 'marks the inline diffs' do
+        expect(subject).to eq(%{<span class="abc">abLEFTcRIGHT</span><span class="space">LEFT RIGHT</span><span class="def">LEFT&lt;dRIGHTef&gt;</span>})
+        expect(subject).to be_html_safe
+      end
+    end
+
+    context "when the rich text is not html safe" do
+      let(:raw)  { "abc <def>" }
+      let(:inline_diffs) { [2..5] }
+      subject do
+        described_class.new(raw).mark(inline_diffs) do |text, left:, right:|
+          "LEFT#{text}RIGHT"
+        end
+      end
+
+      it 'marks the inline diffs' do
+        expect(subject).to eq(%{abLEFTc &lt;dRIGHTef&gt;})
+        expect(subject).to be_html_safe
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/string_regex_marker_spec.rb b/spec/lib/gitlab/string_regex_marker_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2f5cf6c6e3b61645320ac9169c94483aab6545f3
--- /dev/null
+++ b/spec/lib/gitlab/string_regex_marker_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Gitlab::StringRegexMarker, lib: true do
+  describe '#mark' do
+    let(:raw)  { %{"name": "AFNetworking"} }
+    let(:rich) { %{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>}.html_safe }
+    subject do
+      described_class.new(raw, rich).mark(/"[^"]+":\s*"(?<name>[^"]+)"/, group: :name) do |text, left:, right:|
+        %{<a href="#">#{text}</a>}
+      end
+    end
+
+    it 'marks the inline diffs' do
+      expect(subject).to eq(%{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"<a href="#">AFNetworking</a>"</span>})
+      expect(subject).to be_html_safe
+    end
+  end
+end