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.
Finish the header boilerplate text 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.
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.
For the colors, I'm mostly using the Tomorrow Night colors as listed at https://github.com/chriskempson/tomorrow-theme
* { color: #cccccc; background: #2d2d2d; max-width: 700px; } tt, pre { background: #1d1f21; color: #b5bd68; font-family: monospace; white-space: pre; display: block; width: 100%; } .indentedcode { margin-left: 2em; margin-right: 2em; } .codeblock { background: #1d1f21; color: #b5bd68; 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; } .indentedlist { margin-left: 2em; color: #cccccc; background: #2d2d2d; } span { white-space: pre; background: #1d1f21; } .text { color: #c5c8c6; white-space: pre } .colon { color: #cc6666; } .note { color: #969896; } .str { color: #f0c674; } .num { color: #8abeb7; } .fnum { color: #8abeb7; font-weight: bold; } .ptr { color: #b294bb; font-weight: bold; } .fetch { color: #b294bb; } .store { color: #b294bb; } .char { color: #81a2be; } .inst { color: #de935f; } .defer { color: #888888; } .imm { color: #de935f; } .prim { color: #b5bd68; font-weight: bold; }