RETRO programs are written using a literate format called Unu which allows mixing of code and commentary in a somewhat literate format.
Code (and optionally tests) is extracted from fenced blocks, and commentary normally uses a subset of Markdown.
This tool processes both parts, generating formatted HTML documents that look nice, and also provides syntax highlighting for the test and code blocks.
For Markdown:
• lists
• indented code blocks
• paragraphs
• headers
• fenced code and test blocks
• horizontal rules
• inline formatting elements
For RETRO:
• syntax highlighting of most elements
• uses introspection to identify primitives
For both:
• easily customizable via CSS at the end of this file
This only supports a limited subset of full Markdown. I am not adding support for the various linking formats, ordered lists, underlined headers, doubled asterisk, doubled underscores, multiple line/paragraph list entries, or images.
The formatting must follow the following limits:
# Title ## Subtitle ### Level 3 Title Paragraph. *Bold*, _italics_, `inline code`. Another paragraph. - list element - list element - nested list element - nested list element - list element ~~~ :retro (code ; ~~~ ``` tests ``` Sample code or output with four leading spaces is note colorized. this will be code, but not run through the colorizer. More paragraph text. ---- Above is a horizontal separator.
This is not very intelligent. If you have text like 3 * 4, it'll happily treat the * as the start of a bold sequence. Use a leading backslash to avoid this.
HTML is pretty verbose and wants a bunch of boilerplate to work nicely, so I start with some header stuff.
Locate and embed the CSS from the end of this file. The CSS will be at the end of the file, starting with the line reading "## CSS".
Finish the header boilerplate and switch to the body.
The first couple of words are a variation of *s:put that generates HTML codes for specific characters. This ensures that code output displays correctly.
For regular text, there are a couple of inline formatting things to deal with.
These are:
• emphasis
• strong (bold)
• escaped characters
• code
*Code and Test Blocks*
The biggest element is the code and test blocks.
These will be generated in an enclosure that looks like:
<div class='codeblock'><tt> ... code ... </tt></div>
The actual words in the code will be in elements.
The fences need to start and end with ~~~ or three backticks
on a line by itself.
So, identifying and generating an HTML container for a code
block is a matter of:
And test blocks are basically the same, except for the
delimiters.
On to generating the actual HTML for the syntax highlighted
source. This is driven by the sigil, then by word class via
a little quick introspection.
*Headers*
After this, I define detection and formatting of headers. The
headers should look like:
# Level 1
## Level 2
### Level 3
*Indented Code Blocks*
Indented code blocks are lines indented by four spaces.
These are *not* syntax highlighted as they are ignored by
Unu.
*Horizontal Rules*
Horizonal rules consist of four or more - characters on
a line. E.g.,
----
--------
This also accepts sequences of -+-+ which were used in
some older RETRO source files.
*Lists*
Lists start with a - or , followed by a space, then
the item text. Additionally, this allows for nested lists starting
with two spaces before the list marker.
*Paragraphs*
Blank lines denote paragraph breaks.
*The Formatter*
This ties together the various words above, generating the
output.
This concludes the Markdown (subset) in RETRO utility. All that's
left is the CSS.
* { color: #000; background: #fff; max-width: 700px; }
tt, pre { background: #dedede; color: #111; font-family: monospace;
white-space: pre; display: block; width: 100%; }
.indentedcode { margin-left: 2em; margin-right: 2em; }
.codeblock {
background: #dedede; color: #111; font-family: monospace;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
padding: 7px;
display: block;
}
.indentedlist { margin-left: 2em; color: #000; }
span { white-space: pre; }
.text { color: #000; white-space: pre; background: #dedede; }
.colon { color: #000; background: #dedede; }
.note { color: #000; background: #dedede; }
.str { color: #000; text-decoration: underline; background: #dedede; }
.num { color: #000; background: #dedede; font-weight: bold; font-style: italic; }
.fnum { color: #000; font-weight: bold; background: #dedede; }
.ptr { color: #000; font-weight: bold; background: #dedede; }
.fetch { color: #000; font-style: italic; background: #dedede; }
.store { color: #000; font-style: italic; background: #dedede; }
.char { color: #000; background: #dedede; }
.inst { color: #000; background: #dedede; }
.defer { color: #000; background: #dedede; }
.imm { color: #000; font-weight: bold; background: #dedede; }
.prim { color: #000; font-weight: bolder; background: #dedede; }
.tt { white-space: pre; font-family: monospace; background: #dedede; }
.h1, .h2, .h3, .h4 { white-space: normal; }
.h1 { font-size: 125%; }
.h2 { font-size: 120%; }
.h3 { font-size: 115%; }
.h4 { font-size: 110%; }
.hr { display: block; height: 2px; background: #000000; }
CSS