local M = {}
--- this function will split a string into a table of tokens, like it would
--- be passed into the `argv` of a program that was executed from the commandline
---
--- @param raw string string of cli args that should be split
--- @return table tokens args as a table
M.tokenize_args = function(raw)
  -- NOTE: string.gmatch is does not use regex, but a smaller pattern matcher!
  -- A complete regex parser would be larger than lua itself. See
  -- [Programming in Lua 20.2](https://www.lua.org/pil/20.2.html).
  --
  -- Notable differences:
  -- '-' is ungreedy wildcard
  -- '*?' does not work
  -- '|' is not or
  --
  -- This means we're better of implementing the lexer with an algorithm.
  local t = {}
  local current = ''
  local in_str = false
  local str_seek
  for c in string.gmatch(raw, '.') do -- iterate through all chars
    if c == ' ' and not in_str then
      if string.len(current) > 0 then
        table.insert(t, current)
        current = ''
      end
    elseif c == '"' and not in_str then
      in_str = true
      str_seek = '"'
    elseif c == "'" and not in_str then
      in_str = true
      str_seek = "'"
    elseif c == str_seek and in_str then
      in_str = false
      table.insert(t, current)
      current = ''
    else
      current = current .. c
    end
  end
  if string.len(current) > 0 then
    table.insert(t, current)
  end
  return t
end

--- dumps a variable into a string, so it can be printed. This is meant for
--- debug prints
--- @param t any variable
--- @return string t_dumped t dumped to string
M.dump = function(t)
  if type(t) == 'table' then
    local s = '{ '
    for k, v in pairs(t) do
      if type(k) ~= 'number' then
        k = '"' .. k .. '"'
      end
      if k ~= 1 then
        s = s .. ', '
      end
      s = s .. '[' .. k .. "] = '" .. M.dump(v) .. "'\n"
    end
    return s .. ' }'
  else
    return tostring(t)
  end
end

--- Try to require a module
--- @param module string module name
--- @return boolean available is the module available?
--- @return any loaded_module the loaded module if it is available
M.try_require = function(module)
  local available, loaded_module = pcall(require, module)
  if not available then
    return available, nil
  else
    return available, loaded_module
  end
end

return M
