{ config, lib, pkgs, ... }: with lib; let cfg = config.cli.rofi-project-opener; # Convert list of paths to colon-separated string projectDirsStr = concatStringsSep ":" cfg.projectDirs; in { options.cli.rofi-project-opener = { enable = mkEnableOption "Rofi-based project directory launcher"; projectDirs = mkOption { type = types.listOf types.str; default = ["~/dev" "~/projects"]; description = '' List 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. Supports ~ for home directory expansion. ''; example = literalExpression ''["~/dev" "~/projects" "~/code"]''; }; 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 pass to the terminal. Use %s as a placeholder for the project path. If empty, defaults to opening a shell in the project directory and running opencode. Examples: - "" (empty) - Uses default: cd to project, run opencode - "-e zsh -c 'cd %s && opencode'" - Custom shell with explicit path - "--hold -e nvim" - Open editor directly (no %s = no cd) ''; example = literalExpression ''"-e zsh -c 'cd %s && opencode'"''; }; 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 " - Use specific rofi theme - "-width " - Window width - "-lines " - Number of visible lines ''; example = literalExpression ''["-dmenu" "-i" "-theme gruvbox"]''; }; }; config = mkIf cfg.enable { home.packages = [pkgs.rofi-project-opener]; # Write config file (shell-independent) xdg.configFile."rofi-project-opener/config".text = '' # rofi-project-opener configuration PROJECT_DIRS="${projectDirsStr}" 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}" ''; }; }