-- texdoclib-util.tlu: utility functions for texdoc -- -- The TeX Live Team, GPLv3, see texdoclib.tlu for details -- dependencies local texdoc = { const = require 'texdoclib-const', config = require 'texdoclib-config', } -- shortcuts local M = {} local C = texdoc.const -- lowercase and change '/' to '\' on windows for display -- Note: Internal representation of files always use forward slashes. -- This function should be called only before displaying a path. if os.type == 'windows' then function M.w32_path(path) return (string.gsub(string.lower(path), '/', '\\')) end else function M.w32_path(path) return path end end -- remove the last directory component of a path if os.type == 'windows' then function M.path_parent(path) return string.match(path, '^(.*)[\\/]') end else function M.path_parent(path) return string.match(path, '^(.*)/') end end -- generic log display function local function log(label, msg, ...) io.stderr:write('texdoc ' .. label .. ': ' .. msg:format(...) .. '\n') end -- generic error display function (see the err_priority constant) function M.err_print(lvl, msg, ...) -- be careful: maybe config item "verbosity_level" has not set yet local verbosity_level = texdoc.config.get_value('verbosity_level') or tonumber(C.def_verbosity) -- print if the priority is higher than current verbosity level if C.err_priority[lvl] <= verbosity_level then log(lvl, msg, ...) end end local err_print = M.err_print do -- begin scope of active_debugs local active_debugs -- set active_debugs local function set_active_debugs() local debug_list = texdoc.config.get_value('debug_list') if not debug_list then return end active_debugs = {} -- all debug options imply version info if debug_list[1] then active_debugs.version = true else return end -- if 'all' is the first keyword, just activate all categories if debug_list[1] == 'all' then for dbg in pairs(C.known_debugs) do active_debugs[dbg] = true end return end -- activate options from the list for _, dbg in ipairs(debug_list) do local deps = C.known_debugs[dbg] if deps then active_debugs[dbg] = true for _, d in ipairs(deps) do active_debugs[d] = true end else err_print('warning', 'Unknown debug category "' .. dbg .. '".') end end end -- generic debug function function M.dbg_print(cat, msg, ...) -- make sure active_debugs is set if not active_debugs then set_active_debugs() end -- print message it belongs to an active category if active_debugs and active_debugs[cat] or cat == 'XXX' then log('debug-' .. cat, msg, ...) end end end -- end scope of active_debugs -- if filename is base .. '.' .. zip with zip in zipext_list, return: base, zip -- otherwise, return: filename, nil function M.parse_zip(filename) local zip for _, zip in ipairs(texdoc.config.get_value('zipext_list')) do local l = #zip + 1 if string.sub(filename, -l, -1) == '.' .. zip then return string.sub(filename, 1, -l - 1), zip end end return filename, nil end -- take a known extension according to ext_list function M.get_ext(filename) filename = M.parse_zip(filename) for _, e in ipairs(texdoc.config.get_value('ext_list')) do if e == '*' then local dot = filename:find('.', 1, true) if not dot then return '' else return filename:sub(-dot + 1) end elseif (e == '') then if not filename:find('.', 1, true) then return '' end else local dot_e = '.' .. e if filename:sub(-#dot_e) == dot_e then return dot_e:sub(2) end end end end -- print a usage message function M.print_usage() local groups = { action = {}, mode = {}, interaction = {}, debug = {}, } for _, opt in ipairs(C.options) do local line = '' local shortopt = '' local longopt = '' if opt['short'] then if opt['short'] == 'D' then opt['long'] = 'debug' end if opt['metavar'] then shortopt = '-' .. opt['short'] .. ' ' .. opt['metavar'] else shortopt = '-' .. opt['short'] end end if opt['long'] then if opt['metavar'] then local sep = '=' if opt['group'] == 'action' then sep = ' ' end longopt = '--' .. opt['long'] .. sep .. opt['metavar'] else longopt = '--' .. opt['long'] end end if #shortopt > 0 and #longopt > 0 then line = ' ' .. shortopt .. ', ' .. longopt elseif #shortopt > 0 then line = ' ' .. shortopt elseif #longopt > 0 then line = ' ' .. longopt end if #line > 20 then line = line .. "\n" end for _ = 1, 20 - #string.gsub(line, ".*\n", '') do line = line .. ' ' end line = line .. opt['desc'] table.insert(groups[opt['group']], line) end local usage_msg = C.usage_msg for k, v in pairs(groups) do usage_msg = string.gsub(usage_msg, '{{' .. k .. '}}', table.concat(v, "\n")) end print(usage_msg) end function M.print_zsh_completion() local groups = { action = {}, mode = {}, interaction = {}, debug = {}, } local option = '' local complete = '' local choices = {} local prefix = '' for _, opt in ipairs(C.options) do local stop_completions = {opt['group']} if opt['group'] == 'action' then stop_completions = {'-', ':', '*'} end prefix = '"(' .. table.concat(stop_completions, ' ') .. ')"' if opt['short'] and opt['long'] then if opt['long'] == 'debug' then option = '{-' .. opt['short'] .. ',--' .. opt['long'] .. '=-}' else option = '{-' .. opt['short'] .. ',--' .. opt['long'] .. '}' end elseif opt['short'] then option = '-' .. opt['short'] elseif opt['long'] then option = '--' .. opt['long'] end option = prefix .. option .. '"[' .. opt['desc'] .. ']' if opt['type'] == 'string' then if opt['complete'] == 'options' then choices = {} for _, v in pairs(C.known_options) do v = string.gsub(v, '%.%*', '') table.insert(choices, v) end elseif opt['complete'] == 'debugs' then choices = {} for i, _ in pairs(C.known_debugs) do table.insert(choices, i) end elseif type(opt['complete']) == 'table' then choices = opt['complete'] end complete = '(' .. table.concat(choices, ' ') .. ')' if opt['complete'] == 'files' then opt['metavar'] = ' ' complete = '_files' end option = option .. ':' .. string.lower(opt['metavar']) .. ':' .. complete end option = option .. '"' table.insert(groups[opt['group']], option) end local completion = C.zsh_completion for k, v in pairs(groups) do completion = string.gsub(completion, '{{' .. k .. '}}', table.concat(v, "\n ")) end print(completion) end return M -- vim: ft=lua: