diff --git a/lib/ex_doc/formatter/html/autolink.ex b/lib/ex_doc/formatter/html/autolink.ex
index aa8c3557f..21b094181 100644
--- a/lib/ex_doc/formatter/html/autolink.ex
+++ b/lib/ex_doc/formatter/html/autolink.ex
@@ -5,7 +5,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do
import ExDoc.Formatter.HTML.Templates, only: [h: 1, enc_h: 1]
@type language :: :elixir | :erlang | :markdown
- @type kind :: :function | :module
+ @type kind :: :function | :module | :mix_task
@type link_type :: :normal | :custom
@backtick_token ""
@@ -106,7 +106,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do
language <- [:elixir, :erlang],
kind <- [:module, :function] do
{kind, language, link_type}
- end)
+ end) ++ [{:mix_task, :elixir, :normal}]
@doc """
Autolinks any documentation in the project.
@@ -325,7 +325,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do
#
# `language` can be: `:elixir`, `:erlang` or `:markdown`.
#
- # `kind` is either `:function` or `:module`.
+ # `kind` is either `:function`, `:module`, or `:mix_task`.
#
# It accepts a list of `options` used in the replacement functions.
# - `:aliases
@@ -447,6 +447,37 @@ defmodule ExDoc.Formatter.HTML.Autolink do
end
end
+ defp replace_fun(:mix_task, :elixir, :normal, options) do
+ extension = options[:extension] || ".html"
+ lib_dirs = options[:lib_dirs] || default_lib_dirs(:elixir)
+ module_id = options[:module_id] || nil
+ modules_refs = options[:modules_refs] || []
+
+ fn all, text, "mix " <> task_name ->
+ task_module =
+ task_name
+ |> String.split(".")
+ |> Enum.map(&Macro.camelize/1)
+ |> Enum.join(".")
+
+ match = "Mix.Tasks." <> task_module
+
+ cond do
+ match == module_id ->
+ "[#{text}](#{match}#{extension}#content)"
+
+ match in modules_refs ->
+ "[#{text}](#{match}#{extension})"
+
+ doc = module_docs(:elixir, match, lib_dirs) ->
+ "[#{text}](#{doc}#{match}.html)"
+
+ true ->
+ all
+ end
+ end
+ end
+
## Helpers
defp default_text(_, :custom, _match, _pmfa, text),
@@ -721,6 +752,12 @@ defmodule ExDoc.Formatter.HTML.Autolink do
}x
end
+ defp re_kind_language(:mix_task, :elixir) do
+ ~r{
+ mix\ ([a-z][a-z0-9\._]*)
+ }x
+ end
+
defp re_kind_language_link_type(kind, language, link_type) do
source = Regex.source(re_kind_language(kind, language))
diff --git a/test/ex_doc/formatter/html/autolink_test.exs b/test/ex_doc/formatter/html/autolink_test.exs
index 9a280e9a6..42e8d0247 100644
--- a/test/ex_doc/formatter/html/autolink_test.exs
+++ b/test/ex_doc/formatter/html/autolink_test.exs
@@ -327,6 +327,45 @@ defmodule ExDoc.Formatter.HTML.AutolinkTest do
end
end
+ describe "Mix tasks" do
+ test "autolinks built-in tasks" do
+ assert project_doc("`mix test`", %{}) ==
+ "[`mix test`](#{@elixir_docs}mix/Mix.Tasks.Test.html)"
+ end
+
+ test "autolinks custom tasks" do
+ assert project_doc("`mix foo.bar.baz`", %{modules_refs: ["Mix.Tasks.Foo.Bar.Baz"]}) ==
+ "[`mix foo.bar.baz`](Mix.Tasks.Foo.Bar.Baz.html)"
+ end
+
+ test "autolinks task in the same module" do
+ assert project_doc("`mix foo`", %{
+ modules_refs: ["Mix.Tasks.Foo"],
+ module_id: "Mix.Tasks.Foo"
+ }) == "[`mix foo`](Mix.Tasks.Foo.html#content)"
+ end
+
+ test "autolinks tasks from dependencies" do
+ # Using Hex (archive) as we don't depend on any packages with Mix tasks
+ lib_dirs = [{Application.app_dir(:hex), "#{@elixir_docs}hex/"}]
+
+ assert project_doc("`mix hex.publish`", %{
+ docs_refs: ["MyModule"],
+ module_id: "MyModule",
+ extension: ".html",
+ lib_dirs: lib_dirs
+ }) == "[`mix hex.publish`](#{@elixir_docs}hex/Mix.Tasks.Hex.Publish.html)"
+ end
+
+ test "does not autolink task with arguments" do
+ assert project_doc("`mix test test/`", %{}) == "`mix test test/`"
+ end
+
+ test "does not autolink unknown task" do
+ assert project_doc("`mix foo`", %{}) == "`mix foo`"
+ end
+ end
+
describe "Erlang modules" do
test "autolinks to Erlang modules" do
assert project_doc("`:erlang`", %{}) == "[`:erlang`](#{@erlang_docs}erlang.html)"
diff --git a/test/ex_doc/formatter/html_test.exs b/test/ex_doc/formatter/html_test.exs
index 2d962f71f..3926b12ea 100644
--- a/test/ex_doc/formatter/html_test.exs
+++ b/test/ex_doc/formatter/html_test.exs
@@ -268,6 +268,9 @@ defmodule ExDoc.Formatter.HTMLTest do
assert content =~
~r{atom/0
}
+
+ assert content =~
+ ~r{mix compile.elixir
}
end
test "without any other content" do
diff --git a/test/fixtures/README.md b/test/fixtures/README.md
index b7a855250..e005988d3 100644
--- a/test/fixtures/README.md
+++ b/test/fixtures/README.md
@@ -5,6 +5,7 @@
`==/2`
[`===`](`Kernel.===/2`)
`t:atom/0`
+`mix compile.elixir`
## `Header` sample