From e386aef450d469b023ed349c29ff732302c02ea7 Mon Sep 17 00:00:00 2001 From: alejandro-alzate <57909935+alejandro-alzate@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:48:32 -0500 Subject: [PATCH] Update markup.lua --- ldoc/markup.lua | 642 ++++++++++++++++++++++++------------------------ 1 file changed, 322 insertions(+), 320 deletions(-) diff --git a/ldoc/markup.lua b/ldoc/markup.lua index 425fb072..7d605408 100644 --- a/ldoc/markup.lua +++ b/ldoc/markup.lua @@ -14,102 +14,102 @@ local backtick_references -- inline use same lookup as @see local function resolve_inline_references (ldoc, txt, item, plain) - local do_escape = not plain and not ldoc.dont_escape_underscore - local res = (txt:gsub('@{([^}]-)}',function (name) - if name:match '^\\' then return '@{'..name:sub(2)..'}' end - local qname,label = utils.splitv(name,'%s*|') - if not qname then - qname = name + local do_escape = not plain and not ldoc.dont_escape_underscore + local res = (txt:gsub('@{([^}]-)}',function (name) + if name:match '^\\' then return '@{'..name:sub(2)..'}' end + local qname,label = utils.splitv(name,'%s*|') + if not qname then + qname = name + end + local ref, err + local custom_ref, refname = utils.splitv(qname,':') + if custom_ref and ldoc.custom_references then + custom_ref = ldoc.custom_references[custom_ref] + if custom_ref then + ref,err = custom_ref(refname) end - local ref, err - local custom_ref, refname = utils.splitv(qname,':') - if custom_ref and ldoc.custom_references then - custom_ref = ldoc.custom_references[custom_ref] - if custom_ref then - ref,err = custom_ref(refname) - end - end - if not ref then - ref,err = markup.process_reference(qname) - end - if not ref then - err = err .. ' ' .. qname - if item and item.warning then item:warning(err) - else - io.stderr:write('nofile error: ',err,'\n') - end - return '???' + end + if not ref then + ref,err = markup.process_reference(qname) + end + if not ref then + err = err .. ' ' .. qname + if item and item.warning then item:warning(err) + else + io.stderr:write('nofile error: ',err,'\n') end - if not label then - label = ref.label + return '???' + end + if not label then + label = ref.label + end + if label and do_escape then -- a nastiness with markdown.lua and underscores + label = label:gsub('_','\\_') + end + local html = ldoc.href(ref) or '#' + label = ldoc.escape(label or qname) + local res = ('%s'):format(html,label) + return res + end)) + if backtick_references then + res = res:gsub('`([^`]+)`',function(name) + local ref,_ = markup.process_reference(name) + local label = name + if name and do_escape then + label = name:gsub('_', '\\_') end - if label and do_escape then -- a nastiness with markdown.lua and underscores - label = label:gsub('_','\\_') + label = ldoc.escape(label) + if ref then + return ('%s'):format(ldoc.href(ref),label) + else + return ''..label..'' end - local html = ldoc.href(ref) or '#' - label = ldoc.escape(label or qname) - local res = ('%s'):format(html,label) - return res - end)) - if backtick_references then - res = res:gsub('`([^`]+)`',function(name) - local ref,_ = markup.process_reference(name) - local label = name - if name and do_escape then - label = name:gsub('_', '\\_') - end - label = ldoc.escape(label) - if ref then - return ('%s'):format(ldoc.href(ref),label) - else - return ''..label..'' - end - end) - end - return res + end) + end + return res end -- for readme text, the idea here is to create module sections at ## so that -- they can appear in the contents list as a ToC. function markup.add_sections(F, txt) - local sections, L, first = {}, 1, true - local title_pat - local lstrip = stringx.lstrip - for line in stringx.lines(txt) do - if first then - local level,header = line:match '^(#+)%s*(.+)' - if level then - level = level .. '#' - else - level = '##' - end - title_pat = '^'..level..'([^#]%s*.+)' - title_pat = lstrip(title_pat) - first = false - F.display_name = header - end - local title = line:match (title_pat) - if title then - --- Windows line endings are the cockroaches of text - title = title:gsub('\r$','') - -- Markdown allows trailing '#'... - title = title:gsub('%s*#+$','') - sections[L] = F:add_document_section(lstrip(title)) + local sections, L, first = {}, 1, true + local title_pat + local lstrip = stringx.lstrip + for line in stringx.lines(txt) do + if first then + local level,header = line:match '^(#+)%s*(.+)' + if level then + level = level .. '#' + else + level = '##' end - L = L + 1 - end - F.sections = sections - return txt + title_pat = '^'..level..'([^#]%s*.+)' + title_pat = lstrip(title_pat) + first = false + F.display_name = header + end + local title = line:match (title_pat) + if title then + --- Windows line endings are the cockroaches of text + title = title:gsub('\r$','') + -- Markdown allows trailing '#'... + title = title:gsub('%s*#+$','') + sections[L] = F:add_document_section(lstrip(title)) + end + L = L + 1 + end + F.sections = sections + return txt end local function indent_line (line) - line = line:gsub('\t',' ') -- support for barbarians ;) - local indent = #line:match '^%s*' - return indent,line + line = line:gsub('\t',' ') -- support for barbarians ;) + local indent = #line:match '^%s*' + return indent,line end local function blank (line) - return not line:find '%S' + return not line:find '%S' end local global_context, local_context @@ -121,96 +121,98 @@ local global_context, local_context -- - prettify any code blocks local function process_multiline_markdown(ldoc, txt, F, filename, deflang) - local res, L, append = {}, 0, table.insert - local err_item = { - warning = function (self,msg) - io.stderr:write(filename..':'..L..': '..msg,'\n') - end - } - local get = stringx.lines(txt) - local getline = function() - L = L + 1 - return get() - end - local function pretty_code (code, lang) - code = concat(code,'\n') - if code ~= '' then - local _ - -- If we omit the following '\n', a '--' (or '//') comment on the - -- last line won't be recognized. - code, _ = prettify.code(lang,filename,code..'\n',L,false) - code = resolve_inline_references(ldoc, code, err_item,true) - append(res,'
')
-         append(res, code)
-         append(res,'
') - else - append(res,code) - end - end - local indent,start_indent - local_context = nil - local line = getline() - while line do - local name = line:match '^@lookup%s+(%S+)' - if name then - local_context = name .. '.' - line = getline() - end + local res, L, append = {}, 0, table.insert + local err_item = { + warning = function (self,msg) + io.stderr:write(filename..':'..L..': '..msg,'\n') + end + } + local get = stringx.lines(txt) + local getline = function() + L = L + 1 + return get() + end + local function pretty_code (code, lang) + code = concat(code,'\n') + if code ~= '' then + local _ + -- If we omit the following '\n', a '--' (or '//') comment on the + -- last line won't be recognized. + code, _ = prettify.code(lang,filename,code..'\n',L,false) + code = resolve_inline_references(ldoc, code, err_item,true) + append(res,'
')
+      append(res, code)
+      append(res,'
') + else + append(res,code) + end + end + local indent,start_indent + local_context = nil + local line = getline() + while line do + local name = line:match '^@lookup%s+(%S+)' + if name then + local_context = name .. '.' + line = getline() + end + if line then local fence = line:match '^```(.*)' if fence then - local plain = fence=='' - line = getline() - local code = {} - while not line:match '^```' do - if not plain then - append(code, line) - else - append(res, ' '..line) - end - line = getline() - end - pretty_code (code,fence) - line = getline() -- skip fence - if not line then break end + local plain = fence=='' + line = getline() + local code = {} + while not line:match '^```' do + if not plain then + append(code, line) + else + append(res, ' '..line) + end + line = getline() + end + pretty_code (code,fence) + line = getline() -- skip fence + if not line then break end end indent, line = indent_line(line) if indent >= 4 then -- indented code block - local code = {} - local plain - while indent >= 4 or blank(line) do - if not start_indent then - start_indent = indent - if line:match '^%s*@plain%s*$' then - plain = true - line = getline() - end - end - if not plain then - append(code,line:sub(start_indent + 1)) - else - append(res,line) + local code = {} + local plain + while indent >= 4 or blank(line) do + if not start_indent then + start_indent = indent + if line:match '^%s*@plain%s*$' then + plain = true + line = getline() end - line = getline() - if line == nil then break end - indent, line = indent_line(line) - end - start_indent = nil - while #code > 1 and blank(code[#code]) do -- trim blank lines. - table.remove(code) - end - pretty_code (code,deflang) + end + if not plain then + append(code,line:sub(start_indent + 1)) + else + append(res,line) + end + line = getline() + if line == nil then break end + indent, line = indent_line(line) + end + start_indent = nil + while #code > 1 and blank(code[#code]) do -- trim blank lines. + table.remove(code) + end + pretty_code (code,deflang) else - local section = F and F.sections[L] - if section then - append(res,(''):format(section)) - end - line = resolve_inline_references(ldoc, line, err_item) - append(res,line) - line = getline() + local section = F and F.sections[L] + if section then + append(res,(''):format(section)) + end + line = resolve_inline_references(ldoc, line, err_item) + append(res,line) + line = getline() end - end - res = concat(res,'\n') - return res + end + end + res = concat(res,'\n') + return res end @@ -219,202 +221,202 @@ end -- try all the others we know about. If they don't work, fall back to text. local function generic_formatter(format) - local ok, f = pcall(require, format) - return ok and f + local ok, f = pcall(require, format) + return ok and f end local formatters = { - markdown = function(format) - local ok, markdown = pcall(require, 'markdown') - if not ok then - print('format: using built-in markdown') - ok, markdown = pcall(require, 'ldoc.markdown') - end - return ok and markdown - end, - discount = function(format) - local ok, markdown = pcall(require, 'discount') - if ok then - -- luacheck: push ignore 542 - if 'function' == type(markdown) then - -- lua-discount by A.S. Bradbury, https://luarocks.org/modules/luarocks/lua-discount - elseif 'table' == type(markdown) and ('function' == type(markdown.compile) or 'function' == type(markdown.to_html)) then - -- discount by Craig Barnes, https://luarocks.org/modules/craigb/discount - -- result of apt-get install lua-discount (links against libmarkdown2) - local mysterious_debian_variant = markdown.to_html ~= nil - markdown = markdown.compile or markdown.to_html - return function(text) - local result, errmsg = markdown(text) - if result then - if mysterious_debian_variant then - return result - else - return result.body - end - else - io.stderr:write('LDoc discount failed with error ',errmsg) - os.exit(1) - end + markdown = function(format) + local ok, markdown = pcall(require, 'markdown') + if not ok then + print('format: using built-in markdown') + ok, markdown = pcall(require, 'ldoc.markdown') + end + return ok and markdown + end, + discount = function(format) + local ok, markdown = pcall(require, 'discount') + if ok then + -- luacheck: push ignore 542 + if 'function' == type(markdown) then + -- lua-discount by A.S. Bradbury, https://luarocks.org/modules/luarocks/lua-discount + elseif 'table' == type(markdown) and ('function' == type(markdown.compile) or 'function' == type(markdown.to_html)) then + -- discount by Craig Barnes, https://luarocks.org/modules/craigb/discount + -- result of apt-get install lua-discount (links against libmarkdown2) + local mysterious_debian_variant = markdown.to_html ~= nil + markdown = markdown.compile or markdown.to_html + return function(text) + local result, errmsg = markdown(text) + if result then + if mysterious_debian_variant then + return result + else + return result.body end - else - ok = false - end - -- luacheck: pop - end - if not ok then - print('format: using built-in markdown') - ok, markdown = pcall(require, 'ldoc.markdown') - end - return ok and markdown - end, - lunamark = function(format) - local ok, lunamark = pcall(require, format) - if ok then - local writer = lunamark.writer.html.new() - local parse = lunamark.reader.markdown.new(writer, - { smart = true }) - return function(text) return parse(text) end + else + io.stderr:write('LDoc discount failed with error ',errmsg) + os.exit(1) + end + end + else + ok = false end - end, - commonmark = function(format) - local ok, cmark = pcall(require, 'cmark') - if ok then - return function(text) - local doc = cmark.parse_document(text, string.len(text), cmark.OPT_DEFAULT) - return cmark.render_html(doc, cmark.OPT_DEFAULT) - end + -- luacheck: pop + end + if not ok then + print('format: using built-in markdown') + ok, markdown = pcall(require, 'ldoc.markdown') + end + return ok and markdown + end, + lunamark = function(format) + local ok, lunamark = pcall(require, format) + if ok then + local writer = lunamark.writer.html.new() + local parse = lunamark.reader.markdown.new(writer, + { smart = true }) + return function(text) return parse(text) end + end + end, + commonmark = function(format) + local ok, cmark = pcall(require, 'cmark') + if ok then + return function(text) + local doc = cmark.parse_document(text, string.len(text), cmark.OPT_DEFAULT) + return cmark.render_html(doc, cmark.OPT_DEFAULT) end - end + end + end } local function get_formatter(format) - local used_format = format - local formatter = (formatters[format] or generic_formatter)(format) - if not formatter then -- try another equivalent processor - for name, f in pairs(formatters) do - formatter = f(name) - if formatter then - print('format: '..format..' not found, using '..name) - used_format = name - break - end + local used_format = format + local formatter = (formatters[format] or generic_formatter)(format) + if not formatter then -- try another equivalent processor + for name, f in pairs(formatters) do + formatter = f(name) + if formatter then + print('format: '..format..' not found, using '..name) + used_format = name + break end - end - return formatter, used_format + end + end + return formatter, used_format end local function text_processor(ldoc) - return function(txt,item) - if txt == nil then return '' end - -- hack to separate paragraphs with blank lines - txt = txt:gsub('\n\n','\n

') - return resolve_inline_references(ldoc, txt, item, true) - end + return function(txt,item) + if txt == nil then return '' end + -- hack to separate paragraphs with blank lines + txt = txt:gsub('\n\n','\n

') + return resolve_inline_references(ldoc, txt, item, true) + end end local plain_processor local function markdown_processor(ldoc, formatter) - return function (txt,item,plain) - if txt == nil then return '' end - if plain then - if not plain_processor then - plain_processor = text_processor(ldoc) - end - return plain_processor(txt,item) + return function (txt,item,plain) + if txt == nil then return '' end + if plain then + if not plain_processor then + plain_processor = text_processor(ldoc) end - local is_file = utils.is_type(item,doc.File) - local is_module = not is_file and item and doc.project_level(item.type) - if is_file or is_module then - local deflang = 'lua' - if ldoc.parse_extra and ldoc.parse_extra.C then - deflang = 'c' - end - if is_module then - txt = process_multiline_markdown(ldoc, txt, nil, item.file.filename, deflang) - else - txt = process_multiline_markdown(ldoc, txt, item, item.filename, deflang) - end + return plain_processor(txt,item) + end + local is_file = utils.is_type(item,doc.File) + local is_module = not is_file and item and doc.project_level(item.type) + if is_file or is_module then + local deflang = 'lua' + if ldoc.parse_extra and ldoc.parse_extra.C then + deflang = 'c' + end + if is_module then + txt = process_multiline_markdown(ldoc, txt, nil, item.file.filename, deflang) else - txt = resolve_inline_references(ldoc, txt, item) + txt = process_multiline_markdown(ldoc, txt, item, item.filename, deflang) end - txt = formatter(txt) - -- We will add our own paragraph tags, if needed. - return (txt:gsub('^%s*

(.+)

%s*$','%1')) - end + else + txt = resolve_inline_references(ldoc, txt, item) + end + txt = formatter(txt) + -- We will add our own paragraph tags, if needed. + return (txt:gsub('^%s*

(.+)

%s*$','%1')) + end end local function get_processor(ldoc, format) - if format == 'plain' then return text_processor(ldoc) end + if format == 'plain' then return text_processor(ldoc) end - local formatter,actual_format = get_formatter(format) - if formatter then - markup.plain = false - -- AFAIK only markdown.lua has underscore-in-identifier problem... - if ldoc.dont_escape_underscore ~= nil then - ldoc.dont_escape_underscore = actual_format ~= 'markdown' - end - return markdown_processor(ldoc, formatter) - end + local formatter,actual_format = get_formatter(format) + if formatter then + markup.plain = false + -- AFAIK only markdown.lua has underscore-in-identifier problem... + if ldoc.dont_escape_underscore ~= nil then + ldoc.dont_escape_underscore = actual_format ~= 'markdown' + end + return markdown_processor(ldoc, formatter) + end - print('format: '..format..' not found, falling back to text') - return text_processor(ldoc) + print('format: '..format..' not found, falling back to text') + return text_processor(ldoc) end function markup.create (ldoc, format, pretty, user_keywords) - local processor - markup.plain = true - if format == 'backtick' then - ldoc.backtick_references = true - format = 'plain' - end - backtick_references = ldoc.backtick_references - global_context = ldoc.package and ldoc.package .. '.' - prettify.set_prettifier(pretty) - prettify.set_user_keywords(user_keywords) + local processor + markup.plain = true + if format == 'backtick' then + ldoc.backtick_references = true + format = 'plain' + end + backtick_references = ldoc.backtick_references + global_context = ldoc.package and ldoc.package .. '.' + prettify.set_prettifier(pretty) + prettify.set_user_keywords(user_keywords) - markup.process_reference = function(name,istype) - if local_context == 'none.' and not name:match '%.' then - return nil,'not found' - end - local mod = ldoc.single or ldoc.module or ldoc.modules[1] - local ref,err = mod:process_see_reference(name, ldoc.modules, istype) + markup.process_reference = function(name,istype) + if local_context == 'none.' and not name:match '%.' then + return nil,'not found' + end + local mod = ldoc.single or ldoc.module or ldoc.modules[1] + local ref,err = mod:process_see_reference(name, ldoc.modules, istype) + if ref then return ref end + if global_context then + local qname = global_context .. name + ref = mod:process_see_reference(qname, ldoc.modules, istype) if ref then return ref end - if global_context then - local qname = global_context .. name - ref = mod:process_see_reference(qname, ldoc.modules, istype) - if ref then return ref end - end - if local_context then - local qname = local_context .. name - ref = mod:process_see_reference(qname, ldoc.modules, istype) - if ref then return ref end - end - -- note that we'll return the original error! - return ref,err - end + end + if local_context then + local qname = local_context .. name + ref = mod:process_see_reference(qname, ldoc.modules, istype) + if ref then return ref end + end + -- note that we'll return the original error! + return ref,err + end - markup.href = function(ref) - return ldoc.href(ref) - end + markup.href = function(ref) + return ldoc.href(ref) + end - processor = get_processor(ldoc, format) - if not markup.plain and backtick_references == nil then - backtick_references = true - end + processor = get_processor(ldoc, format) + if not markup.plain and backtick_references == nil then + backtick_references = true + end - markup.resolve_inline_references = function(txt, errfn) - return resolve_inline_references(ldoc, txt, errfn, markup.plain) - end - markup.processor = processor - prettify.resolve_inline_references = function(txt, errfn) - return resolve_inline_references(ldoc, txt, errfn, true) - end - return processor + markup.resolve_inline_references = function(txt, errfn) + return resolve_inline_references(ldoc, txt, errfn, markup.plain) + end + markup.processor = processor + prettify.resolve_inline_references = function(txt, errfn) + return resolve_inline_references(ldoc, txt, errfn, true) + end + return processor end return markup