Skip to content

Instantly share code, notes, and snippets.

@stevedonovan
Created August 11, 2011 13:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save stevedonovan/1139607 to your computer and use it in GitHub Desktop.
Save stevedonovan/1139607 to your computer and use it in GitHub Desktop.
Script to convert Markdown source with code blocks into syntax-highlighted HTML.
-- translate Markdown with code blocks into HTML
-- with syntax highlighting.
-- If article.md was the source, Lua was the language and we
-- wanted a preview:
-- lua prettify.lua article lua preview
-- Without the last argument it will just write out the HTML body.
-- Languages supported are 'lua', 'cpp', 'java' and 'go
-- Indented code blocks may begin with an explicit @lang name line;
-- if you do this then mark every code block explicitly
-- e.g
-- @lang lua
-- print "hello world"
--
-- (any line)
--
-- @lang go
-- fnt.Println("hello world"
--
-- Needs markdown.lua and Penlight.
-- Steve Donovan, 2011 MIT license.
require 'pl'
require 'markdown'
local tnext = lexer.skipws
local concat = table.concat
local escaped_chars = {
['&'] = '&',
['<'] = '&lt;',
['>'] = '&gt;',
}
local escape_pat = '[&<>]'
local function escape(str)
return (str:gsub(escape_pat,escaped_chars))
end
local function span(t,val)
return ('<span class="%s">%s</span>'):format(t,val)
end
local spans = {keyword=true,number=true,string=true,comment=true}
local jkeywords = {
final = true, extends = true, implements = true,
interface = true, import = true, throws = true, null = true
}
local gkeywords = { byte=true,chan=true,complex64=true,
complex128=true,defer=true,func=true,fallthrough=true,
float32=true,float64=true,string=true,uint=true,uintptr=true,
uint8=true,uint16=true,uint32=true,uint64=true,
var=true,len=true,map=true,package=true,range=true,select=true,
type=true,interface=true,int8=true,int16=true,int32=true,
int64=true,['nil']=true,func=true
}
local function prettify (code,lang)
local res = List()
res:append '<pre>\n'
local xkeywords = {}
local scanner
if lang == 'java' then
lang = 'cpp'
xkeywords = jkeywords
elseif lang == 'go' then
lang = 'cpp'
xkeywords = gkeywords
end
local tok = lexer[lang](code,{},{})
local t,val = tok()
if not t then return nil,"empty file" end
while t do
val = escape(val)
if xkeywords[val] then
t = 'keyword'
end
if spans[t] then
res:append(span(t,val))
else
res:append(val)
end
t,val = tok()
end
res:append '</pre>\n'
return res:join ()
end
local function indent_line (line)
line = line:gsub('\t',' ') -- support for barbarians ;)
local indent = #line:match '^%s*'
return indent,line
end
function prettify_code_blocks (txt,lang)
local res, append = {}, table.insert
local getline = stringx.lines(txt)
local line = getline()
local indent,code,start_indent
while line do
indent,line = indent_line(line)
if indent >= 4 then -- indented code block
code = {}
while indent >= 4 do
if not start_indent then start_indent = indent end
append(code,line:sub(start_indent))
line = getline()
if line == nil then break end
indent,line = indent_line(line)
end
code = concat(code,'\n')
local llang = code:match('^%s*@lang (%a+)')
if llang then
lang = llang
code = code:gsub('%s*@lang%s+%a+\n','')
end
code = prettify(code,lang)
append(res,code)
start_indent = nil
end
append(res,line)
line = getline()
end
return concat(res,'\n')
end
local function remove_spurious_lines (txt)
return txt:gsub('</p>%s*','</p>\n'):gsub('</pre>%s*','</pre>\n')
end
if #arg == 0 then
return print("markdown-file-without-extension language (preview)")
end
name = arg[1]
lang = arg[2] or 'lua'
preview = arg[3]
preamble = [[
<html>
<head>
<style type="text/css">
.keyword {font-weight: bold; color: #6666AA; }
.number { color: #AA6666; }
.string { color: #8888AA; }
.comment { color: #666600; }
pre { font-weight: bold; }
</style>
</head>
<body>
]]
coda = [[
</body></html>
]]
text = utils.readfile(name..'.md')
text = prettify_code_blocks(text,lang)
text = markdown(text)
text = remove_spurious_lines(text)
if preview then
text = preamble .. text .. coda
end
utils.writefile(name..'.html',text)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment