#!/usr/bin/env zsh ## Author: druckdev ## Created: 2020-08-28 ## ## A TUI for git-log using fzf. ## Displays git-log in fzf and git-show as preview command for each commit. # extendedglob is necessary for the expansion of the binds array emulate -L zsh -o extendedglob # Return if fzf is not available if ! command -v fzf &>/dev/null; then printf "command not found: fzf" >&2 return 1 fi # Return if not in git repo git rev-parse || return # One line format for fzf list view # abbreviated commit hash (yellow), title and ref names local formatshort='--pretty=format:%C(yellow)%h %Creset%s%C(auto)%d' # Verbose format for the preview window on the right # This array is stitched together with newlines later local -a format=( '--pretty=format:%C(yellow)' # newline created by this eaten by %- '%-Commit: %H%C(auto)' # yellow commit hash ' %D%Cblue' # auto colored ref names (if any) 'Author: %aN %aE%Cred' # blue author mail 'AuthorDate: %ad%Cblue' # red author date 'Commit: %cN %cE%Cred' # blue commiter mail 'CommitDate: %cd%Cblue' # red commit date 'Signer: %GS%Cgreen' # signer name 'Key (%G?): %GK' # pgp key used to sign '%Creset%C(bold)' # empty line ' %s%Creset' # bold white subject '' # newline '%-b' # body '' # newline ) # Ignore the graph part at the beginning, then capture the commit hash and throw # away the rest of the line. local commit_hash='s/^[^a-f0-9]*([a-f0-9]*).*$/\1/' local dateshort='--date=format:%F' # year local date="$dateshort %T %z" # year time timezone local -A fzf_preview read -r -d '' </dev/null; then fzf_preview[patch]+=" | diff-so-fancy --color=always" fi fzf_preview[patch]+=" }" read -r -d '' </dev/null; then fzf_copy_command+=" | pbcopy" elif command -v xclip &>/dev/null; then fzf_copy_command+=" | xclip -selection c" fi local -A binds=( "ctrl-space" "toggle-preview" "ctrl-alt-j" "preview-down" "ctrl-alt-k" "preview-up" # Copy commit hash "ctrl-y" "execute@$fzf_copy_command@" # Open preview "fullscreen" "enter" "execute@$fzf_preview[patch] | command less -R@" # Clear query if not empty, abort otherwise "esc" "cancel" # Preview stats "ctrl-s" "preview($fzf_preview[stat])" # Preview patch "ctrl-d" "preview($fzf_preview[patch])" "ctrl-p" "preview($fzf_preview[patch])" ) local -a fzf_args=( # Understand ansi color escape sequences. "--ansi" # Expand the binds array in the format "key1:value1,key2:value2". "--bind" "${(@kj:,:)binds/(#m)*/$MATCH:$binds[$MATCH]}" # Execute git show on the commit as preview. "--preview" "$fzf_preview[patch]" # Reverse the layout so that the newest commit is at the top. "--reverse" # Do not sort when typing to maintain the sorting by date. "--no-sort" ) # The preview-window should be placed differently depending on the dimensions of # the terminal. # 0.45 seems to be round about the ratio between cols and lines on my system. # With that I get somewhat decent results with. This probably depends on the # font and font-size of the terminal and needs to be changed potentially. local -a tty_size tty_size=(${=$(command stty size 2>/dev/null)}) if (( ! $? )) && (( $tty_size[2] * 0.4 > $tty_size[1] )); then fzf_args+=(--preview-window=right) else fzf_args+=(--preview-window=down) fi # Display an ascii graph of the commits in the above format and pipe that into # fzf. git log --all "$formatshort" --graph "$dateshort" --color=always "$@" \ | fzf "${fzf_args[@]}" return 0