Files
nixpkgs/modules/home-manager/cli/rofi-project-opener.nix

135 lines
4.1 KiB
Nix

{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.cli.rofi-project-opener;
# Project directory submodule type
projectDirType = types.submodule {
options = {
path = mkOption {
type = types.str;
description = "Base directory path to scan for project subdirectories.";
example = "~/dev";
};
args = mkOption {
type = types.str;
default = "";
description = "Additional arguments to pass to opencode when launching projects from this directory.";
example = "--agent Planner-Sisyphus";
};
};
};
# Convert projectDirs attrset to JSON for config file
projectDirsJson = builtins.toJSON (
mapAttrs (name: value: {
path = value.path;
args = value.args;
})
cfg.projectDirs
);
in {
options.cli.rofi-project-opener = {
enable = mkEnableOption "Rofi-based project directory launcher";
projectDirs = mkOption {
type = types.attrsOf projectDirType;
default = {
dev = {path = "~/dev";};
projects = {path = "~/projects";};
};
description = ''
Attribute set of base directories to scan for project subdirectories.
Each directory will be scanned for immediate subdirectories (non-hidden).
Projects are displayed as "base_dir/project_name" in rofi.
Each entry can specify:
- path: Base directory path (supports ~ for home directory)
- args: Optional arguments to pass to opencode for projects in this directory
'';
example = literalExpression ''
{
nixpkgs = { path = "~/p/NIX/nixpkgs"; args = "--agent Planner-Sisyphus"; };
dev = { path = "~/dev"; };
work = { path = "~/work"; args = "--agent work-agent"; };
}
'';
};
terminal = mkOption {
type = types.either types.str types.package;
default = "kitty";
description = "Terminal emulator to use for launching opencode. Can be a string or package.";
example = literalExpression "pkgs.alacritty";
};
terminalCommand = mkOption {
type = types.str;
default = "";
description = ''
Custom command to run in the terminal.
Placeholders:
- %s = project path
- %a = project args (from projectDirs.<name>.args)
If empty, defaults to: cd to project, run "opencode %a"
Examples:
- "" (empty) - Uses default: cd to project, run opencode with args
- "opencode %a" - Run opencode with project-specific args
- "nvim" - Open editor (no args)
- "myapp %s %a" - Custom app with path and args
'';
example = literalExpression ''"opencode %a"'';
};
rofiPrompt = mkOption {
type = types.str;
default = "Select project";
description = "Prompt text displayed in rofi.";
example = "Open project:";
};
rofiArgs = mkOption {
type = types.listOf types.str;
default = ["-dmenu" "-i"];
description = ''
Arguments to pass to rofi.
Common options:
- "-dmenu" - Enable dmenu mode (required)
- "-i" - Case-insensitive matching
- "-theme <theme>" - Use specific rofi theme
- "-width <percentage>" - Window width
- "-lines <number>" - Number of visible lines
'';
example = literalExpression ''["-dmenu" "-i" "-theme gruvbox"]'';
};
};
config = mkIf cfg.enable {
home.packages = [pkgs.rofi-project-opener];
# Write JSON config file for project directories
xdg.configFile."rofi-project-opener/projects.json".text = projectDirsJson;
# Write shell config file for other settings
xdg.configFile."rofi-project-opener/config".text = ''
# rofi-project-opener configuration
TERMINAL="${
if isDerivation cfg.terminal
then "${cfg.terminal}/bin/${cfg.terminal.pname or (builtins.baseNameOf (toString cfg.terminal))}"
else cfg.terminal
}"
${optionalString (cfg.terminalCommand != "") ''TERMINAL_CMD="${cfg.terminalCommand}"''}
ROFI_PROMPT="${cfg.rofiPrompt}"
ROFI_ARGS="${escapeShellArgs cfg.rofiArgs}"
'';
};
}