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