From cace6427c0e96703a9944b54fb5e5643cc36fa24 Mon Sep 17 00:00:00 2001 From: Wojtek Mach Date: Sat, 16 Dec 2017 17:34:35 +0100 Subject: [PATCH] Autolink basic/built-in types and special forms in docs --- lib/ex_doc/formatter/html/autolink.ex | 38 ++++++++++++++----- test/ex_doc/formatter/html/autolink_test.exs | 12 ++++++ test/ex_doc/formatter/html/templates_test.exs | 2 + test/fixtures/types_and_specs.ex | 3 ++ 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/lib/ex_doc/formatter/html/autolink.ex b/lib/ex_doc/formatter/html/autolink.ex index 9cd11b82f..f5e4fecbf 100644 --- a/lib/ex_doc/formatter/html/autolink.ex +++ b/lib/ex_doc/formatter/html/autolink.ex @@ -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. """ @@ -94,7 +98,7 @@ 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 @@ -102,7 +106,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} @@ -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} @@ -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 fun_re = Regex.source(~r{(([ct]:)?([a-z_]+[A-Za-z_\d]*[\\?\\!]?|[\{\}=&\\|\\.<>~*^@\\+\\%\\!-]+)/\d+)}) regex = ~r{(? - 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 @@ -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 diff --git a/test/ex_doc/formatter/html/autolink_test.exs b/test/ex_doc/formatter/html/autolink_test.exs index 0dd25c9c4..0c0515dfe 100644 --- a/test/ex_doc/formatter/html/autolink_test.exs +++ b/test/ex_doc/formatter/html/autolink_test.exs @@ -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`" @@ -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 diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index 24c966f66..469d31682 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -271,6 +271,8 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do assert content =~ ~s[A public type] assert content =~ ~s[add(#{integer}, opaque()) :: #{integer}] refute content =~ ~s[minus(#{integer}, #{integer}) :: #{integer}] + assert content =~ ~s[Basic type: atom/0.] + assert content =~ ~s[Special form: import/2.] end test "module_page outputs summaries" do diff --git a/test/fixtures/types_and_specs.ex b/test/fixtures/types_and_specs.ex index faa4bd2d2..9d5d3728e 100644 --- a/test/fixtures/types_and_specs.ex +++ b/test/fixtures/types_and_specs.ex @@ -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"