├── LICENSE ├── README.md ├── lib └── resty │ ├── hoedown.lua │ └── hoedown │ ├── autolink.lua │ ├── buffer.lua │ ├── document.lua │ ├── escape.lua │ ├── html.lua │ ├── library.lua │ ├── renderer.lua │ ├── stack.lua │ └── version.lua └── lua-resty-hoedown-dev-1.rockspec /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Aapo Talvensaari 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lua-resty-hoedown 2 | 3 | `lua-resty-hoedown` is a Markdown, SmartyPants, buffer, and html and href/url escaping library implementing LuaJIT bindings to 4 | [Hoedown](https://github.com/hoedown/hoedown). 5 | 6 | ## Hello World with lua-resty-hoedown 7 | 8 | ```lua 9 | local hoedown = require "resty.hoedown" 10 | hoedown[[ 11 | # Are you ready for the truth? 12 | 13 | Now that there is the Tec-9, a crappy spray gun from South Miami. 14 | This gun is advertised as the most popular gun in American crime. 15 | Do you believe that shit? It actually says that in the little book 16 | that comes with it: the most popular gun in American crime. Like 17 | they're actually proud of that shit. 18 | 19 | ## I'm serious as a heart attack 20 | 21 | The path of the righteous man is beset on all sides by the iniquities 22 | of the selfish and the tyranny of evil men. Blessed is he who, in the 23 | name of charity and good will, shepherds the weak through the valley 24 | of darkness, for he is truly his brother's keeper and the finder of 25 | lost children. And I will strike down upon thee with great vengeance 26 | and furious anger those who would attempt to poison and destroy My 27 | brothers. 28 | ]] 29 | ``` 30 | 31 | This will return string containing: 32 | 33 | ```html 34 |
Now that there is the Tec-9, a crappy spray gun from South Miami. 37 | This gun is advertised as the most popular gun in American crime. 38 | Do you believe that shit? It actually says that in the little book 39 | that comes with it: the most popular gun in American crime. Like 40 | they're actually proud of that shit.
41 | 42 |The path of the righteous man is beset on all sides by the iniquities 45 | of the selfish and the tyranny of evil men. Blessed is he who, in the 46 | name of charity and good will, shepherds the weak through the valley 47 | of darkness, for he is truly his brother's keeper and the finder of 48 | lost children. And I will strike down upon thee with great vengeance 49 | and furious anger those who would attempt to poison and destroy My 50 | brothers.
51 | ``` 52 | 53 | ## Installation 54 | 55 | Just place [`resty directory`](https://github.com/bungle/lua-resty-hoedown/blob/master/lib/resty) somewhere in your `package.path`. If you are using OpenResty, the default location would be `/usr/local/openresty/lualib`. 56 | Please check though that you do not overwrite the existing resty-directory if one exists already. 57 | 58 | ### Compiling and Installing Hoedown C-library 59 | 60 | These are just rudimentary notes. Better installation instructions will follow: 61 | 62 | 1. First download Hoedown from here: https://github.com/hoedown/hoedown 63 | 2. Run `make` 64 | 3. Place `libhoedown.so` somewhere in the default search path for dynamic libraries of your operating system (or modify `resty/hoedown/library.lua` and point `ffi_load("libhoedown")` with full path to `libhoedown.so`. 65 | 66 | ### Using LuaRocks or MoonRocks 67 | 68 | If you are using LuaRocks >= 2.2: 69 | 70 | ```Shell 71 | $ luarocks install lua-resty-hoedown 72 | ``` 73 | 74 | If you are using LuaRocks < 2.2: 75 | 76 | ```Shell 77 | $ luarocks install --server=http://rocks.moonscript.org moonrocks 78 | $ moonrocks install lua-resty-hoedown 79 | ``` 80 | 81 | MoonRocks repository for `lua-resty-hoedown` is located here: https://rocks.moonscript.org/modules/bungle/lua-resty-hoedown. 82 | 83 | ## Lua API 84 | 85 | There are some functions called `free` on the API (to be complete implementation of Hoedown). You don't really need to 86 | call `:free()` as the library automatically handles freeing the external resources using normal LuaJIT garbage collector 87 | (the library registers the garbage collector handlers with `ffi.gc`). 88 | 89 | ### Document Processing Extensions 90 | 91 | With extensions, you may extend how to document processing works. 92 | Here are the available extensions: 93 | 94 | ```lua 95 | tables = HOEDOWN_EXT_TABLES, 96 | fenced_code = HOEDOWN_EXT_FENCED_CODE, 97 | footnotes = HOEDOWN_EXT_FOOTNOTES, 98 | autolink = HOEDOWN_EXT_AUTOLINK, 99 | strikethrough = HOEDOWN_EXT_STRIKETHROUGH, 100 | underline = HOEDOWN_EXT_UNDERLINE, 101 | highlight = HOEDOWN_EXT_HIGHLIGHT, 102 | quote = HOEDOWN_EXT_QUOTE, 103 | superscript = HOEDOWN_EXT_SUPERSCRIPT, 104 | math = HOEDOWN_EXT_MATH, 105 | no_intra_emphasis = HOEDOWN_EXT_NO_INTRA_EMPHASIS, 106 | space_headers = HOEDOWN_EXT_SPACE_HEADERS, 107 | math_explicit = HOEDOWN_EXT_MATH_EXPLICIT, 108 | disable_indented_code = HOEDOWN_EXT_DISABLE_INDENTED_CODE 109 | ``` 110 | 111 | ##### Example 112 | 113 | ```lua 114 | local hoedown = require "resty.hoedown" 115 | print(hoedown.document.extensions.tables) 116 | local doc = require "resty.hoedown.document" 117 | local extensions = doc.extensions 118 | print(extensions.tables) 119 | ``` 120 | 121 | ### HTML Rendering Flags 122 | 123 | With HTML rendering flags you can control the HTML rendering process. 124 | Hare are the available flags: 125 | 126 | ```lua 127 | skip_html = HOEDOWN_HTML_SKIP_HTML, 128 | escape = HOEDOWN_HTML_ESCAPE, 129 | hard_wrap = HOEDOWN_HTML_HARD_WRAP, 130 | use_xhtml = HOEDOWN_HTML_USE_XHTML 131 | ``` 132 | 133 | ##### Example 134 | 135 | ```lua 136 | local hoedown = require "resty.hoedown" 137 | print(hoedown.html.flags.skip_html) 138 | local html = require "resty.hoedown.html" 139 | local flags = html.flags 140 | print(flags.use_xhtml) 141 | ``` 142 | 143 | ### HTML Tag States 144 | 145 | These present values returned from `resty.hoedown.html.is_tag` function. 146 | The possible values are: 147 | 148 | ```lua 149 | none = HOEDOWN_HTML_TAG_NONE, 150 | open = HOEDOWN_HTML_TAG_OPEN, 151 | close = HOEDOWN_HTML_TAG_CLOSE 152 | ``` 153 | 154 | ##### Example 155 | 156 | ```lua 157 | local hoedown = require "resty.hoedown" 158 | print(hoedown.html.tag.open) 159 | local html = require "resty.hoedown.html" 160 | local tag = html.tag 161 | print(tag.open) 162 | ``` 163 | 164 | ### resty.hoedown 165 | 166 | A helper library that you may `require` with a single statement. 167 | 168 | #### string hoedown(source, opts) 169 | 170 | Helper function to rendering. `source` is a `string` containing a source document. 171 | You can also pass in options with `opts` argument. Here are the different options 172 | that you may use (you can also skip passing options): 173 | 174 | ```lua 175 | opts = { 176 | renderer = ("html" or "html.toc" or function or nil), 177 | extensions = (table or number or nil), 178 | max_nesting = (number or nil), 179 | flags = (table or number or nil), 180 | nesting = (number or nil), 181 | smartypants = (true or false or nil) 182 | } 183 | ``` 184 | 185 | ##### Example 186 | 187 | ```lua 188 | local hoedown = require "resty.hoedown" 189 | print(hoedown[[ 190 | # Hello World 191 | 192 | Hi this is Markdown. 193 | ]]) 194 | 195 | local flags = hoedown.html.flags 196 | 197 | print(hoedown([[ 198 | # Hello World 199 | 200 | Hi this is Markdown. 201 | ]], { 202 | rendered = "html.toc", 203 | nesting = 1, 204 | flags = { flags.use_xhtml, "escape", 1 }, 205 | extensions = { "underline", "quote" }, 206 | smartypants = true 207 | })) 208 | ``` 209 | 210 | #### Fields 211 | 212 | ##### table resty.hoedown.buffer 213 | 214 | This returns a [`buffer`](#restyhoedownbuffer) module. 215 | 216 | ##### table resty.hoedown.document 217 | 218 | This returns a [`document`](#restyhoedowndocument) module. 219 | 220 | ##### table resty.hoedown.html 221 | 222 | This returns an [`html`](#restyhoedownhtml) module. 223 | 224 | ##### table resty.hoedown.escape 225 | 226 | This returns an [`escape`](#restyhoedownescape) module. 227 | 228 | ##### table resty.hoedown.version 229 | 230 | This returns a [`version`](#restyhoedownversion) module. 231 | 232 | ### resty.hoedown.buffer 233 | 234 | #### cdata buffer.context 235 | #### string buffer.data 236 | #### number buffer.size 237 | #### number buffer.asize 238 | #### number buffer.unit 239 | #### table buffer.new(size) 240 | #### buffer:reset() 241 | #### buffer:grow(size) 242 | #### buffer:put(str) 243 | #### buffer:puts(str) 244 | #### buffer:set(str) 245 | #### buffer:sets(str) 246 | #### boolean buffer:eq(str) 247 | #### boolean buffer:eqs(str) 248 | #### number buffer:prefix(prefix) 249 | #### buffer:slurp(size) 250 | #### cdata buffer:cstr() 251 | #### buffer:printf(format, ...) 252 | #### buffer:free() 253 | #### number buffer.__len() 254 | #### boolean buffer:__eq() 255 | #### string buffer:__concat(x, y) 256 | #### string buffer:__tostring() 257 | 258 | ### resty.hoedown.document 259 | 260 | #### cdata document.context 261 | #### table document.extensions 262 | #### table document.new(renderer, extensions, max_nesting) 263 | #### string document:render(data) 264 | #### string document:render_inline(date) 265 | #### document:free() 266 | 267 | ### resty.hoedown.html 268 | 269 | #### cdata html.context 270 | #### table html.flags 271 | #### table html.tag 272 | #### string html.smartypants(data) 273 | #### number html.is_tag(data, tag) 274 | #### table html.new(flags, nesting) 275 | #### html:free() 276 | #### table html.toc 277 | #### table html.toc.new(nesting) 278 | #### html.toc:free() 279 | 280 | ### resty.hoedown.escape 281 | 282 | #### string escape(source, secure) 283 | #### string escape.href(source) 284 | #### string escape.html(source, secure) 285 | 286 | ### resty.hoedown.version 287 | 288 | #### number version.major 289 | #### number version.minor 290 | #### number version.revision 291 | #### string version:__tostring() 292 | 293 | ## License 294 | 295 | `lua-resty-hoedown` uses two clause BSD license. 296 | 297 | ``` 298 | Copyright (c) 2014, Aapo Talvensaari 299 | All rights reserved. 300 | 301 | Redistribution and use in source and binary forms, with or without modification, 302 | are permitted provided that the following conditions are met: 303 | 304 | * Redistributions of source code must retain the above copyright notice, this 305 | list of conditions and the following disclaimer. 306 | 307 | * Redistributions in binary form must reproduce the above copyright notice, this 308 | list of conditions and the following disclaimer in the documentation and/or 309 | other materials provided with the distribution. 310 | 311 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 312 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 313 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 314 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 315 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 316 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 317 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 318 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 319 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 320 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 321 | ``` 322 | -------------------------------------------------------------------------------- /lib/resty/hoedown.lua: -------------------------------------------------------------------------------- 1 | local setmetatable = setmetatable 2 | local type = type 3 | 4 | local hoedown = {} 5 | 6 | function hoedown:__call(source, opts) 7 | local renderer, extensions, max_nesting, smartypants 8 | if type(opts) == "table" then 9 | extensions, max_nesting, smartypants = opts.extensions, opts.max_nesting, opts.smartypants 10 | local t = type(opts.renderer) 11 | if t == "string" then 12 | if opts.renderer == "html.toc" then 13 | renderer = self.html.toc.new(opts.nesting) 14 | else 15 | renderer = self.html.new(opts.flags, opts.nesting) 16 | end 17 | elseif t == "function" then 18 | renderer = opts.renderer(opts) 19 | else 20 | renderer = self.html.new(opts.flags, opts.nesting) 21 | end 22 | else 23 | renderer = self.html.new() 24 | end 25 | if smartypants then 26 | return self.html.smartypants(self.document.new(renderer, extensions, max_nesting):render(source)) 27 | else 28 | return self.document.new(renderer, extensions, max_nesting):render(source) 29 | end 30 | end 31 | 32 | return setmetatable({ 33 | buffer = require "resty.hoedown.buffer", 34 | document = require "resty.hoedown.document", 35 | html = require "resty.hoedown.html", 36 | escape = require "resty.hoedown.escape", 37 | version = require "resty.hoedown.version" 38 | }, hoedown) 39 | -------------------------------------------------------------------------------- /lib/resty/hoedown/autolink.lua: -------------------------------------------------------------------------------- 1 | require "resty.hoedown.buffer" 2 | local ffi = require "ffi" 3 | local ffi_cdef = ffi.cdef 4 | 5 | ffi_cdef[[ 6 | typedef enum hoedown_autolink_flags { 7 | HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0) 8 | } hoedown_autolink_flags; 9 | int hoedown_autolink_is_safe(const uint8_t *data, size_t size); 10 | size_t hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link, uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags); 11 | size_t hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link, uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags); 12 | size_t hoedown_autolink__url(size_t *rewind_p, hoedown_buffer *link, uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags); 13 | ]] 14 | 15 | return {} 16 | 17 | -- TODO: NYI. -------------------------------------------------------------------------------- /lib/resty/hoedown/buffer.lua: -------------------------------------------------------------------------------- 1 | local lib = require "resty.hoedown.library" 2 | local ffi = require "ffi" 3 | local ffi_gc = ffi.gc 4 | local ffi_str = ffi.string 5 | local ffi_cdef = ffi.cdef 6 | local tonumber = tonumber 7 | local tostring = tostring 8 | local setmetatable = setmetatable 9 | 10 | ffi_cdef[[ 11 | typedef void *(*hoedown_realloc_callback)(void *, size_t); 12 | typedef void (*hoedown_free_callback)(void *); 13 | struct hoedown_buffer { 14 | uint8_t *data; 15 | size_t size; 16 | size_t asize; 17 | size_t unit; 18 | hoedown_realloc_callback data_realloc; 19 | hoedown_free_callback data_free; 20 | hoedown_free_callback buffer_free; 21 | }; 22 | typedef struct hoedown_buffer hoedown_buffer; 23 | void hoedown_buffer_init(hoedown_buffer *buffer, size_t unit, hoedown_realloc_callback data_realloc, hoedown_free_callback data_free, hoedown_free_callback buffer_free); 24 | hoedown_buffer* hoedown_buffer_new(size_t unit) __attribute__ ((malloc)); 25 | void hoedown_buffer_reset(hoedown_buffer *buf); 26 | void hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz); 27 | void hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size); 28 | void hoedown_buffer_puts(hoedown_buffer *buf, const char *str); 29 | void hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c); 30 | void hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size); 31 | void hoedown_buffer_sets(hoedown_buffer *buf, const char *str); 32 | int hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size); 33 | int hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str); 34 | int hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix); 35 | void hoedown_buffer_slurp(hoedown_buffer *buf, size_t size); 36 | const char* hoedown_buffer_cstr(hoedown_buffer *buf); 37 | void hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); 38 | void hoedown_buffer_free(hoedown_buffer *buf); 39 | ]] 40 | 41 | local buffer = {} 42 | function buffer:__index(key) 43 | if key == "data" then 44 | return tostring(self) 45 | elseif key == "size" then 46 | return tonumber(self.context.size) 47 | elseif key == "asize" then 48 | return tonumber(self.context.asize) 49 | elseif key == "unit" then 50 | return tonumber(self.context.unit) 51 | else 52 | return rawget(buffer, key) 53 | end 54 | end 55 | function buffer.new(size) 56 | return setmetatable({ context = ffi_gc(lib.hoedown_buffer_new(size or 64), lib.hoedown_buffer_free) }, buffer) 57 | end 58 | function buffer:reset() 59 | lib.hoedown_buffer_reset(self.context) 60 | end 61 | function buffer:grow(size) 62 | lib.hoedown_buffer_grow(self.context, size) 63 | end 64 | function buffer:put(str) 65 | lib.hoedown_buffer_put(self.context, str, #str) 66 | end 67 | function buffer:puts(str) 68 | lib.hoedown_buffer_puts(self.context, str) 69 | end 70 | function buffer:set(str) 71 | lib.hoedown_buffer_set(self.context, str, #str) 72 | end 73 | function buffer:sets(str) 74 | lib.hoedown_buffer_sets(self.context, str) 75 | end 76 | function buffer:eq(str) 77 | return tonumber(lib.hoedown_buffer_eq(self.context, str, #str)) == 1 78 | end 79 | function buffer:eqs(str) 80 | return tonumber(lib.hoedown_buffer_eqs(self.context, str)) == 1 81 | end 82 | function buffer:prefix(prefix) 83 | return tonumber(lib.hoedown_buffer_prefix(self.context, prefix)) 84 | end 85 | function buffer:slurp(size) 86 | lib.hoedown_buffer_slurp(self.context, size) 87 | end 88 | function buffer:cstr() 89 | return lib.hoedown_buffer_cstr(self.context) 90 | end 91 | function buffer:printf(format, ...) 92 | lib.hoedown_buffer_printf(self.context, format, ...) 93 | end 94 | function buffer:free() 95 | lib.hoedown_buffer_free(self.context) 96 | end 97 | function buffer:__len() 98 | return tonumber(self.context.size) 99 | end 100 | function buffer.__eq(x, y) 101 | return tostring(x) == tostring(y) 102 | end 103 | function buffer.__concat(x, y) 104 | return tostring(x) .. tostring(y) 105 | end 106 | function buffer:__tostring() 107 | return ffi_str(self.context.data, self.context.size) 108 | end 109 | 110 | return buffer -------------------------------------------------------------------------------- /lib/resty/hoedown/document.lua: -------------------------------------------------------------------------------- 1 | local buffer = require "resty.hoedown.buffer" 2 | local new_buf = buffer.new 3 | local lib = require "resty.hoedown.library" 4 | local ffi = require "ffi" 5 | local ffi_gc = ffi.gc 6 | local ffi_cdef = ffi.cdef 7 | local bit = require "bit" 8 | local bor = bit.bor 9 | local type = type 10 | local tostring = tostring 11 | local ipairs = ipairs 12 | local setmetatable = setmetatable 13 | 14 | ffi_cdef[[ 15 | typedef enum hoedown_extensions { 16 | HOEDOWN_EXT_TABLES = (1 << 0), 17 | HOEDOWN_EXT_FENCED_CODE = (1 << 1), 18 | HOEDOWN_EXT_FOOTNOTES = (1 << 2), 19 | HOEDOWN_EXT_AUTOLINK = (1 << 3), 20 | HOEDOWN_EXT_STRIKETHROUGH = (1 << 4), 21 | HOEDOWN_EXT_UNDERLINE = (1 << 5), 22 | HOEDOWN_EXT_HIGHLIGHT = (1 << 6), 23 | HOEDOWN_EXT_QUOTE = (1 << 7), 24 | HOEDOWN_EXT_SUPERSCRIPT = (1 << 8), 25 | HOEDOWN_EXT_MATH = (1 << 9), 26 | HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11), 27 | HOEDOWN_EXT_SPACE_HEADERS = (1 << 12), 28 | HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13), 29 | HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14) 30 | } hoedown_extensions; 31 | typedef enum hoedown_list_flags { 32 | HOEDOWN_LIST_ORDERED = (1 << 0), 33 | HOEDOWN_LI_BLOCK = (1 << 1) 34 | } hoedown_list_flags; 35 | typedef enum hoedown_table_flags { 36 | HOEDOWN_TABLE_ALIGN_LEFT = 1, 37 | HOEDOWN_TABLE_ALIGN_RIGHT = 2, 38 | HOEDOWN_TABLE_ALIGN_CENTER = 3, 39 | HOEDOWN_TABLE_ALIGNMASK = 3, 40 | HOEDOWN_TABLE_HEADER = 4 41 | } hoedown_table_flags; 42 | typedef enum hoedown_autolink_type { 43 | HOEDOWN_AUTOLINK_NONE, 44 | HOEDOWN_AUTOLINK_NORMAL, 45 | HOEDOWN_AUTOLINK_EMAIL 46 | } hoedown_autolink_type; 47 | struct hoedown_document; 48 | typedef struct hoedown_document hoedown_document; 49 | struct hoedown_renderer_data { void *opaque; }; 50 | typedef struct hoedown_renderer_data hoedown_renderer_data; 51 | struct hoedown_renderer { 52 | void *opaque; 53 | void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data); 54 | void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 55 | void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data); 56 | void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data); 57 | void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data); 58 | void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data); 59 | void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 60 | void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 61 | void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 62 | void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 63 | void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 64 | void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data); 65 | void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 66 | void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data); 67 | void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 68 | int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data); 69 | int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 70 | int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 71 | int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 72 | int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 73 | int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 74 | int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 75 | int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data); 76 | int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data); 77 | int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data); 78 | int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 79 | int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 80 | int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 81 | int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data); 82 | int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data); 83 | int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 84 | void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 85 | void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 86 | void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data); 87 | void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data); 88 | }; 89 | typedef struct hoedown_renderer hoedown_renderer; 90 | hoedown_document* hoedown_document_new(const hoedown_renderer *renderer, hoedown_extensions extensions, size_t max_nesting) __attribute__ ((malloc)); 91 | void hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size); 92 | void hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size); 93 | void hoedown_document_free(hoedown_document *doc); 94 | ]] 95 | 96 | local exts = { 97 | tables = lib.HOEDOWN_EXT_TABLES, 98 | fenced_code = lib.HOEDOWN_EXT_FENCED_CODE, 99 | footnotes = lib.HOEDOWN_EXT_FOOTNOTES, 100 | autolink = lib.HOEDOWN_EXT_AUTOLINK, 101 | strikethrough = lib.HOEDOWN_EXT_STRIKETHROUGH, 102 | underline = lib.HOEDOWN_EXT_UNDERLINE, 103 | highlight = lib.HOEDOWN_EXT_HIGHLIGHT, 104 | quote = lib.HOEDOWN_EXT_QUOTE, 105 | superscript = lib.HOEDOWN_EXT_SUPERSCRIPT, 106 | math = lib.HOEDOWN_EXT_MATH, 107 | no_intra_emphasis = lib.HOEDOWN_EXT_NO_INTRA_EMPHASIS, 108 | space_headers = lib.HOEDOWN_EXT_SPACE_HEADERS, 109 | math_explicit = lib.HOEDOWN_EXT_MATH_EXPLICIT, 110 | disable_indented_code = lib.HOEDOWN_EXT_DISABLE_INDENTED_CODE 111 | } 112 | 113 | local document = { extensions = exts } 114 | document.__index = document 115 | 116 | function document.new(renderer, extensions, max_nesting) 117 | local t = type(extensions) 118 | local e = 0 119 | if t == "number" then 120 | e = extensions 121 | elseif t == "table" then 122 | for _, v in ipairs(extensions) do 123 | if type(v) == "number" then 124 | e = bor(v, e) 125 | else 126 | e = bor(exts[v] or 0, e) 127 | end 128 | end 129 | end 130 | return setmetatable({ context = ffi_gc(lib.hoedown_document_new(renderer.context or renderer, e, max_nesting or 16), lib.hoedown_document_free) }, document) 131 | end 132 | function document:render(data) 133 | local str = tostring(data) 134 | local len = #str 135 | local buf = new_buf(len); 136 | lib.hoedown_document_render(self.context, buf.context, str, len) 137 | return tostring(buf) 138 | end 139 | function document:render_inline(data) 140 | local str = tostring(data) 141 | local len = #str 142 | local buf = new_buf(len); 143 | lib.hoedown_document_render_inline(self.context, buf.context, str, len) 144 | return tostring(buf) 145 | end 146 | function document:free() 147 | lib.hoedown_document_free(self.context) 148 | end 149 | 150 | return document 151 | -------------------------------------------------------------------------------- /lib/resty/hoedown/escape.lua: -------------------------------------------------------------------------------- 1 | local buffer = require "resty.hoedown.buffer" 2 | local new_buf = buffer.new 3 | local lib = require "resty.hoedown.library" 4 | local ffi = require "ffi" 5 | local ffi_cdef = ffi.cdef 6 | local setmetatable = setmetatable 7 | local tostring = tostring 8 | 9 | ffi_cdef[[ 10 | void hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size); 11 | void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure); 12 | ]] 13 | 14 | local escape = {} 15 | 16 | function escape.href(source) 17 | local str = tostring(source) 18 | local len = #str 19 | local buf = new_buf(len); 20 | lib.hoedown_escape_href(buf.context, str, len); 21 | return tostring(buf) 22 | end 23 | function escape.html(source, secure) 24 | local str = tostring(source) 25 | local len = #str 26 | local buf = new_buf(len); 27 | lib.hoedown_escape_html(buf.context, str, len, secure and 1 or 0); 28 | return tostring(buf) 29 | end 30 | return setmetatable(escape, { __call = function(_, source, secure) 31 | return escape.html(source, secure) 32 | end }) -------------------------------------------------------------------------------- /lib/resty/hoedown/html.lua: -------------------------------------------------------------------------------- 1 | local buffer = require "resty.hoedown.buffer" 2 | local new_buf = buffer.new 3 | local lib = require "resty.hoedown.library" 4 | local ffi = require "ffi" 5 | local ffi_gc = ffi.gc 6 | local ffi_cdef = ffi.cdef 7 | local bit = require "bit" 8 | local bor = bit.bor 9 | local type = type 10 | local ipairs = ipairs 11 | local tostring = tostring 12 | local tonumber = tonumber 13 | local setmetatable = setmetatable 14 | 15 | ffi_cdef[[ 16 | typedef enum hoedown_html_flags { 17 | HOEDOWN_HTML_SKIP_HTML = (1 << 0), 18 | HOEDOWN_HTML_ESCAPE = (1 << 1), 19 | HOEDOWN_HTML_HARD_WRAP = (1 << 2), 20 | HOEDOWN_HTML_USE_XHTML = (1 << 3) 21 | } hoedown_html_flags; 22 | typedef enum hoedown_html_tag { 23 | HOEDOWN_HTML_TAG_NONE = 0, 24 | HOEDOWN_HTML_TAG_OPEN, 25 | HOEDOWN_HTML_TAG_CLOSE 26 | } hoedown_html_tag; 27 | struct hoedown_html_renderer_state { 28 | void *opaque; 29 | struct { 30 | int header_count; 31 | int current_level; 32 | int level_offset; 33 | int nesting_level; 34 | } toc_data; 35 | hoedown_html_flags flags; 36 | void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data); 37 | }; 38 | typedef struct hoedown_html_renderer_state hoedown_html_renderer_state; 39 | void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size); 40 | hoedown_html_tag hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname); 41 | hoedown_renderer* hoedown_html_renderer_new(hoedown_html_flags render_flags, int nesting_level) __attribute__ ((malloc)); 42 | hoedown_renderer* hoedown_html_toc_renderer_new(int nesting_level) __attribute__ ((malloc)); 43 | void hoedown_html_renderer_free(hoedown_renderer *renderer); 44 | ]] 45 | 46 | local html_flags = { 47 | skip_html = lib.HOEDOWN_HTML_SKIP_HTML, 48 | escape = lib.HOEDOWN_HTML_ESCAPE, 49 | hard_wrap = lib.HOEDOWN_HTML_HARD_WRAP, 50 | use_xhtml = lib.HOEDOWN_HTML_USE_XHTML 51 | } 52 | 53 | local html_tag = { 54 | none = lib.HOEDOWN_HTML_TAG_NONE, 55 | open = lib.HOEDOWN_HTML_TAG_OPEN, 56 | close = lib.HOEDOWN_HTML_TAG_CLOSE 57 | } 58 | 59 | local function free(self) 60 | lib.hoedown_html_renderer_free(self.context) 61 | end 62 | 63 | local toc = { free = free } 64 | toc.__index = toc 65 | 66 | function toc.new(nesting) 67 | return setmetatable({ context = ffi_gc(lib.hoedown_html_toc_renderer_new(nesting or 6), lib.hoedown_html_renderer_free) }, toc) 68 | end 69 | 70 | local html = { free = free, toc = toc, flags = html_flags, tag = html_tag } 71 | html.__index = html 72 | 73 | function html.new(flags, nesting) 74 | local t = type(flags) 75 | local f = 0 76 | if t == "number" then 77 | f = flags 78 | elseif t == "table" then 79 | for _, v in ipairs(flags) do 80 | if type(v) == "number" then 81 | f = bor(v, f) 82 | else 83 | f = bor(html_flags[v] or 0, f) 84 | end 85 | end 86 | end 87 | return setmetatable({ context = ffi_gc(lib.hoedown_html_renderer_new(f, nesting or 0), lib.hoedown_html_renderer_free) }, html) 88 | end 89 | function html.smartypants(data) 90 | local str = tostring(data) 91 | local len = #str 92 | local buf = new_buf(len); 93 | lib.hoedown_html_smartypants(buf.context, str, len); 94 | return tostring(buf) 95 | end 96 | function html.is_tag(data, tag) 97 | local str = tostring(data) 98 | local len = #str 99 | return tonumber(lib.hoedown_html_is_tag(str, len, tostring(tag))) 100 | end 101 | 102 | return html -------------------------------------------------------------------------------- /lib/resty/hoedown/library.lua: -------------------------------------------------------------------------------- 1 | local ffi = require "ffi" 2 | local ffi_load = ffi.load 3 | 4 | return ffi_load "hoedown" 5 | -------------------------------------------------------------------------------- /lib/resty/hoedown/renderer.lua: -------------------------------------------------------------------------------- 1 | local ffi = require "ffi" 2 | local ffi_cdef = ffi.cdef 3 | 4 | ffi_cdef[[ 5 | void *opaque; 6 | void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data); 7 | void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 8 | void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data); 9 | void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data); 10 | void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data); 11 | void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data); 12 | void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 13 | void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 14 | void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 15 | void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 16 | void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 17 | void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data); 18 | void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 19 | void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data); 20 | void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 21 | int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data); 22 | int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 23 | int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 24 | int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 25 | int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 26 | int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 27 | int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 28 | int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data); 29 | int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data); 30 | int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data); 31 | int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 32 | int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 33 | int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data); 34 | int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data); 35 | int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data); 36 | int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 37 | void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 38 | void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data); 39 | void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data); 40 | void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data); 41 | ]] 42 | 43 | -- TODO: NYI. -------------------------------------------------------------------------------- /lib/resty/hoedown/stack.lua: -------------------------------------------------------------------------------- 1 | require "resty.hoedown.buffer" 2 | 3 | local ffi = require "ffi" 4 | local ffi_cdef = ffi.cdef 5 | 6 | ffi_cdef[[ 7 | struct hoedown_stack { 8 | void **item; 9 | size_t size; 10 | size_t asize; 11 | }; 12 | typedef struct hoedown_stack hoedown_stack; 13 | void hoedown_stack_init(hoedown_stack *st, size_t initial_size); 14 | void hoedown_stack_uninit(hoedown_stack *st); 15 | void hoedown_stack_grow(hoedown_stack *st, size_t neosz); 16 | void hoedown_stack_push(hoedown_stack *st, void *item); 17 | void *hoedown_stack_pop(hoedown_stack *st); 18 | void *hoedown_stack_top(const hoedown_stack *st); 19 | ]] 20 | 21 | -- TODO: NYI. -------------------------------------------------------------------------------- /lib/resty/hoedown/version.lua: -------------------------------------------------------------------------------- 1 | local lib = require "resty.hoedown.library" 2 | local ffi = require "ffi" 3 | local ffi_new = ffi.new 4 | local ffi_cdef = ffi.cdef 5 | local tonumber = tonumber 6 | local concat = table.concat 7 | local setmetatable = setmetatable 8 | 9 | ffi_cdef[[ 10 | void hoedown_version(int *major, int *minor, int *revision); 11 | ]] 12 | 13 | local version = {} 14 | 15 | function version:__tostring() 16 | return concat({ self.major, self.minor, self.revision }, '.') 17 | end 18 | 19 | do 20 | local major = ffi_new("int[1]", 0) 21 | local minor = ffi_new("int[1]", 0) 22 | local revision = ffi_new("int[1]", 0) 23 | 24 | lib.hoedown_version(major, minor, revision) 25 | 26 | version.major = tonumber(major[0]) 27 | version.minor = tonumber(minor[0]) 28 | version.revision = tonumber(revision[0]) 29 | end 30 | 31 | return setmetatable(version, version) 32 | -------------------------------------------------------------------------------- /lua-resty-hoedown-dev-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lua-resty-hoedown" 2 | version = "dev-1" 3 | source = { 4 | url = "git://github.com/bungle/lua-resty-hoedown.git" 5 | } 6 | description = { 7 | summary = "LuaJIT FFI bindings to Hoedown, a standards compliant, fast, secure markdown processing library in C", 8 | detailed = "lua-resty-hoedown is a Markdown, SmartyPants, buffer, and HTML/URL escaping library for LuaJIT.", 9 | homepage = "https://github.com/bungle/lua-resty-hoedown", 10 | maintainer = "Aapo Talvensaari