From: Alexandre Terrasa Date: Tue, 29 May 2018 23:54:13 +0000 (-0400) Subject: lib/markdown2: introduce markdown rendering to Manpages X-Git-Url: http://nitlanguage.org lib/markdown2: introduce markdown rendering to Manpages Signed-off-by: Alexandre Terrasa --- diff --git a/lib/markdown2/markdown_man_rendering.nit b/lib/markdown2/markdown_man_rendering.nit new file mode 100644 index 0000000..b2ee9eb --- /dev/null +++ b/lib/markdown2/markdown_man_rendering.nit @@ -0,0 +1,232 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# 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. + +# Manpages rendering of Markdown documents +module markdown_man_rendering + +import markdown_rendering + +# Markdown document renderer to Manpage +class ManRenderer + super MdRenderer + + # Output under construction + private var man: Buffer is noinit + + # Render `node` as Markdown + redef fun render(node) do + man = new Buffer + enter_visit(node) + return man.write_to_string + end + + redef fun visit(node) do node.render_man(self) + + # Add `string` to `man` + fun add(string: String) do + man.append(string.replace("-", "\\-")) + end + + # Add code that need to be escaped + fun add_code(code: String) do + add code.replace(" ", "\\ ") + end + + # Add a blank line to the output + fun add_line do + add "\n" + end +end + +redef class MdNode + + # Render `self` as Manpage format + fun render_man(v: ManRenderer) do visit_all(v) +end + +# Blocks + +redef class MdBlockQuote + redef fun render_man(v) do + v.add ".RS" + visit_all(v) + v.add ".RE" + v.add_line + end +end + +redef class MdCodeBlock + redef fun render_man(v) do + v.add ".RS\n.nf\n\\f[C]" + v.add_line + + var literal = self.literal + if literal != null then + var lines = literal.split("\n") + for i in [0 .. lines.length[ do + if i == lines.length - 1 then break + var line = lines[i] + v.add_code line + v.add_line + end + end + + v.add "\\f[]\n.fi\n.RE" + v.add_line + end +end + +redef class MdHeading + redef fun render_man(v) do + var level = self.level + + if level == 1 then + v.add ".SH " + else if level == 2 then + v.add ".SS " + else if level >= 3 then + # We use dictionary (titled paragraph) to simulate a 3rd level (or more) + v.add ".TP\n" + end + visit_all(v) + v.add_line + end +end + +redef class MdUnorderedList + redef fun render_man(v) do + v.add ".RS" + v.add_line + + var node = first_child + while node != null do + v.add ".IP \\[bu] 3" + v.add_line + v.enter_visit node + v.add_line + node = node.next + end + + v.add ".RE" + v.add_line + end +end + +redef class MdOrderedList + redef fun render_man(v) do + v.add ".RS" + v.add_line + + var index = start_number + var node = first_child + while node != null do + v.add ".IP \"{index}.\" 3" + v.add_line + v.enter_visit node + v.add_line + node = node.next + index += 1 + end + + v.add ".RE" + v.add_line + end +end + +redef class MdParagraph + redef fun render_man(v) do + var in_list = is_in_list + if not in_list then + v.add_line + end + visit_all(v) + if not in_list then + v.add_line + end + end +end + +redef class MdThematicBreak + redef fun render_man(v) do + v.add "***" + v.add_line + end +end + +redef class MdHtmlBlock + redef fun render_man(v) do + v.add_line + v.add literal or else "" + v.add_line + end +end + +# Inlines + +redef class MdLineBreak + redef fun render_man(v) do + v.add_line + end +end + +redef class MdCode + redef fun render_man(v) do + v.add "\\f[C]" + v.add_code literal + v.add "\\f[]" + end +end + +redef class MdEmphasis + redef fun render_man(v) do + v.add "\\f[I]" + visit_all(v) + v.add "\\f[]" + end +end + +redef class MdStrongEmphasis + redef fun render_man(v) do + v.add "\\f[B]" + visit_all(v) + v.add "\\f[]" + end +end + +redef class MdHtmlInline + redef fun render_man(v) do + v.add literal + end +end + +redef class MdLinkOrImage + redef fun render_man(v) do + var title = self.title + + visit_all(v) + v.add " (" + v.add destination + if title != null and not title.is_empty then + v.add " " + v.add title + end + v.add ")" + end +end + +redef class MdText + redef fun render_man(v) do + v.add literal + end +end diff --git a/lib/markdown2/tests/test_markdown_man.nit b/lib/markdown2/tests/test_markdown_man.nit new file mode 100644 index 0000000..e64dd2a --- /dev/null +++ b/lib/markdown2/tests/test_markdown_man.nit @@ -0,0 +1,386 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# 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. + +# Tests for markdown rendering to manpage +module test_markdown_man is test + +import test_markdown +import markdown_man_rendering + +# Abstract test class that defines the test methods for Man rendering +abstract class TestMarkdownMan + super TestMarkdown + + # Man renderer used in tests + var man_renderer = new ManRenderer + + # Render the `md` string as Manpage format + fun md_to_man(md: String): String do + var node = parse_md(md) + return man_renderer.render(node) + end +end + +class TestManRendering + super TestMarkdownMan + test + + fun test_headings is test do + var md = """# title1\n## title2\n### title3\n#### title4\n##### title5\n###### title6\n""" + var man = """.SH title1\n.SS title2\n.TP\ntitle3\n.TP\ntitle4\n.TP\ntitle5\n.TP\ntitle6\n""" + assert md_to_man(md) == man + end + + fun test_bquotes is test do + var md = """> line 1\n> line 2\n\n> line 3\n>line 4""" + var man = """.RS\nline 1\nline 2\n.RE\n.RS\nline 3\nline 4\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_breaks is test do + var md = """* * *""" + var man = """***\n""" + assert md_to_man(md) == man + end + + fun test_indented_code is test do + var md = """\tline 1\n\tline 2\n""" + var man = """.RS\n.nf\n\\f[C]\nline\\ 1\nline\\ 2\n\\f[]\n.fi\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_fenced_code is test do + var md = """~~~\nline 1\nline 2\n~~~\n""" + var man = """.RS\n.nf\n\\f[C]\nline\\ 1\nline\\ 2\n\\f[]\n.fi\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_escaped_code is test do + var md = """\tline - 1\n\tline - 2\n""" + var man = """.RS\n.nf\n\\f[C]\nline\\ \\-\\ 1\nline\\ \\-\\ 2\n\\f[]\n.fi\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_unordered_list is test do + var md = """* line 1\n* line 2\n""" + var man = """.RS\n.IP \\[bu] 3\nline 1\n.IP \\[bu] 3\nline 2\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_ordered_list is test do + var md = """2) line 1\n3) line 2\n""" + var man = """.RS\n.IP "2." 3\nline 1\n.IP "3." 3\nline 2\n.RE\n""" + assert md_to_man(md) == man + end + + fun test_paragraph is test do + var md = """line 1\nline 2\n\nline 3\nline 4\n""" + var man = """\nline 1\nline 2\n\nline 3\nline 4\n""" + assert md_to_man(md) == man + end + + fun test_escaped_text is test do + var md = """foo - bar\n""" + var man = """\nfoo \\- bar\n""" + assert md_to_man(md) == man + end + + fun test_inline_code is test do + var md = """`foo - bar`\n""" + var man = """\n\\f[C]foo\\ \\-\\ bar\\f[]\n""" + assert md_to_man(md) == man + end + + fun test_emphasis is test do + var md = """*foo*\n""" + var man = """\n\\f[I]foo\\f[]\n""" + assert md_to_man(md) == man + end + + fun test_strong_emphasis is test do + var md = """**foo**\n""" + var man = """\n\\f[B]foo\\f[]\n""" + assert md_to_man(md) == man + end + + fun test_link is test do + var md = """[foo](url "title")\n""" + var man = """\nfoo (url title)\n""" + assert md_to_man(md) == man + end + + fun test_image is test do + var md = """![foo](url "title")\n""" + var man = """\nfoo (url title)\n""" + assert md_to_man(md) == man + end + + fun test_full_document is test do + + var md = """ +# NAME + +nitdoc - generates HTML pages of API documentation from Nit source files. + +# SYNOPSIS + +nitdoc [*options*]... FILE... + +# DESCRIPTION + +`nitdoc` takes one or more modules and generate HTML pages of API documentation for these modules and their imported modules. + +The documentation is extracted from the comments found above the definition of modules, classes, and properties. + +Internally, `nitdoc` relies on the presence of the `dot` command from the [graphviz] project. +If the dot program is not present or not found, no image of hierarchies are generated. +See option `--no-dot`. + +The documentation of the Nit [standard library] is generated with this tool. + + [graphviz]: http://www.graphviz.org + [standard library]: http://nitlanguage.org/doc/stdlib + +# DOCUMENTATION FORMAT + +The format of the documentation is a dialect of [markdown] that allows GitHub fences (`~~~`). + +Code blocks are interpreted as snippets of Nit programs and intended to be used as examples of code. +When these code snippets are valid, executable and contain at least and `assert` clause, they could be automatically executed and verified. +See `nitunit(1)` for details. + + [markdown]: http://daringfireball.net/projects/markdown + +# OPTIONS + +### `-d`, `--dir` +Output directory. + +Where the HTML files are generated. + +By default, the directory is named `doc`. + +### `--source` +Format to link source code. + +The format string is used to generated links to some parts of the source-code. +Use `%f` for filename, `%l` for first line, and `%L` for last line. + +For instance, the [standard library] use the following value to link to files in GitHub: + + "https://github.com/nitlang/nit/blob/$(git rev-parse HEAD)/%f#L%l-%L" + +Here, the `git rev-parse HEAD` is used to link to the current snapshot revision of the file. + +### `--no-attributes` +Ignore the attributes. + +Note: In Nit, attributes are private. Therefore, this option is only useful +when combined with `--private`. + +### `--no-dot` +Do not generate graphs with graphviz. + +### `--private` +Also generate private API. + +## CUSTOMIZATION + +### `--share-dir` +Directory containing tools assets. + +By default `$NIT_DIR/share/nitdoc/` is used. + +### `--shareurl` +Use shareurl instead of copy shared files. + +By default, assets from the sharedir a copied into the output directory and referred with a relative path in the generated files. +With this option, the assets are not copied and the given URL of path is used in the generated files to locate assets. + +### `--custom-title` +Custom title for homepage. + +### `--custom-footer-text` +Custom footer text. + +### `--custom-overview-text` +Custom intro text for homepage. + +### `--custom-brand` +Custom link to external site. + +## SERVICES + +### `--github-upstream` +Git branch where edited commits will be pulled into (ex: user:repo:branch). + +### `--github-base-sha1` +Git sha1 of base commit used to create pull request. + +### `--github-gitdir` +Git working directory used to resolve path name (ex: /home/me/myproject/). + +### `--piwik-tracker` +Piwik tracker URL (ex: `nitlanguage.org/piwik/`). + +### `--piwik-site-id` +Piwik site ID. + +## TESTING + +### `--test` +Print test data (metrics and structure). + +### `--no-render` +Do not render HTML files. + +# SEE ALSO + +The Nit language documentation and the source code of its tools and libraries may be downloaded from +""" + + var man = """ +.SH NAME + +nitdoc \\- generates HTML pages of API documentation from Nit source files. +.SH SYNOPSIS + +nitdoc [\\f[I]options\\f[]]... FILE... +.SH DESCRIPTION + +\\f[C]nitdoc\\f[] takes one or more modules and generate HTML pages of API documentation for these modules and their imported modules. + +The documentation is extracted from the comments found above the definition of modules, classes, and properties. + +Internally, \\f[C]nitdoc\\f[] relies on the presence of the \\f[C]dot\\f[] command from the graphviz (http://www.graphviz.org) project. +If the dot program is not present or not found, no image of hierarchies are generated. +See option \\f[C]\\-\\-no\\-dot\\f[]. + +The documentation of the Nit standard library (http://nitlanguage.org/doc/stdlib) is generated with this tool. +.SH DOCUMENTATION FORMAT + +The format of the documentation is a dialect of markdown (http://daringfireball.net/projects/markdown) that allows GitHub fences (\\f[C]~~~\\f[]). + +Code blocks are interpreted as snippets of Nit programs and intended to be used as examples of code. +When these code snippets are valid, executable and contain at least and \\f[C]assert\\f[] clause, they could be automatically executed and verified. +See \\f[C]nitunit(1)\\f[] for details. +.SH OPTIONS +.TP +\\f[C]\\-d\\f[], \\f[C]\\-\\-dir\\f[] + +Output directory. + +Where the HTML files are generated. + +By default, the directory is named \\f[C]doc\\f[]. +.TP +\\f[C]\\-\\-source\\f[] + +Format to link source code. + +The format string is used to generated links to some parts of the source\\-code. +Use \\f[C]%f\\f[] for filename, \\f[C]%l\\f[] for first line, and \\f[C]%L\\f[] for last line. + +For instance, the standard library (http://nitlanguage.org/doc/stdlib) use the following value to link to files in GitHub: +.RS +.nf +\\f[C] +"https://github.com/nitlang/nit/blob/$(git\\ rev\\-parse\\ HEAD)/%f#L%l\\-%L" +\\f[] +.fi +.RE + +Here, the \\f[C]git\\ rev\\-parse\\ HEAD\\f[] is used to link to the current snapshot revision of the file. +.TP +\\f[C]\\-\\-no\\-attributes\\f[] + +Ignore the attributes. + +Note: In Nit, attributes are private. Therefore, this option is only useful +when combined with \\f[C]\\-\\-private\\f[]. +.TP +\\f[C]\\-\\-no\\-dot\\f[] + +Do not generate graphs with graphviz. +.TP +\\f[C]\\-\\-private\\f[] + +Also generate private API. +.SS CUSTOMIZATION +.TP +\\f[C]\\-\\-share\\-dir\\f[] + +Directory containing tools assets. + +By default \\f[C]$NIT_DIR/share/nitdoc/\\f[] is used. +.TP +\\f[C]\\-\\-shareurl\\f[] + +Use shareurl instead of copy shared files. + +By default, assets from the sharedir a copied into the output directory and referred with a relative path in the generated files. +With this option, the assets are not copied and the given URL of path is used in the generated files to locate assets. +.TP +\\f[C]\\-\\-custom\\-title\\f[] + +Custom title for homepage. +.TP +\\f[C]\\-\\-custom\\-footer\\-text\\f[] + +Custom footer text. +.TP +\\f[C]\\-\\-custom\\-overview\\-text\\f[] + +Custom intro text for homepage. +.TP +\\f[C]\\-\\-custom\\-brand\\f[] + +Custom link to external site. +.SS SERVICES +.TP +\\f[C]\\-\\-github\\-upstream\\f[] + +Git branch where edited commits will be pulled into (ex: user:repo:branch). +.TP +\\f[C]\\-\\-github\\-base\\-sha1\\f[] + +Git sha1 of base commit used to create pull request. +.TP +\\f[C]\\-\\-github\\-gitdir\\f[] + +Git working directory used to resolve path name (ex: /home/me/myproject/). +.TP +\\f[C]\\-\\-piwik\\-tracker\\f[] + +Piwik tracker URL (ex: \\f[C]nitlanguage.org/piwik/\\f[]). +.TP +\\f[C]\\-\\-piwik\\-site\\-id\\f[] + +Piwik site ID. +.SS TESTING +.TP +\\f[C]\\-\\-test\\f[] + +Print test data (metrics and structure). +.TP +\\f[C]\\-\\-no\\-render\\f[] + +Do not render HTML files. +.SH SEE ALSO + +The Nit language documentation and the source code of its tools and libraries may be downloaded from http://nitlanguage.org (http://nitlanguage.org) +""" + assert md_to_man(md) == man + end +end