2.home-manager/modules/programs/smug.nix
James Davidson f72ed9c97d smug: add project session setting
Add an optional session setting so that session names can be different
than the smug project name. This also enables using template variables
when naming sessions.
2026-03-19 15:36:43 +00:00

187 lines
6.2 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.smug;
iniFormat = pkgs.formats.yaml { };
mkOptionCommands =
description:
lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
default = null;
description = description;
};
mkOptionRoot =
description:
lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = description;
};
in
{
meta.maintainers = with lib.hm.maintainers; [ mipmip ];
options.programs.smug = {
enable = lib.mkEnableOption "Smug session manager";
package = lib.mkPackageOption pkgs "smug" { nullable = true; };
projects = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
session = lib.mkOption {
type = lib.types.str;
default = name;
description = "Session name for the smug project.";
example = lib.literalExpression ''{ session = "project-\''${worktree}"; }'';
};
root = mkOptionRoot ''
Root path in filesystem of the smug project. This is where tmux
changes its directory to.
Application defaults to `$HOME`.
'';
windows = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule [
{
options = {
name = lib.mkOption {
type = lib.types.str;
description = ''
Name of the tmux window;
'';
};
selected = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
default = null;
description = ''
Whether this window should be selected by default at session start.
'';
};
root = mkOptionRoot "Root path of window. This is relative to the path of the smug project.";
commands = mkOptionCommands "Commands to execute when window starts.";
layout = lib.mkOption {
type = lib.types.enum [
"main-horizontal"
"main-vertical"
"even-vertical"
"even-horizontal"
"tiled"
];
description = ''
Layout of window when opening panes.
'';
};
manual = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
default = null;
description = ''
Start window only manually, using the -w arg
'';
};
panes = lib.mkOption {
default = null;
description = ''
Panes to open in a window.
'';
type = lib.types.nullOr (
lib.types.listOf (
lib.types.submodule [
{
options = {
root = mkOptionRoot "Root path of pane. This is relative to the path of the smug project.";
commands = mkOptionCommands "Commands to execute when pane starts.";
type = lib.mkOption {
type = lib.types.enum [
"horizontal"
"vertical"
];
description = ''
Type of pane.
'';
};
};
}
]
)
);
};
};
}
]
);
description = ''
Windows to create in the project session
'';
};
env = lib.mkOption {
type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
default = null;
description = "Environment Variables to set in session.";
};
beforeStart = mkOptionCommands "Commands to execute before the tmux-session starts.";
stop = mkOptionCommands "Commands to execute after the tmux-session is destroyed.";
};
}
)
);
default = { };
description = "Attribute set with project configurations.";
};
};
config =
let
cleanedProjects = lib.filterAttrsRecursive (name: value: value != null) cfg.projects;
mkProjects = lib.attrsets.mapAttrs' (
k: v: {
name = "${config.home.homeDirectory}/.config/smug/${k}.yml";
value.source =
let
prjConf =
lib.attrsets.mapAttrs' (
name: value:
(lib.attrsets.nameValuePair (if name == "beforeStart" then "before_start" else name) value)
) v
// {
session = v.session;
windows = lib.lists.forEach v.windows (
winprop: (lib.filterAttrsRecursive (name: value: value != null) winprop)
);
};
in
iniFormat.generate "smug-project-${k}" prjConf;
}
);
in
lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file = mkProjects cleanedProjects;
};
}