Overview

HastyScribe is a self-contained Markdown compiler that can create single-file HTML documents. All documents created by HastyScribe use well-formed HTML and embed all stylesheets, fonts, and images that are necessary to display them in any (modern) browser (don’t even try to display them in IE8 or lower).

In other words, all documents created by HastyScribe are constituted by only one .HTML file, for easy distribution.

Rationale

There are plenty of programs and services that can convert Markdown into HTML but they are typically either too simple –they convert markdown code into an HTML fragment– or too complex –they produce a well-formed document, but they require too much configuration, or the installation of additional software dependencies.

Sometimes you just want to write your document in markdown, and get a full HTML file out, ready to be distributed, ideally with no dependencies (external stylesheets or images) –that’s where HastyScribe comes in.

HastyScribe:

Key Features

Standard Markdown

HastyScribe supports standard markdown for formatting text. Markdown is a lightweight markup language created by John Gruber, and used on many web sites and programs to enable users to write HTML code without actually writing HTML tags.

Tip

You can learn about Markdown syntax in the Syntax Reference section of this document. Alternatively, you can also read the original Markdown syntax page on John Gruber’s blog, Daring Fireball.

Discount Extensions

Standard markdown is great, but sometimes you wish it had a few more features, like tables or fenced code blocks perhaps. The good news is that under the hood HastyScribe uses Discount, a markdown compiler library written in C that extends markdown with a few useful extensions, which allow you to, for example:

Text Snippets

Although not part of neither markdown nor Discount, HastyScribe allows you to create text snippets to reuse content. Useful when you have to use a sentence or a formatted block of text over and over in a document, or shorten long words (like the word HastyScribe in this document ).

Custom Fields

HastyScribe also supports fields to easily include things like the current date or time, but also custom values specified as command-line parameters.

Content Transclusion

When managing long documents, you can take advantage of HastyScribe’s transclusion support to split your content into several files, and transclude them as you see fit.

Substitution Macros

If you find yourself writing chunks of text that follows the same format except for some content, you can define simple text substitution macros for even higher content reuse.

Image (and font) Embedding

HastyScribe only produces single HTML files. With no dependencies:

FontAwesome Icons

FontAwesome icons can be used in badges or simply to customize text.

Notes, tips, warnings, sidebars and badges

…and this is a comment badge.

Responsive Design

All HTML documents created by HastyScribe are responsive and can be viewed perfectly on small devices.

Printed Media Support

HastyScribe’s stylesheet contains styles that are specific for printed media. This means that if you try to print an HTML file generated by HastyScribe it will paginate properly and it will display headers and footers (with page numbers).

Getting Started

Downloading Pre-built Binaries

The easiest way to get HastyScribe is by downloading one of the prebuilt binaries from the Github Release Page:

Installing using Nimble

If you already have Nim installed on your computer, you can simply run

nimble install hastyscribe

Building from Source

To build on a different operating system and architecture from the ones for which a pre-built binary is provided, you also need to get or build the markdown static library (see Orc/discount for more information and sources).

Then:

  1. Download and install Nim.
  2. Clone the HastyScribe repository.
  3. Run the following command:

    nimble build -d:release --passL:"-static -L<dir> -lmarkdown"

Where <dir> is a directory containing the libmarkdown.a static library.

Usage

HastyScribe is a command-line application that can compile one or more Markdown files into one or more HTML files with the same name(s).

Command Line Syntax

hastyscribe filename-or-glob-expression [ <options> ]

Where:

Linux and macOS Examples

Executing HastyScribe to compile my_markdown_file.md within the current directory:

./hastyscribe my_markdown_file.md

Executing HastyScribe to compile all .md files within the current directory:

./hastyscribe *.md

Windows Examples

Executing HastyScribe to compile my_markdown_file.md within the current directory:

hastyscribe.exe my_markdown_file.md

Executing HastyScribe to compile all .md files within the current directory:

hastyscribe.exe *.md

Tip

You can also drag a Markdown file directly on hastyscribe.exe to compile it to HTML.

Syntax Reference

Document Headers

HastyScribe supports Pandoc-style Document Headers, as implemented by the Discount library. Basically, you can specify the title of the document, author and date as the first three lines of the document, prepending each with a %, like this

% HastyScribe User Guide
% Fabio Cevasco
% -

Important

  • The order of the document headers is significant.
  • If you want to use the current date, enter % - in the third line.

Transclusion

When writing a long document, it is often useful to split it into many different files, to manage its contents better. HastyScribe provides basic content transclusion support through the following syntax:

{@ my-file.md || 1 @}

When a file is processed, the line above will cause the contents of file my-file.md to be included in the current file, as if they were part of it. Additionally, when using content transclusion syntax, it is mandatory to specify a number between 0 and 5 to indicate the offset of the headings present in the transcluded file. In this example, the heading numbers of all headings present in my-file.md will be increased by 1, so any h2 will become h3, any h3 will become h4, and so on.

Limitations

  • It is recommended to place all transcluded files in the same folder as the transcluding file. If a transcluded file includes any image, its relative path will be interpreted as if it was relative to the transcluding file.
  • Heading offset will only work if headings are created using #s. Underline syntax for h1 and h2 is not supported.

Snippets

If you want to reuse a few words or even entire blocks of texts, you can use HastyScribe’s snippets.

A snippet definition is constituted by an identifier, followed by an arrow (->), followed by some text – all wrapped in double curly brackets.

The following definition creates a snippet called test which is transformed into the text “This is a test snippet.”.

{{test -> This is a test snippet.}}

Once a snippet is defined anywhere in the document, you can use its identifier wrapped in double curly brackets ({{test}}} in the previous example) anywhere in the document to reuse the specified text.

Fields

Besides user-defined snippets, HastyScribe also support fields, which can be used to insert current time and date information in a variety of formats:

Source Output
{{$timestamp}} 1693490700
{{$date}} 2023-08-31
{{$full-date}} Thursday, August 31, 2023
{{$long-date}} August 31, 2023
{{$medium-date}} Aug 31, 2023
{{$short-date}} 8/31/23
{{$short-time}} 16:05 PM
{{$short-time-24}} 16:05
{{$time}} 16:05:00 PM
{{$time-24}} 16:05:00
{{$day}} 31
{{$short-day}} 31
{{$month}} 08
{{$short-month}} 8
{{$year}} 2023
{{$short-year}} 23
{{$weekday}} Thursday
{{$weekday-abbr}} 31
{{$month-name}} August
{{$month-name-abbr}} Aug
{{$timezone-offset}} +02:00

Additionally, you can define your own custom fields via command-line parameters, using the --field/ dynamic parameter, like this:

hastyscribe my-document.md --field/product:HastyScribe --field/version:1.2.0

In this case it will be possible to access the product and product fields within my-document.md using {{$product}} and {{$version}}.

Macros

If snippets are not enough, and you want to reuse chunks of similar content, you can define substitution macros using the following syntax:

{#greet => Hello, $1! Are you $2?#}

This defines a macro called greet that takes two parameters which will be substituted instead of $1 and $2. To use the macro, use the following syntax:

{#greet||Fabio||ready#}

Note

  • Like snippets, macros can be multiline.
  • Spaces and newline character are preseved ad the start and end of parameters.
  • You can use snippets and fields within macros (but you cannot nest macros inside other macros).
  • You can define macros using either -> or =>, although => is preferred.

Inline Formatting

The following table lists all the most common ways to format inline text:

Source Output
**strong emphasis** or __strong emphasis__ strong emphasis
*emphasis* or _emphasis_ emphasis
~~deleted text~~ deleted text
<ins>inserted text<ins> inserted text
`code` code
[HTML](abbr:Hypertext Markup Language) HTML
<kbd>CTRL</kbd>+<kbd>C</kbd> CTRL+C
<mark>marked</mark> marked.
Sample output: <samp>This is a test.</samp> Sample output: This is a test.
Set the variable <var>test</var> to 1. Set the variable test to 1.
<q>This is a short quotation</q> This is a short quotation
<cite>Hamlet</cite>, by William Shakespeare. Hamlet, by William Shakespeare.
A [.md](class:ext) file A .md file
[my_markdown_file.md](class:file) file my_markdown_file.md file

Tip

The kwd, opt, file, dir, arg, tt and cmd classes are all rendered as inline monospace text. kwd and ext are also rendered in bold.

SmartyPants Substitutions

Special characters can be easily entered using some special character sequences.

HastyScribe supports all the sequences supported by Discount:

Icons

HastyScribe bundles the FontAwesome icon font. To prepend an icon to text you can use Discount’s class: pseudo-protocol, and specify a valid fa-* (non-alias) class.

Examples:

Source Output
[a paper plane](class:fa-paper-plane) a paper plane
[Galactic Empire](class:fa-empire) Galactic Empire
[Rebel Alliance](class:fa-rebel) Rebel Alliance

Tip

See the FontAwesome Icon Reference for a complete list of all CSS classes to use for icons (aliases are not supported).

Badges

Badges are shorthands for Icons formatted with different colors. To add a badge to some inline text, use the corresponding class among those listed in the following table. For example, the following code:

[Genoa, Italy](class:badge-geo)

produces the following result:

Genoa, Italy

HastyScribe currently supports the following badges:

Class Badge Class Badge
badge-todo badge-user
badge-fixme badge-tag
badge-deadline badge-tags
badge-comment badge-attachment
badge-urgent badge-bug
badge-verify badge-geo
badge-project badge-square
badge-star badge-check
badge-heart badge-rss
badge-lock badge-danger
badge-unlock badge-question
badge-folder badge-flag
badge-story badge-feature
badge-add badge-remove
badge-time badge-date
badge-html5 badge-css3
badge-apple badge-windows
badge-linux badge-android
badge-freebsd badge-aws
badge-idea badge-link
badge-chrome badge-firefox
badge-ie badge-edge
badge-safari badge-opera
badge-php badge-erlang
badge-python badge-java
badge-nodejs badge-js
badge-toggle-on badge-toggle-off
badge-debian badge-fedora
badge-centos badge-suse
badge-redhat badge-ubuntu
badge-rust badge-go
badge-rpi badge-markdown
badge-react badge-angular
badge-vue badge-code
badge-address badge-org
badge-toxic badge-network
badge-upload badge-download

Anchors

You can define HTML anchors inline by wrapping their ID in hashes. For example, the following code:

 Some text goes here. #some_text#

Is converted to:

 Some text goes here. <a id="some_text"></a>

Note

  • Anchor markup must be preceded by at least one space.
  • IDs must start with a letter, and can contain letters, numbers, and any of the following characters: _ - . :

Links

Source Output
[H3RALD](https://h3rald.com/) H3RALD
[H3RALD](https://h3rald.com/ "H3RALD") H3RALD
<https://h3rald.com> https://h3rald.com

Additionally, you can define placeholders for URLs and link titles, like this:

[h3rald]: https://h3rald.com/ "Fabio Cevasco's Web Site"

And use them in hyperlinks (note the usage of square brackets instead of round brackets):

[H3RALD][h3rald]

Block-level Formatting

Headings

Headings can be specified simply by prepending #s to text, as follows:

# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

Note

If you use Document Headers, A H1 is used for the title of the HastyScribe document. Within the document, start using headings from H2.

Tables

HastyScribe supports PHP Markdown Extra table syntax using pipes and dashes.

The following HastyScribe Markdown code:

Column Header 1 | Column Header 2 | Column Header 3 
----------------|-----------------|----------------
Cell 1,1        | Cell 1,2        | Cell 1, 3
Cell 2,1        | Cell 2,2        | Cell 2, 3
Cell 3,1        | Cell 3,2        | Cell 3, 3

Produces the following output:

Column Header 1 Column Header 2 Column Header 3
Cell 1,1 Cell 1,2 Cell 1, 3
Cell 2,1 Cell 2,2 Cell 2, 3
Cell 3,1 Cell 3,2 Cell 3, 3

Note

Multi-row cells are not supported. If you need more complex tables, use HTML code instead.

Block Quotes

Block quotes can be created simply by prepending a > to a line, and they can be nested by prepending additional >s.

The following HastyScribe Markdown code:

> This is a block quote.
> > This is a nested quote. 

Produces the following output:

This is a block quote.

This is a nested quote.

Code Blocks

To format a block of source code, indent it by at least four spaces. Here’s the result:

proc encode_image_file*(file, format): string =
  if (file.existsFile):
    let contents = file.readFile
    return encode_image(contents, format)
  else: 
    echo("Warning: image '"& file &"' not found.")
    return file

Alternatively, you can also use Github-style fenced blocks, by adding three tildes (~~~) or backticks (```) before and after the source code.

Warning

HastyScribe does not support syntax highlighting for code blocks. To do so, it would require Javascript and HastyScribe is currently kept purposedly “Javascript-free”.

Images

The following HastyScribe Markdown code:

![HastyScribe Logo](./images/hastyscribe.png =221x65)

Produces the following output:

HastyScribe Logo

Tip

You can use URL placeholders for images as well, exactly like for links.

Limitations on automatic image download

HastyScribe will attempt to download all HTTP image links. Note that:

  • If no response is received within 5 seconds, the download will be aborted.
  • Connecting through a proxy is currently not supported.
  • To download an image via HTTPS, you must explicitly recompile HastyScribe with -d:ssl and OpenSSL must be installed on your system.

If HastyScribe is unable to download an image, it will leave it linked.

Details

The following HastyScribe Markdown code:

<details>
<summary>Details</summary>
The `details` element can be used to create a disclosure element whose contents are only visible when the element is toggled open.
</details>

Produces the following output:

Details The details element can be used to create a disclosure element whose contents are only visible when the element is toggled open.

Footnotes

The following HastyScribe Markdown code:

This is some text[^1]

[^1]: This is a footnote!

Produces the following output:

This is some text1

Lists

Unordered Lists

The following HastyScribe Markdown code:

* An item
* Another item
* And another...

Produces the following output:

Ordered Lists

The following HastyScribe Markdown code:

1. First item
2. Second item
3. Third item

Produces the following output:

  1. First item
  2. Second item
  3. Third item

Tip

You don’t have to write numbers in order – any number followed by a dot will do.

Alphabetical Lists

The following HastyScribe Markdown code:

a. First item
b. Second item
c. Third item

Produces the following output:

  1. First item
  2. Second item
  3. Third item

Tip

You don’t have to write letters in order – any letter followed by a dot will do.

Checklists

The following HastyScribe Markdown code:

- [ ] Do something
- [ ] Do something else
- [x] Done!

Produces the following output:

Unstyled Lists

The following HastyScribe Markdown code:

> %unstyled%
> * An item
> * Another item
> * And another...

Produces the following output:

  • An item
  • Another item
  • And another…
Nested Lists

To create a list within a list, simply indent the whole nested list with four space.

The following HastyScribe Markdown code:

* This is a normal list
* Another item
    * A nested unordered list
    * Another item
* Back in the main list
    a. A nested alphabetical list
    b. Another item

Produces the following output:

Definition Lists

In some cases you may want to write a list of terms and their corresponding definitions. You could use an ordinary unordered list, but semantically speaking the proper type of list to use in this case is a definition list.

The following HastyScribe Markdown code:

unordered list
: A list for unordered items. Also called _bulleted list_.
ordered list 
: A list for ordered items. Also called _numbered list_.
alphabetical list
: Technically speaking just an ordered list, but formatted with letters instead 
  of numbers
definition list
: A list of terms and definitions.

Produces the following output:

unordered list
A list for unordered items. Also called bulleted list.
ordered list
A list for ordered items. Also called numbered list.
alphabetical list
Technically speaking just an ordered list, but formatted with letters instead of numbers
definition list
A list of terms and definitions.

Alternatively, you can write the above definition list as follows:

=unordered list=
  A list for unordered items. Also called _bulleted list_.
=ordered list=
  A list for ordered items. Also called _numbered list_.
=alphabetical list=
  Technically speaking just an ordered list, but formatted with letters instead
  of numbers
=definition list=
  A list of terms and definitions.

Class Blocks

Notes

Discount supports the definition of class blocks: divs with a class attribute. The syntax is very similar to the one used for block quotes, with the addition of the class name wrapped in %s on the first line.

In HastyScribe, this syntax is used to produce notes, tips, warmings, sidebars and terminal sessions.

The following HastyScribe Markdown code:

> %note%
> Note
> 
> This is a note.

Produces the following output:

Note

This is a note.

Tips

Tips are used for optional information that can help the user in some way.

The following HastyScribe Markdown code:

> %tip%
> Tip
> 
> This is a tip.

Produces the following output:

Tip

This is a tip.

Warnings

Warnings are used for important information the user should not overlook.

The following HastyScribe Markdown code:

> %warning%
> Warning
> 
> This is a warning or an important note.

Produces the following output:

Warning

This is a warning or an important note.

Sidebars

Sidebars are used for digressions and asides.

The following HastyScribe Markdown code:

> %sidebar%
> This is a _sidebar_
> 
> Although not always placed on the side of the page, _sidebars_ contain 
> additional content and asides.

Produces the following output:

Blank Sidebars

Blank sidebars can be customized to include custom icons. They are suitable for conditional (operating system or browser specific) instructions.

The following HastyScribe Markdown code:

> %blank-sidebar%
> [](class:chrome)[](class:firefox)[](class:edge) Browser Support
> 
> This web app supports only modern browsers, i.e. the latest versions of Google Chrome, Mozilla Firefox and Microsoft Edge, but _not_ Microsoft Internet Explorer.

Produces the following output:

Browser Support

This web app supports only modern browsers, i.e. the latest versions of Google Chrome, Mozilla Firefox and Microsoft Edge, but not Microsoft Internet Explorer.

Terminal Sessions

Terminal sessions are used to display commands entered in a terminal, in sequence, without displaying their output.

The following HastyScribe Markdown code:

> %terminal%
> 
> cd src
> 
> ./configure
> 
> make && sudo make install

Produces the following output:

cd src

./configure

make && sudo make install

If commands must be executed as a super-user, use the terminal-su class instead:

The following HastyScribe Markdown code:

> %terminal-su%
> 
> shutdown -h now

Produces the following output:

shutdown -h now

Nim API

Besides its command libe, you can also import HastyScribe as a library within your Nim program.

Types

HastyScribe exposes the following Nim types:

HastyOptions* = object
  toc*: bool
  input*: string
  output*: string
  css*: string
  js*: string
  watermark*: string
  fragment*: bool

HastyFields* = Table[string, proc():string]

HastySnippets* = Table[string, string]

HastyMacros* = Table[string, string]

HastyScribe* = object
  options: HastyOptions
  fields: HastyFields
  snippets: HastySnippets
  macros: HastyMacros
  document: string

Procs

HastyScribe exposes the following procs.

newHastyScribe

 proc newHastyScribe*(options: HastyOptions, fields: HastyFields): HastyScribe

Instantiates a new HastyScribe object.

dump

 proc dump*(hs: var HastyScribe, data="all", dest=".")

Saves linked resources to the dest directory.

data can be set to one of the following values:

all
Dumps all resource files.
styles
Dumps all stylesheet files.
fonts
Dumps all font files.

compileFragment

 proc compileFragment*(hs: var HastyScribe, input, dir: string, toc = false): string {.discardable.}

Compiles the input markdown text into an HTML fragment, without embedding stylesheets or fonts. dir identifies the directory containing the input text (it is only used to resolve transclusions).

compileDocument

 proc compileDocument*(hs: var HastyScribe, input, dir: string): string {.discardable.}

Compiles the input markdown text into a self-contained HTML document, embedding stylesheets and fonts. dir identifies the directory containing the input text (it is only used to resolve transclusions).

compile

 proc compile*(hs: var HastyScribe, input_file: string)

Compiles the markdown file input_file into a self-contained HTML document.

Credits

HastyScribe is powered by the following open source software (see LICENSE.md for licensing details):

Special thanks to:


  1. This is a footnote!