Skip to content

Commit

Permalink
rework to use the new config system
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreLouisIssa committed May 19, 2024
1 parent 3e2a0ec commit 92801b0
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 106 deletions.
69 changes: 19 additions & 50 deletions src/def.lua
Original file line number Diff line number Diff line change
@@ -1,61 +1,30 @@
---@meta SGG_Modding-Chalk
local chalk = {}

chalk.config = {}

---@param path string path to config file to save the data to
---@param data table toml-compatible lua table to save to the file
---@return boolean success whether the file was able to be saved
---@return string? message the error message if the file failed to be saved
function chalk.config.save(path,data) end
---@alias SGG_Modding-Chalk.config.save ...

---@param path string path to config file to load the data from
---@param default table lua table to use if the file does not exist
---@return table data data loaded from the file, or otherwise `default`
function chalk.config.load(path,default) end
---@alias SGG_Modding-Chalk.config.load ...

---@param path string path to config file to load the data from
---@param default table lua table to use if newer than the file, or if the file does not exist
---@param vercmp? fun(a: any, b:any): sign: number C-style comparison function of the `version` field.
---@return table data data loaded from the file if it was not older, otherwise `default`
function chalk.config.default_if_new_else_load(path,default,vercmp) end
---@alias SGG_Modding-Chalk.config.default_if_new_else_load ...

---@param path string path to config file to load data from and save data to
---@param default table toml-compatible lua table to save if newer than the file, or if the file does not exist
---@param vercmp? fun(a: any, b:any): sign: number C-style comparison function of the `version` field.
---@return table data data loaded from the file if it was not older, otherwise `default`
function chalk.config.save_if_new_else_load(path,default,vercmp) end
---@alias SGG_Modding-Chalk.config.save_if_new_else_load ...

---@param path string path to config file to load data from and save data to
---@param default table toml-compatible lua table to merge into the data and save, if newer than the file, or if the file does not exist
---@param vercmp? fun(a: any, b:any): sign: number C-style comparison function of the `version` field.
---@return table data data loaded from the file if it was not older, otherwise the data merged with `default`
function chalk.config.save_if_new_else_load_and_merge(path,default,vercmp) end
---@alias SGG_Modding-Chalk.config.save_if_new_else_load_and_merge ...
-- TODO: define all the other public functions

--[[
Loads and finds the more recent (by version) of the given plugin's `config.toml` and `config.lua`, and updates the `config.toml`.
Loads the more recent (by version) of a `.cfg` file and a lua table, and updates the `.cfg` file accordingly (replacing vs. merging entries recursively).
]]
---@param env table? plugin's environment (or nil, but then the paths must be absolute)
---@param config_lua string name of (or path to) the config file to use as a default
---@param config_toml string name of (or path to) the config file to keep updated
---@param vercmp? fun(a: any, b:any): sign: number C-style comparison function of your config's `version` field.
---@return table data toml-compatible lua table with the updated config data
function chalk.update_lua_toml(env,config_lua,config_toml,vercmp) end
---@alias SGG_Modding-Chalk.update_lua_toml ...
---@param path string name of (or path to) the config file to keep updated
---@param default? table lua config table to use as a default
---@param descript? table<any,string> recursive table of descriptions of the keys in the config
---@param is_newer? fun(a: any, b:any): sign: number C-style comparison function of your config's `version` field.
---@return table wrapper a table-like wrapper around the config system
---@return table config the actual config object
function chalk.load(path,default,descript,section,is_newer) end
---@alias SGG_Modding-Chalk.load ...

--[[
Loads and finds the more recent (by version) of *your plugin's* `config.toml` and `config.lua`, and updates the `config.toml`.
Loads the more recent (by version) of *your plugin's* `config.cfg` and `config.lua`, and updates the `config.cfg` accordingly (replacing vs. merging entries recursively).
]]
---@param config_lua string name of (or path to) the config file to use as a default
---@param config_toml string name of (or path to) the config file to keep updated
---@param vercmp? fun(a: any, b:any): sign: number C-style comparison function of your config's `version` field.
---@return table data toml-compatible lua table with the updated config data
function chalk.auto_lua_toml(config_lua,config_toml,vercmp) end
---@alias SGG_Modding-Chalk.auto_lua_toml ...
---@param config_lua? string name of (or path to) the `lua` config file to use as a default
---@param config_cfg? string name of (or path to) the `cfg` config file to keep updated
---@param descript? table<any,string> recursive table of descriptions of the keys in the config
---@param is_newer? fun(a: any, b:any): sign: number C-style comparison function of your config's `version` field.
---@return table wrapper a table-like wrapper around the config system
---@return table config the actual config object
function chalk.auto(config_lua,config_cfg,descript,section,is_newer) end
---@alias SGG_Modding-Chalk.auto ...

return chalk
259 changes: 204 additions & 55 deletions src/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,236 @@ local envy = rom.mods['SGG_Modding-ENVY']
---@module 'SGG_Modding-ENVY-auto'
envy.auto()

public.config = {}
-- TODO: better array-like table handling (check ahead, pack into string, unpack from string)

function version_comparison(a,b)
local _wrap = setmetatable({},{__mode = 'v'})
local _orig = setmetatable({},{__mode = 'k'})
local _path = setmetatable({},{__mode = 'k'})

local default_config_lua = 'config.lua'

local flat = {
string = true,
number = true,
boolean = true
}

local section_root = 'config'

local function find_pair(config,section,key)
for k,v in pairs(config.entries) do
if k.section == section and k.key == key then
return k,v
end
end
end

local create_wrapper

local _meta = {
__index = function(s,k)
local _,e = find_pair(_orig[s],_path[s],k)
if e == nil then
return create_wrapper(s,k)
else
return e:get()
end
end,
__newindex = function(s,k,v)
local _,e = find_pair(_orig[s],_path[s],k)
if e == nil then
e:bind(_path[s],k,v)
else
e:set(v)
end
end,
__pairs = function(s)
local es = _orig[s].entries
local p = _path[s]
return function(_,k)
while true do
local d,e
if k == nil then
d,e = next(es)
else
d,e = next(es,p .. '.' .. k)
end
if d == nil then return end
k = d.key
if p == d.section then
return k,e:get()
end
end
end, s
end,
__ipairs = function(s)
local es = _orig[s].entries
local p = _path[s]
return function(_,k)
while true do
local d,e
if type(k) == 'number' then
k = tostring(k)
end
if k == nil then
d,e = next(es)
else
d,e = next(es,p .. '.' .. k)
end
if d == nil then return end
k = d.key
local i = tonumber(k)
if i ~= nil and p == d.section then
return i,e:get()
end
end
end, s
end
}

function create_wrapper(o,k)
local w = setmetatable({},_meta)
local path = _path[o] or section_root
if k == nil then
_wrap[o] = w
_path[o] = path
else
path = path .. '.' .. k
end
_wrap[w] = w
_path[w] = path
_orig[w] = _orig[o] or o
return w
end

function public.wrapper(o)
local w = _wrap[o]
if w ~= nil then return w end
return create_wrapper(o)
end

function public.original(w)
return _orig[w] or w
end

local function cmp_version(a,b)
local ta, tb = type(a), type(b)
if ta == 'number' and tb == 'number' then
return b - a
if tb == 'string' then
if ta ~= 'string' then return true end
-- TODO: compare version strings
return false
end
if ta == 'number' then
return 1
if tb == 'number' then
if ta ~= 'number' then return true end
return b > a
end
-- TODO: compare version strings
return 0
return false
end

function config.save(config_file_path,data)
return pcall(rom.toml.encodeToFile, data, { file = config_file_path, overwrite = true })
local function get_version(obj)
if type(obj) == 'userdata' then
obj = public.wrapper(obj)
end
return obj.version
end

function config.load(config_file_path,default)
succeeded, data = pcall(rom.toml.decodeFromFile, config_file_path)
if succeeded then
return data
end
return default
local function is_version_newer(a,b)
local va, vb = get_version(a), get_version(b)
return cmp_version(va,vb)
end

function config.default_if_new_else_load(config_file_path,default,vercmp)
local data = config.load(config_file_path,default)
if data ~= default and default ~= nil and default.version ~= nil then
vercmp = vercmp or version_comparison
if data.version == nil or vercmp(data.version,default.version) > 0 then
data = default
function public.load(path,default,descript,section,is_newer)
local loaded
do
local success, data = pcall(rom.toml.decodeFromFile, path)
if success then
loaded = select(2,next(data))
end
end
return data
local config = rom.config.config_file:new(path, true)
if loaded ~= nil and default ~= nil then
is_newer = is_newer or is_version_newer
if is_newer(loaded,default) then
return public.merge(config,default,descript,section)
end
public.merge(config,default,descript,section)
return public.merge(config,loaded,descript,section)
elseif loaded ~= nil then
return public.merge(config,loaded,descript,section)
elseif default ~= nil then
return public.merge(config,default,descript,section)
else
return public.wrapper(config), config
end
end

function config.save_if_new_else_load(config_file_path,default,vercmp)
local data = config.default_if_new_else_load(config_file_path,default,vercmp)
if data == default then
config.save(config_file_path,default)
local function merge(k,v,config,default,descript,section)
local _,c = find_pair(config,section,k)
local t = type(v)
local d = descript and descript[k]
if flat[t] then
if c == nil then
c = config:bind(section,k,v,d or '')
else
c:set(v)
end
else
public.merge(config,v,d,section .. '.' .. k)
end
return data
end

function config.save_if_new_else_load_and_merge(config_file_path,default,vercmp)
local data = config.default_if_new_else_load(config_file_path,default,vercmp)
if data ~= default then
for k,v in pairs(default) do
if data[k] == nil then
data[k] = v
end
function public.merge(config,default,descript,section)
config = public.original(config)
section = section or section_root
for i,v in ipairs(default) do
local k = tostring(i)
merge(k,v,config,default,descript,section)
end
for k,v in pairs(default) do
if type(k) == 'string' then
merge(k,v,config,default,descript,section)
end
end
config.save(config_file_path,data)
return data
config:save()
return public.wrapper(config), config
end

local default_config_name = 'config'
function public.replace(config,default,descript,section)
config = public.original(config)
local path = config.config_file_path
pcall(os.remove,path)
config = rom.config.config_file:new(path, true)
public.merge(config,default,descript,section)
return public.wrapper(config), config
end

function public.update_lua_toml(env,config_lua,config_toml,vercmp)
if config_toml == nil then
if config_lua == nil then
config_lua = default_config_name
end
config_toml = config_lua .. '.toml'
config_lua = config_lua .. '.lua'
function public.update(config,default,descript,section,is_newer)
is_newer = is_newer or is_version_newer
if is_newer(config,default) then
return public.replace(config,default,descript,section)
end
return public.merge(config,default,descript,section)
end

function public.auto(config_lua,config_cfg,descript,section,is_newer)
local env = envy.getfenv(2)
if config_lua == nil then
config_lua = default_config_lua
end
local default
if env and env._PLUGIN then
default = envy.import(env,config_lua)
rom.path.create_directory(env._PLUGIN.config_mod_folder_path)
config_lua = rom.path.combine(env._PLUGIN.plugins_mod_folder_path, config_lua)
config_toml = rom.path.combine(env._PLUGIN.config_mod_folder_path, config_toml)
if config_cfg ~= nil then
config_cfg = rom.path.combine(rom.paths.config(),env._PLUGIN.guid .. '-' .. config_cfg)
else
config_cfg = rom.path.combine(rom.paths.config(),env._PLUGIN.guid .. '.cfg')
end
else
default = envy.import(rom.game,config_lua)
env = rom.game
end
return config.save_if_new_else_load_and_merge(config_toml,default,vercmp)
end

function public.auto_lua_toml(config_lua,config_toml,vercmp)
local env = envy.getfenv(2)
return update_lua_toml(env,config_lua,config_toml,vercmp)
local path,default,_descript,_section,_is_newer = envy.import(env,config_lua)
descript = descript or _descript
section = section or _section
is_newer = is_newer or _is_newer
return public.load(config_cfg,path,default,descript,section,is_newer)
end
2 changes: 1 addition & 1 deletion thunderstore.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ websiteUrl = "https://github.com/SGG-Modding/Chalk"
containsNsfwContent = false

[package.dependencies]
Hell2Modding-Hell2Modding = "1.0.22"
Hell2Modding-Hell2Modding = "1.0.26"
SGG_Modding-ENVY = "1.0.0"

[build]
Expand Down

0 comments on commit 92801b0

Please sign in to comment.