diff --git a/modules/module-list.nix b/modules/module-list.nix index 3a7ede023963..9f1563c0768d 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -53,6 +53,7 @@ ./programs/ssmtp.nix ./programs/venus.nix ./programs/wvdial.nix + ./programs/zsh/zsh.nix ./rename.nix ./security/apparmor.nix ./security/apparmor-suid.nix diff --git a/modules/programs/zsh/zinputrc b/modules/programs/zsh/zinputrc new file mode 100644 index 000000000000..6121f3e21f16 --- /dev/null +++ b/modules/programs/zsh/zinputrc @@ -0,0 +1,42 @@ +# Stolen from ArchWiki + +# create a zkbd compatible hash; +# to add other keys to this hash, see: man 5 terminfo +typeset -A key + +key[Home]=${terminfo[khome]} + +key[End]=${terminfo[kend]} +key[Insert]=${terminfo[kich1]} +key[Delete]=${terminfo[kdch1]} +key[Up]=${terminfo[kcuu1]} +key[Down]=${terminfo[kcud1]} +key[Left]=${terminfo[kcub1]} +key[Right]=${terminfo[kcuf1]} +key[PageUp]=${terminfo[kpp]} +key[PageDown]=${terminfo[knp]} + +# setup key accordingly +[[ -n "${key[Home]}" ]] && bindkey "${key[Home]}" beginning-of-line +[[ -n "${key[End]}" ]] && bindkey "${key[End]}" end-of-line +[[ -n "${key[Insert]}" ]] && bindkey "${key[Insert]}" overwrite-mode +[[ -n "${key[Delete]}" ]] && bindkey "${key[Delete]}" delete-char +[[ -n "${key[Up]}" ]] && bindkey "${key[Up]}" up-line-or-history +[[ -n "${key[Down]}" ]] && bindkey "${key[Down]}" down-line-or-history +[[ -n "${key[Left]}" ]] && bindkey "${key[Left]}" backward-char +[[ -n "${key[Right]}" ]] && bindkey "${key[Right]}" forward-char +[[ -n "${key[PageUp]}" ]] && bindkey "${key[PageUp]}" beginning-of-buffer-or-history +[[ -n "${key[PageDown]}" ]] && bindkey "${key[PageDown]}" end-of-buffer-or-history + +# Finally, make sure the terminal is in application mode, when zle is +# active. Only then are the values from $terminfo valid. +if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then + function zle-line-init () { + printf '%s' "${terminfo[smkx]}" + } + function zle-line-finish () { + printf '%s' "${terminfo[rmkx]}" + } + zle -N zle-line-init + zle -N zle-line-finish +fi diff --git a/modules/programs/zsh/zsh.nix b/modules/programs/zsh/zsh.nix new file mode 100644 index 000000000000..97e7a49e5765 --- /dev/null +++ b/modules/programs/zsh/zsh.nix @@ -0,0 +1,180 @@ +# This module defines global configuration for the zshell. + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfge = config.environment; + + cfg = config.programs.zsh; + + zshAliases = concatStringsSep "\n" ( + mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases + ); + +in + +{ + + options = { + + programs.zsh = { + + enable = mkOption { + default = false; + description = '' + Whenever to configure Zsh as an interactive shell. + Note that this tries to make Zsh the default + , + which in turn means that you might need to explicitly + set this variable if you have another shell configured + with NixOS. + ''; + type = types.bool; + }; + + shellAliases = mkOption { + default = config.environment.shellAliases; + description = '' + Set of aliases for zsh shell. See + for an option format description. + ''; + type = types.attrs; # types.attrsOf types.stringOrPath; + }; + + shellInit = mkOption { + default = ""; + description = '' + Shell script code called during zsh shell initialisation. + ''; + type = types.lines; + }; + + loginShellInit = mkOption { + default = ""; + description = '' + Shell script code called during zsh login shell initialisation. + ''; + type = types.lines; + }; + + interactiveShellInit = mkOption { + default = ""; + description = '' + Shell script code called during interactive zsh shell initialisation. + ''; + type = types.lines; + }; + + promptInit = mkOption { + default = '' + autoload -U promptinit && promptinit && prompt walters + ''; + description = '' + Shell script code used to initialise the zsh prompt. + ''; + type = types.lines; + }; + + }; + + }; + + config = mkIf cfg.enable { + + programs.zsh = { + + shellInit = '' + . /etc/environment + + ${cfge.shellInit} + ''; + + loginShellInit = cfge.loginShellInit; + + interactiveShellInit = '' + ${cfge.interactiveShellInit} + + ${cfg.promptInit} + ${zshAliases} + + # Some sane history defaults + export SAVEHIST=2000 + export HISTSIZE=2000 + export HISTFILE=$HOME/.zsh_history + + setopt HIST_IGNORE_DUPS SHARE_HISTORY + ''; + + }; + + environment.etc."zshenv".text = + '' + # /etc/zshenv: DO NOT EDIT -- this file has been generated automatically. + # This file is read for all shells. + + # Only execute this file once per shell. + if [ -n "$__ETC_ZSHENV_SOURCED" ]; then return; fi + __ETC_ZSHENV_SOURCED=1 + + ${cfg.shellInit} + + # Read system-wide modifications. + if test -f /etc/zshenv.local; then + . /etc/zshenv.local + fi + ''; + + environment.etc."zprofile".text = + '' + # /etc/zprofile: DO NOT EDIT -- this file has been generated automatically. + # This file is read for login shells. + + # Only execute this file once per shell. + if [ -n "$__ETC_ZPROFILE_SOURCED" ]; then return; fi + __ETC_ZPROFILE_SOURCED=1 + + ${cfg.loginShellInit} + + # Read system-wide modifications. + if test -f /etc/zprofile.local; then + . /etc/zprofile.local + fi + ''; + + environment.etc."zshrc".text = + '' + # /etc/zshrc: DO NOT EDIT -- this file has been generated automatically. + # This file is read for interactive shells. + + # Only execute this file once per shell. + if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi + __ETC_ZSHRC_SOURCED=1 + + . /etc/zinputrc + + ${cfg.interactiveShellInit} + + # Read system-wide modifications. + if test -f /etc/zshrc.local; then + . /etc/zshrc.local + fi + ''; + + environment.etc."zinputrc".source = ./zinputrc; + + environment.systemPackages = [ pkgs.zsh ]; + + users.defaultUserShell = mkDefault "/run/current-system/sw/bin/zsh"; + + environment.shells = + [ "/run/current-system/sw/bin/zsh" + "/var/run/current-system/sw/bin/zsh" + "${pkgs.zsh}/bin/zsh" + ]; + + }; + +}