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