79 lines
1.8 KiB
Lua
79 lines
1.8 KiB
Lua
local M = {}
|
|
|
|
---Parses a list of arguments **kind of** like the getopts shell builtin.
|
|
---@param args string[]
|
|
---@param optstring string
|
|
---@return function
|
|
function M.getopts(args, optstring)
|
|
local spec = {}
|
|
local last
|
|
|
|
for i = 1, #optstring do
|
|
local c = optstring:sub(i, i)
|
|
|
|
if c == ':' and last then
|
|
spec[last] = true
|
|
elseif i == #optstring then
|
|
spec[c] = false
|
|
elseif last and last ~= ':' then
|
|
spec[last] = false
|
|
end
|
|
|
|
last = c
|
|
end
|
|
|
|
-- 1. if the option takes a value either
|
|
-- a. take the rest of the slice as its values if at least one char
|
|
-- remains in the slice
|
|
-- b. take the next whole argument as its value
|
|
-- 2. find the next option name (char)
|
|
local i = 1 -- arg index
|
|
local n = 1 -- slice index
|
|
local g = 1 -- I am not very smart
|
|
return function ()
|
|
while args[i] do
|
|
local arg = args[i]
|
|
|
|
-- TODO: Maybe write some tests instead :^)
|
|
if g > 2097152 then
|
|
error 'logic error'
|
|
end
|
|
g = g + 1
|
|
|
|
if n == 1 and not vim.startswith(arg, '-') then
|
|
-- "Normal" arguments end the iterator.
|
|
return
|
|
end
|
|
|
|
n = n + 1
|
|
local c = arg:sub(n, n)
|
|
if #c > n then
|
|
n = n + 1
|
|
end
|
|
|
|
if #c == 1 then
|
|
if spec[c] then
|
|
local optval = arg:sub(n + 1, #arg)
|
|
n = 1
|
|
i = i + 1
|
|
if #optval > 0 then
|
|
return i, c, optval
|
|
end
|
|
-- Remaining argument does not contain optval, consume the next argument
|
|
-- as optval.
|
|
i = i + 1
|
|
return i, c, args[i - 1]
|
|
end
|
|
|
|
-- Do not handle nil. If the opt is invalid the caller must handle it.
|
|
return i + 1, c, nil
|
|
end
|
|
|
|
-- Stray '-' ends the iterator.
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
return M
|