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
38 changes: 29 additions & 9 deletions lib/ex_doc/formatter/html/autolink.ex
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ defmodule ExDoc.Formatter.HTML.Autolink do
timeout: 0
]

@basic_type_strings (for {f, a} <- @basic_types, do: "t:#{f}/#{a}")
@built_in_type_strings (for {f, a} <- @built_in_types, do: "t:#{f}/#{a}")
@special_form_strings (for {f, a} <- Kernel.SpecialForms.__info__(:macros), do: "#{f}/#{a}")

@doc """
Receives a list of module nodes and autolink all docs and typespecs.
"""
Expand Down Expand Up @@ -94,15 +98,15 @@ defmodule ExDoc.Formatter.HTML.Autolink do
moduledoc =
if module.doc do
module.doc
|> local_doc(locals)
|> local_doc(locals, extension, lib_dirs)
|> project_doc(modules, module.id, extension, lib_dirs)
end

docs = for module_node <- module.docs do
doc =
if module_node.doc do
module_node.doc
|> local_doc(locals)
|> local_doc(locals, extension, lib_dirs)
|> project_doc(modules, module.id, extension, lib_dirs)
end
%{module_node | doc: doc}
Expand All @@ -112,7 +116,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do
doc =
if module_node.doc do
module_node.doc
|> local_doc(locals)
|> local_doc(locals, extension, lib_dirs)
|> project_doc(modules, module.id, extension, lib_dirs)
end
%{module_node | doc: doc}
Expand Down Expand Up @@ -339,15 +343,29 @@ defmodule ExDoc.Formatter.HTML.Autolink do
or trailing `]`, e.g. `[my link link/1 is here](url)`, the fun/arity
will get translated to the new href of the function.
"""
def local_doc(bin, locals) when is_binary(bin) do
def local_doc(bin, locals, extension \\ ".html", lib_dirs \\ elixir_lib_dirs()) when is_binary(bin) do
Copy link
Member Author

@wojtekmach wojtekmach Dec 16, 2017

Choose a reason for hiding this comment

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

Kernel.SpecialForms calls are neither local as in local_doc nor remote as in elixir_functions calls, so having this logic doesn't quite fit in either function.

Another approach is to combine local_doc and elixir_functions into one function, see: https://github.com/elixir-lang/ex_doc/blob/wm-autolink-bak/lib/ex_doc/formatter/html/autolink.ex#L347

fun_re = Regex.source(~r{(([ct]:)?([a-z_]+[A-Za-z_\d]*[\\?\\!]?|[\{\}=&\\|\\.<>~*^@\\+\\%\\!-]+)/\d+)})
regex = ~r{(?<!\[)`\s*(#{fun_re})\s*`(?!\])}
elixir_doc = get_source(Kernel, [], lib_dirs)

Regex.replace(regex, bin, fn all, match ->
if match in locals do
{prefix, _, function, arity} = split_function(match)
"[`#{function}/#{arity}`](##{prefix}#{enc_h function}/#{arity})"
else
all
{prefix, _, function, arity} = split_function(match)

cond do
match in locals ->
"[`#{function}/#{arity}`](##{prefix}#{enc_h function}/#{arity})"

match in @basic_type_strings ->
"[`#{function}/#{arity}`](#{elixir_doc}#{@basic_types_page})"

match in @built_in_type_strings ->
"[`#{function}/#{arity}`](#{elixir_doc}#{@built_in_types_page})"

match in @special_form_strings ->
"[`#{function}/#{arity}`](#{elixir_doc}Kernel.SpecialForms#{extension}##{prefix}#{enc_h function}/#{arity})"

true ->
all
end
end)
end
Expand Down Expand Up @@ -406,8 +424,10 @@ defmodule ExDoc.Formatter.HTML.Autolink do
cond do
match in project_funs ->
"[`#{module}.#{function}/#{arity}`](#{module}#{extension}##{prefix}#{enc_h function}/#{arity})"

doc = lib_dirs_to_doc("Elixir." <> module, lib_dirs) ->
"[`#{module}.#{function}/#{arity}`](#{doc}#{module}.html##{prefix}#{enc_h function}/#{arity})"

true ->
all
end
Expand Down
12 changes: 12 additions & 0 deletions test/ex_doc/formatter/html/autolink_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ defmodule ExDoc.Formatter.HTML.AutolinkTest do
# links to types without arity don't work
assert Autolink.local_doc("`t:my_type`", ["t:my_type/0"]) == "`t:my_type`"
end
test "autolink to basic and built-in types" do
assert Autolink.local_doc("`t:atom/0`", []) ==
"[`atom/0`](#{@elixir_docs}elixir/typespecs.html#basic-types)"

assert Autolink.local_doc("`t:term/0`", []) ==
"[`term/0`](#{@elixir_docs}elixir/typespecs.html#built-in-types)"
end

test "autolink doesn't create links for undefined functions in docs" do
assert Autolink.local_doc("`example/1`", ["example/2"]) == "`example/1`"
Expand All @@ -54,6 +61,11 @@ defmodule ExDoc.Formatter.HTML.AutolinkTest do
assert Autolink.local_doc("`{}/1`", ["{}/1"]) === "[`{}/1`](#%7B%7D/1)"
end

test "autolink creates links for Kernel special forms" do
assert Autolink.local_doc("`<<>>/1`", []) ===
"[`<<>>/1`](#{@elixir_docs}elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1)"
end

# elixir_functions

test "autolink functions Module.fun/arity in docs" do
Expand Down
2 changes: 2 additions & 0 deletions test/ex_doc/formatter/html/templates_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
assert content =~ ~s[A public type]
assert content =~ ~s[add(#{integer}, <a href="#t:opaque/0">opaque</a>()) :: #{integer}]
refute content =~ ~s[minus(#{integer}, #{integer}) :: #{integer}]
assert content =~ ~s[Basic type: <a href=\"https://hexdocs.pm/elixir/typespecs.html#basic-types\"><code class=\"inline\">atom/0</code></a>.]
assert content =~ ~s[Special form: <a href=\"https://hexdocs.pm/elixir/Kernel.SpecialForms.html#import/2\"><code class=\"inline\">import/2</code></a>.]
end

test "module_page outputs summaries" do
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/types_and_specs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ defmodule TypesAndSpecs do

@moduledoc """
Types and tests fixture.

Basic type: `t:atom/0`.
Special form: `import/2`.
"""

@typedoc "A public type"
Expand Down