nim-markdown
Most markdown parsers parse markdown documents in two steps, so does nim-markdown. The two-step consists of blocks parsing and inline parsing.
- Block Parsing: One or more lines belongs to blocks, such as <p>, <h1>, etc.
- Inline Parsing: Textual contents within the lines belongs to inlines, such as <a>, <em>, <strong>, etc.
When parsing block elements, nim-markdown follows this algorithm:
- Step 1. Track current position pos in the document.
- Step 2. If the document since pos matches one of our parsers, then apply it.
- Step 3. After parsing, a new token is appended to the parent token, and then we advance pos.
- Step 4. Go back to Step 1 until the end of file.
# Hello World\nWelcome to **nim-markdown**.\nLet's parse it. ^ ^ ^ 0 14 EOF ^Document, pos=0 ^Heading(level=1, doc="Hello World"), pos=14. ^Paragraph(doc="Wel..."), pos=EOF. ^EOF, exit parsing.
After the block parsing step, a tree with only Block Tokens is constructed.
Document() +-Heading(level=1, doc="Hello World") +-Paragraph(doc="Wel...")
Then, we proceed to inline parsing. It walks the tree and expands more inline elements. The algorithm is the same, except we apply it to every Block Token. Eventually, we get something like this:
Document() +-Heading(level=1) +-Text("H") +-Text("e") +-Text("l") +-Text("l") +-Text("o") ... +-Paragraph() +-Text("W") +-Text("e") ... +-Em() +-Text("n") +-Text("i") +-Text("m") ... +-Text(".") ...
Finally, All Token types support conversion to HTML strings with the special $ proc,
Types
AtxHeadingParser = ref object of Parser
- Source Edit
AutoLinkParser = ref object of Parser
- Source Edit
BlanklineParser = ref object of Parser
- Source Edit
Blockquote = ref object of Block chunks*: seq[Chunk]
- Source Edit
BlockquoteParser = ref object of Parser
- Source Edit
CodeSpanParser = ref object of Parser
- Source Edit
Delimiter = ref object of Inline token*: Text kind*: string num*: int originalNum*: int isActive*: bool canOpen*: bool canClose*: bool
- Source Edit
DelimiterParser = ref object of Parser
- Source Edit
EscapeParser = ref object of Parser
- Source Edit
FencedCodeParser = ref object of Parser
- Source Edit
HardBreakParser = ref object of Parser
- Source Edit
HtmlBlockParser = ref object of Parser
- Source Edit
HtmlEntity = ref object of Inline
- Source Edit
HtmlEntityParser = ref object of Parser
- Source Edit
HtmlTableParser = ref object of Parser
- Source Edit
Image = ref object of Inline refId*: string allowNested*: bool url*: string alt*: string title*: string
- Source Edit
ImageParser = ref object of Parser
- Source Edit
IndentedCodeParser = ref object of Parser
- Source Edit
InlineHtml = ref object of Inline
- Source Edit
InlineHtmlParser = ref object of Parser
- Source Edit
Link = ref object of Inline refId*: string text*: string ## A link contains link text (the visible text). url*: string ## A link contains destination (the URI that is the link destination). title*: string ## A link contains a optional title.
- Source Edit
LinkParser = ref object of Parser
- Source Edit
MarkdownConfig = ref object escape*: bool ## escape ``<``, ``>``, and ``&`` characters to be HTML-safe keepHtml*: bool ## deprecated: preserve HTML tags rather than escape it blockParsers*: seq[Parser] inlineParsers*: seq[Parser]
- Options for configuring parsing or rendering behavior. Source Edit
MarkdownError = object of ValueError
- The error object for markdown parsing and rendering. Usually, you should not see MarkdownError raising in your application unless it's documented. Otherwise, please report it as an issue. Source Edit
ParagraphParser = ref object of Parser
- Source Edit
ParseResult = ref object token*: Token pos*: int
- Source Edit
ReferenceParser = ref object of Parser
- Source Edit
SetextHeadingParser = ref object of Parser
- Source Edit
SoftBreakParser = ref object of Parser
- Source Edit
State = ref object references*: Table[string, Reference] config*: MarkdownConfig
- Source Edit
Strikethrough = ref object of Inline
- Source Edit
StrikethroughParser = ref object of Parser
- Source Edit
TextParser = ref object of Parser
- Source Edit
ThematicBreak = ref object of Block
- Source Edit
ThematicBreakParser = ref object of Parser
- Source Edit
Procs
proc appendChild(token: Token; child: Token) {....raises: [], tags: [], forbids: [].}
- Source Edit
proc finalizeList(state: State; token: Token) {. ...raises: [Exception, KeyError, RegexError], tags: [RootEffect], forbids: [].}
- Source Edit
proc getAtxHeading(s: string; start: int = 0): tuple[level: int, doc: string, size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc getDelimiterStack(token: Token): DoublyLinkedList[Delimiter] {....raises: [], tags: [], forbids: [].}
- Source Edit
proc getIndentedCodeFirstLine(doc: string; start: int = 0): tuple[code: string, size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc getIndentedCodeRestLines(doc: string; start: int = 0): tuple[code: string, size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc getLinkDestination(doc: string; start: int): tuple[slice: Slice[int], size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc getLinkLabel(doc: string; start: int): tuple[label: string, size: int] {. ...raises: [MarkdownError, KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc getLinkText(doc: string; start: int; allowNested: bool = false): tuple[ slice: Slice[int], size: int] {....raises: [MarkdownError, ValueError, KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc getLinkTitle(doc: string; start: int): tuple[slice: Slice[int], size: int] {. ...raises: [], tags: [], forbids: [].}
- Source Edit
proc getSetextHeading(doc: string; start = 0): tuple[level: int, doc: string, size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc initCommonmarkConfig(escape = true; keepHtml = true; blockParsers = @[ ReferenceParser(), ThematicBreakParser(), BlockquoteParser(), UlParser(), OlParser(), IndentedCodeParser(), FencedCodeParser(), HtmlBlockParser(), AtxHeadingParser(), SetextHeadingParser(), BlanklineParser(), ParagraphParser()]; inlineParsers = @[DelimiterParser(), ImageParser(), AutoLinkParser(), LinkParser(), HtmlEntityParser(), InlineHtmlParser(), EscapeParser(), CodeSpanParser(), HardBreakParser(), SoftBreakParser(), TextParser()]): MarkdownConfig {....raises: [], tags: [], forbids: [].}
- Source Edit
proc initGfmConfig(escape = true; keepHtml = true; blockParsers = @[ ReferenceParser(), ThematicBreakParser(), BlockquoteParser(), UlParser(), OlParser(), IndentedCodeParser(), FencedCodeParser(), HtmlBlockParser(), HtmlTableParser(), AtxHeadingParser(), SetextHeadingParser(), BlanklineParser(), ParagraphParser()]; inlineParsers = @[DelimiterParser(), ImageParser(), AutoLinkParser(), LinkParser(), HtmlEntityParser(), InlineHtmlParser(), EscapeParser(), StrikethroughParser(), CodeSpanParser(), HardBreakParser(), SoftBreakParser(), TextParser()]): MarkdownConfig {. ...raises: [], tags: [], forbids: [].}
- Source Edit
proc isBlockquote(s: string; start: int = 0): bool {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc isContinuationText(doc: string; start: int = 0; stop: int = 0): bool {. ...raises: [KeyError, RegexError, Exception, ValueError], tags: [RootEffect], forbids: [].}
- Source Edit
proc isOlNo1ListItem(doc: string; start: int = 0; stop: int = 0): bool {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc isUlEmptyListItem(doc: string; start: int = 0; stop: int = 0): bool {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc markdown(doc: string; config: MarkdownConfig = nil; root: Token = Document()): string {. ...raises: [KeyError, RegexError, Exception, MarkdownError], tags: [RootEffect], forbids: [].}
-
Convert a markdown document into a HTML document.
config:
- You can set config=initCommonmarkConfig() to apply commonmark syntax (default).
- Or, set config=initGfmConfig() to apply GFM syntax.
root:
- You can set root=Document() (default).
- Or, set root to any other token types, such as root=Blockquote(), or even your customized Token types, such as root=Div().
proc matchHtmlStart(doc: string; start: int = 0; bufsize: int = 0): tuple[ startRe: Regex, endRe: Regex, endMatch: bool, continuation: bool] {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc normalizeLabel(label: string): string {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc parseBlankLine(doc: string; start: int): ParseResult {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
proc parseCodeContent(doc: string; indent: int; fence: string): tuple[ code: string, size: int] {....raises: [KeyError, RegexError, ValueError], tags: [], forbids: [].}
- Source Edit
proc parseCodeInfo(doc: string; start: int = 0): tuple[info: string, size: int] {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc parseHTMLBlockContent(doc: string; startPattern: string; endPattern: string; ignoreCase = false): tuple[ html: string, size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc parseIndentedCode(doc: string; start: int): ParseResult {. ...raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
proc parseOrderedListItem(doc: string; start = 0; marker: var string; listItemDoc: var string; index: var int = 1): int {. ...raises: [KeyError, RegexError, ValueError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
proc parseTableAligns(doc: string): tuple[aligns: seq[string], matched: bool] {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc parseTableRow(doc: string): seq[string] {....raises: [], tags: [], forbids: [].}
- Source Edit
proc parseTildeBlockCodeInfo(doc: string; start: int = 0): tuple[info: string, size: int] {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
proc parseUnorderedListItem(doc: string; start = 0; marker: var string; listItemDoc: var string): int {. ...raises: [KeyError, RegexError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
proc processEmphasis(state: State; token: Token) {....raises: [], tags: [], forbids: [].}
- Source Edit
proc readCLIOptions(): MarkdownConfig {....raises: [], tags: [], forbids: [].}
-
Read options from command line. If no option passed, the corresponding option will be the default.
Available options:
- -e / --escape
- --no-escape
- -k / --keep-html
- '--no-keep-html`
proc removeDelimiter(delimiter: var DoublyLinkedNode[Delimiter]) {....raises: [], tags: [], forbids: [].}
- Source Edit
proc replaceInitialTabs(doc: string): string {....raises: [], tags: [], forbids: [].}
- Source Edit
proc scanInlineDelimiters(doc: string; start: int; delimiter: var Delimiter) {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
Methods
method `$`(token: AutoLink): string {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method `$`(token: Blockquote): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: CodeBlock): string {....raises: [KeyError, RegexError, ValueError], tags: [], forbids: [].}
- Source Edit
method `$`(token: Em): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: Heading): string {....raises: [Exception, ValueError], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: HtmlEntity): string {....raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method `$`(token: HtmlTable): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: Image): string {....raises: [KeyError, RegexError, ValueError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: InlineHtml): string {....raises: [ValueError, KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method `$`(token: Li): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: Link): string {....raises: [KeyError, RegexError, ValueError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: Ol): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: Paragraph): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: Strikethrough): string {....raises: [], tags: [], forbids: [].}
- Source Edit
method `$`(token: Strong): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: TableRow): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: TBody): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: TBodyCell): string {....raises: [Exception, ValueError], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: THead): string {....raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: THeadCell): string {....raises: [Exception, ValueError], tags: [RootEffect], forbids: [].}
- Source Edit
method `$`(token: ThematicBreak): string {....raises: [], tags: [], forbids: [].}
- Source Edit
method apply(this: Blockquote; state: State; res: ParseResult): ParseResult {. ...raises: [Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method apply(this: Image; state: State; res: ParseResult): ParseResult {. ...raises: [KeyError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method apply(this: Link; state: State; res: ParseResult): ParseResult {. ...raises: [KeyError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method apply(this: Ol; state: State; res: ParseResult): ParseResult {. ...raises: [Exception, KeyError, RegexError], tags: [RootEffect], forbids: [].}
- Source Edit
method apply(this: Reference; state: State; res: ParseResult): ParseResult {. ...raises: [], tags: [], forbids: [].}
- Source Edit
method apply(this: Token; state: State; res: ParseResult): ParseResult {.base, ...raises: [], tags: [], forbids: [].}
- Source Edit
method apply(this: Ul; state: State; res: ParseResult): ParseResult {. ...raises: [Exception, KeyError, RegexError], tags: [RootEffect], forbids: [].}
- Source Edit
method parse(this: AutoLinkParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, ValueError], tags: [], forbids: [].}
- Source Edit
method parse(this: BlanklineParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: BlockquoteParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, ValueError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method parse(this: CodeSpanParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: DelimiterParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: EscapeParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: FencedCodeParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, ValueError], tags: [], forbids: [].}
- Source Edit
method parse(this: HardBreakParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: HtmlBlockParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: HtmlEntityParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: HtmlTableParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: ImageParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, MarkdownError, ValueError], tags: [], forbids: [].}
- Source Edit
method parse(this: IndentedCodeParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: InlineHtmlParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: LinkParser; doc: string; start: int): ParseResult {. ...raises: [MarkdownError, ValueError, KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: OlParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, ValueError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method parse(this: ParagraphParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, Exception, ValueError], tags: [RootEffect], forbids: [].}
- Source Edit
method parse(this: Parser; doc: string; start: int): ParseResult {.base, ...raises: [], tags: [], forbids: [].}
- Source Edit
method parse(this: ReferenceParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit
method parse(this: SoftBreakParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: StrikethroughParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: TextParser; doc: string; start: int): ParseResult {. ...raises: [], tags: [], forbids: [].}
- Source Edit
method parse(this: ThematicBreakParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError], tags: [], forbids: [].}
- Source Edit
method parse(this: UlParser; doc: string; start: int): ParseResult {. ...raises: [KeyError, RegexError, Exception], tags: [RootEffect], forbids: [].}
- Source Edit