Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions lib/ex_doc/formatter/html/autolink.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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 "<B706848484895T>"
Expand Down Expand Up @@ -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}]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could also support :custom links.
such as we do with the rest of the funtions.

assert project_doc("[the :erlang.apply/2 function](`Kernel.apply/2`)", %{}) ==
"[the :erlang.apply/2 function](#{@elixir_docs}elixir/Kernel.html#apply/2)"

      assert project_doc("[the :erlang.apply/2 function](`Kernel.apply/2`)", %{}) ==
               "[the :erlang.apply/2 function](#{@elixir_docs}elixir/Kernel.html#apply/2)"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fertapric convinced me that custom links can sometimes hurt IEx experience so how about we hold off on this change for now?

Copy link
Contributor

@eksperimental eksperimental Oct 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fertapric convinced me that custom links can sometimes hurt IEx experience so how about we hold off on this change for now?

Is that something that we could improve on the IEx side?


@doc """
Autolinks any documentation in the project.
Expand Down Expand Up @@ -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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with :mix_task, but I'm wondering. Is there any other kind of task?
Should it be called just task?
is there a equivalent of a Mix Task in Erlang?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are Rebar tasks which we might similarly support one day but not sure how hard that would be.

Copy link
Contributor

@eksperimental eksperimental Oct 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beacuse I'm seeing we are calling {:mix_task, :elixir, :normal}, it is a bit redundant I guess.
{:mix_task, :elixir, :normal}, and in the future we could call {:task, :erlang, :normal} looks better IMO

My only concern is that there are other tools other than Mix and Rebar for creating tasks that we may support

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for mix_task because that's also what we call it in the sidebar.

#
# It accepts a list of `options` used in the replacement functions.
# - `:aliases
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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))

Expand Down
39 changes: 39 additions & 0 deletions test/ex_doc/formatter/html/autolink_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as the 1st step I skipped it but autolinking these too can be nice, see screenshot.

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)"
Expand Down
3 changes: 3 additions & 0 deletions test/ex_doc/formatter/html_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ defmodule ExDoc.Formatter.HTMLTest do

assert content =~
~r{<a href="https://hexdocs.pm/elixir/typespecs.html#basic-types"><code(\sclass="inline")?>atom/0</code></a>}

assert content =~
~r{<a href="https://hexdocs.pm/mix/Mix.Tasks.Compile.Elixir.html"><code(\sclass="inline")?>mix compile.elixir</code></a>}
end

test "without any other content" do
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
`==/2`
[`===`](`Kernel.===/2`)
`t:atom/0`
`mix compile.elixir`

## `Header` sample

Expand Down