Skip to content

Instantly share code, notes, and snippets.

@paulcuth
Last active August 13, 2017 20:25
Show Gist options
  • Save paulcuth/8967731 to your computer and use it in GitHub Desktop.
Save paulcuth/8967731 to your computer and use it in GitHub Desktop.
Lua port of Slimdown.

Slimdown

This is a Lua port of of jbroadway's PHP project of the same name.

A very basic pattern-based Markdown parser. Supports the following elements (and can be extended via slimdown.addRule()):

  • Headers
  • Links
  • Bold
  • Emphasis
  • Deletions
  • Quotes
  • Inline code
  • Code blocks
  • Blockquotes
  • Ordered/unordered lists

Usage

Here is the general use case:

local slimdown = require 'slimdown'
local html = slimdown.render '# Page title\n\nAnd **now** for something _completely_ different.'

Adding rules

A simple rule to convert :) to an image:

local slimdown = require 'slimdown'
slimdown.addRule(':%)', '<img src="smiley.png" />')

print(slimdown.render 'Know what I\'m sayin? :)')

A longer example

local slimdown = require 'slimdown'

print(slimdown.render [[# Title

And *now* [a link](http://www.google.com) to **follow** and [another](http://yahoo.com/).

* One
* Two
* Three

## Subhead

One **two** three **four** five.

One __two__ three _four_ five __six__ seven _eight_.

1. One
2. Two
3. Three

More text with `inline($code)` sample.

> A block quote
> across two lines.

More text...]])
-------------------------------------------------------------------------------
-- Slimdown - A very basic pattern-based Markdown parser.
-- Supports the following elements (and can be extended via addRule()):
--
-- * Headers
-- * Links
-- * Bold
-- * Emphasis
-- * Deletions
-- * Quotes
-- * Inline code
-- * Blockquotes
-- * Ordered/unordered lists
-- * Horizontal rules
--
-- Website:
-- PHP: https://gist.github.com/jbroadway/2836900
-- Lua: https://gist.github.com/paulcuth/8967731
--
-- @module Slimdown
-- @author Johnny Broadway <[email protected]>
-- @author Paul Cuthbertson <[email protected]>
-- @license MIT
--
-------------------------------------------------------------------------------
-- Trims whitespace from the beginning and end of a string.
-- @tparam string str String to be trimmed.
-- @treturn string Trimmed string.
--
local function trim (str)
return str:match '^[%s\n]*(.-)[%s\n]*$'
end
-------------------------------------------------------------------------------
-- Mark up a line as an HTML paragraph.
-- @tparam string line The line to mark up.
-- @treturn string HTML tag.
--
local function parseParagraph (line)
local trimmed = trim(line)
if
string.find(trimmed, '^</?ul')
or string.find(trimmed, '^</?ol')
or string.find(trimmed, '^</?li')
or string.find(trimmed, '^</?h')
or string.find(trimmed, '^</?p')
or string.find(trimmed, '^</?bl')
then
return '\n'..line..'\n'
end
return string.format('\n<p>%s</p>\n', trimmed)
end
-------------------------------------------------------------------------------
-- Mark up a line as an HTML unordered list.
-- @tparam string item The line to mark up.
-- @treturn string HTML tag.
--
local function parseUnorderedList (item)
return string.format('\n<ul>\n\t<li>%s</li>\n</ul>', trim(item))
end
-------------------------------------------------------------------------------
-- Mark up a line as an HTML ordered list.
-- @tparam string item The line to mark up.
-- @treturn string HTML tag.
--
local function parseOrderedList (item)
return string.format('\n<ol>\n\t<li>%s</li>\n</ol>', trim(item))
end
-------------------------------------------------------------------------------
-- Mark up a line as an HTML blockquote.
-- @tparam string item The line to mark up.
-- @treturn string HTML tag.
--
local function parseBlockquote (item)
return string.format('\n<blockquote>%s</blockquote>', trim(item))
end
-------------------------------------------------------------------------------
-- Mark up a line as an HTML ordered list.
-- @tparam string chars The characters used to markdown the header.
-- @tparam string header Header string.
-- @treturn string HTML tag.
--
local function parseHeader (chars, header)
local level = #chars
return string.format('<h%d>%s</h%d>', level, trim(header), level)
end
-------------------------------------------------------------------------------
-- Conversion rules.
--
local rules = {
{ '(#+)(.-%\n)', parseHeader }, -- headers
{ '%[(.-)%]%((.-)%)', '<a href="%2">%1</a>' }, -- links
{ '%*%*([^%\n]-)%*%*', '<strong>%1</strong>' }, -- bold *
{ '__([^%\n]-)__', '<strong>%1</strong>' }, -- bold _
{ '%*([^%\n]-)%*', '<em>%1</em>' }, -- emphasis *
{ '_([^%\n]-)_', '<em>%1</em>' }, -- emphasis _
{ '~~([^%\n]-)~~', '<del>%1</del>' }, -- del
{ ':"([^%\n]-)":', '<q>%1</q>' }, -- quote
{ '`([^%\n]-)`', '<code>%1</code>' }, -- inline code
{ '```(.-)```', '<code>%1</code>' }, -- code block
{ '%\n%*([^%\n]*)', parseUnorderedList }, -- ul lists
{ '%\n[0-9]+%.([^%\n]*)', parseOrderedList }, -- ol lists
{ '%\n%-%-%-%-%-%-*', '\n<hr />' }, -- horizontal rule
{ '%\n&gt;([^%\n]*)', parseBlockquote }, -- blockquotes &gt;
{ '%\n>([^%\n]*)', parseBlockquote }, -- blockquotes >
{ '%\n([^%\n]+)%\n', parseParagraph }, -- add paragraphs
{ '</ul>%s*<ul>%\n', '' }, -- fix extra ul
{ '</ol>%s*<ol>%\n', '' }, -- fix extra ol
{ '</blockquote>%s*<blockquote>', '</br>' }, -- fix extra blockquote
}
-------------------------------------------------------------------------------
-- Adds a new rule to the mix.
-- @usage slimdown.addRule(':%)', '<img src="smiley.png" />')
-- @tparam string pattern Pattern to match.
-- @tparam string|function replacement Replacement string or parsing function.
--
function addRule (pattern, replacement)
table.insert(rules, { pattern, replacement })
end
-------------------------------------------------------------------------------
-- Renders markdown text as HTML.
-- @usage slimdown.render('[Slimdown in Lua](https://gist.github.com/paulcuth/8967731)')
-- @tparam string text Markdown content.
-- @treturn string HTML.
--
function render (text)
text = '\n'..text..'\n'
for i = 1, #rules do
text = string.gsub(text, unpack(rules[i]))
end
return trim(text)
end
-------------------------------------------------------------------------------
-- Module definition
return {
addRule = addRule,
render = render
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment