diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asciideck_block_parser.erl | 13 | ||||
-rw-r--r-- | src/asciideck_inline_pass.erl | 17 | ||||
-rw-r--r-- | src/asciideck_to_html.erl | 58 |
3 files changed, 71 insertions, 17 deletions
diff --git a/src/asciideck_block_parser.erl b/src/asciideck_block_parser.erl index e0faceb..09d3f1a 100644 --- a/src/asciideck_block_parser.erl +++ b/src/asciideck_block_parser.erl @@ -1018,12 +1018,13 @@ para(St) -> fold_para(eof) -> done; -fold_para(Line0) -> - case trim(Line0) of +fold_para(Line) -> + case trim(Line) of <<>> -> done; <<"+">> -> done; + <<"//", _/bits>> -> done; %% @todo Detect delimited block or list. - Line -> {more, Line} + _ -> {more, Line} end. -ifdef(TEST). @@ -1042,6 +1043,12 @@ para_test() -> [{paragraph, _, LoremIpsum, _}] = parse(<< LoremIpsum/binary, "\n">>), %% Paragraph followed by end of file with no trailing line break.. [{paragraph, _, LoremIpsum, _}] = parse(LoremIpsum), + %% Paragraph followed by list continuation. + [{paragraph, _, LoremIpsum, _}, {list_item_continuation, _, _, _}] + = parse(<<LoremIpsum/binary, "\n+">>), + %% Paragraph followed by comment. + [{paragraph, _, LoremIpsum, _}, {comment_line, _, <<"@todo Double check.">>, _}] + = parse(<<LoremIpsum/binary, "\n// @todo Double check.">>), %% Two paragraphs. [{paragraph, _, LoremIpsum, _}, {paragraph, _, LoremIpsum, _}] = parse(<< diff --git a/src/asciideck_inline_pass.erl b/src/asciideck_inline_pass.erl index 3ed79b1..469c9f3 100644 --- a/src/asciideck_inline_pass.erl +++ b/src/asciideck_inline_pass.erl @@ -170,7 +170,10 @@ direct_link(Data, Prefix) -> {Target0, Rest0} = while(fun(C) -> (C =/= $[) andalso (C =/= $\s) andalso (C =/= $\t) andalso (C =/= $\r) andalso (C =/= $\n) + andalso (C =/= $,) end, Data), + %% The link must be more than just the prefix. + false = Target0 =:= <<>>, Target = <<Prefix/binary, Target0/binary>>, %% It is optionally followed by a caption. Otherwise %% the link itself is the caption. @@ -191,6 +194,13 @@ direct_link(Data, Prefix) -> -ifdef(TEST). http_link_test() -> + <<"Incomplete http: link">> = inline(<<"Incomplete http: link">>), + [ + {link, #{ + target := <<"http://example.org:8080">> + }, <<"http://example.org:8080">>, _}, + <<", continued">> + ] = inline(<<"http://example.org:8080, continued">>), [ <<"If you have ">>, {link, #{ @@ -221,6 +231,13 @@ https_link(<<"https:", Rest/bits>>, Prev) when ?IS_BOUNDARY(Prev) -> -ifdef(TEST). https_link_test() -> + <<"Incomplete https: link">> = inline(<<"Incomplete https: link">>), + [ + {link, #{ + target := <<"https://example.org:8080">> + }, <<"https://example.org:8080">>, _}, + <<", continued">> + ] = inline(<<"https://example.org:8080, continued">>), [ <<"If you have ">>, {link, #{ diff --git a/src/asciideck_to_html.erl b/src/asciideck_to_html.erl index b904f3a..6f8a393 100644 --- a/src/asciideck_to_html.erl +++ b/src/asciideck_to_html.erl @@ -71,21 +71,42 @@ ast_node(Node={Type, _, _, _}) -> listing_block -> listing_block(Node); list -> list(Node); table -> table(Node); + block_macro -> block_macro(Node); comment_line -> comment_line(Node); - _ -> - io:format("Ignored AST node ~p~n", [Node]), - [] + _ -> ast_error({unknown_type, Node}) end - catch _:_ -> - io:format("Ignored AST node ~p~n", [Node]), - [] + catch C:E -> + ast_error({crash, C, E, erlang:get_stacktrace(), Node}) end. +ast_error(Error) -> + [ + "<p class=\"asciideck-error\">", + html_encode(unicode:characters_to_binary(io_lib:format("~p", [Error]))), + "</p>" + ]. + %% Section titles. -section_title({section_title, #{level := Level}, Title, _}) -> +section_title({section_title, Attrs=#{level := Level}, Title, _}) -> LevelC = $1 + Level, - ["<h", LevelC, ">", inline(Title), "</h", LevelC, ">\n"]. + ID = case Attrs of + #{<<"id">> := ID0} -> ID0; + _ -> id_from_title(Title) + end, + ["<h", LevelC, " id=\"", ID, "\">", inline(Title), "</h", LevelC, ">\n"]. + +%% Asciidoc User Guide 8.4.2 +%% @todo Handle cases where the title is repeated in the same document. +id_from_title(Title) -> + ID0 = unicode:characters_to_binary(string:to_lower(unicode:characters_to_list(Title))), + ID1 = <<if + C >= $a, C =< $z -> <<C/utf8>>; + C >= $0, C =< $9 -> <<C/utf8>>; + true -> <<$_>> + end || <<C/utf8>> <= ID0>>, + ID = string:strip(unicode:characters_to_list(ID1), both, $_), + [$_, unicode:characters_to_binary(ID)]. %% Paragraphs. @@ -129,11 +150,10 @@ bulleted_list_item({list_item, _, [{paragraph, _, Text, _}|AST], _}) -> "</li>\n" ]. -labeled_list_item({list_item, #{label := Label}, [{paragraph, _, Text, _}|AST], _}) -> +labeled_list_item({list_item, #{label := Label}, AST, _}) -> [ "<dt>", inline(Label), "</dt>\n", "<dd>", - inline(Text), "\n", ast(AST), "</dd>\n" ]. @@ -160,6 +180,13 @@ table_body_cells(Cells) -> [["<td>", inline(Text), "</td>\n"] || {cell, _, Text, _} <- Cells]. +%% Block macros. + +block_macro({block_macro, #{name := <<"image">>, + target := Target, 1 := Caption}, _, _}) -> + ["<img src=\"", html_encode(Target), "\" " + "alt=\"", html_encode(Caption), "\"/>"]. + %% Comment lines are printed in the generated file %% but are not visible in viewers. @@ -170,9 +197,10 @@ comment_line({comment_line, _, Text, _}) -> inline(Text) when is_binary(Text) -> html_encode(Text); -inline({Link, #{target := Target}, Text, _}) - when Link =:= link; Link =:= xref -> +inline({link, #{target := Target}, Text, _}) -> ["<a href=\"", html_encode(Target), "\">", html_encode(Text), "</a>"]; +inline({xref, #{id := ID}, Text, _}) -> + ["<a href=\"#", html_encode(ID), "\">", html_encode(Text), "</a>"]; inline({emphasized, _, Text, _}) -> ["<em>", inline(Text), "</em>"]; inline({strong, _, Text, _}) -> @@ -187,5 +215,7 @@ html_encode(Text) -> $& -> <<"&">>; $< -> <<"<">>; $> -> <<">">>; - _ -> <<C>> - end || <<C>> <= Text>>. + $" -> <<""">>; + $' -> <<"'">>; + _ -> <<C/utf8>> + end || <<C/utf8>> <= Text>>. |