2023-11-20 08:44:10 +00:00
|
|
|
# bonsai docs: <https://sr.ht/~stacyharper/bonsai/>
|
2023-11-20 02:31:23 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
2024-02-23 15:06:25 +00:00
|
|
|
cfg = config.sane.programs.bonsai;
|
2023-11-20 06:46:44 +00:00
|
|
|
|
|
|
|
delayType = with lib; types.submodule {
|
|
|
|
options = {
|
|
|
|
type = mkOption {
|
|
|
|
type = types.enum [ "delay" ];
|
|
|
|
# default = "delay";
|
|
|
|
};
|
|
|
|
delay_duration = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
description = ''
|
|
|
|
used for "delay" types only.
|
|
|
|
nanoseconds until the event is finalized.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
transitions = mkOption {
|
|
|
|
type = types.listOf transitionType;
|
2023-11-20 08:44:10 +00:00
|
|
|
default = [];
|
2023-11-20 06:46:44 +00:00
|
|
|
description = ''
|
2023-11-20 08:44:10 +00:00
|
|
|
list of transitions out of this state (i.e. after completing the delay).
|
2023-11-20 06:46:44 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
eventType = with lib; types.submodule {
|
|
|
|
options = {
|
|
|
|
type = mkOption {
|
|
|
|
type = types.enum [ "event" ];
|
|
|
|
# default = "event";
|
|
|
|
};
|
|
|
|
event_name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
name of event which this transition applies to.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
transitions = mkOption {
|
|
|
|
type = types.listOf transitionType;
|
2023-11-20 08:44:10 +00:00
|
|
|
default = [];
|
2023-11-20 06:46:44 +00:00
|
|
|
description = ''
|
|
|
|
list of transitions out of this state.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
execType = with lib; types.submodule {
|
|
|
|
options = {
|
|
|
|
type = mkOption {
|
|
|
|
type = types.enum [ "exec" ];
|
|
|
|
# default = "exec";
|
|
|
|
};
|
|
|
|
command = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
description = ''
|
|
|
|
command to run when the event is triggered.
|
|
|
|
'';
|
|
|
|
};
|
2023-11-20 08:44:10 +00:00
|
|
|
transitions = mkOption {
|
|
|
|
type = types.listOf transitionType;
|
|
|
|
default = [];
|
|
|
|
description = ''
|
|
|
|
list of transitions out of this state (i.e. after successfully executing the command)
|
|
|
|
'';
|
|
|
|
};
|
2023-11-20 06:46:44 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
isDelay = x: delayType.check x && x.type == "delay";
|
|
|
|
isEvent = x: eventType.check x && x.type == "event";
|
|
|
|
isExec = x: execType.check x && x.type == "exec";
|
|
|
|
# unfortunately, `types.oneOf` is naive about submodules, so we need our own type.
|
|
|
|
# transitionType = lib.types.oneOf [ delayType eventType execType ];
|
|
|
|
transitionType = with lib.types; mkOptionType {
|
|
|
|
name = "transition";
|
|
|
|
check = x: isDelay x || isEvent x || isExec x;
|
|
|
|
merge = loc: defs: let
|
|
|
|
defList = builtins.map (d: d.value) defs;
|
|
|
|
in
|
|
|
|
if builtins.all isDelay defList then
|
|
|
|
delayType.merge loc defs
|
|
|
|
else if builtins.all isEvent defList then
|
|
|
|
eventType.merge loc defs
|
|
|
|
else if builtins.all isExec defList then
|
|
|
|
execType.merge loc defs
|
|
|
|
else
|
|
|
|
mergeOneOption loc defs
|
|
|
|
;
|
|
|
|
};
|
2023-11-20 02:31:23 +00:00
|
|
|
in
|
2023-11-20 01:55:15 +00:00
|
|
|
{
|
2024-02-23 02:52:35 +00:00
|
|
|
sane.programs.bonsai = {
|
|
|
|
configOption = with lib; mkOption {
|
|
|
|
default = {};
|
|
|
|
type = types.submodule {
|
|
|
|
options = {
|
|
|
|
transitions = mkOption {
|
|
|
|
type = types.listOf transitionType;
|
|
|
|
default = [];
|
|
|
|
};
|
|
|
|
configFile = mkOption {
|
|
|
|
type = types.path;
|
2024-02-23 15:06:25 +00:00
|
|
|
default = pkgs.writeText "bonsai_tree.json" (builtins.toJSON cfg.config.transitions);
|
2024-02-23 02:52:35 +00:00
|
|
|
description = ''
|
|
|
|
configuration file to pass to bonsai.
|
|
|
|
usually auto-generated from the sibling options; exposed mainly for debugging or convenience.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2023-11-20 06:46:44 +00:00
|
|
|
};
|
2024-02-23 02:52:35 +00:00
|
|
|
|
2024-03-02 22:34:38 +00:00
|
|
|
sandbox.method = "bwrap";
|
|
|
|
sandbox.extraRuntimePaths = [
|
|
|
|
"/" #< just needs "bonsai", but needs to create it first...
|
|
|
|
];
|
|
|
|
|
2024-02-23 02:52:35 +00:00
|
|
|
services.bonsaid = {
|
|
|
|
description = "bonsai: programmable input dispatcher";
|
|
|
|
after = [ "graphical-session.target" ];
|
|
|
|
wantedBy = [ "graphical-session.target" ];
|
|
|
|
|
2024-03-21 10:36:24 +00:00
|
|
|
serviceConfig.ExecStart = "bonsaid -t ${cfg.config.configFile}";
|
|
|
|
serviceConfig.ExecStopPost = "rm -f $XDG_RUNTIME_DIR/bonsai";
|
2023-11-20 02:31:23 +00:00
|
|
|
};
|
|
|
|
};
|
2023-11-20 01:55:15 +00:00
|
|
|
}
|