teach minirst to output reasonable markdown

Summary:
Sapling knows how to output it's documentation for the terminal and to html.
Let's add some rough markdown support that we can use for the docusaurus site.

Reviewed By: bolinfest

Differential Revision: D39264810

fbshipit-source-id: 902c8439708c02e8887228ff18564f44fb2fefc2
This commit is contained in:
Katie Mancini 2022-09-09 11:41:51 -07:00 committed by Facebook GitHub Bot
parent 6c5ead0ea6
commit b30d7f0057
3 changed files with 388 additions and 0 deletions

View File

@ -598,6 +598,114 @@ def formatblock(block, width):
return util.wrap(text, width=width, initindent=indent, hangindent=subindent) + "\n"
def formatmd(blocks):
out = []
headernest = ""
# We generally ignore indents because markdown does not like them, however
# we do want to preserve the indentation of lists. The first bullet point
# in a list will be translated to a 0 indent, and we will adust each
# subsequent indent relative to this first one.
# We keep a stack of the translated indentation levels for lists here.
indentation_translation = []
def translate_indent(indent: int) -> int:
nonlocal indentation_translation
if len(indentation_translation) == 0:
indentation_translation.append((indent, 0))
return 0
while len(indentation_translation) > 0:
(last_raw_indent, last_real_indent) = indentation_translation[-1]
# same level of indent
if last_raw_indent == indent:
return last_real_indent
# We have a subindent
if last_raw_indent < indent:
new_indent = indent - last_raw_indent + last_real_indent
indentation_translation.append((indent, new_indent))
return new_indent
# we broke out of a subindent, pop and find the parent/sibling level
# of indent
indentation_translation.pop()
# we broke out to the top level
indentation_translation.append((indent, 0))
return 0
for pos, b in enumerate(blocks):
btype = b["type"]
lines = b["lines"]
if btype != "bullet":
# new paragraphs of markdown bullets need to restart their indents
indentation_translation = []
if btype == "paragraph":
text = "\n".join(lines)
out.append(f"\n{text}\n")
elif btype == "literal":
text = "\n".join(lines)
out.append(f"\n```\n{text}\n```\n")
elif btype == "section":
i = b["underline"]
if i not in headernest:
headernest += i
level = headernest.index(i) + 1
header_value = "#" * level
text = lines[0]
out.append(f"\n{header_value} {text}\n")
elif btype == "table":
table = b["table"]
if len(table):
out.append("\n")
tableheader = ("| " * len(table[0])) + "|\n"
tablemiddle = ("| - " * len(table[0])) + "|\n"
out.append(tableheader)
out.append(tablemiddle)
for row in table:
for v in row:
out.append("| ")
out.append(v)
out.append(" ")
out.append("|\n")
elif btype == "definition":
term = lines[0]
text = "\n> ".join(map(str.strip, lines[1:]))
out.append(f"\n{term}\n> {text}\n")
elif btype == "bullet":
out.append("\n")
indent = " " * translate_indent(b["indent"])
out.extend([f"{indent}{line}" for line in lines])
out.append("\n")
elif btype == "field":
key = b["key"]
text = " ".join(map(str.strip, lines))
out.append(f"\n{key}\n{text}\n")
elif btype == "option":
opt = b["optstr"]
desc = " ".join(map(str.strip, lines))
out.append(f"\n{opt}\n{desc}\n")
elif btype == "admonition":
# TODO: at some point we should figure out how to convert these to
# markdown well. The only text included in the admonition block
# itself is the label like "note" or "warn" and the actual contents
# often comes in a later block. The rst indicates the text is part
# of the admonition with indentation. But we generally are ignoring
# indentation here because markdown doesn't do indentation well.
# for now we just skip the label as all existing admonitions make
# sense with out it.
pass
elif btype == "margin":
# markdown and indentation don't go well, so we just skip these
# blocks
pass
return "".join(out)
def formathtml(blocks):
"""Format RST blocks as HTML"""
@ -767,6 +875,8 @@ def format(text, width=80, indent=0, keep=None, style="plain", section=None):
if style == "html":
text = formathtml(blocks)
elif style == "md":
text = formatmd(blocks)
else:
text = "".join(formatblock(b, width) for b in blocks)
if keep is None:

View File

@ -1,3 +1,8 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2.
from __future__ import absolute_import, print_function
import pprint
@ -10,6 +15,9 @@ def debugformat(text, form, **kwargs):
if form == "html":
print("html format:")
out = minirst.format(text, style=form, **kwargs)
elif form == "md":
print("md format:")
out = minirst.format(text, style=form, **kwargs)
else:
print("%d column format:" % form)
out = minirst.format(text, width=form, **kwargs)
@ -30,6 +38,7 @@ def debugformats(title, text, **kwargs):
debugformat(text, 60, **kwargs)
debugformat(text, 30, **kwargs)
debugformat(text, "html", **kwargs)
debugformat(text, "md", **kwargs)
paragraphs = """
@ -96,6 +105,8 @@ We can have indented lists:
- This is an indented list item
- a subindented list item
- Another indented list item::
- A literal block in the middle

View File

@ -37,6 +37,18 @@ The third and final paragraph.
</p>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
This is some text in the first paragraph.
A small indented paragraph.
It is followed by some lines
containing random whitespace.
The third and final paragraph.
----------------------------------------------------------------------
== definitions ==
60 column format:
----------------------------------------------------------------------
@ -83,6 +95,22 @@ html format:
</dl>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
A Term
> Definition. The indented
> lines make up the definition.
Another Term
> Another definition. The final line in the
> definition determines the indentation, so
> this will be indented with four spaces.
A Nested/Indented Term
> Definition.
----------------------------------------------------------------------
== literals ==
60 column format:
----------------------------------------------------------------------
@ -153,6 +181,34 @@ This literal block is started with '::',
</pre>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
The fully minimized form is the most
convenient form:
```
Hello
literal
world
```
In the partially minimized form a paragraph
simply ends with space-double-colon.
```
////////////////////////////////////////
long un-wrapped line in a literal block
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
```
```
This literal block is started with '::',
the so-called expanded form. The paragraph
with '::' disappears in the final output.
```
----------------------------------------------------------------------
== lists ==
60 column format:
----------------------------------------------------------------------
@ -166,6 +222,7 @@ This literal block is started with '::',
We can have indented lists:
- This is an indented list item
- a subindented list item
- Another indented list item:
- A literal block in the middle
@ -211,6 +268,7 @@ We can have indented lists:
- This is an indented list
item
- a subindented list item
- Another indented list
item:
@ -262,6 +320,7 @@ We can have indented lists:
</p>
<ul>
<li> This is an indented list item
<li> a subindented list item
<li> Another indented list item:
<pre>
- A literal block in the middle
@ -300,6 +359,66 @@ Bullet lists are also detected:
</ul>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
- This is the first list item.
Second paragraph in the first list item.
- List items need not be separated by a blank line.
- And will be rendered without one in any case.
We can have indented lists:
- This is an indented list item
- a subindented list item
- Another indented list item:
```
- A literal block in the middle
of an indented list.
```
```
(The above is not a list item since we are in the literal block.)
```
```
Literal block with no indentation (apart from
the two spaces added to all literal blocks).
```
1. This is an enumerated list (first item).
2. Continuing with the second item.
(1) foo
(2) bar
1) Another
2) List
Line blocks are also a form of list:
| This is the first line. The line continues here.
| This is the second line.
Bullet lists are also detected:
* This is the first bullet
* This is the second bullet It has 2 lines
* This is the third bullet
----------------------------------------------------------------------
== options ==
60 column format:
----------------------------------------------------------------------
@ -433,6 +552,39 @@ marker after the option. It is treated as a normal paragraph:
</p>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
There is support for simple option lists,
but only with long options:
-X --exclude filter
an option with a short and long option with an argument
-I --include
an option with both a short option and a long option
--all
Output all.
--both
Output both (this description is quite long).
--long
Output all day long.
--par
This option has two paragraphs in its description. This is the first.
This is the second. Blank lines may be omitted between
options (as above) or left in (as here).
The next paragraph looks like an option list, but lacks the two-space
marker after the option. It is treated as a normal paragraph:
--foo bar baz
----------------------------------------------------------------------
== fields ==
60 column format:
----------------------------------------------------------------------
@ -488,6 +640,24 @@ Next list:
</dl>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
a
First item.
ab
Second item. Indentation and wrapping is handled automatically.
Next list:
small
The larger key below triggers full indentation here.
much too large
This key is big enough to get its own line.
----------------------------------------------------------------------
== containers (normal) ==
60 column format:
----------------------------------------------------------------------
@ -506,6 +676,12 @@ Normal output.
</p>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
Normal output.
----------------------------------------------------------------------
== containers (verbose) ==
60 column format:
----------------------------------------------------------------------
@ -537,6 +713,16 @@ Verbose output.
['debug', 'debug']
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
Normal output.
Verbose output.
----------------------------------------------------------------------
['debug', 'debug']
----------------------------------------------------------------------
== containers (debug) ==
60 column format:
----------------------------------------------------------------------
@ -568,6 +754,16 @@ Initial debug output.
['verbose']
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
Normal output.
Initial debug output.
----------------------------------------------------------------------
['verbose']
----------------------------------------------------------------------
== containers (verbose debug) ==
60 column format:
----------------------------------------------------------------------
@ -613,6 +809,20 @@ Debug output.
[]
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
Normal output.
Initial debug output.
Verbose output.
Debug output.
----------------------------------------------------------------------
[]
----------------------------------------------------------------------
== roles ==
60 column format:
----------------------------------------------------------------------
@ -631,6 +841,12 @@ Please see 'hg add'.
</p>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
Please see 'hg add'.
----------------------------------------------------------------------
== sections ==
60 column format:
----------------------------------------------------------------------
@ -670,6 +886,18 @@ html format:
<h2>Markup: &quot;foo&quot; and 'hg help'</h2>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
# Title
## Section
### Subsection
## Markup: "foo" and 'hg help'
----------------------------------------------------------------------
== admonitions ==
60 column format:
----------------------------------------------------------------------
@ -722,6 +950,16 @@ This is a note
</p>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
This is a note
- Bullet 1
- Bullet 2
----------------------------------------------------------------------
== comments ==
60 column format:
----------------------------------------------------------------------
@ -752,6 +990,16 @@ Some indented text.
<p>
Empty comment above
</p>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
Some text.
Some indented text.
Empty comment above
----------------------------------------------------------------------
=== === ========================================
@ -793,6 +1041,16 @@ html format:
<td>bar</td>
<td>baz this list is very very very long man</td></tr>
</table>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
| | | |
| - | - | - |
| a | b | c |
| 1 | 2 | 3 |
| foo | bar | baz this list is very very very long man |
----------------------------------------------------------------------
= ==== ======================================
@ -826,3 +1084,12 @@ html format:
</table>
----------------------------------------------------------------------
md format:
----------------------------------------------------------------------
| | | |
| - | - | - |
| s | long | line goes on here |
| | xy | tried to fix here by indenting |
----------------------------------------------------------------------