diff options
author | Loïc Hoguin <[email protected]> | 2018-06-11 12:38:07 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2018-06-11 12:38:07 +0200 |
commit | 976dfc5d92e3e23f356cb19f17ff51b22c75e634 (patch) | |
tree | 2589053dfc25bd6f38afdd9a06bdbbf63680464c /src/asciideck_to_html.erl | |
parent | 524777054be30c848c1883ffd15b245c29f73004 (diff) | |
download | asciideck-976dfc5d92e3e23f356cb19f17ff51b22c75e634.tar.gz asciideck-976dfc5d92e3e23f356cb19f17ff51b22c75e634.tar.bz2 asciideck-976dfc5d92e3e23f356cb19f17ff51b22c75e634.zip |
Add scripts/asciidoc ad-hoc replacement and HTML output
This allows me to build ninenines.eu using Asciideck and
while the results are not perfect yet things are looking
pretty, pretty good. Adding source-highlight support,
showing images and fixing a few minor issues should bring
me to the point where I can drop Asciidoc.
Diffstat (limited to 'src/asciideck_to_html.erl')
-rw-r--r-- | src/asciideck_to_html.erl | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/asciideck_to_html.erl b/src/asciideck_to_html.erl new file mode 100644 index 0000000..c6fbbff --- /dev/null +++ b/src/asciideck_to_html.erl @@ -0,0 +1,187 @@ +%% Copyright (c) 2018, Loïc Hoguin <[email protected]> +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +%% @todo https://www.gnu.org/software/src-highlite/source-highlight.html + +-module(asciideck_to_html). + +-export([translate/2]). + +translate(AST, Opts) -> + Output0 = ast(AST), + Output1 = header_footer(Output0, Opts), + {CompressExt, Output} = case Opts of + #{compress := gzip} -> {".gz", zlib:gzip(Output1)}; + _ -> {"", Output1} + end, + case Opts of + #{outdir := Path, outfile := Filename} -> + file:write_file(binary_to_list(iolist_to_binary( + [Path, "/", Filename, ".html", CompressExt])), Output); + #{outdir := Path} -> + Filename = filename_from_ast(AST), + file:write_file(binary_to_list(iolist_to_binary( + [Path, "/", Filename, ".html", CompressExt])), Output); + _ -> + Output + end. + +header_footer(Body, _Opts) -> + [ + "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + "<head>\n" + "<meta charset=\"utf-8\"/>\n" + "<title>TODO title</title>\n" %% @todo + "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://ninenines.eu/css/99s.css?r=1\"/>\n" + "</head>\n" + "<body>\n", + Body, + "</body>\n" + "</html>\n" + ]. + +filename_from_ast([{section_title, #{level := 0}, Filename, _}|_]) -> + Filename. + +%% Loop over all types of AST nodes. + +ast(AST) -> + fold(AST, fun ast_node/1). + +fold(AST, Fun) -> + lists:reverse(lists:foldl( + fun(Node, Acc) -> [Fun(Node)|Acc] end, + [], AST)). + +ast_node(Node={Type, _, _, _}) -> + try + case Type of + section_title -> section_title(Node); + paragraph -> paragraph(Node); + listing_block -> listing_block(Node); + list -> list(Node); + table -> table(Node); + comment_line -> comment_line(Node); + _ -> + io:format("Ignored AST node ~p~n", [Node]), + [] + end + catch _:_ -> + io:format("Ignored AST node ~p~n", [Node]), + [] + end. + +%% Section titles. + +section_title({section_title, #{level := Level}, Title, _}) -> + LevelC = $1 + Level, + ["<h", LevelC, ">", inline(Title), "</h", LevelC, ">\n"]. + +%% Paragraphs. + +paragraph({paragraph, _, Text, _}) -> + ["<p>", inline(Text), "</p>\n"]. + +%% Listing blocks. + +listing_block({listing_block, Attrs, Listing, _}) -> + [ + "<div class=\"listingblock\">", + case Attrs of + #{<<"title">> := Title} -> + ["<div class=\"title\">", inline(Title), "</div>\n"]; + _ -> + [] + end, + "<div class=\"content\"><pre>", + html_encode(Listing), + "</pre></div></div>\n" + ]. + +%% Lists. + +list({list, #{type := bulleted}, Items, _}) -> + ["<ul>", fold(Items, fun bulleted_list_item/1), "</ul>\n"]; +list({list, #{type := labeled}, Items, _}) -> + ["<dl>", fold(Items, fun labeled_list_item/1), "</dl>\n"]. + +bulleted_list_item({list_item, _, [{paragraph, _, Text, _}|AST], _}) -> + [ + "<li>", + inline(Text), "\n", + ast(AST), + "</li>\n" + ]. + +labeled_list_item({list_item, #{label := Label}, [{paragraph, _, Text, _}|AST], _}) -> + [ + "<dt>", inline(Label), "</dt>\n", + "<dd>", + inline(Text), "\n", + ast(AST), + "</dd>\n" + ]. + +%% Tables. + +table({table, _, [{row, _, Head, _}|Rows], _}) -> + [ + "<table rules=\"all\" width=\"100%\" frame=\"border\" cellspacing=\"0\" cellpadding=\"4\">\n" + "<thead><tr>", table_head(Head), "</tr></thead>" + "<tbody>", table_body(Rows), "</tbody>" + "</table>\n" + ]. + +table_head(Cells) -> + [["<th>", inline(Text), "</th>\n"] + || {cell, _, Text, _} <- Cells]. + +table_body(Rows) -> + [["<tr>", table_body_cells(Cells), "</tr>\n"] + || {row, _, Cells, _} <- Rows]. + +table_body_cells(Cells) -> + [["<td>", inline(Text), "</td>\n"] + || {cell, _, Text, _} <- Cells]. + +%% Comment lines are printed in the generated file +%% but are not visible in viewers. + +comment_line({comment_line, _, Text, _}) -> + ["<!-- ", html_encode(Text), "-->\n"]. + +%% Inline formatting. + +inline(Text) when is_binary(Text) -> + html_encode(Text); +inline({Link, #{target := Target}, Text, _}) + when Link =:= link; Link =:= xref -> + ["<a href=\"", html_encode(Target), "\">", html_encode(Text), "</a>"]; +inline({emphasized, _, Text, _}) -> + ["<em>", inline(Text), "</em>"]; +inline({strong, _, Text, _}) -> + ["<strong>", inline(Text), "</strong>"]; +inline({inline_literal_passthrough, _, Text, _}) -> + ["<code>", inline(Text), "</code>"]; +inline(Text) when is_list(Text) -> + [inline(T) || T <- Text]. + +html_encode(Text) -> + <<case C of + $& -> <<"&">>; + $< -> <<"<">>; + $> -> <<">">>; + _ -> <<C>> + end || <<C>> <= Text>>. |