From 8cdebe9fa917f9eee42c7276ea6cb654868818f0 Mon Sep 17 00:00:00 2001 From: Daiderd Jordan Date: Mon, 30 Jan 2017 23:04:29 +0100 Subject: add fzf history keybindings for zsh --- modules/programs/zsh.nix | 183 ----------------------------------- modules/programs/zsh/default.nix | 176 +++++++++++++++++++++++++++++++++ modules/programs/zsh/fzf-history.zsh | 28 ++++++ 3 files changed, 204 insertions(+), 183 deletions(-) delete mode 100644 modules/programs/zsh.nix create mode 100644 modules/programs/zsh/default.nix create mode 100644 modules/programs/zsh/fzf-history.zsh (limited to 'modules/programs') diff --git a/modules/programs/zsh.nix b/modules/programs/zsh.nix deleted file mode 100644 index 7f33bf4..0000000 --- a/modules/programs/zsh.nix +++ /dev/null @@ -1,183 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.programs.zsh; - - zshVariables = - mapAttrsToList (n: v: ''${n}="${v}"'') cfg.variables; - - shell = pkgs.runCommand pkgs.zsh.name - { buildInputs = [ pkgs.makeWrapper ]; } - '' - source $stdenv/setup - - mkdir -p $out/bin - makeWrapper ${pkgs.zsh}/bin/zsh $out/bin/zsh - ''; - -in - -{ - options = { - - programs.zsh.enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to configure zsh as an interactive shell. - ''; - }; - - programs.zsh.variables = mkOption { - type = types.attrsOf (types.either types.str (types.listOf types.str)); - default = {}; - description = '' - A set of environment variables used in the global environment. - These variables will be set on shell initialisation. - The value of each variable can be either a string or a list of - strings. The latter is concatenated, interspersed with colon - characters. - ''; - apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v); - }; - - programs.zsh.shellInit = mkOption { - type = types.lines; - default = ""; - description = '' - Shell script code called during zsh shell initialisation. - ''; - }; - - programs.zsh.loginShellInit = mkOption { - type = types.lines; - default = ""; - description = '' - Shell script code called during zsh login shell initialisation. - ''; - }; - - programs.zsh.interactiveShellInit = mkOption { - type = types.lines; - default = ""; - description = '' - Shell script code called during interactive zsh shell initialisation. - ''; - }; - - programs.zsh.promptInit = mkOption { - type = types.lines; - default = "autoload -U promptinit && promptinit && prompt walters"; - description = '' - Shell script code used to initialise the zsh prompt. - ''; - }; - - programs.zsh.enableCompletion = mkOption { - type = types.bool; - default = true; - description = '' - Enable zsh completion for all interactive zsh shells. - ''; - }; - - programs.zsh.enableBashCompletion = mkOption { - type = types.bool; - default = true; - description = '' - Enable bash completion for all interactive zsh shells. - ''; - }; - - }; - - config = mkIf cfg.enable { - - environment.systemPackages = - [ # Include zsh package - pkgs.zsh - ] ++ optional cfg.enableCompletion pkgs.nix-zsh-completions; - - environment.loginShell = mkDefault "${shell}/bin/zsh -l"; - environment.variables.SHELL = mkDefault "${shell}/bin/zsh"; - - 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. - # But don't clobber the environment of interactive non-login children! - if [ -n "$__ETC_ZSHENV_SOURCED" ]; then return; fi - export __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 - - ${concatStringsSep "\n" zshVariables} - - ${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. - - bindkey -e - - # Only execute this file once per shell. - if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi - __ETC_ZSHRC_SOURCED=1 - - # history defaults - SAVEHIST=2000 - HISTSIZE=2000 - HISTFILE=$HOME/.zsh_history - - setopt HIST_IGNORE_DUPS SHARE_HISTORY HIST_FCNTL_LOCK - - export PATH=${config.environment.systemPath}''${PATH:+:$PATH} - ${config.system.build.setEnvironment} - ${config.system.build.setAliases} - - ${config.environment.extraInit} - ${config.environment.interactiveShellInit} - ${cfg.interactiveShellInit} - ${cfg.promptInit} - - # Tell zsh how to find installed completions - for p in ''${(z)NIX_PROFILES}; do - fpath+=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions) - done - - ${optionalString cfg.enableCompletion "autoload -U compinit && compinit"} - ${optionalString cfg.enableBashCompletion "autoload -U bashcompinit && bashcompinit"} - - # Read system-wide modifications. - if test -f /etc/zshrc.local; then - . /etc/zshrc.local - fi - ''; - - }; -} diff --git a/modules/programs/zsh/default.nix b/modules/programs/zsh/default.nix new file mode 100644 index 0000000..688064b --- /dev/null +++ b/modules/programs/zsh/default.nix @@ -0,0 +1,176 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.zsh; + + zshVariables = + mapAttrsToList (n: v: ''${n}="${v}"'') cfg.variables; + + shell = pkgs.runCommand pkgs.zsh.name + { buildInputs = [ pkgs.makeWrapper ]; } + '' + source $stdenv/setup + + mkdir -p $out/bin + makeWrapper ${pkgs.zsh}/bin/zsh $out/bin/zsh + ''; + +in + +{ + options = { + + programs.zsh.enable = mkOption { + type = types.bool; + default = false; + description = "Whether to configure zsh as an interactive shell."; + }; + + programs.zsh.variables = mkOption { + type = types.attrsOf (types.either types.str (types.listOf types.str)); + default = {}; + description = '' + A set of environment variables used in the global environment. + These variables will be set on shell initialisation. + The value of each variable can be either a string or a list of + strings. The latter is concatenated, interspersed with colon + characters. + ''; + apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v); + }; + + programs.zsh.shellInit = mkOption { + type = types.lines; + default = ""; + description = "Shell script code called during zsh shell initialisation."; + }; + + programs.zsh.loginShellInit = mkOption { + type = types.lines; + default = ""; + description = "Shell script code called during zsh login shell initialisation."; + }; + + programs.zsh.interactiveShellInit = mkOption { + type = types.lines; + default = ""; + description = "Shell script code called during interactive zsh shell initialisation."; + }; + + programs.zsh.promptInit = mkOption { + type = types.lines; + default = "autoload -U promptinit && promptinit && prompt walters"; + description = "Shell script code used to initialise the zsh prompt."; + }; + + programs.zsh.enableCompletion = mkOption { + type = types.bool; + default = true; + description = "Enable zsh completion for all interactive zsh shells."; + }; + + programs.zsh.enableBashCompletion = mkOption { + type = types.bool; + default = true; + description = "Enable bash completion for all interactive zsh shells."; + }; + + programs.zsh.enableFzfHistory = mkOption { + type = types.bool; + default = true; + description = "Enable fzf keybinding for Ctrl-r history search."; + }; + + }; + + config = mkIf cfg.enable { + + environment.systemPackages = + [ # Include zsh package + pkgs.zsh + ] ++ optional cfg.enableCompletion pkgs.nix-zsh-completions; + + environment.loginShell = mkDefault "${shell}/bin/zsh -l"; + environment.variables.SHELL = mkDefault "${shell}/bin/zsh"; + + 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. + # But don't clobber the environment of interactive non-login children! + if [ -n "$__ETC_ZSHENV_SOURCED" ]; then return; fi + export __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 + + ${concatStringsSep "\n" zshVariables} + + ${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. + + bindkey -e + ${optionalString cfg.enableFzfHistory "source ${./fzf-history.zsh}"} + + # Only execute this file once per shell. + if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi + __ETC_ZSHRC_SOURCED=1 + + # history defaults + SAVEHIST=2000 + HISTSIZE=2000 + HISTFILE=$HOME/.zsh_history + + setopt HIST_IGNORE_DUPS SHARE_HISTORY HIST_FCNTL_LOCK + + export PATH=${config.environment.systemPath}''${PATH:+:$PATH} + ${config.system.build.setEnvironment} + ${config.system.build.setAliases} + + ${config.environment.extraInit} + ${config.environment.interactiveShellInit} + ${cfg.interactiveShellInit} + ${cfg.promptInit} + + # Tell zsh how to find installed completions + for p in ''${(z)NIX_PROFILES}; do + fpath+=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions) + done + + ${optionalString cfg.enableCompletion "autoload -U compinit && compinit"} + ${optionalString cfg.enableBashCompletion "autoload -U bashcompinit && bashcompinit"} + + # Read system-wide modifications. + if test -f /etc/zshrc.local; then + . /etc/zshrc.local + fi + ''; + + }; +} diff --git a/modules/programs/zsh/fzf-history.zsh b/modules/programs/zsh/fzf-history.zsh new file mode 100644 index 0000000..ba69095 --- /dev/null +++ b/modules/programs/zsh/fzf-history.zsh @@ -0,0 +1,28 @@ +__fzf_use_tmux__() { + [ -n "$TMUX_PANE" ] && [ "${FZF_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] +} + +__fzfcmd() { + __fzf_use_tmux__ && + echo "fzf-tmux -d${FZF_TMUX_HEIGHT:-40%}" || echo "fzf" +} + +# CTRL-R - Paste the selected command from history into the command line +fzf-history-widget() { + local selected num + setopt localoptions noglobsubst pipefail 2> /dev/null + selected=( $(fc -l 1 | + FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS +s --tac -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS --query=${(q)LBUFFER} +m" $(__fzfcmd)) ) + local ret=$? + if [ -n "$selected" ]; then + num=$selected[1] + if [ -n "$num" ]; then + zle vi-fetch-history -n $num + fi + fi + zle redisplay + typeset -f zle-line-init >/dev/null && zle zle-line-init + return $ret +} +zle -N fzf-history-widget +bindkey '^R' fzf-history-widget -- cgit v1.2.3