Permalink
Browse files

first commit; not yet working right

  • Loading branch information...
0 parents commit 8da5e783aff38be9b401d831fab6bdbea54ab603 Ulf Wiger committed Oct 22, 2010
6 NOTICE
@@ -0,0 +1,6 @@
+EDown is derived from code in EDoc, and designed to be an extension
+to EDoc.
+
+EDoc was written by Richard Carlsson, (c) 2001-2007 Richard Carlsson.
+It is part of Erlang/OTP (http://www.erlang.org) and available
+via the Erlang Public License (EPL).
43 README
@@ -0,0 +1,43 @@
+EDown - EDoc Extension for generating Github-flavored Markdown
+==============================================================
+
+<ulf.wiger@erlang-solutions.com>
+
+Status:
+------
+More-or-less readable Markdown can be generated.
+A doclet needs to be written that also creates
+a markdown-based index and overview. Currently, the
+edoc_doclet creates an index.html and overview.html,
+which do not point to the .md files.
+
+To generate markdown edoc, run:
+
+<pre>
+edoc:application(App, [{doclet, edown_doclet} | OtherOpts]).
+</pre>
+
+The `edown_xmerl` module is used as an xmerl export module.
+It converts xmerl's "simple xml" to Markdown syntax. Note that
+GH-flavored Markdown allows HTML markup (at least common tags),
+but doesn't expand markdown markup inside HTML markup, so the
+`edown_xmerl` module has to know the context in which it operates.
+
+NOTE
+====
+EDoc provides a plugin structure, so that one may specify own
+layout modules, export modules, and doclets. However, there is
+some overlap esp. between the layout and doclet modules, and
+several functions are expected to produce files on their own.
+This causes a problem for EDown, since it cannot handle frames.
+Instead, it would probably like to create one overview file with
+different sections. It would have been better to have a framework
+where some plugin functions identify the different files to be
+written, and the outline of each, other plugins convert to suitable
+content representation (e.g. HTML or Markdown), and EDoc then
+writes the files necessary.
+
+For now, EDown focuses on producing reasonable Markdown, rather
+than complying fully with the plugin framework. That is, the
+edown_doclet module will not go out of its way to function together
+with any other layout module than edown_layout, and vice versa.
3 doc/edoc-info
@@ -0,0 +1,3 @@
+{application,edown}.
+{packages,[]}.
+{modules,[edown_doclet,edown_layout,edown_lib,edown_test,edown_xmerl]}.
146 doc/edown_doclet.md
@@ -0,0 +1,146 @@
+Module edown_doclet
+===================
+
+<div class="navbar">
+<a name="#navbar_top"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+
+#Module edown_doclet#
+* [Description](#description)
+* [Data Types](#types)
+* [Function Index](#index)
+* [Function Details](#functions)
+EDoc Doclet module for producing Github-flavored Markdown.
+Copyright © 2010 Erlang Solutions Ltd
+__Authors:__ Ulf Wiger ([`ulf.wiger@erlang-solutions.com`](mailto:ulf.wiger@erlang-solutions.com)).
+
+##<a name="description">Description</a>##
+EDoc Doclet module for producing Github-flavored Markdown.
+
+##<a name="types">Data Types</a>##
+
+<a name="type-doclet_gen"></a>
+
+
+###doclet_gen()##
+
+`doclet_gen() = #doclet_gen{sources = [string()], app = [no_app()](#type-no_app) | atom(), packages = [atom()], modules = [atom()], modules = [atom()], filemap = function()}`
+<a name="type-doclet_toc"></a>
+
+
+###doclet_toc()##
+
+`doclet_toc() = #doclet_gen{paths = [string()], indir = string()}`
+<a name="type-edoc_context"></a>
+
+
+###edoc_context()##
+
+`edoc_context() = #context{dir = string(), env = [edoc_lib:edoc_env()](edoc_lib.html#type-edoc_env), opts = [term()]}`
+<a name="type-no_app"></a>
+
+
+###no_app()##
+
+__abstract datatype__: `no_app()`
+A value used to mark absence of an Erlang application
+ context. Use the macro `NO_APP` defined in
+ [`edoc_doclet.hrl`](../include/edoc_doclet.hrl)
+ to produce this value.
+
+##<a name="index">Function Index</a>##
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#run-2">run/2</a></td><td>Main doclet entry point.</td></tr></table>
+
+<a name="functions"></a>
+
+
+##Function Details##
+
+<a name="run-2"></a>
+
+
+###run/2##
+
+
+`run(Command::[doclet_gen()](#type-doclet_gen) | [doclet_toc()](#type-doclet_toc), Ctxt::[edoc_context()](#type-edoc_context)) -> ok`
+
+
+Main doclet entry point.
+
+
+Also see [`edoc:layout/2`](edoc.html#layout-2) for layout-related options, and
+ [`edoc:get_doc/2`](edoc.html#get_doc-2) for options related to reading source
+files.
+
+ Options:
+
+
+
+###`{file_suffix, string()}`##
+
+
+Specifies the suffix used for output files. The default value is
+ `".md"`.
+
+
+
+###`{hidden, bool()}`##
+
+
+If the value is `true`, documentation of hidden modules and
+ functions will also be included. The default value is `false`.
+
+
+
+###`{overview, [edoc:filename()](edoc.html#type-filename)}`##
+
+
+Specifies the name of the overview-file. By default, this doclet
+ looks for a file `"overview.edoc"` in the target directory.
+
+
+
+###`{private, bool()}`##
+
+
+If the value is `true`, documentation of private modules and
+ functions will also be included. The default value is `false`.
+
+
+
+###`{stylesheet, string()}`##
+
+
+Specifies the URI used for referencing the stylesheet. The
+ default value is `"stylesheet.css"`. If an empty string is
+ specified, no stylesheet reference will be generated.
+
+
+
+###`{stylesheet_file, [edoc:filename()](edoc.html#type-filename)}`##
+
+
+Specifies the name of the stylesheet file. By default, this
+ doclet uses the file `"stylesheet.css"` in the `priv`
+ subdirectory of the EDoc installation directory. The named file
+ will be copied to the target directory.
+
+
+
+###`{title, string()}`##
+
+
+Specifies the title of the overview-page.
+
+
+<div class="navbar">
+<a name="#navbar_bottom"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+_Generated by EDoc, Oct 22 2010, 15:27:00._
121 doc/edown_layout.md
@@ -0,0 +1,121 @@
+Module edown_layout
+===================
+
+<div class="navbar">
+<a name="#navbar_top"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+
+#Module edown_layout#
+* [Description](#description)
+* [Function Index](#index)
+* [Function Details](#functions)
+Github-flavored Markdown layout module for EDoc.
+Copyright © 2010 Erlang Solutions Ltd
+__Authors:__ Ulf Wiger ([`ulf.wiger@erlang-solutions.com`](mailto:ulf.wiger@erlang-solutions.com)).
+
+##<a name="description">Description</a>##
+Github-flavored Markdown layout module for EDoc.
+ Derived from `edoc_layout`, which is part of the Erlang/OTP application EDoc.
+ The module is intended to be used together with edoc.
+
+##<a name="index">Function Index</a>##
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#markdown-3">markdown/3</a></td><td></td></tr><tr><td valign="top"><a href="#module-2">module/2</a></td><td>The layout function.</td></tr><tr><td valign="top"><a href="#overview-2">overview/2</a></td><td></td></tr><tr><td valign="top"><a href="#package-2">package/2</a></td><td></td></tr><tr><td valign="top"><a href="#type-1">type/1</a></td><td></td></tr></table>
+
+<a name="functions"></a>
+
+
+##Function Details##
+
+<a name="markdown-3"></a>
+
+
+###markdown/3##
+
+
+`markdown(Title, CSS, Body) -> any()`
+
+<a name="module-2"></a>
+
+
+###module/2##
+
+
+`module(Element, Options) -> any()`
+
+
+The layout function.
+
+ Options to the standard layout:
+
+
+
+###`{index_columns, integer()}`##
+
+
+Specifies the number of column pairs used for the function
+ index tables. The default value is 1.
+
+
+
+###`{stylesheet, string()}`##
+
+
+Specifies the URI used for referencing the stylesheet. The
+ default value is `"stylesheet.css"`. If an empty string is
+ specified, no stylesheet reference will be generated.
+
+
+
+###`{sort_functions, bool()}`##
+
+
+If `true`, the detailed function descriptions are listed by
+ name, otherwise they are listed in the order of occurrence in
+ the source file. The default value is `true`.
+
+
+
+###`{xml_export, Module::atom()}`##
+
+
+Specifies an [`xmerl`](/Users/uwiger/ETC/git/xmerl/doc/index.html) callback module to be
+ used for exporting the documentation. See [`//xmerl/xmerl:export_simple_content/2`](/Users/uwiger/ETC/git/xmerl/doc/xmerl.html#export_simple_content-2) for details.
+
+
+
+__See also:__ [edoc:layout/2](edoc.html#layout-2).
+<a name="overview-2"></a>
+
+
+###overview/2##
+
+
+`overview(E, Options) -> any()`
+
+<a name="package-2"></a>
+
+
+###package/2##
+
+
+`package(E, Options) -> any()`
+
+<a name="type-1"></a>
+
+
+###type/1##
+
+
+`type(E) -> any()`
+
+<div class="navbar">
+<a name="#navbar_bottom"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+_Generated by EDoc, Oct 22 2010, 15:27:00._
45 doc/edown_lib.md
@@ -0,0 +1,45 @@
+Module edown_lib
+================
+
+<div class="navbar">
+<a name="#navbar_top"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+
+#Module edown_lib#
+* [Description](#description)
+* [Function Index](#index)
+* [Function Details](#functions)
+Github-flavored Markdown for EDoc - common support functions.
+Copyright © 2010 Erlang Solutions Ltd
+__Authors:__ Ulf Wiger ([`ulf.wiger@erlang-solutions.com`](mailto:ulf.wiger@erlang-solutions.com)).
+
+##<a name="description">Description</a>##
+Github-flavored Markdown for EDoc - common support functions
+
+##<a name="index">Function Index</a>##
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#export-1">export/1</a></td><td></td></tr></table>
+
+<a name="functions"></a>
+
+
+##Function Details##
+
+<a name="export-1"></a>
+
+
+###export/1##
+
+
+`export(Data) -> any()`
+
+<div class="navbar">
+<a name="#navbar_bottom"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+_Generated by EDoc, Oct 22 2010, 15:27:00._
40 doc/edown_test.md
@@ -0,0 +1,40 @@
+Module edown_test
+=================
+
+<div class="navbar">
+<a name="#navbar_top"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+
+#Module edown_test#
+* [Function Index](#index)
+* [Function Details](#functions)
+
+
+##<a name="index">Function Index</a>##
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#foo-1">foo/1</a></td><td>test module.</td></tr></table>
+
+<a name="functions"></a>
+
+
+##Function Details##
+
+<a name="foo-1"></a>
+
+
+###foo/1##
+
+
+`foo(Context) -> any()`
+
+test module.
+<div class="navbar">
+<a name="#navbar_bottom"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+_Generated by EDoc, Oct 22 2010, 15:27:00._
65 doc/edown_xmerl.md
@@ -0,0 +1,65 @@
+Module edown_xmerl
+==================
+
+<div class="navbar">
+<a name="#navbar_top"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+
+#Module edown_xmerl#
+* [Function Index](#index)
+* [Function Details](#functions)
+
+Copyright © 2010 Erlang Solutions Ltd
+__Authors:__ Ulf Wiger ([`ulf.wiger@erlang-solutions.com`](mailto:ulf.wiger@erlang-solutions.com)).
+
+##<a name="index">Function Index</a>##
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#%23element%23-5">'#element#'/5</a></td><td></td></tr><tr><td valign="top"><a href="#%23root%23-4">'#root#'/4</a></td><td></td></tr><tr><td valign="top"><a href="#%23text%23-1">'#text#'/1</a></td><td></td></tr><tr><td valign="top"><a href="#%23xml-inheritance%23-0">'#xml-inheritance#'/0</a></td><td></td></tr></table>
+
+<a name="functions"></a>
+
+
+##Function Details##
+
+<a name="%23element%23-5"></a>
+
+
+###'#element#'/5##
+
+
+`#element#(Tag, Data, Attrs, Parents, E) -> any()`
+
+<a name="%23root%23-4"></a>
+
+
+###'#root#'/4##
+
+
+`#root#(Data, Attrs, X3, E) -> any()`
+
+<a name="%23text%23-1"></a>
+
+
+###'#text#'/1##
+
+
+`#text#(Text) -> any()`
+
+<a name="%23xml-inheritance%23-0"></a>
+
+
+###'#xml-inheritance#'/0##
+
+
+`#xml-inheritance#() -> any()`
+
+<div class="navbar">
+<a name="#navbar_bottom"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+_Generated by EDoc, Oct 22 2010, 15:27:00._
BIN doc/erlang.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 doc/index.md
@@ -0,0 +1,44 @@
+The edown application
+=====================
+---------
+The edown application
+=====================
+
+<div class="navbar">
+<a name="#navbar_top"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+
+#The edown application#
+---------
+
+<div class="navbar">
+<a name="#navbar_bottom"></a>
+
+<table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table>
+</div>
+
+_Generated by EDoc, Oct 22 2010, 15:27:00._[{h2,[{class,"indextitle"}],["Modules"]},
+ {table,[{width,"100%"},{border,0},{summary,"list of modules"}],
+ ["\n",
+ {tr,[{td,[],
+ [{a,[{href,"edown_doclet.md"},{class,"module"}],
+ ["edown_doclet"]}]}]},
+ "\n",
+ {tr,[{td,[],
+ [{a,[{href,"edown_layout.md"},{class,"module"}],
+ ["edown_layout"]}]}]},
+ "\n",
+ {tr,[{td,[],
+ [{a,[{href,"edown_lib.md"},{class,"module"}],
+ ["edown_lib"]}]}]},
+ "\n",
+ {tr,[{td,[],
+ [{a,[{href,"edown_test.md"},{class,"module"}],
+ ["edown_test"]}]}]},
+ "\n",
+ {tr,[{td,[],
+ [{a,[{href,"edown_xmerl.md"},{class,"module"}],
+ ["edown_xmerl"]}]}]}]}]
55 doc/stylesheet.css
@@ -0,0 +1,55 @@
+/* standard EDoc style sheet */
+body {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ margin-left: .25in;
+ margin-right: .2in;
+ margin-top: 0.2in;
+ margin-bottom: 0.2in;
+ color: #000000;
+ background-color: #ffffff;
+}
+h1,h2 {
+ margin-left: -0.2in;
+}
+div.navbar {
+ background-color: #add8e6;
+ padding: 0.2em;
+}
+h2.indextitle {
+ padding: 0.4em;
+ background-color: #add8e6;
+}
+h3.function,h3.typedecl {
+ background-color: #add8e6;
+ padding-left: 1em;
+}
+div.spec {
+ margin-left: 2em;
+ background-color: #eeeeee;
+}
+a.module,a.package {
+ text-decoration:none
+}
+a.module:hover,a.package:hover {
+ background-color: #eeeeee;
+}
+ul.definitions {
+ list-style-type: none;
+}
+ul.index {
+ list-style-type: none;
+ background-color: #eeeeee;
+}
+
+/*
+ * Minor style tweaks
+ */
+ul {
+ list-style-type: square;
+}
+table {
+ border-collapse: collapse;
+}
+td {
+ padding: 3
+}
BIN rebar
Binary file not shown.
9 rebar.config
@@ -0,0 +1,9 @@
+%% -*- erlang -*-
+{erl_opts, [debug_info]}.
+{xref_checks, [undefined_function_calls]}.
+
+{cover_enabled, true}.
+{eunit_opts, [verbose]}.
+
+{clean_files, ["*~","*/*~","ebin/*.beam"]}.
+
25 src/edown.app.src
@@ -0,0 +1,25 @@
+%% -*- erlang -*-
+%%==============================================================================
+%% Copyright 2010 Erlang Solutions Ltd.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+
+{application, edown,
+ [
+ {vsn, "0.1"},
+ {description, "Github-flavored Markdown extension for EDoc"},
+ {applications, [kernel, stdlib]},
+ {mod, {jobs_app, []}},
+ {env, []}
+ ]}.
479 src/edown_doclet.erl
@@ -0,0 +1,479 @@
+%%==============================================================================
+%% Copyright 2010 Erlang Solutions Ltd.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+%% @author Ulf Wiger <ulf.wiger@erlang-solutions.com>
+%% @copyright 2010 Erlang Solutions Ltd
+%% @end
+%% =====================================================================
+
+%% @doc EDoc Doclet module for producing Github-flavored Markdown.
+
+%% TODO: copy "doc-files" subdirectories, recursively.
+%% TODO: generate summary page of TODO-notes
+%% TODO: generate summary page of deprecated things
+%% TODO: generate decent indexes over modules, methods, records, etc.
+
+-module(edown_doclet).
+
+-export([run/2]).
+
+-import(edoc_report, [report/2, warning/2]).
+
+%% @headerfile "edoc_doclet.hrl"
+-include_lib("edoc/include/edoc_doclet.hrl").
+
+-define(EDOC_APP, edoc).
+-define(DEFAULT_FILE_SUFFIX, ".md").
+-define(INDEX_FILE, "index.md").
+-define(OVERVIEW_FILE, "overview.edoc").
+-define(PACKAGE_SUMMARY, "package-summary.md").
+-define(OVERVIEW_SUMMARY, "overview-summary.md").
+-define(PACKAGES_FRAME, "packages-frame.md").
+-define(MODULES_FRAME, "modules-frame.md").
+-define(STYLESHEET, "stylesheet.css").
+-define(IMAGE, "erlang.png").
+-define(NL, "\n").
+
+-include_lib("xmerl/include/xmerl.hrl").
+
+%% Sources is the list of inputs in the order they were found. Packages
+%% and Modules are sorted lists of atoms without duplicates. (They
+%% usually include the data from the edoc-info file in the target
+%% directory, if it exists.) Note that the "empty package" is never
+%% included in Packages!
+
+%% @spec (Command::doclet_gen() | doclet_toc(), edoc_context()) -> ok
+%% @doc Main doclet entry point.
+%%
+%% Also see {@link edoc:layout/2} for layout-related options, and
+%% {@link edoc:get_doc/2} for options related to reading source
+%% files.
+%%
+%% Options:
+%% <dl>
+%% <dt>{@type {file_suffix, string()@}}
+%% </dt>
+%% <dd>Specifies the suffix used for output files. The default value is
+%% `".md"'.
+%% </dd>
+%% <dt>{@type {hidden, bool()@}}
+%% </dt>
+%% <dd>If the value is `true', documentation of hidden modules and
+%% functions will also be included. The default value is `false'.
+%% </dd>
+%% <dt>{@type {overview, edoc:filename()@}}
+%% </dt>
+%% <dd>Specifies the name of the overview-file. By default, this doclet
+%% looks for a file `"overview.edoc"' in the target directory.
+%% </dd>
+%% <dt>{@type {private, bool()@}}
+%% </dt>
+%% <dd>If the value is `true', documentation of private modules and
+%% functions will also be included. The default value is `false'.
+%% </dd>
+%% <dt>{@type {stylesheet, string()@}}
+%% </dt>
+%% <dd>Specifies the URI used for referencing the stylesheet. The
+%% default value is `"stylesheet.css"'. If an empty string is
+%% specified, no stylesheet reference will be generated.
+%% </dd>
+%% <dt>{@type {stylesheet_file, edoc:filename()@}}
+%% </dt>
+%% <dd>Specifies the name of the stylesheet file. By default, this
+%% doclet uses the file `"stylesheet.css"' in the `priv'
+%% subdirectory of the EDoc installation directory. The named file
+%% will be copied to the target directory.
+%% </dd>
+%% <dt>{@type {title, string()@}}
+%% </dt>
+%% <dd>Specifies the title of the overview-page.
+%% </dd>
+%% </dl>
+
+%% INHERIT-OPTIONS: title/2
+%% INHERIT-OPTIONS: sources/5
+%% INHERIT-OPTIONS: overview/4
+%% INHERIT-OPTIONS: copy_stylesheet/2
+%% INHERIT-OPTIONS: stylesheet/1
+
+run(#doclet_gen{}=Cmd, Ctxt) ->
+ gen(Cmd#doclet_gen.sources,
+ Cmd#doclet_gen.app,
+ Cmd#doclet_gen.packages,
+ Cmd#doclet_gen.modules,
+ Cmd#doclet_gen.filemap,
+ Ctxt);
+run(#doclet_toc{}=Cmd, Ctxt) ->
+ toc(Cmd#doclet_toc.paths, Ctxt).
+
+gen(Sources, App, Packages, Modules, FileMap, Ctxt) ->
+ Dir = Ctxt#context.dir,
+ Env = Ctxt#context.env,
+ Options0 = Ctxt#context.opts,
+ Options = [{layout,edown_layout},
+ {file_suffix,".md"}
+ | Options0],
+ Title = title(App, Options),
+ %% CSS = stylesheet(Options),
+ io:fwrite("sources...~n", []),
+ {Modules1, Error} = sources(Sources, Dir, Modules, Env, Options),
+ io:fwrite("packages...~n", []),
+ packages(Packages, Dir, FileMap, Env, Options),
+ io:fwrite("overview...~n", []),
+ Overview = overview(Dir, Title, Env, Options),
+ Data =
+ [{title, [Title]},
+ hr]
+ ++ Overview
+ ++ [packages_frame(Packages) || Packages =/= []]
+ ++ [modules_frame(Modules1) || Modules1 =/= []],
+
+ io:fwrite("*************~nData = ~p~n*************~n", [Data]),
+
+ Text = xmerl:export_simple_content(Data, edown_xmerl),
+ edoc_lib:write_file(Text, Dir, ?INDEX_FILE),
+ edoc_lib:write_info_file(App, Packages, Modules1, Dir),
+ copy_stylesheet(Dir, Options),
+ copy_image(Dir),
+ %% handle postponed error during processing of source files
+ case Error of
+ true -> exit(error);
+ false -> ok
+ end.
+
+
+%% NEW-OPTIONS: title
+%% DEFER-OPTIONS: run/2
+
+title(App, Options) ->
+ proplists:get_value(title, Options,
+ if App == ?NO_APP ->
+ "Overview";
+ true ->
+ io_lib:fwrite("Application: ~s", [App])
+ end).
+
+
+%% Processing the individual source files.
+
+%% NEW-OPTIONS: file_suffix, private, hidden
+%% INHERIT-OPTIONS: edoc:layout/2
+%% INHERIT-OPTIONS: edoc:get_doc/3
+%% DEFER-OPTIONS: run/2
+
+sources(Sources, Dir, Modules, Env, Options) ->
+ Suffix = proplists:get_value(file_suffix, Options,
+ ?DEFAULT_FILE_SUFFIX),
+ Private = proplists:get_bool(private, Options),
+ Hidden = proplists:get_bool(hidden, Options),
+ {Ms, E} = lists:foldl(fun (Src, {Set, Error}) ->
+ source(Src, Dir, Suffix, Env, Set,
+ Private, Hidden, Error, Options)
+ end,
+ {sets:new(), false}, Sources),
+ {[M || M <- Modules, sets:is_element(M, Ms)], E}.
+
+
+%% Generating documentation for a source file, adding its name to the
+%% set if it was successful. Errors are just flagged at this stage,
+%% allowing all source files to be processed even if some of them fail.
+
+source({M, P, Name, Path}, Dir, Suffix, Env, Set, Private, Hidden,
+ Error, Options) ->
+ io:fwrite("source: ~p...~n", [Name]),
+ File = filename:join(Path, Name),
+ case catch {ok, edoc:get_doc(File, Env, Options)} of
+ {ok, {Module, Doc}} ->
+ io:fwrite("get_doc() ok~n", []),
+ check_name(Module, M, P, File),
+ case ((not is_private(Doc)) orelse Private)
+ andalso ((not is_hidden(Doc)) orelse Hidden) of
+ true ->
+ Text = edoc:layout(Doc, Options),
+ io:fwrite("edoc:layout() ok~n", []),
+ Name1 = packages:last(M) ++ Suffix,
+ edoc_lib:write_file(Text, Dir, Name1, P),
+ {sets:add_element(Module, Set), Error};
+ false ->
+ {Set, Error}
+ end;
+ R ->
+ report("skipping source file '~s': ~W.", [File, R, 15]),
+ {Set, true}
+ end.
+
+check_name(M, M0, P0, File) ->
+ P = list_to_atom(packages:strip_last(M)),
+ N = packages:last(M),
+ N0 = packages:last(M0),
+ case N of
+ [$? | _] ->
+ %% A module name of the form '?...' is assumed to be caused
+ %% by the epp_dodger parser when the module declaration has
+ %% the form '-module(?MACRO).'; skip the filename check.
+ ok;
+ _ ->
+ if N =/= N0 ->
+ warning("file '~s' actually contains module '~s'.",
+ [File, M]);
+ true ->
+ ok
+ end
+ end,
+ if P =/= P0 ->
+ warning("file '~s' belongs to package '~s', not '~s'.",
+ [File, P, P0]);
+ true ->
+ ok
+ end.
+
+
+%% Generating the summary files for packages.
+
+%% INHERIT-OPTIONS: read_file/4
+%% INHERIT-OPTIONS: edoc_lib:run_layout/2
+
+packages(Packages, Dir, FileMap, Env, Options) ->
+ lists:foreach(fun (P) ->
+ package(P, Dir, FileMap, Env, Options)
+ end,
+ Packages).
+
+package(P, Dir, FileMap, Env, Opts) ->
+ Tags = case FileMap(P) of
+ "" ->
+ [];
+ File ->
+ read_file(File, package, Env, Opts)
+ end,
+ Data = edoc_data:package(P, Tags, Env, Opts),
+ F = fun (M) ->
+ M:package(Data, Opts)
+ end,
+ Text = edoc_lib:run_layout(F, Opts),
+ edoc_lib:write_file(Text, Dir, ?PACKAGE_SUMMARY, P).
+
+
+
+packages_frame(Ps) ->
+ [{h2, [{class, "indextitle"}], ["Packages"]},
+ {table, [{width, "100%"}, {border, 0},
+ {summary, "list of packages"}],
+ lists:concat(
+ [[{tr, [{td, [], [{a, [{href, package_ref(P)},
+ {class, "package"}],
+ [atom_to_list(P)]}]}]}]
+ || P <- Ps])}].
+
+
+modules_frame(Ms) ->
+ [{h2, [{class, "indextitle"}], ["Modules"]},
+ {table, [{width, "100%"}, {border, 0},
+ {summary, "list of modules"}],
+ lists:concat(
+ [[?NL,
+ {tr, [{td, [],
+ [{a, [{href, module_ref(M)},
+ {class, "module"}],
+ [atom_to_list(M)]}]}]}]
+ || M <- Ms])}].
+
+module_ref(M) ->
+ edoc_refs:relative_package_path(M, '') ++ ?DEFAULT_FILE_SUFFIX.
+
+package_ref(P) ->
+ edoc_lib:join_uri(edoc_refs:relative_package_path(P, ''),
+ ?PACKAGE_SUMMARY).
+
+
+%% xhtml(Title, CSS, Content) ->
+%% xhtml_1(Title, CSS, {body, [{bgcolor, "white"}], Content}).
+
+%% xhtml_1(Title, CSS, Body) ->
+%% {html, [?NL,
+%% {head, [?NL, {title, [Title]}, ?NL] ++ CSS},
+%% ?NL,
+%% Body,
+%% ?NL]
+%% }.
+
+%% NEW-OPTIONS: overview
+%% INHERIT-OPTIONS: read_file/4
+%% INHERIT-OPTIONS: edoc_lib:run_layout/2
+%% INHERIT-OPTIONS: edoc_extract:file/4
+%% DEFER-OPTIONS: run/2
+
+overview(Dir, Title, Env, Opts) ->
+ File = proplists:get_value(overview, Opts,
+ filename:join(Dir, ?OVERVIEW_FILE)),
+ Tags = read_file(File, overview, Env, Opts),
+ Data = edoc_data:overview(Title, Tags, Env, Opts),
+ F = fun (M) ->
+ M:overview(Data, Opts)
+ end,
+ Markdown = edoc_lib:run_layout(F, Opts).
+ %% edoc_lib:write_file(Text, Dir, ?OVERVIEW_SUMMARY).
+
+
+copy_image(Dir) ->
+ case code:priv_dir(?EDOC_APP) of
+ PrivDir when is_list(PrivDir) ->
+ From = filename:join(PrivDir, ?IMAGE),
+ edoc_lib:copy_file(From, filename:join(Dir, ?IMAGE));
+ _ ->
+ report("cannot find default image file.", []),
+ exit(error)
+ end.
+
+%% NEW-OPTIONS: stylesheet_file
+%% DEFER-OPTIONS: run/2
+
+copy_stylesheet(Dir, Options) ->
+ case proplists:get_value(stylesheet, Options) of
+ undefined ->
+ From = case proplists:get_value(stylesheet_file, Options) of
+ File when is_list(File) ->
+ File;
+ _ ->
+ case code:priv_dir(?EDOC_APP) of
+ PrivDir when is_list(PrivDir) ->
+ filename:join(PrivDir, ?STYLESHEET);
+ _ ->
+ report("cannot find default "
+ "stylesheet file.", []),
+ exit(error)
+ end
+ end,
+ edoc_lib:copy_file(From, filename:join(Dir, ?STYLESHEET));
+ _ ->
+ ok
+ end.
+
+%% NEW-OPTIONS: stylesheet
+%% DEFER-OPTIONS: run/2
+
+%% stylesheet(Options) ->
+%% case proplists:get_value(stylesheet, Options) of
+%% "" ->
+%% [];
+%% S ->
+%% Ref = case S of
+%% undefined ->
+%% ?STYLESHEET;
+%% "" ->
+%% ""; % no stylesheet
+%% S when is_list(S) ->
+%% S;
+%% _ ->
+%% report("bad value for option 'stylesheet'.",
+%% []),
+%% exit(error)
+%% end,
+%% [{link, [{rel, "stylesheet"},
+%% {type, "text/css"},
+%% {href, Ref},
+%% {title, "EDoc"}], []},
+%% ?NL]
+%% end.
+
+is_private(E) ->
+ case get_attrval(private, E) of
+ "yes" -> true;
+ _ -> false
+ end.
+
+is_hidden(E) ->
+ case get_attrval(hidden, E) of
+ "yes" -> true;
+ _ -> false
+ end.
+
+get_attrval(Name, #xmlElement{attributes = As}) ->
+ case get_attr(Name, As) of
+ [#xmlAttribute{value = V}] ->
+ V;
+ [] -> ""
+ end.
+
+get_attr(Name, [#xmlAttribute{name = Name} = A | As]) ->
+ [A | get_attr(Name, As)];
+get_attr(Name, [_ | As]) ->
+ get_attr(Name, As);
+get_attr(_, []) ->
+ [].
+
+%% Read external source file. Fails quietly, returning empty tag list.
+
+%% INHERIT-OPTIONS: edoc_extract:file/4
+
+read_file(File, Context, Env, Opts) ->
+ case edoc_extract:file(File, Context, Env, Opts) of
+ {ok, Tags} ->
+ Tags;
+ {error, _} ->
+ []
+ end.
+
+
+%% TODO: FIXME: meta-level index generation
+
+%% Creates a Table of Content from a list of Paths (ie paths to applications)
+%% and an overview file.
+
+-define(EDOC_DIR, "doc").
+-define(INDEX_DIR, "doc/index").
+-define(CURRENT_DIR, ".").
+
+toc(_Paths, _Ctxt) ->
+ erlang:error(nyi).
+ %% Opts = Ctxt#context.opts,
+ %% Dir = Ctxt#context.dir,
+ %% Env = Ctxt#context.env,
+ %% app_index_file(Paths, Dir, Env, Opts).
+
+%% TODO: FIXME: it's unclear how much of this is working at all
+
+%% NEW-OPTIONS: title
+%% INHERIT-OPTIONS: overview/4
+
+%% app_index_file(Paths, Dir, Env, Options) ->
+%% Title = proplists:get_value(title, Options,"Overview"),
+%% % Priv = proplists:get_bool(private, Options),
+%% CSS = stylesheet(Options),
+%% Apps1 = [{filename:dirname(A),filename:basename(A)} || A <- Paths],
+%% index_file(Dir, false, Title),
+%% application_frame(Dir, Apps1, Title, CSS),
+%% modules_frame(Dir, [], Title, CSS),
+%% overview(Dir, Title, Env, Options),
+%% % edoc_lib:write_info_file(Prod, [], Modules1, Dir),
+%% copy_stylesheet(Dir, Options).
+
+%% application_frame(Dir, Apps, Title, CSS) ->
+%% Body = [?NL,
+%% {h2, ["Applications"]},
+%% ?NL,
+%% {table, [{width, "100%"}, {border, 0}],
+%% lists:concat(
+%% [[{tr, [{td, [], [{a, [{href,app_ref(Path,App)},
+%% {target,"_top"}],
+%% [App]}]}]}]
+%% || {Path,App} <- Apps])},
+%% ?NL],
+%% XML = xhtml(Title, CSS, Body),
+%% Text = xmerl:export_simple([XML], xmerl_html, []),
+%% edoc_lib:write_file(Text, Dir, ?MODULES_FRAME).
+
+%% app_ref(Path,M) ->
+%% filename:join([Path,M,?EDOC_DIR,?INDEX_FILE]).
867 src/edown_layout.erl
@@ -0,0 +1,867 @@
+%%==============================================================================
+%% Copyright 2010 Erlang Solutions Ltd.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+%% @author Ulf Wiger <ulf.wiger@erlang-solutions.com>
+%% @copyright 2010 Erlang Solutions Ltd
+%% @end
+%% =====================================================================
+
+%% @doc Github-flavored Markdown layout module for EDoc.
+%% Derived from `edoc_layout', which is part of the Erlang/OTP application EDoc.
+%% The module is intended to be used together with edoc.
+%% @end
+
+-module(edown_layout).
+
+-export([module/2, package/2, overview/2, type/1]).
+-export([markdown/3]).
+
+-import(edoc_report, [report/2]).
+
+-include_lib("xmerl/include/xmerl.hrl").
+
+-define(HTML_EXPORT, edown_xmerl).
+-define(DEFAULT_XML_EXPORT, ?HTML_EXPORT).
+-define(OVERVIEW_SUMMARY, "overview-summary.html").
+-define(STYLESHEET, "stylesheet.css").
+-define(NL, "\n").
+-define(DESCRIPTION_TITLE, "Description").
+-define(DESCRIPTION_LABEL, "description").
+-define(DATA_TYPES_TITLE, "Data Types").
+-define(DATA_TYPES_LABEL, "types").
+-define(FUNCTION_INDEX_TITLE, "Function Index").
+-define(FUNCTION_INDEX_LABEL, "index").
+-define(FUNCTIONS_TITLE, "Function Details").
+-define(FUNCTIONS_LABEL, "functions").
+
+
+%% @doc The layout function.
+%%
+%% Options to the standard layout:
+%% <dl>
+%% <dt>{@type {index_columns, integer()@}}
+%% </dt>
+%% <dd>Specifies the number of column pairs used for the function
+%% index tables. The default value is 1.
+%% </dd>
+%% <dt>{@type {stylesheet, string()@}}
+%% </dt>
+%% <dd>Specifies the URI used for referencing the stylesheet. The
+%% default value is `"stylesheet.css"'. If an empty string is
+%% specified, no stylesheet reference will be generated.
+%% </dd>
+%% <dt>{@type {sort_functions, bool()@}}
+%% </dt>
+%% <dd>If `true', the detailed function descriptions are listed by
+%% name, otherwise they are listed in the order of occurrence in
+%% the source file. The default value is `true'.
+%% </dd>
+%% <dt>{@type {xml_export, Module::atom()@}}
+%% </dt>
+%% <dd>Specifies an {@link //xmerl. `xmerl'} callback module to be
+%% used for exporting the documentation. See {@link
+%% //xmerl/xmerl:export_simple_content/2} for details.
+%% </dd>
+%% </dl>
+%%
+%% @see edoc:layout/2
+
+%% NEW-OPTIONS: xml_export, index_columns, stylesheet
+
+module(Element, Options) ->
+ XML = layout_module(Element, init_opts(Element, Options)),
+ Export = proplists:get_value(xml_export, Options,
+ ?DEFAULT_XML_EXPORT),
+ xmerl:export_simple(XML, Export, []).
+
+% Put layout options in a data structure for easier access.
+
+%% %Commented out until it can be made private
+%% %@type opts() = #opts{root = string(),
+%% % stylesheet = string(),
+%% % index_columns = integer()}
+
+-record(opts, {root, stylesheet, index_columns, sort_functions}).
+
+init_opts(Element, Options) ->
+ R = #opts{root = get_attrval(root, Element),
+ index_columns = proplists:get_value(index_columns,
+ Options, 1),
+ sort_functions = proplists:get_value(sort_functions,
+ Options, true)
+ },
+ case proplists:get_value(stylesheet, Options) of
+ undefined ->
+ S = edoc_lib:join_uri(R#opts.root, ?STYLESHEET),
+ R#opts{stylesheet = S};
+ "" ->
+ R; % don't use any stylesheet
+ S when is_list(S) ->
+ R#opts{stylesheet = S};
+ _ ->
+ report("bad value for option `stylesheet'.", []),
+ exit(error)
+ end.
+
+
+%% =====================================================================
+%% XML-BASED LAYOUT ENGINE
+%% =====================================================================
+
+%% We assume that we have expanded XML data.
+
+%% <!ELEMENT module (behaviour*, description?, author*, copyright?,
+%% version?, since?, deprecated?, see*, reference*,
+%% todo?, typedecls?, functions)>
+%% <!ATTLIST module
+%% name CDATA #REQUIRED
+%% private NMTOKEN(yes | no) #IMPLIED
+%% root CDATA #IMPLIED>
+%% <!ELEMENT behaviour (#PCDATA)>
+%% <!ATTLIST behaviour
+%% href CDATA #IMPLIED>
+%% <!ELEMENT description (briefDescription, fullDescription?)>
+%% <!ELEMENT briefDescription (#PCDATA)>
+%% <!ELEMENT fullDescription (#PCDATA)>
+%% <!ELEMENT author EMPTY>
+%% <!ATTLIST author
+%% name CDATA #REQUIRED
+%% email CDATA #IMPLIED
+%% website CDATA #IMPLIED>
+%% <!ELEMENT version (#PCDATA)>
+%% <!ELEMENT since (#PCDATA)>
+%% <!ELEMENT copyright (#PCDATA)>
+%% <!ELEMENT deprecated (description)>
+%% <!ELEMENT see (#PCDATA)>
+%% <!ATTLIST see
+%% name CDATA #REQUIRED
+%% href CDATA #IMPLIED>
+%% <!ELEMENT reference (#PCDATA)>
+%% <!ELEMENT todo (#PCDATA)>
+%% <!ELEMENT typedecls (typedecl+)>
+%% <!ELEMENT functions (function+)>
+
+%% TODO: improve layout of parameterized modules
+
+layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
+ Args = module_params(get_content(args, Es)),
+ Name = get_attrval(name, E),
+ Title = case get_elem(args, Es) of
+ [] -> ["Module ", Name];
+ _ -> ["Abstract module ", Name, " [", {Args}, "]"]
+ end,
+ Desc = get_content(description, Es),
+ ShortDesc = get_content(briefDescription, Desc),
+ FullDesc = get_content(fullDescription, Desc),
+ Functions = [{function_name(Ex), Ex} || Ex <- get_content(functions, Es)],
+ Types = [{type_name(Ex), Ex} || Ex <- get_content(typedecls, Es)],
+ SortedFs = lists:sort(Functions),
+ Body = (navigation("top")
+ ++ [{h1, Title}]
+ ++ doc_index(FullDesc, Functions, Types)
+ ++ ShortDesc
+ ++ copyright(Es)
+ ++ deprecated(Es, "module")
+ ++ version(Es)
+ ++ since(Es)
+ ++ behaviours(Es, Name)
+ ++ authors(Es)
+ ++ references(Es)
+ ++ sees(Es)
+ ++ todos(Es)
+ ++ if FullDesc == [] -> [];
+ true -> [{h2, [{a, [{name, "description"}],
+ ["Description"]}]}
+ | FullDesc]
+ end
+ ++ types(lists:sort(Types))
+ ++ function_index(SortedFs, Opts#opts.index_columns)
+ ++ if Opts#opts.sort_functions -> functions(SortedFs);
+ true -> functions(Functions)
+ end
+ ++ navigation("bottom")
+ ++ timestamp()),
+ %% if Name == "edown_doclet" ->
+ %% io:fwrite("edown_doclet:~n"
+ %% "-----------------~n"
+ %% "~p~n"
+ %% "-----------------~n", [Body]);
+ %% true ->
+ %% io:fwrite("not edown_doclet (~p)~n", [Name])
+ %% end,
+ %% xhtml(Title, stylesheet(Opts), Body).
+ Res = markdown(Title, stylesheet(Opts), Body),
+ %% io:fwrite("Res = ~p~n", [Res]),
+ Res.
+
+module_params(Es) ->
+ As = [{get_text(argName, Es1),
+ get_content(fullDescription, get_content(description, Es1))}
+ || #xmlElement{content = Es1} <- Es],
+ case As of
+ [] -> [];
+ [First | Rest] ->
+ [element(1, First) | [ {[", ",A]} || {A, _D} <- Rest]]
+ end.
+
+timestamp() ->
+ [{p, [{i, [io_lib:fwrite("Generated by EDoc, ~s, ~s.",
+ [edoc_lib:datestr(date()),
+ edoc_lib:timestr(time())])
+ ]}]}].
+
+stylesheet(Opts) ->
+ case Opts#opts.stylesheet of
+ undefined ->
+ [];
+ CSS ->
+ [{link, [{rel, "stylesheet"},
+ {type, "text/css"},
+ {href, CSS},
+ {title, "EDoc"}], []}]
+ end.
+
+navigation(Where) ->
+ [{'div', [{class, "navbar"}],
+ [{a, [{name, "#navbar_" ++ Where}], []},
+ {table, [{width, "100%"}, {border,0},
+ {cellspacing, 0}, {cellpadding, 2},
+ {summary, "navigation bar"}],
+ [{tr,
+ [{td, [{a, [{href, ?OVERVIEW_SUMMARY}, {target,"overviewFrame"}],
+ ["Overview"]}]},
+ {td, [{a, [{href, "http://www.erlang.org/"}],
+ [{img, [{src, "erlang.png"}, {align, "right"},
+ {border, 0}, {alt, "erlang logo"}],
+ []}]}
+ ]}
+ ]}
+ ]}
+ ]}
+ ].
+
+doc_index(FullDesc, Functions, Types) ->
+ case doc_index_rows(FullDesc, Functions, Types) of
+ [] -> [];
+ Rs ->
+ [{ul, [{class, "index"}],
+ [{li, [{a, [{href, local_label(R)}], [T]}]}
+ || {T, R} <- Rs]}]
+ end.
+
+doc_index_rows(FullDesc, Functions, Types) ->
+ (if FullDesc == [] -> [];
+ true -> [{?DESCRIPTION_TITLE, ?DESCRIPTION_LABEL}]
+ end
+ ++ if Types == [] -> [];
+ true -> [{?DATA_TYPES_TITLE, ?DATA_TYPES_LABEL}]
+ end
+ ++ if Functions == [] -> [];
+ true -> [{?FUNCTION_INDEX_TITLE, ?FUNCTION_INDEX_LABEL},
+ {?FUNCTIONS_TITLE, ?FUNCTIONS_LABEL}]
+ end).
+
+function_index(Fs, Cols) ->
+ case function_index_rows(Fs, Cols, []) of
+ [] -> [];
+ Rows ->
+ [{h2, [{a, [{name, ?FUNCTION_INDEX_LABEL}],
+ [?FUNCTION_INDEX_TITLE]}]},
+ {table, [{width, "100%"}, {border, 1},
+ {cellspacing,0}, {cellpadding,2},
+ {summary, "function index"}],
+ Rows}]
+ end.
+
+function_index_rows(Fs, Cols, Title) ->
+ Rows = (length(Fs) + (Cols - 1)) div Cols,
+ (if Title == [] -> [];
+ true -> [{tr, [{th, [{colspan, Cols * 2}, {align, left}],
+ [Title]}]}]
+ end
+ ++ lists:flatmap(fun index_row/1,
+ edoc_lib:transpose(edoc_lib:segment(Fs, Rows)))).
+
+index_row(Fs) ->
+ [{tr, lists:flatmap(fun index_col/1, Fs)}].
+
+index_col({Name, F=#xmlElement{content = Es}}) ->
+ [{td, [{valign, "top"}],
+ label_href(function_header(Name, F, "*"), F)},
+ {td, index_desc(Es)}].
+
+index_desc(Es) ->
+ Desc = get_content(description, Es),
+ (case get_content(deprecated, Es) of
+ [] -> [];
+ _ -> ["(", {em, ["Deprecated"]}, ".) "]
+ end
+ ++ case get_content(briefDescription, Desc) of
+ [] ->
+ equiv(Es); % no description at all if no equiv
+ ShortDesc ->
+ ShortDesc
+ end).
+
+label_href(Content, F) ->
+ case get_attrval(label, F) of
+ "" -> Content;
+ Ref -> [{a, [{href, local_label(Ref)}], Content}]
+ end.
+
+%% <!ELEMENT function (args, typespec?, returns?, throws?, equiv?,
+%% description?, since?, deprecated?, see*, todo?)>
+%% <!ATTLIST function
+%% name CDATA #REQUIRED
+%% arity CDATA #REQUIRED
+%% exported NMTOKEN(yes | no) #REQUIRED
+%% label CDATA #IMPLIED>
+%% <!ELEMENT args (arg*)>
+%% <!ELEMENT equiv (expr, see?)>
+%% <!ELEMENT expr (#PCDATA)>
+
+functions(Fs) ->
+ Es = lists:flatmap(fun ({Name, E}) -> function(Name, E) end, Fs),
+ if Es == [] -> [];
+ true ->
+ [{a, [{name, ?FUNCTIONS_LABEL}], []},
+ {h2, [?FUNCTIONS_TITLE]} | Es]
+ end.
+
+function(Name, E=#xmlElement{content = Es}) ->
+ FHead = function_header(Name, E, " *"),
+ (label_anchor(FHead, E)
+ ++ [{h3, [lists:flatten(FHead)]},
+ {p, []},
+ {p,
+ case typespec(get_content(typespec, Es)) of
+ [] ->
+ signature(get_content(args, Es),
+ get_attrval(name, E));
+ Spec -> Spec
+ end},
+ {p, []}]
+ ++ case params(get_content(args, Es)) of
+ [] -> [];
+ Ps -> [{p, Ps}]
+ end
+ ++ case returns(get_content(returns, Es)) of
+ [] -> [];
+ Rs -> [{p, Rs}]
+ end
+ ++ throws(Es)
+ ++ equiv_p(Es)
+ ++ deprecated(Es, "function")
+ ++ fulldesc(Es)
+ ++ since(Es)
+ ++ sees(Es)
+ ++ todos(Es)).
+
+function_name(E) ->
+ atom(get_attrval(name, E)) ++ "/" ++ get_attrval(arity, E).
+
+function_header(Name, E, Private) ->
+ case is_exported(E) of
+ true -> [Name];
+ false -> [Name, Private]
+ end.
+
+is_exported(E) ->
+ case get_attrval(exported, E) of
+ "yes" -> true;
+ _ -> false
+ end.
+
+label_anchor(Content, E) ->
+ case get_attrval(label, E) of
+ "" -> Content;
+ Ref -> [{a, [{name, Ref}], ""}]
+ end.
+
+%% <!ELEMENT args (arg*)>
+%% <!ELEMENT arg (argName, description?)>
+%% <!ELEMENT argName (#PCDATA)>
+
+%% This is currently only done for functions without type spec.
+
+signature(Es, Name) ->
+ [{tt, [Name, "("] ++ seq(fun arg/1, Es) ++ [") -> any()"]}].
+
+arg(#xmlElement{content = Es}) ->
+ [get_text(argName, Es)].
+
+%% parameter and return value descriptions (if any)
+
+params(Es) ->
+ As = [{get_text(argName, Es1),
+ get_content(fullDescription, get_content(description, Es1))}
+ || #xmlElement{content = Es1} <- Es],
+ As1 = [A || A <- As, element(2, A) /= []],
+ if As1 == [] ->
+ [];
+ true ->
+ [ { [{tt, [A]}, ": "] ++ D ++ [br] }
+ || {A, D} <- As1]
+ end.
+
+returns(Es) ->
+ case get_content(fullDescription, get_content(description, Es)) of
+ [] ->
+ [];
+ D ->
+ ["returns: "] ++ D
+ end.
+
+%% <!ELEMENT throws (type, localdef*)>
+
+throws(Es) ->
+ case get_content(throws, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, (["throws ", {tt, t_utype(get_elem(type, Es1))}]
+ ++ local_defs(get_elem(localdef, Es1)))}]
+ end.
+
+%% <!ELEMENT typespec (erlangName, type, localdef*)>
+
+typespec([]) -> [];
+typespec(Es) ->
+ [{tt, ([t_name(get_elem(erlangName, Es))]
+ ++ t_utype(get_elem(type, Es)))}]
+ ++ local_defs(get_elem(localdef, Es)).
+
+%% <!ELEMENT typedecl (typedef, description?)>
+%% <!ELEMENT typedef (erlangName, argtypes, type?, localdef*)>
+
+types([]) -> [];
+types(Ts) ->
+ Es = lists:flatmap(fun ({Name, E}) -> typedecl(Name, E) end, Ts),
+ [{h2, [{a, [{name, ?DATA_TYPES_LABEL}],
+ [?DATA_TYPES_TITLE]}]} | Es].
+
+typedecl(Name, E=#xmlElement{content = Es}) ->
+ Lbl = Name ++ "()",
+ (label_anchor(Lbl, E)
+ ++ [{h3, [{class, "typedecl"}], [Lbl]}]
+ ++ [{p, typedef(get_content(typedef, Es))}]
+ ++ fulldesc(Es)).
+
+type_name(#xmlElement{content = Es}) ->
+ t_name(get_elem(erlangName, get_content(typedef, Es))).
+
+typedef(Es) ->
+ Name = ([t_name(get_elem(erlangName, Es)), "("]
+ ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), [")"])),
+ (case get_elem(type, Es) of
+ [] -> [{b, ["abstract datatype"]}, ": ", {tt, Name}];
+ Type ->
+ [{tt, Name ++ [" = "] ++ t_utype(Type)}]
+ end
+ ++ local_defs(get_elem(localdef, Es))).
+
+local_defs([]) -> [];
+local_defs(Es) ->
+ [{ul, [{class, "definitions"}],
+ lists:concat([[{li, [{tt, localdef(E)}]}] || E <- Es])}].
+
+localdef(E = #xmlElement{content = Es}) ->
+ (case get_elem(typevar, Es) of
+ [] ->
+ T_abs = t_abstype(get_content(abstype, Es)),
+ label_anchor(T_abs, E) ++ [{tt, T_abs}];
+ [V] ->
+ t_var(V)
+ end
+ ++ [" = "] ++ t_utype(get_elem(type, Es))).
+
+fulldesc(Es) ->
+ case get_content(fullDescription, get_content(description, Es)) of
+ [] -> [];
+ Desc -> [{p, Desc}]
+ end.
+
+sees(Es) ->
+ case get_elem(see, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, [{b, ["See also:"]}, " "] ++ seq(fun see/1, Es1, ["."])}]
+ end.
+
+see(E=#xmlElement{content = Es}) ->
+ see(E, Es).
+
+see(E, Es) ->
+ case href(E) of
+ [] -> Es;
+ Ref ->
+ [{a, Ref, Es}]
+ end.
+
+href(E) ->
+ case get_attrval(href, E) of
+ "" -> [];
+ URI ->
+ T = case get_attrval(target, E) of
+ "" -> [];
+ S -> [{target, S}]
+ end,
+ [{href, URI} | T]
+ end.
+
+equiv_p(Es) ->
+ equiv(Es, true).
+
+equiv(Es) ->
+ equiv(Es, false).
+
+equiv(Es, P) ->
+ case get_content(equiv, Es) of
+ [] -> [];
+ Es1 ->
+ case get_content(expr, Es1) of
+ [] -> [];
+ [Expr] ->
+ Expr1 = [{tt, [Expr]}],
+ Expr2 = case get_elem(see, Es1) of
+ [] ->
+ Expr1;
+ [E=#xmlElement{}] ->
+ see(E, Expr1)
+ end,
+ Txt = ["Equivalent to "] ++ Expr2 ++ ["."],
+ (case P of
+ true -> [{p, Txt}];
+ false -> Txt
+ end)
+ end
+ end.
+
+copyright(Es) ->
+ case get_content(copyright, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, ["Copyright \251 " | Es1]}]
+ end.
+
+version(Es) ->
+ case get_content(version, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, [{b, ["Version:"]}, " " | Es1]}]
+ end.
+
+since(Es) ->
+ case get_content(since, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, [{b, ["Introduced in:"]}, " " | Es1]}]
+ end.
+
+deprecated(Es, S) ->
+ Es1 = get_content(description, get_content(deprecated, Es)),
+ case get_content(fullDescription, Es1) of
+ [] -> [];
+ Es2 ->
+ [{p, [{b, ["This " ++ S ++ " is deprecated:"]}, " " | Es2]}]
+ end.
+
+behaviours(Es, Name) ->
+ (case get_elem(behaviour, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, ([{b, ["Behaviours:"]}, " "]
+ ++ seq(fun behaviour/1, Es1, ["."]))}]
+ end
+ ++
+ case get_content(callbacks, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, ([{b, ["This module defines the ", {tt, [Name]},
+ " behaviour."]},
+ br, " Required callback functions: "]
+ ++ seq(fun callback/1, Es1, ["."]))}]
+ end).
+
+behaviour(E=#xmlElement{content = Es}) ->
+ see(E, [{tt, Es}]).
+
+callback(E=#xmlElement{}) ->
+ Name = get_attrval(name, E),
+ Arity = get_attrval(arity, E),
+ [{tt, [Name, "/", Arity]}].
+
+authors(Es) ->
+ case get_elem(author, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, [{b, ["Authors:"]}, " "] ++ seq(fun author/1, Es1, ["."])}]
+ end.
+
+atom(String) ->
+ io_lib:write_atom(list_to_atom(String)).
+
+%% <!ATTLIST author
+%% name CDATA #REQUIRED
+%% email CDATA #IMPLIED
+%% website CDATA #IMPLIED>
+
+author(E=#xmlElement{}) ->
+ Name = get_attrval(name, E),
+ Mail = get_attrval(email, E),
+ URI = get_attrval(website, E),
+ (if Name == Mail ->
+ [{a, [{href, "mailto:" ++ Mail}],[{tt, [Mail]}]}];
+ true ->
+ if Mail == "" -> [Name];
+ true -> [Name, " (", {a, [{href, "mailto:" ++ Mail}],
+ [{tt, [Mail]}]}, ")"]
+ end
+ end
+ ++ if URI == "" ->
+ [];
+ true ->
+ [" [", {em, ["web site:"]}, " ",
+ {tt, [{a, [{href, URI}, {target, "_top"}], [URI]}]},
+ "]"]
+ end).
+
+references(Es) ->
+ case get_elem(reference, Es) of
+ [] -> [];
+ Es1 ->
+ [{p, [{b, ["References"]},
+ {ul, [{li, C} || #xmlElement{content = C} <- Es1]}]}]
+ end.
+
+todos(Es) ->
+ case get_elem(todo, Es) of
+ [] -> [];
+ Es1 ->
+ Todos = [{li, [{font, [{color,red}], C}]}
+ || #xmlElement{content = C} <- Es1],
+ [{p, [{b, [{font, [{color,red}], ["To do"]}]},
+ {ul, Todos}]}]
+ end.
+
+t_name([E]) ->
+ N = get_attrval(name, E),
+ case get_attrval(module, E) of
+ "" -> atom(N);
+ M ->
+ S = atom(M) ++ ":" ++ atom(N),
+ case get_attrval(app, E) of
+ "" -> S;
+ A -> "//" ++ atom(A) ++ "/" ++ S
+ end
+ end.
+
+t_utype([E]) ->
+ t_utype_elem(E).
+
+t_utype_elem(E=#xmlElement{content = Es}) ->
+ case get_attrval(name, E) of
+ "" -> t_type(Es);
+ Name ->
+ T = t_type(Es),
+ case T of
+ [Name] -> T; % avoid generating "Foo::Foo"
+ T -> [Name] ++ ["::"] ++ T
+ end
+ end.
+
+t_type([E=#xmlElement{name = typevar}]) ->
+ t_var(E);
+t_type([E=#xmlElement{name = atom}]) ->
+ t_atom(E);
+t_type([E=#xmlElement{name = integer}]) ->
+ t_integer(E);
+t_type([E=#xmlElement{name = float}]) ->
+ t_float(E);
+t_type([#xmlElement{name = nil}]) ->
+ t_nil();
+t_type([#xmlElement{name = list, content = Es}]) ->
+ t_list(Es);
+t_type([#xmlElement{name = tuple, content = Es}]) ->
+ t_tuple(Es);
+t_type([#xmlElement{name = 'fun', content = Es}]) ->
+ t_fun(Es);
+t_type([#xmlElement{name = record, content = Es}]) ->
+ t_record(Es);
+t_type([E = #xmlElement{name = abstype, content = Es}]) ->
+ T = t_abstype(Es),
+ see(E, T);
+t_type([#xmlElement{name = union, content = Es}]) ->
+ t_union(Es).
+
+t_var(E) ->
+ [get_attrval(name, E)].
+
+t_atom(E) ->
+ [get_attrval(value, E)].
+
+t_integer(E) ->
+ [get_attrval(value, E)].
+
+t_float(E) ->
+ [get_attrval(value, E)].
+
+t_nil() ->
+ ["[]"].
+
+t_list(Es) ->
+ ["["] ++ t_utype(get_elem(type, Es)) ++ ["]"].
+
+t_tuple(Es) ->
+ ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]).
+
+t_fun(Es) ->
+ ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es),
+ [") -> "] ++ t_utype(get_elem(type, Es))).
+
+t_record(Es) ->
+ ["#"] ++ t_type(get_elem(atom, Es)) ++ ["{"]
+ ++ seq(fun t_field/1, get_elem(field, Es), ["}"]).
+
+t_field(#xmlElement{content = Es}) ->
+ t_type(get_elem(atom, Es)) ++ [" = "] ++ t_utype(get_elem(type, Es)).
+
+t_abstype(Es) ->
+ ([t_name(get_elem(erlangName, Es)), "("]
+ ++ seq(fun t_utype_elem/1, get_elem(type, Es), [")"])).
+
+t_union(Es) ->
+ seq(fun t_utype_elem/1, Es, " | ", []).
+
+seq(F, Es) ->
+ seq(F, Es, []).
+
+seq(F, Es, Tail) ->
+ seq(F, Es, ", ", Tail).
+
+seq(F, [E], _Sep, Tail) ->
+ F(E) ++ Tail;
+seq(F, [E | Es], Sep, Tail) ->
+ F(E) ++ [Sep] ++ seq(F, Es, Sep, Tail);
+seq(_F, [], _Sep, Tail) ->
+ Tail.
+
+get_elem(Name, [#xmlElement{name = Name} = E | Es]) ->
+ [E | get_elem(Name, Es)];
+get_elem(Name, [_ | Es]) ->
+ get_elem(Name, Es);
+get_elem(_, []) ->
+ [].
+
+get_attr(Name, [#xmlAttribute{name = Name} = A | As]) ->
+ [A | get_attr(Name, As)];
+get_attr(Name, [_ | As]) ->
+ get_attr(Name, As);
+get_attr(_, []) ->
+ [].
+
+get_attrval(Name, #xmlElement{attributes = As}) ->
+ case get_attr(Name, As) of
+ [#xmlAttribute{value = V}] ->
+ V;
+ [] -> ""
+ end.
+
+get_content(Name, Es) ->
+ case get_elem(Name, Es) of
+ [#xmlElement{content = Es1}] ->
+ Es1;
+ [] -> []
+ end.
+
+get_text(Name, Es) ->
+ case get_content(Name, Es) of
+ [#xmlText{value = Text}] ->
+ Text;
+ [] -> ""
+ end.
+
+local_label(R) ->
+ "#" ++ R.
+
+
+markdown(Title, _CSS, Body) ->
+ [{title, [lists:flatten(Title)]}|
+ Body].
+
+%% xhtml(Title, CSS, Body) ->
+%% [{html, [?NL,
+%% {head, [?NL,
+%% {title, Title},
+%% ?NL] ++ CSS},
+%% ?NL,
+%% {body, [{bgcolor, "white"}], Body},
+%% ?NL]
+%% },
+%% ?NL].
+
+%% ---------------------------------------------------------------------
+
+type(E) ->
+ type(E, []).
+
+type(E, Ds) ->
+ xmerl:export_simple_content(t_utype_elem(E) ++ local_defs(Ds),
+ ?HTML_EXPORT).
+
+package(E=#xmlElement{name = package, content = Es}, Options) ->
+ Opts = init_opts(E, Options),
+ Name = get_text(packageName, Es),
+ Title = ["Package ", Name],
+ Desc = get_content(description, Es),
+% ShortDesc = get_content(briefDescription, Desc),
+ FullDesc = get_content(fullDescription, Desc),
+ Body = ([{h1, [Title]}]
+% ++ ShortDesc
+ ++ copyright(Es)
+ ++ deprecated(Es, "package")
+ ++ version(Es)
+ ++ since(Es)
+ ++ authors(Es)
+ ++ references(Es)
+ ++ sees(Es)
+ ++ todos(Es)
+ ++ FullDesc),
+ %% XML = xhtml(Title, stylesheet(Opts), Body),
+ XML = markdown(Title, stylesheet(Opts), Body),
+ xmerl:export_simple_content(XML, ?HTML_EXPORT).
+
+overview(E=#xmlElement{name = overview, content = Es}, Options) ->
+ Opts = init_opts(E, Options),
+ Title = [get_text(title, Es)],
+ Desc = get_content(description, Es),
+% ShortDesc = get_content(briefDescription, Desc),
+ FullDesc = get_content(fullDescription, Desc),
+ Body = (navigation("top")
+ ++ [{h1, [Title]}]
+% ++ ShortDesc
+ ++ copyright(Es)
+ ++ version(Es)
+ ++ since(Es)
+ ++ authors(Es)
+ ++ references(Es)
+ ++ sees(Es)
+ ++ todos(Es)
+ ++ FullDesc
+ ++ [hr]
+ ++ navigation("bottom")
+ ++ timestamp()),
+ %% XML = xhtml(Title, stylesheet(Opts), Body),
+ XML = markdown(Title, stylesheet(Opts), Body).
+ %% xmerl:export_simple_content(XML, ?HTML_EXPORT).
30 src/edown_lib.erl
@@ -0,0 +1,30 @@
+%%==============================================================================
+%% Copyright 2010 Erlang Solutions Ltd.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+%% @author Ulf Wiger <ulf.wiger@erlang-solutions.com>
+%% @copyright 2010 Erlang Solutions Ltd
+%% @end
+%% =====================================================================
+
+%% @doc Github-flavored Markdown for EDoc - common support functions
+%% @end
+
+-module(edown_lib).
+
+-export([export/1]).
+
+
+export(Data) ->
+ xmerl:export_simple_content(Data, edown_xmerl).
12 src/edown_test.erl
@@ -0,0 +1,12 @@
+-module(edown_test).
+
+-export([foo/1]).
+
+-include_lib("edoc/include/edoc_doclet.hrl").
+-include_lib("xmerl/include/xmerl.hrl").
+
+%% @doc test module.
+%% @end
+
+foo(#context{}) ->
+ x.
156 src/edown_xmerl.erl
@@ -0,0 +1,156 @@
+%%==============================================================================
+%% Copyright 2010 Erlang Solutions Ltd.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%==============================================================================
+%% @author Ulf Wiger <ulf.wiger@erlang-solutions.com>
+%% @copyright 2010 Erlang Solutions Ltd
+%% @end
+%% =====================================================================
+
+%% Description : Callback module for exporting XML to Github-flavored Markdown.
+
+-module(edown_xmerl).
+
+-export(['#xml-inheritance#'/0]).
+
+%% Note: we assume XML data, so all tags are lowercase!
+
+-export(['#root#'/4,
+ '#element#'/5,
+ '#text#'/1]).
+
+-import(xmerl_lib, [markup/3, find_attribute/2, export_text/1]).
+
+-include_lib("xmerl/include/xmerl.hrl").
+
+
+'#xml-inheritance#'() -> [].
+
+
+%% The '#text#' function is called for every text segment.
+
+'#text#'(Text) ->
+ %% export_text(Text).
+ try binary_to_list(list_to_binary(Text))
+ catch
+ error:_ ->
+ lists:flatten(io_lib:fwrite("~p", [Text]))
+ end.
+
+
+
+%% The '#root#' tag is called when the entire structure has been
+%% exported. It does not appear in the structure itself.
+
+'#root#'(Data, Attrs, [], _E) ->
+ case find_attribute(header, Attrs) of
+ {value, Hdr} ->
+ [lists:flatten(io_lib:fwrite("HEADER: ~p~n", [Hdr])), Data];
+ false ->
+ Data
+ end.
+
+%% Note that SGML does not have the <Tag/> empty-element form.
+%% Furthermore, for some element types, the end tag may be forbidden -
+%% this can be handled by extending this module - see xmerl_otpsgml.erl
+%% for an example. (By default, we always generate the end tag, to make
+%% sure that the scope of a markup is not extended by mistake.)
+
+'#element#'(Tag, Data, Attrs, Parents, E) ->
+ case within_html(Parents) of
+ true ->
+ xmerl_html:'#element#'(Tag, Data, Attrs, Parents, E);
+ false ->
+ elem(Tag, Data, Attrs, Parents, E)
+ end.
+
+elem(a, Data, Attrs, _Parents, _E) ->
+ %% io:fwrite("A TAG = ~p~nPs = ~p~n", [Data, _Parents]),
+ case lists:keyfind(href, #xmlAttribute.name, Attrs) of
+ #xmlAttribute{value = HRef} ->
+ "[" ++ Data ++ "](" ++ HRef ++ ")";
+ false ->
+ case lists:keyfind(name, #xmlAttribute.name, Attrs) of
+ #xmlAttribute{} ->
+ ["\n",
+ xmerl_lib:start_tag(a,Attrs),
+ Data,
+ xmerl_lib:end_tag(a),
+ "\n"]
+ end
+ end;
+elem(img, _Data, Attrs, _Parents, _E) ->
+ #xmlAttribute{value = Src} = lists:keyfind(src,#xmlAttribute.name,Attrs),
+ #xmlAttribute{value = Alt} = lists:keyfind(alt,#xmlAttribute.name,Attrs),
+ "![" ++ Alt ++ "](" ++ Src ++ ")";
+elem(li, Data, _Attrs, [{ul,_}|_], _E) ->
+ "* " ++ Data ++ "\n";
+elem(li, Data, _Attrs, [{ol,_}|_], _E) ->
+ "1. " ++ Data ++ "\n";
+elem(Tag, Data, Attrs, Parents, E) ->
+ case Tag of
+ title ->
+ %% io:fwrite("TITLE = |~s|~n", [Data]),
+ Str = lists:flatten(Data),
+ Str ++ "\n" ++ [$= || _ <- Str] ++ "\n";
+ html -> Data;
+ body -> Data;
+ ul -> Data;
+ ol -> Data;
+ p -> "\n" ++ Data;
+ b -> "__" ++ no_nl(Data) ++ "__";
+ em -> "_" ++ no_nl(Data) ++ "_";
+ i -> "_" ++ no_nl(Data) ++ "_";
+ tt -> "`" ++ no_nl(Data) ++ "`";
+ code -> "`" ++ no_nl(Data) ++ "`";
+ dl -> Data;
+ dt -> elem(h3, Data, Attrs, Parents, E);
+ dd -> elem(p, Data, Attrs, Parents, E);
+ h1 -> "\n\n#" ++ no_nl(Data) ++ "#\n";
+ h2 -> "\n\n##" ++ no_nl(Data) ++ "##\n";
+ h3 -> "\n\n###" ++ no_nl(Data) ++ "##\n";
+ h4 -> "\n\n####" ++ no_nl(Data) ++ "##\n";
+ hr -> "---------\n";
+ head -> [];
+ _ ->
+ ["\n",
+ xmerl_lib:start_tag(Tag,Attrs),
+ Data,
+ xmerl_lib:end_tag(Tag),
+ "\n"]
+ end.
+
+within_html(Tags) ->
+ lists:any(fun needs_html/1, Tags).
+
+needs_html({T,_}) ->
+ lists:member(T, [table]).
+
+no_nl(S) ->
+ string:strip([C || C <- lists:flatten(S),
+ C =/= $\n], both).
+
+%% attr(#xmlAttribute{name = N, value = V}) ->
+%% "(" ++ atom_to_list(N) ++ "=" ++ [a_val(V)] ++ ")".
+
+%% a_val(V) when is_atom(V) ->
+%% atom_to_list(V);
+%% a_val(V) when is_integer(V) ->
+%% integer_to_list(V);
+%% a_val(V) ->
+%% V.
+
+
+
+

0 comments on commit 8da5e78

Please sign in to comment.