mmark

package module
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 2, 2016 License: BSD-2-Clause Imports: 16 Imported by: 74

README

Mmark

Mmark is a powerful markdown processor Go geared for writing IETF document. It is, however also suited for writing books and other technical documentation.

Further documentation can be found at my site. A complete syntax document is being created. That syntax doc will also be mirrored on my website.

With Mmark your can write RFCs using markdown. Mmark (written in Go) provides an advanced markdown dialect that processes a single file to produce internet-drafts in XML format. Internet-drafts written in mmark can produce xml2rfc v2, xml2rfc v3 and HTML5 output.

It also allows for writing large documents such as technical books, like my Learning Go book. Sample text output of this book (when rendered as an I-D) can be found here. It is not perfect due to limitations in xml2rfc version 2. Fully rendered HTML version can be found here.

Mmark is a fork of blackfriday which is a [Markdown][1] processor implemented in [Go][2]. It supports a number of extensions, inspired by Leanpub, kramdown and Asciidoc, that allows for large documents to be written.

It adds the following syntax elements to black friday:

  • More enumerated lists.
  • Table and codeblock captions.
  • Table footer.
  • Subfigures.
  • Quote attribution.
  • Including other files.
  • [TOML][3] titleblock.
  • Inline Attribute Lists.
  • Indices.
  • Citations.
  • Abstract/Preface/Notes sections.
  • Parts.
  • Asides.
  • Main-, middle- and backmatter divisions.
  • Math support.
  • Example lists.
  • HTML Comment parsing.
  • BCP14 (RFC2119) keyword detection.
  • Include raw XML references.
  • Abbreviations.
  • Super- and subscript.
  • Callouts in code blocks.

There is no pretty printed output if you need that pipe the output through xmllint --format -.

Usage

In the mmark subdirectory you can build the mmark tool:

% cd mmark
% go build
% ./mmark -h
Mmark Markdown Processor v1.0
...

To output v2 xml just give it a markdown file and:

% ./mmark/mmark -xml2 -page mmark2rfc.md

Making a draft in text form:

% ./mmark/mmark -xml2 -page mmark2rfc.md > x.xml \
&& xml2rfc --text x.xml \
&& rm x.xml && mv x.txt mmark2rfc.txt

Outputting v3 xml is done with the -xml switch. There is not yet a processor for this XML, but you should be able to validate the resulting XML against the schema from the xml2rfc v3 draft. I'm trying to stay current with the latest draft for the V3 spec: https://tools.ietf.org/html/draft-hoffman-xml2rfc-21

TO BE MOVED TO THE SYNTAX DOCUMENT

Extensions

In addition to the standard markdown syntax, this package implements the following extensions:

  • Intra-word emphasis supression. The _ character is commonly used inside words when discussing code, so having markdown interpret it as an emphasis command is usually the wrong thing. Blackfriday lets you treat all emphasis markers as normal characters when they occur inside a word.

  • Tables. Tables can be created by drawing them in the input using a simple syntax:

    Name    | Age
    --------|-----:
    Bob     | 27
    Alice   | 23
    

    Tables can also have a footer, use equal signs instead of dashes for the separator. If there are multiple footer lines, the first one is used as a starting point for the table footer.

    Name    | Age
    --------|-----:
    Bob     | 27
    Alice   | 23
    ======= | ====
    Charlie | 4
    

    If a table is started with a block table header, which starts with a pipe or plus sign and a minimum of three dashes, it is a Block Table. A block table may include block level elements in each (body) cell. If we want to start a new cell reuse the block table header syntax. In the example below we include a list in one of the cells.

    |+-----------------------------------------------|
    | Default aligned |Left aligned| Center aligned  |
    |-----------------|:-----------|:---------------:|
    | First body part |Second cell | Third cell      |
    | Second line     |foo         | **strong**      |
    | Third line      |quux        | baz             |
    |------------------------------------------------|
    | Second body     |            | 1. Item2        |
    | 2 line          |            | 2. Item2        |
    |================================================|
    | Footer row      |            |                 |
    |-----------------+------------+-----------------|
    

    Note that the header and footer can't contain block level elements.

    Row spanning is supported as well, by using the multiple pipe syntax.

  • Subfigure. Fenced code blocks and indented code block can be grouped into a single figure containing both (or more) elements. Use the special quote prefix F> for this.

  • Fenced code blocks. In addition to the normal 4-space indentation to mark code blocks, you can explicitly mark them and supply a language (to make syntax highlighting simple). Just mark it like this:

    ``` go
    func getTrue() bool {
        return true
    }
    ```
    

    You can use 3 or more bac kticks to mark the beginning of the block, and the same number to mark the end of the block.

  • Autolinking. Mmark can find URLs that have not been explicitly marked as links and turn them into links.

  • Strikethrough. Use two tildes to mark text that should be crossed out.

  • Short References. Internal references use the syntax [](#id), usually the need for the title within the brackets is not needed, so mmark has the shorter syntax (#id) to cross reference in the document.

  • Hard line breaks. With this extension enabled newlines in the input translate into line breaks in the output. This is activate by using two trailing spaces before a new line. Another way to get a hard line break is to escape the newline with a . And yet another another way to do this is to use 2 backslashes it the end of the line.

  • Includes, support including files with {{filename}} syntax. This is only done when include is started at the beginning of a line.

  • Code Block Includes, use the syntax <{{code/hello.c}}[address], where address is the syntax described in https://godoc.org/golang.org/x/tools/present/, the OMIT keyword in the code also works.

    So including a code snippet will work like so:

    <{{test.go}}[/START OMIT/,/END OMIT/]
    

    where test.go looks like this:

    tedious_code = boring_function()
    // START OMIT
    interesting_code = fascinating_function()
    // END OMIT
    

    To aid in including HTML or XML fragments, where the OMIT key words is probably embedded in comments, lines which end in OMIT --> are also excluded.

    Of course the captioning works here as well:

    <{{test.go}}[/START OMIT/,/END OMIT/]
    Figure: A sample program.
    

    The address may be omitted: <{{test.go}} is legal as well.

    Note that the special prefix attribute can be set in an IAL and it will be used to prefix each line with the value of prefix.

    {prefix="S"}
    <{{test.go}}
    

    Will cause test.go to be included with each line being prefixed with S.

  • Indices, using (((item, subitem))) syntax. To make item primary, use an !: (((!item, subitem))). Just (((item))) is allowed as well.

  • Citations, using the citation syntax from pandoc [@RFC2535 p. 23], the citation can either be informative (default) or normative, this can be indicated by using the ? or ! modifier: [@!RFC2535]. Use [-@RFC1000] to add the citation to the references, but suppress the output in the document. The highest modifier seen determines the final type, i.e. once a citation is declared normative it will stay normative, but informative will be upgraded to normative.

    If you reference an RFC or I-D the reference will be constructed automatically. For I-Ds you may need to add a draft sequence number, which can be done as such: [@?I-D.blah#06]. If you have other references you can include the raw XML in the document (before the {backmatter}). Also see XML references.

    If you reference an I-D without a sequence number it will create a reference to the last I-D in citation index.

    Once a citation has been defined (i.e. the reference anchor is known to mmark) you can use @RFC2535 is a shortcut for the citation.

  • Captions, table and figure/code block captions. For tables add the string Table: caption text after the table, this will be rendered as an caption. For code blocks you'll need to use Figure:

     Name    | Age
     --------|-----:
     Bob     | 27
     Alice   | 23
     Table: This is a table.
    

    Or for a code block:

     ``` go
     func getTrue() bool {
         return true
     }
     ```
     Figure: Look! A Go function.
    
  • Quote attribution, after a block quote you can optionally use Quote: http://example.org -- John Doe, where the quote will be attributed to John Doe, pointing to the URL:

     > Ability is nothing without opportunity.
     Quote: http://example.com -- Napoleon Bonaparte
    
  • Abstracts, use the special header .# Abstract. Note that the header name, when lowercased, must match 'abstract'.

  • Notes, use the special header #. Title, if the Title does not match (lowercase) abstract it will be a note.

  • Asides, any paragraph prefixed with A> .

  • Subfigures, any paragraph prefix with F> will wrap all images and code in a single figure.

  • {frontmatter}/{mainmatter}/{backmatter} Create useful divisions in your document.

  • IAL, kramdown's Inline Attribute List syntax, but took the CommonMark proposal, thus without the colon after the brace {#id .class key=value key="value"}. IALs are used for the following (block) elements:

    • Table
    • Code Block
    • Fenced Code Block
    • List (any type)
    • Section Header
    • Image
    • Quote
    • ...
  • Definitition lists, the markdown extra syntax.

     Apple
     :   Pomaceous fruit of plants of the genus Malus in
         the family Rosaceae.
    
     Orange
     :   The fruit of an evergreen tree of the genus Citrus.
    
  • Enumerated lists, roman, uppercase roman and normal letters can be used to start lists. Note that you'll need two space after the list counter:

     a.  Item2
     b.  Item2
    
  • TOML TitleBlock, add an extended title block prefixed with % in TOML. See the examples RFC in the rfc/ subdirectory. An alternate way of typesetting the TOML title block is wrapping it between two lines consisting out of 3 or more %%%s. Added benefit of wrapping it in %%%-lines is that the block may be indented (TOML disregards whitespace) 4 spaces, making it look like code in other markdown renderers (think Github).

  • Unique anchors, make anchors unique by adding sequence numbers (-1, -2, etc.) to them. All numeric section get an anchor prefixed with section-.

  • Example lists, a list that is started with (@good) is subsequently numbered i throughout the document. First use is rendered (1), the second one (2) and so on. You can reference the last item of the list with (@good).

  • HTML comments An HTML comment in the form of <!-- Miek Gieben -- really --> is detected and will be converted to a cref with the source attribute set to "Miek Gieben" and the comment text set to "really".

  • XML references Any XML reference fragment included before the back matter, can be used as a citation reference.

  • BCP 14 If a RFC 2119 word is found enclosed in ** it will be rendered as an <bcp14> element: **MUST** becomes <bcp14>MUST</bcp14>.

  • Abbreviations: See https://michelf.ca/projects/php-markdown/extra/#abbr, any text defined by:

     *[HTML]: Hyper Text Markup Language
    

    Allows you to use HTML in the document and it will be expanded to <abbr title="Hyper Text Markup Language">HTML</abbr>. If you need text that looks like an abbreviation, but isn't, escape the colon:

     *[HTML]\: HyperTextMarkupLanguage
    
  • Super and subscripts, for superscripts use '^' and for subscripts use '~'. For example:

     H~2~O is a liquid. 2^10^ is 1024.
    

    Inside a sub/superscript you must escape spaces. Thus, if you want the letter P with 'a cat' in subscripts, use P~a\ cat~, not P~a cat~.

  • Parts, use the special part header -# to start a new part. This follows the header syntax, so -# Part {#part1} is a valid part header.

  • Math support, use $$ as the delimiter. If the math is part of a paragraph it will be displayed in line, if the entire paragraph consists out of math it considered display math. No attempt is made to parse what is between the $$.

  • Callouts, in codeblocks you can use <number> to create a callout, later you can reference it:

         Code  <1>
         More  <1>
         Not a callout \<3>
    
     As you can see in <1> but not in \<1>. There is no <3>.
    

    You can escape a callout with a backslash. The backslash will be removed in the output (both in source code and text). The callout identifiers will be remembered until the next code block. The above would render as:

             Code <1>
             Code <2>
             Not a callout <3>
    
         As you can see in (1, 2) but not in <1>. There is no <3>.
    

    Note that callouts are only detected with the IAL {callout="yes"} or any other non-empty value is defined before the code block. Now, you don't usually want to clobber your source code with callouts as this will lead to code that does not compile. To fix this the callout needs to be placed in a comment, but then your source show useless empty comments. To fix this mmark can optionally detect (and remove!) the comment and the callout, leaving your example pristine. This can be enabled by setting {callout="//"} for instance. The allowed comment patterns are //, # and ;.

Documentation

Overview

Package markdown is a package for parsing and processing markdown text. It translates plain text with simple formatting rules into HTML or XML.

Index

Constants

View Source
const (
	HTML_SKIP_HTML                 = 1 << iota // skip preformatted HTML blocks
	HTML_SKIP_STYLE                            // skip embedded <style> elements
	HTML_SKIP_IMAGES                           // skip embedded images
	HTML_SKIP_LINKS                            // skip all links
	HTML_SAFELINK                              // only link to trusted protocols
	HTML_NOFOLLOW_LINKS                        // only link with rel="nofollow"
	HTML_HREF_TARGET_BLANK                     // add a blank target
	HTML_OMIT_CONTENTS                         // skip the main contents (for a standalone table of contents)
	HTML_COMPLETE_PAGE                         // generate a complete HTML page
	HTML_USE_SMARTYPANTS                       // enable smart punctuation substitutions
	HTML_SMARTYPANTS_FRACTIONS                 // enable smart fractions (with HTML_USE_SMARTYPANTS)
	HTML_SMARTYPANTS_DASHES                    // enable smart dashes (with HTML_USE_SMARTYPANTS)
	HTML_SMARTYPANTS_LATEX_DASHES              // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS and HTML_SMARTYPANTS_DASHES)
	HTML_SMARTYPANTS_ANGLED_QUOTES             // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering
	HTML_FOOTNOTE_RETURN_LINKS                 // generate a link at the end of a footnote to return to the source
)

Html renderer configuration options.

View Source
const (
	EXTENSION_ABBREVIATIONS              // Render abbreviations `*[HTML]: Hyper Text Markup Language`
	EXTENSION_AUTO_HEADER_IDS            // Create the header ID from the text
	EXTENSION_AUTOLINK                   // Detect embedded URLs that are not explicitly marked
	EXTENSION_CITATION                   // Support citations via the link syntax
	EXTENSION_EXAMPLE_LISTS              // Render '(@tag)  ' example lists
	EXTENSION_FENCED_CODE                // Render fenced code blocks
	EXTENSION_FOOTNOTES                  // Pandoc-style footnotes
	EXTENSION_HARD_LINE_BREAK            // Translate newlines into line breaks
	EXTENSION_HEADER_IDS                 // Specify header IDs with {#id}
	EXTENSION_INCLUDE                    // Include file with {{ syntax
	EXTENSION_INLINE_ATTR                // Detect CommonMark's IAL syntax
	EXTENSION_LAX_HTML_BLOCKS            // Loosen up HTML block parsing rules
	EXTENSION_MATH                       // Detect $$...$$ and parse as math
	EXTENSION_MATTER                     // Use {frontmatter} {mainmatter} {backmatter}
	EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, order list, unorder list)block
	EXTENSION_PARTS                      // Detect part headers (-#)
	EXTENSION_QUOTES                     // Allow A> AS> and N> to be parsed as abstract, asides and notes
	EXTENSION_SHORT_REF                  // (#id) will be a cross reference.
	EXTENSION_SPACE_HEADERS              // Be strict about prefix header rules
	EXTENSION_TABLES                     // Render tables
	EXTENSION_TITLEBLOCK_TOML            // Titleblock in TOML
	EXTENSION_UNIQUE_HEADER_IDS          // When detecting identical anchors add a sequence number -1, -2 etc.
	EXTENSION_BACKSLASH_LINE_BREAK       // Translate trailing backslashes into line breaks
	EXTENSION_RFC7328                    // Parse RFC 7328 markdown. Depends on FOOTNOTES extension.

)

These are the supported markdown parsing extensions. OR these values together to select multiple extensions.

View Source
const (
	DefaultIpr  = "trust200902"
	DefaultArea = "Internet"
)
View Source
const Version = "1.3.1"
View Source
const (
	XML2_STANDALONE = 1 << iota // create standalone document
)

XML renderer configuration options.

View Source
const (
	XML_STANDALONE = 1 << iota // create standalone document
)

XML renderer configuration options.

Variables

View Source
var (

	// CitationsRFC is the URL where the citations for RFCs are.
	CitationsRFC = "http://xml2rfc.ietf.org/public/rfc/bibxml/"

	// CitationsANSI is the URL where the citations for ANSI documents are.
	CitationsANSI = "http://xml2rfc.ietf.org/public/rfc/bibxml2/"

	// CitationsID is the URL where the citations for I-Ds are.
	CitationsID = "http://xml2rfc.ietf.org/public/rfc/bibxml3/"

	// CitationsW3C is the URL where the citations for W3C documents are.
	CitationsW3C = "http://xml2rfc.ietf.org/public/rfc/bibxml4/"
)
View Source
var PIs = []string{"toc", "symrefs", "sortrefs", "compact", "subcompact", "private", "topblock", "header", "footer", "comments"}

PIs the processing instructions.

View Source
var SourceCodeTypes = map[string]bool{
	"abnf":       true,
	"asn.1":      true,
	"bash":       true,
	"c++":        true,
	"c":          true,
	"cbor":       true,
	"dtd":        true,
	"java":       true,
	"javascript": true,
	"json":       true,
	"mib":        true,
	"perl":       true,
	"pseudocode": true,
	"python":     true,
	"rnc":        true,
	"xml":        true,

	"go": true,
}

SourceCodeTypes are the different languages that are supported as a type attribute in sourcecode, see Section 2.48.4 of XML2RFC v3 (-21).

Functions

func Parse

func Parse(input []byte, renderer Renderer, extensions int) *bytes.Buffer

Parse is the main rendering function. It parses and renders a block of markdown-encoded text. The supplied Renderer is used to format the output, and extensions dictates which non-standard extensions are enabled.

To use the supplied Html or XML renderers, see HtmlRenderer, XmlRenderer and Xml2Renderer, respectively.

Types

type HtmlRendererParameters

type HtmlRendererParameters struct {
	// Prepend this text to each relative URL.
	AbsolutePrefix string
	// Add this text to each footnote anchor, to ensure uniqueness.
	FootnoteAnchorPrefix string
	// Show this text inside the <a> tag for a footnote return link, if the
	// HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
	// <sup>[return]</sup> is used.
	FootnoteReturnLinkContents string
}

type Markdown

type Markdown struct {
	// contains filtered or unexported fields
}

Markdown is an io.Writer. Writing a buffer with markdown text will be converted to the output format the renderer outputs. Note that the conversion only takes place when String() or Bytes() is called.

func NewMarkdown

func NewMarkdown(renderer Renderer, extensions int) *Markdown

func (*Markdown) Bytes

func (m *Markdown) Bytes() []byte

func (*Markdown) String

func (m *Markdown) String() string

func (*Markdown) Write

func (m *Markdown) Write(p []byte) (n int, err error)

type Renderer

type Renderer interface {
	// block-level callbacks
	BlockCode(out *bytes.Buffer, text []byte, lang string, caption []byte, subfigure bool, callouts bool)
	BlockQuote(out *bytes.Buffer, text []byte, attribution []byte)
	BlockHtml(out *bytes.Buffer, text []byte)
	CommentHtml(out *bytes.Buffer, text []byte)
	// SpecialHeader is used for Abstract and Preface. The what string contains abstract or preface.
	SpecialHeader(out *bytes.Buffer, what []byte, text func() bool, id string)
	// Note is use for typesetting notes.
	Note(out *bytes.Buffer, text func() bool, id string)
	Part(out *bytes.Buffer, text func() bool, id string)
	Header(out *bytes.Buffer, text func() bool, level int, id string)
	HRule(out *bytes.Buffer)
	List(out *bytes.Buffer, text func() bool, flags, start int, group []byte)
	ListItem(out *bytes.Buffer, text []byte, flags int)
	Paragraph(out *bytes.Buffer, text func() bool, flags int)

	Table(out *bytes.Buffer, header []byte, body []byte, footer []byte, columnData []int, caption []byte)
	TableRow(out *bytes.Buffer, text []byte)
	TableHeaderCell(out *bytes.Buffer, text []byte, flags, colspan int)
	TableCell(out *bytes.Buffer, text []byte, flags, colspan int)

	Footnotes(out *bytes.Buffer, text func() bool)
	FootnoteItem(out *bytes.Buffer, name, text []byte, flags int)
	TitleBlockTOML(out *bytes.Buffer, data *title)
	Aside(out *bytes.Buffer, text []byte)
	Figure(out *bytes.Buffer, text []byte, caption []byte)

	// Span-level callbacks
	AutoLink(out *bytes.Buffer, link []byte, kind int)
	CodeSpan(out *bytes.Buffer, text []byte)
	// CalloutText is called when a callout is seen in the text. Id is the text
	// seen between < and > and ids references the callout counter(s) in the code.
	CalloutText(out *bytes.Buffer, id string, ids []string)
	// Called when a callout is seen in a code block. Index is the callout counter, id
	// is the number seen between < and >.
	CalloutCode(out *bytes.Buffer, index, id string)
	DoubleEmphasis(out *bytes.Buffer, text []byte)
	Emphasis(out *bytes.Buffer, text []byte)
	Subscript(out *bytes.Buffer, text []byte)
	Superscript(out *bytes.Buffer, text []byte)
	Image(out *bytes.Buffer, link []byte, title []byte, alt []byte, subfigure bool)
	LineBreak(out *bytes.Buffer)
	Link(out *bytes.Buffer, link []byte, title []byte, content []byte)
	RawHtmlTag(out *bytes.Buffer, tag []byte)
	TripleEmphasis(out *bytes.Buffer, text []byte)
	StrikeThrough(out *bytes.Buffer, text []byte)
	FootnoteRef(out *bytes.Buffer, ref []byte, id int)
	Index(out *bytes.Buffer, primary, secondary []byte, prim bool)
	Citation(out *bytes.Buffer, link, title []byte)
	Abbreviation(out *bytes.Buffer, abbr, title []byte)
	Example(out *bytes.Buffer, index int)
	Math(out *bytes.Buffer, text []byte, display bool)

	// Low-level callbacks
	Entity(out *bytes.Buffer, entity []byte)
	NormalText(out *bytes.Buffer, text []byte)

	// Header and footer
	DocumentHeader(out *bytes.Buffer, start bool)
	DocumentFooter(out *bytes.Buffer, start bool)

	// Frontmatter, mainmatter or backmatter
	DocumentMatter(out *bytes.Buffer, matter int)
	References(out *bytes.Buffer, citations map[string]*citation)

	// Helper functions
	Flags() int

	// Attr returns the inline attribute.
	Attr() *inlineAttr
	// SetAttr set the inline attribute.
	SetAttr(*inlineAttr)
	// AttrString return the string representation of this inline attribute.
	AttrString(*inlineAttr) string
}

Renderer is the rendering interface. This is mostly of interest if you are implementing a new rendering format.

When a byte slice is provided, it contains the (rendered) contents of the element.

When a callback is provided instead, it will write the contents of the respective element directly to the output buffer and return true on success. If the callback returns false, the rendering function should reset the output buffer as though it had never been called.

Currently Html, XML2RFC v3 and XML2RFC v2 implementations are provided.

func HtmlRenderer

func HtmlRenderer(flags int, css, head string) Renderer

HtmlRenderer creates and configures an Html object, which satisfies the Renderer interface.

flags is a set of HTML_* options ORed together. css is a URL for the document's stylesheet.

func HtmlRendererWithParameters

func HtmlRendererWithParameters(flags int, css, head string, renderParameters HtmlRendererParameters) Renderer

func Xml2Renderer

func Xml2Renderer(flags int) Renderer

Xml2Renderer creates and configures a Xml2 object, which satisfies the Renderer interface.

flags is a set of XML2_* options ORed together

func XmlRenderer

func XmlRenderer(flags int) Renderer

XmlRenderer creates and configures a Xml object, which satisfies the Renderer interface.

flags is a set of XML_* options ORed together

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL