Skip to content

YAL-Tools/DocMd

Repository files navigation

DocMd (working title?)

A Markdown-esque renderer written in Haxe.

As per name, it is primarily used for writing section-based documentation (example), although it has since been expanded for use in my blog posts and various other bits (like my portfolio, or my other portfolio, or one-off uses).

  • Lack of support for nested sections in "vanilla" Markdown.
  • Syntactic ambiguities in "vanilla" Markdown.
    (e.g. mixing lists/tables/code blocks gets nasty quickly and you have to hand-write HTML)
  • Documents that I write often require "one-off" tags to maintain editable source files.

  • Mostly-familiar syntax (see notes below)
  • GML syntax highlighting (complete with cross-links)
  • Supports hscript for automation and implementing custom tags on per-document basis.

haxe -lib hscript -cp src -neko bin/docmd.n -D hscriptPos -main DocMdSys -dce no

neko docmd.n <input.dmd> <template.html> <output.html> [...options]

Required arguments:

  • input
    A path to a file with markdown to render.
  • template
    The template page to insert generated HTML to.
  • output
    A path to a file to save resulting HTML to.

If the three are named like name.html (input), name.dmd.html (template), name.html (output), template/output arguments can be omitted.

Supported options:

  • --linear
    Enables "linear" render mode (e.g. for blog posts or this README, as opposed to the default nested section mode), along with related post-fixes.
  • --watch
    Keeps the application running and re-renders the file whenever the source files (or their included dependencies) change.
  • --server <port>
    Same as above, but also opens a very simple web server on specified port.
    Combine with localhost-live.js userscript to have the in-browser preview update whenever you save the file.
  • --include <path>
    Prepends the markdown by contents of the given file.
    Good for setting up shared variables/helpers for multiple dmd files.
  • --unindent
    Removes leading spaces from "plaintext" parts of the output.
    When generating a md file from dmd (like this one!), you'll want this to prevent Markdown renderer from turning indented snippets of HTML into code blocks.
  • --gml-api <path>
    Loads API entries (in fnames-like format) for GML syntax highlighting.
  • --gml-assets <path>
    Loads asset names (read: grabs every single identifier in the file) for GML syntax highlighting.
  • --gml-rx-script <regular expression>
    Specifies a regular expression for determining that an identifier in GML code is a script name and should be highlighted accordingly.
  • --gml-rx-asset <regular expression>
    Specifies a regular expression for determining that an identifier in GML code is an asset name and should be highlighted accordingly.
  • --set <name>, --set <name>=<value>
    Fills out template variables (as an alternative to using ```set in dmd itself)

Here, means no native tag, which can be workarounded with HTML insertion in Markdown, plugins in Markdown renderers that support them, or custom tags and/or variables in DocMd.

Tag

Markdown

DMD

Notes on DMD

Line break

2 spaces before EOL

2 spaces before EOL
or \ before EOL

Italic

*text*, _text_

_text_

Doesn't trigger on mid-identifier matches

Bold

**text**, __text__

*text*

strikethrough

~~text~~

~~text~~

Headers

# Text,
## Text,

Text
------

# Text,
## Text, etc.

# [Text](name) for permalinks;
# [Text]() to auto-create permalink;

Links

[text](url)

[text](url)
or [text-url]

Auto-converts URLs not starting with a protocol or a slash into #urls;
URL➜text generation uses same rules as headers;
Prepend URL with + for new tab (noreferrer noopener);
Prepend URL with ! to add nofollow;

Ruler


---
***
___
 ---

Abbr

[text](^title)

Sup

^(text), ^[text]

^[] doesn't unwrap, so ^[1] becomes [1] - good for mid-section citations

Images

![alt](url)

![alt](url)
or ![url] (no alt-text)

  • Unordered list

- one
* two (alt.)
--{
- one
-- two (alt.)
}

Closing } may also be preceded by --

  1. Ordered list

1. one
2. two
##{
- one
-- two (alt.)
}

Not well thought-out - rarely used.

blockquote

> text
```quote
plaintext
```
```quotemd
markdown
```

Not used often either.

 code
```
code
```
```kind
code
```
    code (indented)
```
code
```
```kind
code
```
```kind code```

If code block is the first thing at a line, unindents and matches the closing tag with same indentation, meaning that you can do

Code example:
```
	```
	code
	```
```

More on supported blocks later

DocMd doesn't automatically process HTML tags (with exception of <!--comments-->), but you may use ${} or

```raw
HTML code here
```

to inject HTML.

DocMd supports a number of code block types out of box:

  • raw
    Injects HTML as-is, as per above.
    Note that this will not auto-close paragraphs/etc.

    ```raw
    <b>hello</b>
    ```
    

    hello

  • quote
    Inserts a plaintext blockquote,

    ```quote
    This is *plaintext*
    ```
    

    This is *plaintext*

  • quotemd
    Like above, but will process markdown in it

    ```quotemd
    This is *markdown*
    ```
    

    This is markdown

  • exec
    Executes an hscript code snippet.

    If the code returns a non-null value, it will be appended to output as HTML (see hscript API).

    ```exec
    return "<b>" + ["hello", "there"].join(" ") + "</b>";
    ```
    

    hello there

  • codecss
    Adds the given CSS to the next code block's style attribute - e.g.

    ```codecss
    height: 35%;
    height: 35vh;
    ```
    ```
    this code block will take up 35% of browser height
    ```
    
  • hide
    Doesn't output anything.
  • set, setmd
    Sets template variables.
  • gml
    Pretty reasonable syntax highlighting for GameMaker Language (GML). Has a bunch of tweaks (see below)
  • lua
    Less-reasonable syntax highlighting for Lua that's hacked on top of above.

GML-related tags:

  • gmlapi
    Processes fnames-like entries for GML highlighting, similar to the --gml-api option - e.g.

    ```gmlapi
    a_function()
    a_variable
    a_constant#
    ```
    
  • gmlassets
    Adds asset names for GML highlighting, similar to the --gml-assets option - e.g.

    ```gmlassets
    objPlayer objController
    ```
    
  • gmlkeywords
    Adds keywords for GML highlighting - e.g.

    ```gmlkeywords
    select option
    ```
    

    This is mostly handy if you are using gml tag to highlight something that isn't really GML code (such as Tiny Expression's Runtime documentation does).

  • gmlhint
    The given snippet of GML code (containing #defines and variable declarations) will be used when highlighting the next gml block.

    This is handy for cases when a piece of code is being shown "out of context" (or you are interrupting it halfway through with an explanation of what's going on) but you still want consistent syntax highlighting.

DocMd has a template variable system for reusing snippets of text, inserting contents of other files, and alike.

```set toolname DocMd```
%[toolname] is a Markdown-esque renderer.

DocMd is a Markdown-esque renderer.

You can also load template variables from files,

```set intro ./intro.dmd```
%[intro]

Variables can be also accessed through hscript and used to manipulate generated code (see below).

The following variables have special purpose:

  • template: allows setting page template in the page itself.
  • tag:defcode: changes how code blocks without a "type" will be processed (e.g. setting this to gml will process them as GML snippets by default).

This file will be used as a template for resulting HTML (or HTML-containing) file.

At the very least, your file should contain

<!--<doc--><!--doc>-->

that the generated code will be inserted between, but you may also utilize conditional comments to customize the output or include/exclude parts of it depending on the input:

  • <!--%[variable]-->
    Will be replaced by contents of the given template variable - e.g.

    ```set title cool document```

    and then in the template:

    <title><!--%[title]--></title>
    
  • <!--%[if variable]--> .. [<!--%[else]-->] .. <!--%[endif]-->
    Conditional processing for template variables.

    Currently very simple - just variable and !variable really. Perhaps another use case for hscript.

  • <!--include relPath-->, /*include relPath*/
    Will be replaced by the contents of specified file.
    Useful for generating single-page outputs while keeping the source readable!

This is the template that I use for my documentation.

It supports the following template variables:

  • title: page and OpenGraph title.
  • intro: shown above page controls.
  • theme-color: theme-color meta - used for various accents in browsers and embeds.
  • og:url: an absolute URL to the page for OpenGraph.
  • og:desc: an excerpt for OpenGraph - shown in embeds.
  • og:image: an absolute URL to the image for OpenGraph. Usually 16:9 or so.
  • og:image:width: width of above, in pixels.
  • og:image:height: height of above, in pixels.

  • global
    A reference to this same global scope, in case you need it.

  • print(...values)
    Appends one or more values to output. If the snippet also returns a value, it will be appended afterwards.

  • render(dmd:String)->String
    Processes the given DocMd snippet and returns the resulting HTML.

  • include(path:String)->String
    Reads a file from a relative path, processes it, and returns the resulting HTML.

  • sfmt(format:String, ...values)->String
    A simple helper that replaces %s in a format string by respective values (e.g. sfmt("%/%", 1, 2) returns "1/2").

  • DocMd.makeID(text:String)->String
    Converts a text string into a valid #id (e.g. section 2section-2) using the same rules as the headers/links do.

  • DocMd.addCodeTag(name:String, handler:String->Any)
    Registers a new code block handler. The handler receives the snippet inside the block and should return the resulting HTML. For example, you could do

    ```exec
    DocMd.addCodeTag("center", function(code) {
    	return '<div style="text-align: center">' + render(code) + '</div>';
    });
    ```
    ```center
    hello!
    ```
    

    to have a shorthand for centered text.

  • DocMd.templateVars:Map<String, String>
    A map containing the collected template variables.

  • StringBufExt
    An extension of StringBuf that adds addFormat(format:String, ...values) with same logic as sfmt.

  • File.getContent(path:String)->String
    Grabs file content as text from specified file.

  • File.awaitChanges(path:String)
    When in watch or server mode, will watch for changes to specified path.

See exposed standard library items (Std, Math, StringTools, Reflect, etc.) or add your own in src/dmd/tags/TagExecAPI.hx).


(...is that all?)