mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 13:22:19 +01:00
The pure moves put the KDE and macOS nix files under nix/linux and nix/macos but left the relative paths they read: the JSON schema (now schemas/linux and schemas/macos), the example configurations and key binding samples (docs/linux, docs/macos), the key binding fixtures (komorebi-hotkeys at the top level), the wsl2 probe script (scripts/linux). Each path now names the file in the final directory, one more directory up because the files are one level deeper. Not touched: flake.nix and the nested flakes (next revisions), which still name the old paths. Verified: not verified (nothing evaluates until the flake is rewritten; the new flake checks these paths).
322 lines
10 KiB
Nix
322 lines
10 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.services.komorebi;
|
|
cfgBar = config.services.komorebi-bar;
|
|
|
|
jsonFormat = pkgs.formats.json { };
|
|
|
|
komorebiSchemaPath = ../../schemas/macos/schema.json;
|
|
komorebiBarSchemaPath = ../../schemas/macos/schema.bar.json;
|
|
|
|
filterNulls =
|
|
value:
|
|
if value == null then
|
|
null
|
|
else if builtins.isList value then
|
|
map filterNulls (builtins.filter (x: x != null) value)
|
|
else if builtins.isAttrs value then
|
|
let
|
|
filtered = lib.filterAttrs (_n: v: v != null) (builtins.mapAttrs (_n: v: filterNulls v) value);
|
|
in
|
|
filtered
|
|
else
|
|
value;
|
|
|
|
# validate a json file against the flake's version of a schema, returning the validated file path
|
|
# strips comment lines before validation (common in configs for editor support)
|
|
validateJsonFile =
|
|
{
|
|
name,
|
|
jsonFile,
|
|
schemaFile,
|
|
}:
|
|
pkgs.runCommand "validated-${name}" { nativeBuildInputs = [ pkgs.check-jsonschema ]; } ''
|
|
echo "Validating ${name} against schema..."
|
|
# Strip // comment lines before validation
|
|
grep -v '^\s*//' ${jsonFile} > clean.json
|
|
check-jsonschema --schemafile ${schemaFile} clean.json
|
|
cp clean.json $out
|
|
'';
|
|
|
|
komorebiOptionsModule = import ./komorebi-options.nix { inherit lib; };
|
|
komorebiBarOptionsModule = import ./komorebi-bar-options.nix { inherit lib; };
|
|
|
|
defaultKomorebiConfig = (import ./tests/komorebi-example.nix { }).komorebi;
|
|
defaultKomorebiBarConfig = (import ./tests/komorebi-bar-example.nix { }).komorebi-bar;
|
|
|
|
# fetch application-specific configuration from remote sources
|
|
fetchAppSpecificSource =
|
|
source:
|
|
pkgs.fetchurl {
|
|
url = "https://raw.githubusercontent.com/${source.owner}/${source.repo}/${source.rev}/${source.path}";
|
|
hash = source.hash;
|
|
};
|
|
|
|
applicationSpecificConfigFiles = map fetchAppSpecificSource cfg.applicationSpecificConfiguration.sources;
|
|
|
|
# build app_specific_configuration_path value:
|
|
# - single source: use single path (string)
|
|
# - multiple sources: use array of paths
|
|
appSpecificPaths =
|
|
if builtins.length applicationSpecificConfigFiles == 1 then
|
|
"${builtins.head applicationSpecificConfigFiles}"
|
|
else
|
|
map (f: "${f}") applicationSpecificConfigFiles;
|
|
|
|
# build final komorebi config
|
|
# if applicationSpecificConfiguration is enabled and has sources: set app_specific_configuration_path
|
|
# if disabled or empty sources: remove app_specific_configuration_path entirely (handles default config with $HOME path)
|
|
shouldUseAppSpecific =
|
|
cfg.applicationSpecificConfiguration.enable && applicationSpecificConfigFiles != [ ];
|
|
|
|
baseKomorebiConfig =
|
|
if shouldUseAppSpecific then
|
|
cfg.config
|
|
else
|
|
removeAttrs cfg.config [ "app_specific_configuration_path" ];
|
|
|
|
finalKomorebiConfig = filterNulls (
|
|
baseKomorebiConfig
|
|
// lib.optionalAttrs shouldUseAppSpecific {
|
|
app_specific_configuration_path = appSpecificPaths;
|
|
}
|
|
);
|
|
|
|
generatedKomorebiConfigFile = jsonFormat.generate "komorebi.json" finalKomorebiConfig;
|
|
|
|
# final komorebi config file - either user-provided (validated) or generated from Nix options
|
|
komorebiConfigFile =
|
|
if cfg.configFile != null then
|
|
validateJsonFile {
|
|
name = "komorebi.json";
|
|
jsonFile = cfg.configFile;
|
|
schemaFile = komorebiSchemaPath;
|
|
}
|
|
else
|
|
generatedKomorebiConfigFile;
|
|
|
|
mkGeneratedBarConfigFile =
|
|
name: barCfg: jsonFormat.generate "komorebi-bar-${name}.json" (filterNulls barCfg.config);
|
|
|
|
# final bar config - either user-provided (validated) or generated from Nix options
|
|
mkBarConfigFile =
|
|
name: barCfg:
|
|
if barCfg.configFile != null then
|
|
validateJsonFile {
|
|
name = "komorebi-bar-${name}.json";
|
|
jsonFile = barCfg.configFile;
|
|
schemaFile = komorebiBarSchemaPath;
|
|
}
|
|
else
|
|
mkGeneratedBarConfigFile name barCfg;
|
|
|
|
in
|
|
{
|
|
options.services.komorebi = {
|
|
enable = lib.mkEnableOption "komorebi for Mac";
|
|
package = lib.mkPackageOption pkgs "komorebi" { };
|
|
|
|
logLevel = lib.mkOption {
|
|
type = lib.types.enum [
|
|
"error"
|
|
"warn"
|
|
"info"
|
|
"debug"
|
|
"trace"
|
|
];
|
|
default = "info";
|
|
description = "Log verbosity level";
|
|
};
|
|
|
|
configFile = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default = null;
|
|
description = ''
|
|
Path to a komorebi JSON configuration file.
|
|
If specified, this file will be validated against the schema and used instead of the `config` option.
|
|
'';
|
|
example = lib.literalExpression "./komorebi.json";
|
|
};
|
|
|
|
config = lib.mkOption {
|
|
type = komorebiOptionsModule.options.komorebi.type;
|
|
default = defaultKomorebiConfig;
|
|
description = ''
|
|
komorebi configuration (validated against schema). Defaults to example config.
|
|
Ignored if `configFile` is set.
|
|
'';
|
|
};
|
|
|
|
applicationSpecificConfiguration = {
|
|
enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = "Whether to use application-specific configuration sources.";
|
|
};
|
|
|
|
sources = lib.mkOption {
|
|
type = lib.types.listOf (
|
|
lib.types.submodule {
|
|
options = {
|
|
owner = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "GitHub repository owner.";
|
|
example = "LGUG2Z";
|
|
};
|
|
repo = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "GitHub repository name.";
|
|
example = "komorebi-application-specific-configuration";
|
|
};
|
|
rev = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Git revision (commit hash, tag, or branch).";
|
|
example = "09ebdcd95780b168cecde2f2d49096a58e91365f";
|
|
};
|
|
path = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "applications.mac.json";
|
|
description = "Path to the JSON file within the repository.";
|
|
};
|
|
hash = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "SHA256 hash of the file for reproducibility.";
|
|
example = "sha256-gfYubJpVEU6vxdd/vqujQhQX8mdAEE9ImugqdIyTQKk=";
|
|
};
|
|
};
|
|
}
|
|
);
|
|
default = [
|
|
{
|
|
owner = "LGUG2Z";
|
|
repo = "komorebi-application-specific-configuration";
|
|
rev = "09ebdcd95780b168cecde2f2d49096a58e91365f";
|
|
path = "applications.mac.json";
|
|
hash = "sha256-gfYubJpVEU6vxdd/vqujQhQX8mdAEE9ImugqdIyTQKk=";
|
|
}
|
|
];
|
|
description = ''
|
|
List of remote sources for application-specific configuration files.
|
|
Each source is fetched from GitHub and combined into the final config.
|
|
'';
|
|
example = lib.literalExpression ''
|
|
[
|
|
{
|
|
owner = "LGUG2Z";
|
|
repo = "komorebi-application-specific-configuration";
|
|
rev = "09ebdcd95780b168cecde2f2d49096a58e91365f";
|
|
path = "applications.mac.json";
|
|
hash = "sha256-gfYubJpVEU6vxdd/vqujQhQX8mdAEE9ImugqdIyTQKk=";
|
|
}
|
|
{
|
|
owner = "myuser";
|
|
repo = "my-komorebi-overrides";
|
|
rev = "abc123...";
|
|
path = "overrides.json";
|
|
hash = "sha256-...";
|
|
}
|
|
]
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
options.services.komorebi-bar = {
|
|
enable = lib.mkEnableOption "komorebi-bar status bar(s)";
|
|
package = lib.mkPackageOption pkgs "komorebi-bar" { };
|
|
|
|
bars = lib.mkOption {
|
|
type = lib.types.attrsOf (
|
|
lib.types.submodule {
|
|
options = {
|
|
configFile = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.path;
|
|
default = null;
|
|
description = ''
|
|
Path to a komorebi-bar JSON configuration file.
|
|
If specified, this file will be validated against the schema and used instead of the `config` option.
|
|
'';
|
|
example = lib.literalExpression "./komorebi.bar.json";
|
|
};
|
|
|
|
config = lib.mkOption {
|
|
type = komorebiBarOptionsModule.options.komorebi-bar.type;
|
|
default = defaultKomorebiBarConfig;
|
|
description = ''
|
|
komorebi-bar configuration for this bar instance.
|
|
Ignored if `configFile` is set.
|
|
'';
|
|
};
|
|
};
|
|
}
|
|
);
|
|
default = { };
|
|
example = lib.literalExpression ''
|
|
{
|
|
main = {
|
|
config = {
|
|
monitor = 0;
|
|
left_widgets = [ ... ];
|
|
right_widgets = [ ... ];
|
|
};
|
|
};
|
|
secondary = {
|
|
# Use a JSON file for this bar
|
|
configFile = ./my-secondary-bar.json;
|
|
};
|
|
}
|
|
'';
|
|
description = "Named komorebi-bar instances, one per monitor";
|
|
};
|
|
};
|
|
|
|
config = lib.mkMerge [
|
|
# komorebi
|
|
(lib.mkIf cfg.enable {
|
|
environment.systemPackages = [
|
|
cfg.package
|
|
pkgs.komorebic
|
|
];
|
|
|
|
launchd.user.agents.komorebi = {
|
|
serviceConfig.ProgramArguments = [
|
|
"${cfg.package}/bin/komorebi"
|
|
"--config"
|
|
"${komorebiConfigFile}"
|
|
"--log-level"
|
|
cfg.logLevel
|
|
];
|
|
serviceConfig.KeepAlive = true;
|
|
serviceConfig.RunAtLoad = true;
|
|
serviceConfig.EnvironmentVariables = {
|
|
PATH = "${cfg.package}/bin:${config.environment.systemPath}";
|
|
};
|
|
};
|
|
})
|
|
|
|
# komorebi-bar
|
|
(lib.mkIf cfgBar.enable {
|
|
environment.systemPackages = [ cfgBar.package ];
|
|
|
|
launchd.user.agents = lib.mapAttrs' (
|
|
name: barCfg:
|
|
lib.nameValuePair "komorebi-bar-${name}" {
|
|
serviceConfig.ProgramArguments = [
|
|
"${cfgBar.package}/bin/komorebi-bar"
|
|
"--config"
|
|
"${mkBarConfigFile name barCfg}"
|
|
];
|
|
serviceConfig.KeepAlive = true;
|
|
serviceConfig.RunAtLoad = true;
|
|
}
|
|
) cfgBar.bars;
|
|
})
|
|
];
|
|
}
|