From 3361f2bbe7a028c5c50b0aa000257494bbfab92c Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 18 May 2024 08:01:06 +0000 Subject: [PATCH] zsh: port to sane.programs --- hosts/by-name/moby/default.nix | 2 +- hosts/by-name/servo/default.nix | 2 +- hosts/common/programs/zsh/default.nix | 324 ++++++++++++------------- hosts/common/programs/zsh/starship.nix | 142 ++++++----- 4 files changed, 232 insertions(+), 238 deletions(-) diff --git a/hosts/by-name/moby/default.nix b/hosts/by-name/moby/default.nix index 8f55813f..3eece904 100644 --- a/hosts/by-name/moby/default.nix +++ b/hosts/by-name/moby/default.nix @@ -21,7 +21,7 @@ sane.roles.client = true; sane.roles.handheld = true; - sane.zsh.showDeadlines = false; # unlikely to act on them when in shell + sane.programs.zsh.config.showDeadlines = false; # unlikely to act on them when in shell sane.services.wg-home.enable = true; sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip; diff --git a/hosts/by-name/servo/default.nix b/hosts/by-name/servo/default.nix index 8c9b61fe..3cb915b3 100644 --- a/hosts/by-name/servo/default.nix +++ b/hosts/by-name/servo/default.nix @@ -15,7 +15,7 @@ }; sane.roles.build-machine.enable = true; - sane.zsh.showDeadlines = false; # ~/knowledge doesn't always exist + sane.programs.zsh.config.showDeadlines = false; # ~/knowledge doesn't always exist sane.programs.consoleUtils.suggestedPrograms = [ "consoleMediaUtils" # notably, for go2tv / casting "pcConsoleUtils" diff --git a/hosts/common/programs/zsh/default.nix b/hosts/common/programs/zsh/default.nix index 12384301..7bcca5dc 100644 --- a/hosts/common/programs/zsh/default.nix +++ b/hosts/common/programs/zsh/default.nix @@ -19,186 +19,182 @@ { config, lib, pkgs, ... }: let - inherit (lib) mkIf mkMerge mkOption types; - cfg = config.sane.zsh; + cfg = config.sane.programs.zsh; in { imports = [ ./starship.nix ]; - options = { - # TODO: port to sane.programs options - sane.zsh = { - showDeadlines = mkOption { - type = types.bool; - default = true; - description = "show upcoming deadlines (from my PKM) upon shell init"; - }; - starship = mkOption { - type = types.bool; - default = true; - description = "enable starship prompt"; - }; - guiIntegrations = mkOption { - type = types.bool; - default = config.sane.programs.guiApps.enabled; - description = '' - integrate with things like VTE, so that windowing systems can show the PWD in the title. - drags in gtk+3. - ''; + + sane.programs.zsh = { + configOption = with lib; mkOption { + default = {}; + type = types.submodule { + options.showDeadlines = mkOption { + type = types.bool; + default = true; + description = "show upcoming deadlines (from my PKM) upon shell init"; + }; + options.starship = mkOption { + type = types.bool; + default = true; + description = "enable starship prompt"; + }; + options.guiIntegrations = mkOption { + type = types.bool; + default = config.sane.programs.guiApps.enabled; + description = '' + integrate with things like VTE, so that windowing systems can show the PWD in the title. + drags in gtk+3. + ''; + }; }; }; + + sandbox.enable = false; # TODO: i could at least sandbox the prompt (starship)! + persist.byStore.private = [ + # we don't need to full zsh dir -- just the history file -- + # but zsh will sometimes backup the history file and symlinking just the file messes things up + ".local/share/zsh" + ]; + + fs.".config/zsh/.zshrc".symlink.text = '' + # zsh/prezto complains if zshrc doesn't exist or is empty; + # preserve this comment to prevent that from ever happening. + '' + lib.optionalString cfg.config.showDeadlines '' + ${pkgs.sane-scripts.deadlines}/bin/sane-deadlines + '' + '' + + HISTFILE="$HOME/.local/share/zsh/history" + HISTSIZE=1000000 + SAVEHIST=1000000 + + # auto-cd into any of these dirs by typing them and pressing 'enter': + hash -d 3rd="/home/colin/dev/3rd" + hash -d dev="/home/colin/dev" + hash -d knowledge="/home/colin/knowledge" + hash -d nixos="/home/colin/nixos" + hash -d nixpkgs="/home/colin/dev/3rd/nixpkgs" + hash -d ref="/home/colin/ref" + hash -d secrets="/home/colin/knowledge/secrets" + hash -d tmp="/home/colin/tmp" + hash -d uninsane="/home/colin/dev/uninsane" + hash -d Videos="/home/colin/Videos" + + # emulate bash keybindings + bindkey -e + + # fixup bindings not handled by bash, see: + # `bindkey -e` seems to define most of the `key` array. everything in the Arch defaults except for these: + key[Backspace]="''${terminfo[kbs]}" + key[Control-Left]="''${terminfo[kLFT5]}" + key[Control-Right]="''${terminfo[kRIT5]}" + key[Shift-Tab]="''${terminfo[kcbt]}" + bindkey -- "''${key[Delete]}" delete-char + bindkey -- "''${key[Control-Left]}" backward-word + bindkey -- "''${key[Control-Right]}" forward-word + + # or manually recreate what i care about... + # key[Left]=''${terminfo[kcub1]} + # key[Right]=''${terminfo[kcuf1]} + # bindkey '^R' history-incremental-search-backward + # bindkey '^A' beginning-of-line + # bindkey '^E' end-of-line + # bindkey "^''${key[Left]}" backward-word + # bindkey "^''${key[Right]}" forward-word + + # run any additional, sh-generic commands (useful for e.g. launching a login manager on login) + test -e ~/.profile && source ~/.profile + ''; }; - config = mkMerge [ - ({ - sane.programs.zsh = { - sandbox.enable = false; # TODO: i could at least sandbox the prompt (starship)! - persist.byStore.private = [ - # we don't need to full zsh dir -- just the history file -- - # but zsh will sometimes backup the history file and symlinking just the file messes things up - ".local/share/zsh" - ]; - fs.".config/zsh/.zshrc".symlink.text = '' - # zsh/prezto complains if zshrc doesn't exist or is empty; - # preserve this comment to prevent that from ever happening. - '' + lib.optionalString cfg.showDeadlines '' - ${pkgs.sane-scripts.deadlines}/bin/sane-deadlines - '' + '' + # enable zsh completions + environment.pathsToLink = lib.mkIf cfg.enabled [ "/share/zsh" ]; - HISTFILE="$HOME/.local/share/zsh/history" - HISTSIZE=1000000 - SAVEHIST=1000000 + programs.zsh = lib.mkIf cfg.enabled { + enable = true; + shellAliases = { + ":q" = "exit"; + # common typos + "cd.." = "cd .."; + "cd../" = "cd ../"; + "ecit" = "exit"; + "exi5" = "exit"; + "exiy" = "exit"; + # ls helpers (eza is a nicer `ls` + "l" = "eza --oneline"; # show one entry per line + "ll" = "eza --long --time-style=long-iso"; + # overcome poor defaults + "lsof" = "lsof -P"; #< lsof: use port *numbers*, not names + "tcpdump" = "tcpdump -n"; #< tcpdump: use port *numbers*, not names + }; + setOptions = [ + # docs: `man zshoptions` + # nixos defaults: + "HIST_FCNTL_LOCK" + "HIST_IGNORE_DUPS" + "HIST_EXPIRE_DUPS_FIRST" + "SHARE_HISTORY" + # customizations: + "AUTO_CD" # type directory name to go there + "AUTO_MENU" # show auto-complete menu on double-tab + "CDABLE_VARS" # allow auto-cd to use my `hash` aliases -- not just immediate subdirs + "CLOBBER" # allow `foo > bar.txt` to overwrite bar.txt + "NO_CORRECT" # don't try to correct commands + "PIPE_FAIL" # when `cmd_a | cmd_b`, make $? be non-zero if *any* of cmd_a or cmd_b fail + "RM_STAR_SILENT" # disable `rm *` confirmations + ]; - # auto-cd into any of these dirs by typing them and pressing 'enter': - hash -d 3rd="/home/colin/dev/3rd" - hash -d dev="/home/colin/dev" - hash -d knowledge="/home/colin/knowledge" - hash -d nixos="/home/colin/nixos" - hash -d nixpkgs="/home/colin/dev/3rd/nixpkgs" - hash -d ref="/home/colin/ref" - hash -d secrets="/home/colin/knowledge/secrets" - hash -d tmp="/home/colin/tmp" - hash -d uninsane="/home/colin/dev/uninsane" - hash -d Videos="/home/colin/Videos" + # .zshenv config: + shellInit = '' + ZDOTDIR=$HOME/.config/zsh + ''; - # emulate bash keybindings - bindkey -e + # system-wide .zshrc config: + interactiveShellInit = '' + # zmv is a way to do rich moves/renames, with pattern matching/substitution. + # see for an example: + autoload -Uz zmv - # fixup bindings not handled by bash, see: - # `bindkey -e` seems to define most of the `key` array. everything in the Arch defaults except for these: - key[Backspace]="''${terminfo[kbs]}" - key[Control-Left]="''${terminfo[kLFT5]}" - key[Control-Right]="''${terminfo[kRIT5]}" - key[Shift-Tab]="''${terminfo[kcbt]}" - bindkey -- "''${key[Delete]}" delete-char - bindkey -- "''${key[Control-Left]}" backward-word - bindkey -- "''${key[Control-Right]}" forward-word + HISTORY_IGNORE='(sane-shutdown *|sane-reboot *|rm *|nixos-rebuild.* switch|switch)' - # or manually recreate what i care about... - # key[Left]=''${terminfo[kcub1]} - # key[Right]=''${terminfo[kcuf1]} - # bindkey '^R' history-incremental-search-backward - # bindkey '^A' beginning-of-line - # bindkey '^E' end-of-line - # bindkey "^''${key[Left]}" backward-word - # bindkey "^''${key[Right]}" forward-word + # extra aliases + # TODO: move to `shellAliases` config? + function c() { + # list a dir after entering it + cd "$1" + eza --oneline + } + function deref() { + # convert a symlink into a plain file of the same content + if [ -L "$1" ] && [ -f "$1" ]; then + cp --dereference "$1" "$1.deref" + mv -f "$1.deref" "$1" + fi + chmod u+w "$1" + } + function nd() { + # enter a directory, creating it if necessary + mkdir -p "$1" + pushd "$1" + } - # run any additional, sh-generic commands (useful for e.g. launching a login manager on login) - test -e ~/.profile && source ~/.profile - ''; - }; - }) - (mkIf config.sane.programs.zsh.enabled { - # enable zsh completions - environment.pathsToLink = [ "/share/zsh" ]; - - programs.zsh = { - enable = true; - shellAliases = { - ":q" = "exit"; - # common typos - "cd.." = "cd .."; - "cd../" = "cd ../"; - "ecit" = "exit"; - "exi5" = "exit"; - "exiy" = "exit"; - # ls helpers (eza is a nicer `ls` - "l" = "eza --oneline"; # show one entry per line - "ll" = "eza --long --time-style=long-iso"; - # overcome poor defaults - "lsof" = "lsof -P"; #< lsof: use port *numbers*, not names - "tcpdump" = "tcpdump -n"; #< tcpdump: use port *numbers*, not names - }; - setOptions = [ - # docs: `man zshoptions` - # nixos defaults: - "HIST_FCNTL_LOCK" - "HIST_IGNORE_DUPS" - "HIST_EXPIRE_DUPS_FIRST" - "SHARE_HISTORY" - # customizations: - "AUTO_CD" # type directory name to go there - "AUTO_MENU" # show auto-complete menu on double-tab - "CDABLE_VARS" # allow auto-cd to use my `hash` aliases -- not just immediate subdirs - "CLOBBER" # allow `foo > bar.txt` to overwrite bar.txt - "NO_CORRECT" # don't try to correct commands - "PIPE_FAIL" # when `cmd_a | cmd_b`, make $? be non-zero if *any* of cmd_a or cmd_b fail - "RM_STAR_SILENT" # disable `rm *` confirmations - ]; - - # .zshenv config: - shellInit = '' - ZDOTDIR=$HOME/.config/zsh - ''; - - # system-wide .zshrc config: - interactiveShellInit = '' - # zmv is a way to do rich moves/renames, with pattern matching/substitution. - # see for an example: - autoload -Uz zmv - - HISTORY_IGNORE='(sane-shutdown *|sane-reboot *|rm *|nixos-rebuild.* switch|switch)' - - # extra aliases - # TODO: move to `shellAliases` config? - function c() { - # list a dir after entering it - cd "$1" - eza --oneline - } - function deref() { - # convert a symlink into a plain file of the same content - if [ -L "$1" ] && [ -f "$1" ]; then - cp --dereference "$1" "$1.deref" - mv -f "$1.deref" "$1" - fi - chmod u+w "$1" - } - function nd() { - # enter a directory, creating it if necessary - mkdir -p "$1" - pushd "$1" - } - - function repo() { - # navigate to a local checkout of the source code for repo (i.e. package) $1 - eval $(sane-clone "$1") - }; - - function switch() { - nix run '.#deploy.self' - } - ''; - - syntaxHighlighting.enable = true; - vteIntegration = cfg.guiIntegrations; + function repo() { + # navigate to a local checkout of the source code for repo (i.e. package) $1 + eval $(sane-clone "$1") }; - # enable a command-not-found hook to show nix packages that might provide the binary typed. - # programs.nix-index.enableZshIntegration = true; - programs.command-not-found.enable = false; - }) - ]; + function switch() { + nix run '.#deploy.self' + } + ''; + + syntaxHighlighting.enable = true; + vteIntegration = cfg.config.guiIntegrations; + }; + + # enable a command-not-found hook to show nix packages that might provide the binary typed. + # programs.nix-index.enableZshIntegration = lib.mkIf cfg.enabled true; + programs.command-not-found.enable = lib.mkIf cfg.enabled false; } diff --git a/hosts/common/programs/zsh/starship.nix b/hosts/common/programs/zsh/starship.nix index 0da6c09d..e1ac6a5a 100644 --- a/hosts/common/programs/zsh/starship.nix +++ b/hosts/common/programs/zsh/starship.nix @@ -4,7 +4,7 @@ { config, lib, pkgs, ...}: let - enabled = config.sane.zsh.starship; + enabled = config.sane.programs.zsh.config.starship; toml = pkgs.formats.toml {}; colors = { # colors sorted by the order they appear in the status bar @@ -16,86 +16,84 @@ let _06_blue = "#33658A"; }; in { - config = lib.mkIf config.sane.zsh.starship { - sane.programs.zsh = lib.mkIf enabled { - fs.".config/zsh/.zshrc".symlink.text = '' - eval "$(${pkgs.starship}/bin/starship init zsh)" - ''; - fs.".config/starship.toml".symlink.target = toml.generate "starship.toml" { - format = builtins.concatStringsSep "" [ - "[](${colors._01_purple})" - "$os" - "$username" - "$hostname" - "[](bg:${colors._02_pink} fg:${colors._01_purple})" - "$directory" - "[](fg:${colors._02_pink} bg:${colors._03_orange})" - "$git_branch" - "$git_status" - "[](fg:${colors._03_orange} bg:${colors._04_teal})" - "[](fg:${colors._04_teal} bg:${colors._05_blue})" - "[](fg:${colors._05_blue} bg:${colors._06_blue})" - "$time" - "$status" - "[ ](fg:${colors._06_blue})" - ]; - add_newline = false; # no blank line before prompt + sane.programs.zsh.fs = lib.mkIf enabled { + ".config/zsh/.zshrc".symlink.text = '' + eval "$(${pkgs.starship}/bin/starship init zsh)" + ''; + ".config/starship.toml".symlink.target = toml.generate "starship.toml" { + format = builtins.concatStringsSep "" [ + "[](${colors._01_purple})" + "$os" + "$username" + "$hostname" + "[](bg:${colors._02_pink} fg:${colors._01_purple})" + "$directory" + "[](fg:${colors._02_pink} bg:${colors._03_orange})" + "$git_branch" + "$git_status" + "[](fg:${colors._03_orange} bg:${colors._04_teal})" + "[](fg:${colors._04_teal} bg:${colors._05_blue})" + "[](fg:${colors._05_blue} bg:${colors._06_blue})" + "$time" + "$status" + "[ ](fg:${colors._06_blue})" + ]; + add_newline = false; # no blank line before prompt - os.style = "bg:${colors._01_purple}"; - os.format = "[$symbol]($style)"; - os.disabled = false; - # os.symbols.NixOS = "❄️"; # removes the space after logo + os.style = "bg:${colors._01_purple}"; + os.format = "[$symbol]($style)"; + os.disabled = false; + # os.symbols.NixOS = "❄️"; # removes the space after logo - # TODO: tune foreground color of username - username.style_user = "bg:${colors._01_purple}"; - username.style_root = "bold bg:${colors._01_purple}"; - username.format = "[$user ]($style)"; + # TODO: tune foreground color of username + username.style_user = "bg:${colors._01_purple}"; + username.style_root = "bold bg:${colors._01_purple}"; + username.format = "[$user ]($style)"; - hostname.style = "bold bg:${colors._01_purple}"; - hostname.format = "[$ssh_symbol$hostname ]($style)"; + hostname.style = "bold bg:${colors._01_purple}"; + hostname.format = "[$ssh_symbol$hostname ]($style)"; - directory.style = "bg:${colors._02_pink} fg:#ffffff"; - directory.format = "[ $path ]($style)"; - directory.truncation_length = 3; - directory.truncation_symbol = "…/"; + directory.style = "bg:${colors._02_pink} fg:#ffffff"; + directory.format = "[ $path ]($style)"; + directory.truncation_length = 3; + directory.truncation_symbol = "…/"; - # git_branch.symbol = ""; # looks good in nerd fonts - git_branch.symbol = ""; - git_branch.style = "bg:${colors._03_orange} fg:#ffffff"; - # git_branch.style = "bg:#FF8262"; - git_branch.format = "[ $symbol $branch ]($style)"; + # git_branch.symbol = ""; # looks good in nerd fonts + git_branch.symbol = ""; + git_branch.style = "bg:${colors._03_orange} fg:#ffffff"; + # git_branch.style = "bg:#FF8262"; + git_branch.format = "[ $symbol $branch ]($style)"; - git_status.style = "bold bg:${colors._03_orange} fg:#ffffff"; - # git_status.style = "bg:#FF8262"; - git_status.format = "[$all_status$ahead_behind ]($style)"; - git_status.ahead = "⇡$count"; - git_status.behind = "⇣$count"; - # git_status.diverged = "⇣$behind_count⇡$ahead_count"; - git_status.diverged = "⇡$ahead_count⇣$behind_count"; - git_status.modified = "*"; - git_status.stashed = ""; - git_status.untracked = ""; + git_status.style = "bold bg:${colors._03_orange} fg:#ffffff"; + # git_status.style = "bg:#FF8262"; + git_status.format = "[$all_status$ahead_behind ]($style)"; + git_status.ahead = "⇡$count"; + git_status.behind = "⇣$count"; + # git_status.diverged = "⇣$behind_count⇡$ahead_count"; + git_status.diverged = "⇡$ahead_count⇣$behind_count"; + git_status.modified = "*"; + git_status.stashed = ""; + git_status.untracked = ""; - time.disabled = true; - time.time_format = "%R"; # Hour:Minute Format - time.style = "bg:${colors._06_blue}"; - time.format = "[ $time ]($style)"; + time.disabled = true; + time.time_format = "%R"; # Hour:Minute Format + time.style = "bg:${colors._06_blue}"; + time.format = "[ $time ]($style)"; - status.disabled = false; - status.style = "bg:${colors._06_blue}"; - # status.success_symbol = "♥ "; - # status.success_symbol = "💖"; - # status.success_symbol = "💙"; - # status.success_symbol = "💚"; - # status.success_symbol = "💜"; - # status.success_symbol = "✔️'"; - status.success_symbol = ""; - status.symbol = "❌"; - # status.symbol = "❗️"; - # status.symbol = "‼️"; - status.format = "[$symbol]($style)"; - }; + status.disabled = false; + status.style = "bg:${colors._06_blue}"; + # status.success_symbol = "♥ "; + # status.success_symbol = "💖"; + # status.success_symbol = "💙"; + # status.success_symbol = "💚"; + # status.success_symbol = "💜"; + # status.success_symbol = "✔️'"; + status.success_symbol = ""; + status.symbol = "❌"; + # status.symbol = "❗️"; + # status.symbol = "‼️"; + status.format = "[$symbol]($style)"; }; }; }