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:
- lets you focus on content and keeps things simple, while giving you all the power of Discount-enriched markdown (plus some more goodies).
- takes care of styling your documents properly, making sure they look good on your desktop and even on small screens, ready to be distributed.
- is a single, small executable file, with no dependencies. To be fair, it’s about 1MB in size when compiled for OSX – but that’s only because the HastyScribe executable embeds all the fonts and stylesheets it needs to produce documents.
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:
- format blocks of texts to create notes and sidebars
- style text using CSS classes
- create definition lists and alphabetical lists
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:
- By default, the HastyScribe, FontAwesome, Source Sans Pro, and Source Code Pro fonts are automatically embedded.
- All referenced images (both local and remote) are automatically embedded using the data URI scheme.
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:
- Download and install Nim.
- Clone the HastyScribe repository.
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:
- filename-or-glob-expression is a valid file or glob) expression that will be compiled into HTML.
- The following options are supported:
- --field/<field>=<value> causes HastyScribe to set a custom field to a specific value.
- --notoc causes HastyScribe to output HTML documents without automatically generating a Table of Contents at the start.
- --user-css=<file> causes HastyScribe to insert the contents of the specified local file as a CSS stylesheet.
- --user-js=<file> causes HastyScribe to insert the contents of the specified local file as a Javascript script.
- --output-file=<file> causes HastyScribe to write output to a local file (Use --output-file=- to output to standard output).
- --watermark=<file> causes HastyScribe to embed and display an image as a watermark throughout the document.
- --fragment causes HastyScribe to output just an HTML fragment instead of a full document, without embedding any image, font or stylesheet.
- --noembed causes styles and images not to be embedded.
- --help causes HastyScribe to display the usage information and quit.
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~~ |
|
<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:
`` text‘’
→ “text”."double-quoted text"
→ “double-quoted text”'single-quoted text'
→ ‘single-quoted text’don't
→ don’t. as well as anything-else’t. (But foo'tbar is just foo'tbar.)it's
→ it’s, as well as anything-else’s (except not foo'sbar and the like.)(tm)
→ ™(r)
→ ®(c)
→ ©1/4th
→ ¼th. Same goes for ½ and ¾....
or. . .
→ …---
→ —--
→ –A^B
becomes AB. Complex superscripts can be enclosed in brackets, soA^(B+2)
→ AB+2.
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:
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:
- An item
- Another item
- And another…
Ordered Lists
The following HastyScribe Markdown code:
1. First item
2. Second item
3. Third item
Produces the following output:
- First item
- Second item
- 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:
- First item
- Second item
- 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:
- [ ] Do something
- [ ] Do something else
- [x] Done!
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:
- This is a normal list
- Another item
- A nested unordered list
- Another item
- Back in the main list
- A nested alphabetical list
- Another item
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:
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):
- The wonderful Discount C library, used to parse markdown code.
- The …awesome FontAwesome font, used for all the icons.
- The beautiful Mr Bedfort font, used as the base for the HastyScribe logo.
Special thanks to:
- Philip Wernersbach and Joshua Ellis, for contributing to HastyScribe.
- Andreas Rumpf, creator of the amazing Nim programming language, used to implement HastyScribe.
- This is a footnote!↩