elixir-lang/ex_doc

Admonition does not work in Erlang @doc blocks

RoadRunnr opened this issue · 8 comments

Placing a Admonition block into an Erlang @doc chunk does not work.

This:

%% @doc
%% > #### Error {: .error}
%% >
%% > This syntax will render an error block

results in this output:

> #### Error {: .error} > > This syntax will render an error block

I know that the goal is to push Erlang users to markup docs. But that needs support for the -doc and that is only available in OTP-27. That means that everything that wants or needs to support older versions is stuck with @doc tags and it would be great if they would work too.

The @doc syntax is used by edoc and is can be translated using the edoc_doclet_chunks and edoc_layout_chunks to something that ex_doc understands. So the functionality to do this would have to be in edoc and not ex_doc.

Thoughm I'm not sure what it is you are trying to achieve? Do you want to write Markdown in edoc comments? or is it only the admonition that you are after?

Only the admonition (in whatever syntax).

Have you tried doing it with xhtml?

%% @doc
%% <blockquote><h4 class="error">Error</h4> This syntax will render an error block</blockquote>

Another solution might be to do what we do with peer, that is -ifdef the -doc attribute. That way it will be possible to use the new features, but still compile the code with an older compiler.

I've tried the <blockquote> approach (on OTP-26.2) and it doesn't work. The resulting doc chunk contains the <blockquote> tags a text and not as tag:

                     {p,[],[<<"<blockquote>">>]},
                      {h4,[{class,<<"error">>}],[<<"Error">>]},
                      {p,[],
                         [<<"This syntax will render an error block</blockquote>>

ex_doc does not understand the embedded <blockquote> in that chunk.

The -ifdef approach seems to be the only viable option and I was hopping I could avoid that.

How do you call ex_doc? When I use this module:

-module(t).
-export([go/0]).
%% @doc
%% <blockquote><h4 class="error">Error</h4>aaa</blockquote>
go() -> ok.

and call

Erlang/OTP 26 [erts-14.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Eshell V14.2 (press Ctrl+G to abort, type help(). for help)
1> edoc:run(["t.erl"],[{doclet, edoc_doclet_chunks},{layout, edoc_layout_chunks}]).
t.erl: warning: 'blockquote' is not allowed - skipping tag, extracting content
ok

the output is:

2> {ok, B} = file:read_file("chunks/t.chunk"), binary_to_term(B).
{docs_v1,[{file,"t.erl"},{location,1}],
         erlang,<<"application/erlang+html">>,#{},#{},
         [{{function,go,0},
           [{file,"t.erl"},{location,7}],
           [<<"go()">>],
           #{<<"en">> =>
                 [{h4,[{class,<<"error">>}],[<<"Error">>]},<<"aaa">>]},
           #{}}]}

In Erlang/27 it does however work as it should.

> erl
Erlang/OTP 27 [RELEASE CANDIDATE 3] [erts-14.2.5] [source-c1c93fb293] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Eshell V14.2.5 (press Ctrl+G to abort, type help(). for help)
1> edoc:run(["t.erl"],[{doclet, edoc_doclet_chunks},{layout, edoc_layout_chunks}]).
ok
2> f(), {ok, B} = file:read_file("chunks/t.chunk"), binary_to_term(B).
{docs_v1,[{file,"t.erl"},{location,1}],
         erlang,<<"application/erlang+html">>,#{},#{},
         [{{function,go,0},
           [{file,"t.erl"},{location,7}],
           [<<"go()">>],
           #{<<"en">> =>
                 [{blockquote,[],
                              [{h4,[{class,<<"error">>}],[<<"Error">>]},
                               <<"aaa">>]}]},
           #{}}]}

Because of this PR: erlang/otp#8077

Indeed, that is an interesting question and it took me a while to retrace what I have done to reproduce the problem.

It needs:

  • rebar3 3.22.0+build.5279.ref1b6297d
  • OTP 27-rc2 Erlang/OTP 27 [RELEASE CANDIDATE 2] [erts-14.2.3] [source-44a98ee] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]
  • rebar3_ex_doc v0.2.22

t.erl is moved into a dummy application to build it with rebar3.

Then:

$ rebar3 ex_doc
===> Fetching rebar3_ex_doc v0.2.22
===> Analyzing applications...
===> Compiling rebar3_ex_doc
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling t
===> "/usr/src/erlang/nnas_gw/_checkouts/eradius/1/_build/docs/lib/t/ebin/t.app" is missing description entry
===> Running edoc for t
t.erl: warning: 'blockquote' is not allowed - skipping tag, extracting content
===> Running ex_doc for t
 rebar3 as docs shell --start-clean
===> No entry for profile docs in config.
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling t
===> "/usr/src/erlang/nnas_gw/_checkouts/eradius/1/_build/docs/lib/t/ebin/t.app" is missing description entry
Erlang/OTP 27 [RELEASE CANDIDATE 2] [erts-14.2.3] [source-44a98ee] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]

Eshell V14.2.3 (press Ctrl+G to abort, type help(). for help)
1> rp(code:get_doc(t)).
{ok,{docs_v1,[{file,"t.erl"},{location,1}],
             erlang,<<"application/erlang+html">>,#{},#{},
             [{{function,go,0},
               [{file,"t.erl"},{location,10}],
               [<<"go()">>],
               #{<<"en">> =>
                     [{p,[],[<<"Test <blockquote>">>]},
                      {h4,[{class,<<"error">>}],[<<"Error">>]},
                      {p,[],[<<"aaa</blockquote>">>]}]},
               #{signature =>
                     [{attribute,9,spec,
                                 {{go,0},
                                  [{type,9,'fun',[{type,9,product,[]},{atom,9,ok}]}]}}]}}]}}
ok
2> 

The t.erl that I'm using is:

-module(t).

-export([go/0]).

-ignore_xref([?MODULE]).

%% @doc Test
%% <blockquote><h4 class="error">Error</h4>aaa</blockquote>
-spec go() -> ok.
go() -> ok.

rebar.config:

{plugins, [rebar3_ex_doc]}.

Ah, you are using Erlang 27-rc2, not 26.2 as you stated above. That is why you get that output. erlang/otp#8077 was merged after rc3, so you need to use latest master to get those changes.

If you use 26.2 the <blockquote> will be removed as in my example above.

I did a change in 27.0-rc1 for how unrecognized HTML elements are handled, that is why <blockquote> shows up as part of the string instead of being skipped. I was thinking that it was better to just include the unsupported HTML tag as a string instead of skipping it, but maybe I was wrong about that.

I will close this as it is not an ExDoc issue. :) I did a quick try on Erlang/OTP 27 and it works as desired. I am not sure if there is appetite to backport this to earlier EDoc versions.