Files
DankMaterialShell/quickshell/Common/ConfigIncludeResolve.js
T
purian23 e10102edc0 feat(mango): native mouse/touchpad & keyboard input support
- Hide blur toggle options until mango support is added
2026-10-09 05:55:47 -04:00

177 lines
5.7 KiB
JavaScript

function shQuote(value) {
return "'" + String(value ?? "").replace(/'/g, "'\\''") + "'";
}
function dirname(path) {
const idx = String(path ?? "").lastIndexOf("/");
return idx > 0 ? path.substring(0, idx) : ".";
}
function sectionHeaderFor(includeLine) {
const line = String(includeLine ?? "").trim();
if (line.startsWith("require"))
return "-- DMS Include Configs";
if (line.startsWith("source"))
return "# DMS Include Configs";
return "// DMS Include Configs";
}
function managedIncludePatternFor(includeLine) {
const line = String(includeLine ?? "").trim();
if (line.startsWith("require"))
return "require.*dms[.]";
if (line.startsWith("source"))
return "source.*dms/";
return "include.*dms/";
}
function buildRepairScript(options) {
const configFile = options.configFile;
const backupFile = options.backupFile;
const fragments = options.fragmentFiles || (options.fragmentFile ? [options.fragmentFile] : []);
const includes = options.includes || [
{
grepPattern: options.grepPattern,
includeLine: options.includeLine
}
];
const commands = [];
if (backupFile)
commands.push(`cp ${shQuote(configFile)} ${shQuote(backupFile)} 2>/dev/null || true`);
const dirs = {};
for (const fragment of fragments)
dirs[dirname(fragment)] = true;
for (const dir in dirs)
commands.push(`mkdir -p ${shQuote(dir)}`);
if (fragments.length > 0)
commands.push("touch " + fragments.map(shQuote).join(" "));
for (const include of includes) {
if (!include.grepPattern || !include.includeLine)
continue;
const sectionHeader = options.sectionHeader || sectionHeaderFor(include.includeLine);
const managedIncludePattern = managedIncludePatternFor(include.includeLine);
commands.push(`if ! grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(include.grepPattern)}; then if grep -Fqx ${shQuote(sectionHeader)} ${shQuote(configFile)} 2>/dev/null || grep -v '^[[:space:]]*\\(//\\|#\\|--\\)' ${shQuote(configFile)} 2>/dev/null | grep -q ${shQuote(managedIncludePattern)}; then printf '%s\\n' ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; elif [ -s ${shQuote(configFile)} ]; then printf '\\n%s\\n%s\\n' ${shQuote(sectionHeader)} ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; else printf '%s\\n%s\\n' ${shQuote(sectionHeader)} ${shQuote(include.includeLine)} >> ${shQuote(configFile)}; fi; fi`);
}
return commands.join("; ");
}
const compositorDirs = {
niri: "niri",
hyprland: "hypr",
mango: "mango"
};
const configNames = {
niri: "config.kdl",
hyprland: "hyprland.lua",
mango: "config.conf"
};
const fragmentExtensions = {
niri: "kdl",
hyprland: "lua",
mango: "conf"
};
const kdlInclude = name => ({
grepPattern: `include.*"dms/${name}.kdl"`,
includeLine: `include "dms/${name}.kdl"`
});
const luaInclude = name => ({
grepPattern: `dms.${name}`,
includeLine: `require("dms.${name}")`
});
const confInclude = (name, grepPattern, includeLine) => ({
grepPattern: grepPattern ?? `source.*dms/${name}.conf`,
includeLine: includeLine ?? `source=./dms/${name}.conf`
});
const includeTable = {
outputs: {
niri: [kdlInclude("outputs")],
hyprland: [luaInclude("outputs")],
mango: [confInclude("outputs")]
},
layout: {
niri: [kdlInclude("layout")],
hyprland: [luaInclude("layout")],
mango: [confInclude("layout")]
},
input: {
niri: [kdlInclude("input")],
hyprland: [luaInclude("input")],
mango: [confInclude("input")]
},
windowrules: {
niri: [kdlInclude("windowrules")],
hyprland: [luaInclude("windowrules")],
mango: [confInclude("windowrules", "dms/windowrules.conf")]
},
cursor: {
niri: [kdlInclude("cursor")],
hyprland: [luaInclude("cursor")],
mango: [confInclude("cursor")]
},
binds: {
niri: [kdlInclude("binds")],
hyprland: [luaInclude("binds"), luaInclude("binds-user")],
mango: [confInclude("binds", undefined, "source = ./dms/binds.conf")]
}
};
const fragmentNameTable = {
binds: {
hyprland: ["binds", "binds-user"]
}
};
function includeSpec(kind, compositor) {
const includes = includeTable[kind]?.[compositor];
if (!includes)
return null;
const extension = fragmentExtensions[compositor];
const names = fragmentNameTable[kind]?.[compositor] ?? [kind];
return {
configName: configNames[compositor],
fragmentNames: names.map(name => `${name}.${extension}`),
includes: includes
};
}
function includePaths(kind, compositor, configDir) {
const spec = includeSpec(kind, compositor);
if (!spec)
return null;
const dir = configDir + "/" + compositorDirs[compositor];
return {
configFile: dir + "/" + spec.configName,
fragmentFiles: spec.fragmentNames.map(name => dir + "/dms/" + name),
includes: spec.includes
};
}
function repairScriptFor(kind, compositor, configDir, backupFile) {
const paths = includePaths(kind, compositor, configDir);
if (!paths)
return "";
return buildRepairScript({
configFile: paths.configFile,
backupFile: backupFile,
fragmentFiles: paths.fragmentFiles,
includes: paths.includes
});
}
function resolveIncludeArgs(kind, compositor) {
const spec = includeSpec(kind, compositor);
if (!spec)
return null;
return [compositor === "mango" ? "mangowc" : compositor, spec.fragmentNames[0]];
}