Files
lunch-games/source/lunch/conf.d
2025-04-29 01:59:15 +02:00

159 lines
3.1 KiB
D

module lunch.conf;
import toml;
import std.conv;
import std.traits;
private struct Name
{
string str;
string toString() { return str; }
}
struct AppConfig
{
bool talkative;
bool report_errors;
string report_url;
string config_name;
bool load_config;
bool auto_launch;
bool auto_update;
bool check_update;
}
struct UIConfig
{
bool enabled;
bool launch;
bool update;
bool config_dump;
bool exit;
string message;
string launch_label;
string update_label;
string update_avail_label;
string config_dump_label;
string exit_label;
}
struct LaunchConfig
{
string[] command;
string workdir;
bool use_script;
string entry_file;
string source_dir;
version (Windows):
bool hide_when_running;
}
struct UpdateConfig
{
string seedurl;
string workdir;
size_t parallel_downloads;
string[] exclude;
}
struct Config
{
@Name("application")
AppConfig app;
@Name("interface")
UIConfig ui;
LaunchConfig launcher;
UpdateConfig updater;
}
immutable string default_config_toml = import("config.toml");
immutable Config default_config;
immutable Config config;
private string dash2minus(string str)
{
string newStr = "";
foreach (c; str)
{
if (c == '_')
newStr ~= '-';
else
newStr ~= c;
}
return newStr;
}
void wrapTOML(T)(ref T config, TOMLValue[string] toml, bool ignore_missing = false) @safe
{
static foreach (name; __traits(allMembers, T))
{{
alias member = __traits(getMember, config, name);
alias type = typeof(__traits(getMember, T, name));
type* field = &__traits(getMember, config, name);
static if (hasUDA!(member, Name))
enum key = getUDAs!(member, Name)[0].str;
else
enum key = name.dash2minus;
TOMLValue* value = key in toml;
if (!value)
{
if (!ignore_missing)
throw new Exception("Missing field \""~key~"\" of type "~type.stringof);
}
else
{
static if (isSomeString!type)
{
*field = value.str.to!type;
}
else static if (is(type == string[]))
{
*field = [];
foreach (_, entry; value.array)
*field ~= entry.str;
}
else static if (is(type == bool))
{
*field = value.boolean;
}
else static if (isIntegral!type)
{
*field = value.integer.to!type;
}
else static if (isFloatingPoint!type)
{
*field = value.floating.to!type;
}
else
{
wrapTOML(*field, value.table, ignore_missing);
}
}
}}
}
Config parseConfig(string toml) @safe
{
Config config;
TOMLDocument doc = parseTOML(toml);
wrapTOML(config, doc);
return config;
}
shared static this()
{
default_config = cast(immutable)parseConfig(default_config_toml);
config = default_config;
}