---library for `kpsewhich`
---@module kpathsea
---@copyright 2025
local kpse = require 'kpse'
local argparse = require 'argparse'
local semver = require 'semver'
local M = {}
---get parser
---@param progname string program name
---@return table parser
function M.get_parser(progname)
local parser = argparse(progname):add_complete()
parser:argument('file', 'file name'):args('*')
parser:option('--progname', 'set program name', progname)
parser:option('--help-formats -l', 'display information about all supported file formats by -l, -ll'):args(0):count(
'*')
parser:option('--expand-braces', 'output variable and brace expansion'):count('*')
parser:option('--expand-path', 'output complete path expansion'):count('*')
parser:option('--expand-var', 'output variable expansion'):count('*')
parser:option('--var-value', 'output variable-expanded value of variable'):count('*')
local names = {}
for name, _ in pairs(M.formats) do
table.insert(names, name)
end
for alias, _ in pairs(M.aliases) do
table.insert(names, alias)
end
table.sort(names)
parser:option('--show-path', 'output search path for file type'):count('*'):choices(names)
parser:option('--version', 'display version information number and exit.'):args(0)
parser:option('--debug -d', 'set debug flags'):args(0):count('*')
return parser
end
---**entry for kpsewhich**
---@param args string[] command line arguments
function M.main(args)
local parser = M.get_parser(args[0])
args = parser:parse(args)
if args.version then
print(kpse.version())
return
elseif args.help_formats > 0 then
if args.help_formats > 1 then
kpse.set_program_name(args.progname)
end
local names = {}
for name, _ in pairs(M.formats) do
table.insert(names, name)
end
table.sort(names)
for _, name in ipairs(names) do
local format = M.formats[name]
local aliases = { name }
for k, v in pairs(M.aliases) do
if v == name then
table.insert(aliases, k)
end
end
print(table.concat(aliases, ', ') ..
': ' .. table.concat(format.vars, ', ') .. ': defined by ' .. (format.source or 'texmf.cnf'))
if args.help_formats > 1 then
if format.source then
print(kpse.default_texmfcnf())
else
print(kpse.show_path(name))
end
end
end
return
end
kpse.set_program_name(args.progname)
for _, v in ipairs(args.expand_braces or {}) do
if args.debug == 0 then
v = v .. ' -> ' .. kpse.expand_braces(v)
end
print(v)
end
for _, v in ipairs(args.expand_path or {}) do
if args.debug == 0 then
v = v .. ' -> ' .. kpse.expand_path(v)
end
print(v)
end
for _, v in ipairs(args.expand_var or {}) do
if args.debug == 0 then
v = v .. ' -> ' .. kpse.expand_var(v)
end
print(v)
end
for _, v in ipairs(args.var_value or {}) do
if args.debug == 0 then
v = v .. ' = ' .. kpse.var_value(v)
end
print(v)
end
for _, v in ipairs(args.show_path or {}) do
v = M.aliases[v] or v
if args.debug == 0 then
v = v .. ': ' .. kpse.show_path(v)
end
print(v)
end
local err
for k, v in ipairs(args.file) do
if args.debug == 0 then
v = kpse.lookup(v)
end
if v == nil then
v = args.file[k] .. ' not found'
err = true
end
print(v)
end
if err then
os.exit(1)
end
end