From 026413831cdd62a4edb738a642cbbb7da44cfc84 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Thu, 10 Sep 2015 21:49:41 +0300 Subject: [PATCH] Do not use setfenv in markdown.lua Use local variables instead. --- markdown.lua | 206 +++++++++++++++++++++++++-------------------------- 1 file changed, 100 insertions(+), 106 deletions(-) diff --git a/markdown.lua b/markdown.lua index 87de924..2de8b09 100644 --- a/markdown.lua +++ b/markdown.lua @@ -116,13 +116,6 @@ THE SOFTWARE. // Niklas ]] - --- Set up a table for holding local functions to avoid polluting the global namespace -local M = {} -local MT = {__index = _G} -setmetatable(M, MT) -setfenv(1, M) - ---------------------------------------------------------------------- -- Utility functions ---------------------------------------------------------------------- @@ -130,8 +123,8 @@ setfenv(1, M) -- Locks table t from changes, writes an error if someone attempts to change the table. -- This is useful for detecting variables that have "accidently" been made global. Something -- I tend to do all too much. -function lock(t) - function lock_new_index(t, k, v) +local function lock(t) + local function lock_new_index(t, k, v) error("module has been locked -- " .. k .. " must be declared local", 2) end @@ -141,20 +134,20 @@ function lock(t) end -- Returns the result of mapping the values in table t through the function f -function map(t, f) +local function map(t, f) local out = {} for k,v in pairs(t) do out[k] = f(v,k) end return out end -- The identity function, useful as a placeholder. -function identity(text) return text end +local function identity(text) return text end -- Functional style if statement. (NOTE: no short circuit evaluation) -function iff(t, a, b) if t then return a else return b end end +local function iff(t, a, b) if t then return a else return b end end -- Splits the text into an array of separate lines. -function split(text, sep) +local function split(text, sep) sep = sep or "\n" local lines = {} local pos = 1 @@ -168,7 +161,7 @@ function split(text, sep) end -- Converts tabs to spaces -function detab(text) +local function detab(text) local tab_width = 4 local function rep(match) local spaces = -match:len() @@ -180,7 +173,7 @@ function detab(text) end -- Applies string.find for every pattern in the list and returns the first match -function find_first(s, patterns, index) +local function find_first(s, patterns, index) local res = {} for _,p in ipairs(patterns) do local match = {s:find(p, index)} @@ -192,7 +185,7 @@ end -- If a replacement array is specified, the range [start, stop] in the array is replaced -- with the replacement array and the resulting array is returned. Without a replacement -- array the section of the array between start and stop is returned. -function splice(array, start, stop, replacement) +local function splice(array, start, stop, replacement) if replacement then local n = stop - start + 1 while n > 0 do @@ -213,7 +206,7 @@ function splice(array, start, stop, replacement) end -- Outdents the text one step. -function outdent(text) +local function outdent(text) text = "\n" .. text text = text:gsub("\n ? ? ?", "\n") text = text:sub(2) @@ -221,7 +214,7 @@ function outdent(text) end -- Indents the text one step. -function indent(text) +local function indent(text) text = text:gsub("\n", "\n ") return text end @@ -229,7 +222,7 @@ end -- Does a simple tokenization of html data. Returns the data as a list of tokens. -- Each token is a table with a type field (which is either "tag" or "text") and -- a text field (which contains the original token data). -function tokenize_html(html) +local function tokenize_html(html) local tokens = {} local pos = 1 while true do @@ -287,7 +280,7 @@ local HASH = { -- Inits hashing. Creates a hash_identifier that doesn't occur anywhere -- in the text. -function init_hash(text) +local function init_hash(text) HASH.inited = true HASH.identifier = "" HASH.counter = 0 @@ -305,7 +298,7 @@ function init_hash(text) end -- Returns the hashed value for s. -function hash(s) +local function hash(s) assert(HASH.inited) if not HASH.table[s] then HASH.counter = HASH.counter + 1 @@ -342,18 +335,18 @@ local PD = { -- Nested data. -- -- -function block_pattern(tag) +local function block_pattern(tag) return "\n<" .. tag .. ".-\n[ \t]*\n" end -- Pattern for matching a block tag that begins and ends with a newline -function line_pattern(tag) +local function line_pattern(tag) return "\n<" .. tag .. ".-[ \t]*\n" end -- Protects the range of characters from start to stop in the text and -- returns the protected string. -function protect_range(text, start, stop) +local function protect_range(text, start, stop) local s = text:sub(start, stop) local h = hash(s) PD.blocks[h] = s @@ -363,7 +356,7 @@ end -- Protect every part of the text that matches any of the patterns. The first -- matching pattern is protected first, etc. -function protect_matches(text, patterns) +local function protect_matches(text, patterns) while true do local start, stop = find_first(text, patterns) if not start then break end @@ -373,7 +366,7 @@ function protect_matches(text, patterns) end -- Protects blocklevel tags in the specified text -function protect(text) +local function protect(text) -- First protect potentially nested block tags text = protect_matches(text, map(PD.tags, block_pattern)) -- Then protect block tags at the line level. @@ -385,12 +378,12 @@ function protect(text) end -- Returns true if the string s is a hash resulting from protection -function is_protected(s) +local function is_protected(s) return PD.blocks[s] end -- Unprotects the specified text by expanding all the nonces -function unprotect(text) +local function unprotect(text) for k,v in pairs(PD.blocks) do v = v:gsub("%%", "%%%%") text = text:gsub(k, v) @@ -410,14 +403,14 @@ end -- Returns true if the line is a ruler of (char) characters. -- The line must contain at least three char characters and contain only spaces and -- char characters. -function is_ruler_of(line, char) +local function is_ruler_of(line, char) if not line:match("^[ %" .. char .. "]*$") then return false end if not line:match("%" .. char .. ".*%" .. char .. ".*%" .. char) then return false end return true end -- Identifies the block level formatting present in the line -function classify(line) +local function classify(line) local info = {line = line, text = line} if line:match("^ ") then @@ -483,7 +476,7 @@ end -- Find headers constisting of a normal line followed by a ruler and converts them to -- header entries. -function headers(array) +local function headers(array) local i = 1 while i <= #array - 1 do if array[i].type == "normal" and array[i+1].type == "ruler" and @@ -500,8 +493,45 @@ function headers(array) return array end +-- Forward declarations +local block_transform, span_transform, encode_code + +-- Convert lines to html code +local function blocks_to_html(lines, no_paragraphs) + local out = {} + local i = 1 + while i <= #lines do + local line = lines[i] + if line.type == "ruler" then + table.insert(out, "
") + elseif line.type == "raw" then + table.insert(out, line.html) + elseif line.type == "normal" then + local s = line.line + + while i+1 <= #lines and lines[i+1].type == "normal" do + i = i + 1 + s = s .. "\n" .. lines[i].line + end + + if no_paragraphs then + table.insert(out, span_transform(s)) + else + table.insert(out, "

" .. span_transform(s) .. "

") + end + elseif line.type == "header" then + local s = "" .. span_transform(line.text) .. "" + table.insert(out, s) + else + table.insert(out, line.line) + end + i = i + 1 + end + return out +end + -- Find list blocks and convert them to protected data blocks -function lists(array, sublist) +local function lists(array, sublist) local function process_list(arr) local function any_blanks(arr) for i = 1, #arr do @@ -624,7 +654,7 @@ function lists(array, sublist) end -- Find and convert blockquote markers. -function blockquotes(lines) +local function blockquotes(lines) local function find_blockquote(lines) local start for i,line in ipairs(lines) do @@ -674,7 +704,7 @@ function blockquotes(lines) end -- Find and convert codeblocks. -function codeblocks(lines) +local function codeblocks(lines) local function find_codeblock(lines) local start for i,line in ipairs(lines) do @@ -715,40 +745,6 @@ function codeblocks(lines) return lines end --- Convert lines to html code -function blocks_to_html(lines, no_paragraphs) - local out = {} - local i = 1 - while i <= #lines do - local line = lines[i] - if line.type == "ruler" then - table.insert(out, "
") - elseif line.type == "raw" then - table.insert(out, line.html) - elseif line.type == "normal" then - local s = line.line - - while i+1 <= #lines and lines[i+1].type == "normal" do - i = i + 1 - s = s .. "\n" .. lines[i].line - end - - if no_paragraphs then - table.insert(out, span_transform(s)) - else - table.insert(out, "

" .. span_transform(s) .. "

") - end - elseif line.type == "header" then - local s = "" .. span_transform(line.text) .. "" - table.insert(out, s) - else - table.insert(out, line.line) - end - i = i + 1 - end - return out -end - -- Perform all the block level transforms function block_transform(text, sublist) local lines = split(text) @@ -764,7 +760,7 @@ end -- Debug function for printing a line array to see the result -- of partial transforms. -function print_lines(lines) +local function print_lines(lines) for i, line in ipairs(lines) do print(i, line.type, line.text or line.line) end @@ -778,10 +774,10 @@ end -- These characters may need to be escaped because they have a special -- meaning in markdown. -escape_chars = "'\\`*_{}[]()>#+-.!'" -escape_table = {} +local escape_chars = "'\\`*_{}[]()>#+-.!'" +local escape_table = {} -function init_escape_table() +local function init_escape_table() escape_table = {} for i = 1,#escape_chars do local c = escape_chars:sub(i,i) @@ -790,15 +786,24 @@ function init_escape_table() end -- Adds a new escape to the escape table. -function add_escape(text) +local function add_escape(text) if not escape_table[text] then escape_table[text] = hash(text) end return escape_table[text] -end +end + +-- Encode backspace-escaped characters in the markdown source. +local function encode_backslash_escapes(t) + for i=1,escape_chars:len() do + local c = escape_chars:sub(i,i) + t = t:gsub("\\%" .. c, escape_table[c]) + end + return t +end -- Escape characters that should not be disturbed by markdown. -function escape_special_chars(text) +local function escape_special_chars(text) local tokens = tokenize_html(text) local out = "" @@ -816,17 +821,8 @@ function escape_special_chars(text) return out end --- Encode backspace-escaped characters in the markdown source. -function encode_backslash_escapes(t) - for i=1,escape_chars:len() do - local c = escape_chars:sub(i,i) - t = t:gsub("\\%" .. c, escape_table[c]) - end - return t -end - -- Unescape characters that have been encoded. -function unescape_special_chars(t) +local function unescape_special_chars(t) local tin = t for k,v in pairs(escape_table) do k = k:gsub("%%", "%%%%") @@ -850,7 +846,7 @@ function encode_code(s) end -- Handle backtick blocks. -function code_spans(s) +local function code_spans(s) s = s:gsub("\\\\", escape_table["\\"]) s = s:gsub("\\`", escape_table["`"]) @@ -880,7 +876,7 @@ function code_spans(s) end -- Encode alt text... enodes &, and ". -function encode_alt(s) +local function encode_alt(s) if not s then return s end s = s:gsub('&', '&') s = s:gsub('"', '"') @@ -888,8 +884,11 @@ function encode_alt(s) return s end +-- Forward declaration for link_db as returned by strip_link_definitions. +local link_database + -- Handle image references -function images(text) +local function images(text) local function reference_link(alt, id) alt = encode_alt(alt:match("%b[]"):sub(2,-2)) id = id:match("%[(.*)%]"):lower() @@ -922,7 +921,7 @@ function images(text) end -- Handle anchor references -function anchors(text) +local function anchors(text) local function reference_link(text, id) text = text:match("%b[]"):sub(2,-2) id = id:match("%b[]"):sub(2,-2):lower() @@ -955,7 +954,7 @@ function anchors(text) end -- Handle auto links, i.e. . -function auto_links(text) +local function auto_links(text) local function link(s) return add_escape("") .. s .. "" end @@ -1004,7 +1003,7 @@ end -- Encode free standing amps (&) and angles (<)... note that this does not -- encode free >. -function amps_and_angles(s) +local function amps_and_angles(s) -- encode amps not part of &..; expression local pos = 1 while true do @@ -1029,7 +1028,7 @@ function amps_and_angles(s) end -- Handles emphasis markers (* and _) in the text. -function emphasis(text) +local function emphasis(text) for _, s in ipairs {"%*%*", "%_%_"} do text = text:gsub(s .. "([^%s][%*%_]?)" .. s, "%1") text = text:gsub(s .. "([^%s][^<>]-[^%s][%*%_]?)" .. s, "%1") @@ -1044,7 +1043,7 @@ function emphasis(text) end -- Handles line break markers in the text. -function line_breaks(text) +local function line_breaks(text) return text:gsub(" +\n", "
\n") end @@ -1067,7 +1066,7 @@ end -- Cleanup the text by normalizing some possible variations to make further -- processing easier. -function cleanup(text) +local function cleanup(text) -- Standardize line endings text = text:gsub("\r\n", "\n") -- DOS to UNIX text = text:gsub("\r", "\n") -- Mac to UNIX @@ -1086,7 +1085,7 @@ function cleanup(text) end -- Strips link definitions from the text and stores the data in a lookup table. -function strip_link_definitions(text) +local function strip_link_definitions(text) local linkdb = {} local function link_def(id, url, title) @@ -1109,10 +1108,8 @@ function strip_link_definitions(text) return text, linkdb end -link_database = {} - -- Main markdown processing function -function markdown(text) +local function markdown(text) init_hash(text) init_escape_table() @@ -1128,11 +1125,8 @@ end -- End of module ---------------------------------------------------------------------- -setfenv(1, _G) -M.lock(M) - --- Expose markdown function to the world -markdown = M.markdown +-- For compatibility, set markdown function as a global +_G.markdown = markdown -- Class for parsing command-line options local OptionParser = {} @@ -1183,7 +1177,7 @@ function OptionParser:run(args) info.f() pos = pos + 1 else - param = args[pos+1] + local param = args[pos+1] if not param then print("No parameter for flag: " .. arg) return false end info.f(param) pos = pos+2 @@ -1197,12 +1191,12 @@ function OptionParser:run(args) info.f() else if i == arg:len() then - param = args[pos+1] + local param = args[pos+1] if not param then print("No parameter for flag: -" .. c) return false end info.f(param) pos = pos + 1 else - param = arg:sub(i+1) + local param = arg:sub(i+1) info.f(param) end break