From fe88d487f9bc178c73eb856517a68cb2591d12e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20La=C3=ADn?= Date: Sat, 28 Oct 2023 00:25:25 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20chore(fish):=20plugin=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .config/fish/abbreviations.fish | 1 + .config/fish/conf.d/bin/git-forgit | 995 ++++++++++++++--------------- .config/fish/conf.d/fzf.fish | 2 +- 3 files changed, 485 insertions(+), 513 deletions(-) diff --git a/.config/fish/abbreviations.fish b/.config/fish/abbreviations.fish index 27c52f2a..4f0adb4c 100644 --- a/.config/fish/abbreviations.fish +++ b/.config/fish/abbreviations.fish @@ -4,3 +4,4 @@ abbr -a t --function projectdo_test abbr -a p --function projectdo_tool abbr -a y yadm abbr -a pse pacseek +abbr -a g git diff --git a/.config/fish/conf.d/bin/git-forgit b/.config/fish/conf.d/bin/git-forgit index 4048eb09..0db33a3d 100755 --- a/.config/fish/conf.d/bin/git-forgit +++ b/.config/fish/conf.d/bin/git-forgit @@ -42,27 +42,27 @@ _forgit_warn() { printf "%b[Warn]%b %s\n" '\e[0;33m' '\e[0m' "$@" >&2; } _forgit_info() { printf "%b[Info]%b %s\n" '\e[0;32m' '\e[0m' "$@" >&2; } _forgit_inside_work_tree() { git rev-parse --is-inside-work-tree >/dev/null; } # tac is not available on OSX, tail -r is not available on Linux, so we use either of them -_forgit_reverse_lines() { tac 2>/dev/null || tail -r; } +_forgit_reverse_lines() { tac 2> /dev/null || tail -r; } _forgit_previous_commit() { - # "SHA~" is invalid when the commit is the first commit, but we can use "--root" instead - if [[ "$(git rev-parse "$1")" == "$(git rev-list --max-parents=0 HEAD)" ]]; then - echo "--root" - else - echo "$1~" - fi + # "SHA~" is invalid when the commit is the first commit, but we can use "--root" instead + if [[ "$(git rev-parse "$1")" == "$(git rev-list --max-parents=0 HEAD)" ]]; then + echo "--root" + else + echo "$1~" + fi } _forgit_contains_non_flags() { - while (("$#")); do - case "$1" in - -*) shift ;; - *) - return 0 - ;; - esac - done - return 1 + while (("$#")); do + case "$1" in + -*) shift ;; + *) + return 0 + ;; + esac + done + return 1 } # optional render emoji characters (https://github.com/wfxr/emoji-cli) @@ -86,563 +86,534 @@ _forgit_is_file_tracked="(git ls-files {} --error-unmatch) &> /dev/null" # git commit viewer _forgit_log() { - _forgit_inside_work_tree || return 1 - local opts graph files log_format preview_cmd enter_cmd - files=$(sed -nE 's/.*-- (.*)/\1/p' <<<"$*") # extract files parameters for `git show` command - preview_cmd="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always -U$_forgit_preview_context % -- $files | $_forgit_show_pager" - enter_cmd="echo {} | $_forgit_extract_sha | xargs -I% ${FORGIT} diff %^! $files" -opts=" -$FORGIT_FZF_DEFAULT_OPTS -+s +m --tiebreak=index ---bind=\"enter:execute($enter_cmd)\" ---bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" ---preview=\"$preview_cmd\" -$FORGIT_LOG_FZF_OPTS -" - graph=--graph - [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= - log_format=${FORGIT_GLO_FORMAT:-$_forgit_log_format} - eval "git log $graph --color=always --format='$log_format' $FORGIT_LOG_GIT_OPTS $* $_forgit_emojify" | - FZF_DEFAULT_OPTS="$opts" fzf - fzf_exit_code=$? - # exit successfully on 130 (ctrl-c/esc) - [[ $fzf_exit_code == 130 ]] && return 0 - return $fzf_exit_code + _forgit_inside_work_tree || return 1 + local opts graph files log_format preview_cmd enter_cmd + files=$(sed -nE 's/.*-- (.*)/\1/p' <<< "$*") # extract files parameters for `git show` command + preview_cmd="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always -U$_forgit_preview_context % -- $files | $_forgit_show_pager" + enter_cmd="echo {} | $_forgit_extract_sha | xargs -I% ${FORGIT} diff %^! $files" + opts=" + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index + --bind=\"enter:execute($enter_cmd)\" + --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" + --preview=\"$preview_cmd\" + $FORGIT_LOG_FZF_OPTS + " + graph=--graph + [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= + log_format=${FORGIT_GLO_FORMAT:-$_forgit_log_format} + eval "git log $graph --color=always --format='$log_format' $FORGIT_LOG_GIT_OPTS $* $_forgit_emojify" | + FZF_DEFAULT_OPTS="$opts" fzf + fzf_exit_code=$? + # exit successfully on 130 (ctrl-c/esc) + [[ $fzf_exit_code == 130 ]] && return 0 + return $fzf_exit_code } # git diff viewer _forgit_diff() { - _forgit_inside_work_tree || return 1 - local files opts commits repo get_files preview_cmd enter_cmd - [[ $# -ne 0 ]] && { - if git rev-parse "$1" -- &>/dev/null; then - if [[ $# -gt 1 ]] && git rev-parse "$2" -- &>/dev/null; then - commits="$1 $2" && files=("${@:3}") - else - commits="$1" && files=("${@:2}") - fi - else - files=("$@") - fi - } - repo="$(git rev-parse --show-toplevel)" - # Construct a null-terminated list of the filenames - # The input looks like one of these lines: - # [R100] file -> another file - # [A] file with spaces - # [D] oldfile - # And we transform it to this representation for further usage with "xargs -0": - # file\0another file\0 - # file with spaces\0 - # oldfile\0 - # We have to do a two-step sed -> tr pipe because OSX's sed implementation does - # not support the null-character directly. - get_files="echo {} | sed 's/.*] *//' | sed 's/ -> /\\\n/' | tr '\\\n' '\\\0'" - # Git stashes are named "stash@{x}", which contains the fzf placeholder "{x}". - # In order to support passing stashes as arguments to _forgit_diff, we have to - # prevent fzf from interpreting this substring by escaping the opening bracket. - # The string is evaluated a few subsequent times, so we need multiple escapes. - escaped_commits=${commits//\{/\\\\\{} - git_diff="git diff --color=always $FORGIT_DIFF_GIT_OPTS $escaped_commits" - preview_cmd="cd '$repo' && $get_files | xargs -0 $git_diff -U$_forgit_preview_context -- | $_forgit_diff_pager" - enter_cmd="cd '$repo' && $get_files | xargs -0 $git_diff -U$_forgit_fullscreen_context -- | $_forgit_diff_pager" -opts=" -$FORGIT_FZF_DEFAULT_OPTS -+m -0 --bind=\"enter:execute($enter_cmd | $_forgit_enter_pager)\" ---preview=\"$preview_cmd\" ---bind=\"alt-e:execute-silent($EDITOR \$\($get_files\) >/dev/tty \" -" - eval "git diff --name-status $FORGIT_DIFF_GIT_OPTS $commits -- ${files[*]} | sed -E 's/^([[:alnum:]]+)[[:space:]]+(.*)$/[\1] \2/'" | - sed 's/ / -> /2' | expand -t 8 | - FZF_DEFAULT_OPTS="$opts" fzf - fzf_exit_code=$? - # exit successfully on 130 (ctrl-c/esc) - [[ $fzf_exit_code == 130 ]] && return 0 - return $fzf_exit_code + _forgit_inside_work_tree || return 1 + local files opts commits repo get_files preview_cmd enter_cmd + [[ $# -ne 0 ]] && { + if git rev-parse "$1" -- &>/dev/null ; then + if [[ $# -gt 1 ]] && git rev-parse "$2" -- &>/dev/null; then + commits="$1 $2" && files=("${@:3}") + else + commits="$1" && files=("${@:2}") + fi + else + files=("$@") + fi + } + repo="$(git rev-parse --show-toplevel)" + # Construct a null-terminated list of the filenames + # The input looks like one of these lines: + # [R100] file -> another file + # [A] file with spaces + # [D] oldfile + # And we transform it to this representation for further usage with "xargs -0": + # file\0another file\0 + # file with spaces\0 + # oldfile\0 + # We have to do a two-step sed -> tr pipe because OSX's sed implementation does + # not support the null-character directly. + get_files="echo {} | sed 's/.*] *//' | sed 's/ -> /\\\n/' | tr '\\\n' '\\\0'" + # Similar to the line above, but only gets a single file from a single line + # Gets the new name of renamed files + get_file="echo {} | sed 's/.*] *//' | sed 's/.*-> //'" + # Git stashes are named "stash@{x}", which contains the fzf placeholder "{x}". + # In order to support passing stashes as arguments to _forgit_diff, we have to + # prevent fzf from interpreting this substring by escaping the opening bracket. + # The string is evaluated a few subsequent times, so we need multiple escapes. + escaped_commits=${commits//\{/\\\\\{} + git_diff="git diff --color=always $FORGIT_DIFF_GIT_OPTS $escaped_commits" + preview_cmd="cd '$repo' && $get_files | xargs -0 $git_diff -U$_forgit_preview_context -- | $_forgit_diff_pager" + enter_cmd="cd '$repo' && $get_files | xargs -0 $git_diff -U$_forgit_fullscreen_context -- | $_forgit_diff_pager" + opts=" + $FORGIT_FZF_DEFAULT_OPTS + +m -0 --bind=\"enter:execute($enter_cmd | $_forgit_enter_pager)\" + --preview=\"$preview_cmd\" + --bind=\"alt-e:execute-silent($EDITOR \\\"\$\($get_file)\\\" >/dev/tty \" + " + eval "git diff --name-status $FORGIT_DIFF_GIT_OPTS $commits -- ${files[*]} | sed -E 's/^([[:alnum:]]+)[[:space:]]+(.*)$/[\1] \2/'" | + sed 's/ / -> /2' | expand -t 8 | + FZF_DEFAULT_OPTS="$opts" fzf + fzf_exit_code=$? + # exit successfully on 130 (ctrl-c/esc) + [[ $fzf_exit_code == 130 ]] && return 0 + return $fzf_exit_code } # git add selector _forgit_add() { - _forgit_inside_work_tree || return 1 - local git_add changed unmerged untracked files opts preview extract - git_add="git add $FORGIT_ADD_GIT_OPTS" - # Add files if passed as arguments - [[ $# -ne 0 ]] && { - $git_add "$@" && git status -su - return $? - } + _forgit_inside_work_tree || return 1 + local git_add changed unmerged untracked files opts preview extract + git_add="git add $FORGIT_ADD_GIT_OPTS" + # Add files if passed as arguments + [[ $# -ne 0 ]] && { $git_add "$@" && git status -su; return $?; } - changed=$(git config --get-color color.status.changed red) - unmerged=$(git config --get-color color.status.unmerged red) - untracked=$(git config --get-color color.status.untracked red) - # NOTE: paths listed by 'git status -su' mixed with quoted and unquoted style - # remove indicators | remove original path for rename case | remove surrounding quotes -extract=" -sed 's/^.*] //' | -sed 's/.* -> //' | -sed -e 's/^\\\"//' -e 's/\\\"\$//'" -preview=" -file=\$(echo {} | $extract) -if (git status -s -- \\\"\$file\\\" | grep '^??') &>/dev/null; then # diff with /dev/null for untracked files - git diff --color=always --no-index -- /dev/null \\\"\$file\\\" | $_forgit_diff_pager | sed '2 s/added:/untracked:/' -else - git diff --color=always -- \\\"\$file\\\" | $_forgit_diff_pager - fi" + changed=$(git config --get-color color.status.changed red) + unmerged=$(git config --get-color color.status.unmerged red) + untracked=$(git config --get-color color.status.untracked red) + # NOTE: paths listed by 'git status -su' mixed with quoted and unquoted style + # remove indicators | remove original path for rename case | remove surrounding quotes + extract=" + sed 's/^.*] //' | + sed 's/.* -> //' | + sed -e 's/^\\\"//' -e 's/\\\"\$//'" + preview=" + file=\$(echo {} | $extract) + if (git status -s -- \\\"\$file\\\" | grep '^??') &>/dev/null; then # diff with /dev/null for untracked files + git diff --color=always --no-index -- /dev/null \\\"\$file\\\" | $_forgit_diff_pager | sed '2 s/added:/untracked:/' + else + git diff --color=always -- \\\"\$file\\\" | $_forgit_diff_pager + fi" opts=" - $FORGIT_FZF_DEFAULT_OPTS - -0 -m --nth 2..,.. - --preview=\"$preview\" - --bind=\"alt-e:execute-silent($EDITOR \$\(echo {} | $extract\) >/dev/tty /dev/tty newest when you multiselect - # The instances of "cut", "nl" and "sort" all serve this purpose - # Please see https://github.com/wfxr/forgit/issues/253 for more details + # in this function, we do something interesting to maintain proper ordering as it's assumed + # you generally want to cherry pick oldest->newest when you multiselect + # The instances of "cut", "nl" and "sort" all serve this purpose + # Please see https://github.com/wfxr/forgit/issues/253 for more details - preview="echo {} | cut -f2- | $_forgit_extract_sha | xargs -I% git show --color=always % | $_forgit_show_pager" + preview="echo {} | cut -f2- | $_forgit_extract_sha | xargs -I% git show --color=always % | $_forgit_show_pager" opts=" - $FORGIT_FZF_DEFAULT_OPTS - --preview=\"$preview\" - --multi --ansi --with-nth 2.. -0 --tiebreak=index - $FORGIT_CHERRY_PICK_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + --preview=\"$preview\" + --multi --ansi --with-nth 2.. -0 --tiebreak=index + $FORGIT_CHERRY_PICK_FZF_OPTS " - # Note: do not add any pipe after the fzf call here, otherwise the fzf_exitval is not propagated properly. - # Any eventual post processing can be done afterwards when the "commits" variable is assigned below. - fzf_selection=$(git log --right-only --color=always --cherry-pick --oneline "$base"..."$target" | nl | - FZF_DEFAULT_OPTS="$opts" fzf) - fzf_exitval=$? - [[ $fzf_exitval != 0 ]] && return $fzf_exitval - [[ -z "$fzf_selection" ]] && return $fzf_exitval + # Note: do not add any pipe after the fzf call here, otherwise the fzf_exitval is not propagated properly. + # Any eventual post processing can be done afterwards when the "commits" variable is assigned below. + fzf_selection=$(git log --right-only --color=always --cherry-pick --oneline "$base"..."$target" | nl | + FZF_DEFAULT_OPTS="$opts" fzf) + fzf_exitval=$? + [[ $fzf_exitval != 0 ]] && return $fzf_exitval + [[ -z "$fzf_selection" ]] && return $fzf_exitval - ${IFS+"false"} && unset old_IFS || old_IFS="$IFS" - IFS=$'\n' - # shellcheck disable=2207 - commits=($(echo "$fzf_selection" | sort --numeric-sort --key=1 | cut -f2 | cut -d' ' -f1 | _forgit_reverse_lines)) - ${old_IFS+"false"} && unset IFS || IFS="$old_IFS" - [ ${#commits[@]} -eq 0 ] && return 1 + ${IFS+"false"} && unset old_IFS || old_IFS="$IFS" + IFS=$'\n' + # shellcheck disable=2207 + commits=($(echo "$fzf_selection" | sort --numeric-sort --key=1 | cut -f2 | cut -d' ' -f1 | _forgit_reverse_lines)) + ${old_IFS+"false"} && unset IFS || IFS="$old_IFS" + [ ${#commits[@]} -eq 0 ] && return 1 - $git_cherry_pick "${commits[@]}" + $git_cherry_pick "${commits[@]}" } _forgit_cherry_pick_from_branch() { - _forgit_inside_work_tree || return 1 - local cmd preview opts branch exitval input_branch args base + _forgit_inside_work_tree || return 1 + local cmd preview opts branch exitval input_branch args base - base=$(git branch --show-current) - [[ -z "$base" ]] && echo "Current commit is not on a branch." && return 1 + base=$(git branch --show-current) + [[ -z "$base" ]] && echo "Current commit is not on a branch." && return 1 - args=("$@") - if [[ $# -ne 0 ]]; then - input_branch=${args[0]} - fi - cmd="git branch --color=always --all | LC_ALL=C sort -k1.1,1.1 -rs" - preview="git log --right-only --color=always --cherry-pick --oneline $base...{1}" + args=("$@") + if [[ $# -ne 0 ]]; then + input_branch=${args[0]} + fi + cmd="git branch --color=always --all | LC_ALL=C sort -k1.1,1.1 -rs" + preview="git log --right-only --color=always --cherry-pick --oneline $base...{1}" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s +m --tiebreak=index --header-lines=1 - --preview=\"$preview\" - $FORGIT_CHERRY_PICK_FROM_BRANCH_FZF_OPTS - " - # loop until either the branch selector is closed or a commit to be cherry - # picked has been selected from within a branch - while true; do - if [[ -z $input_branch ]]; then - branch="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')" - else - branch=$input_branch - fi + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index --header-lines=1 + --preview=\"$preview\" + $FORGIT_CHERRY_PICK_FROM_BRANCH_FZF_OPTS + " + # loop until either the branch selector is closed or a commit to be cherry + # picked has been selected from within a branch + while true + do + if [[ -z $input_branch ]]; then + branch="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')" + else + branch=$input_branch + fi - unset input_branch - [[ -z "$branch" ]] && return 1 + unset input_branch + [[ -z "$branch" ]] && return 1 - _forgit_cherry_pick "$branch" + _forgit_cherry_pick "$branch" - exitval=$? - [[ $exitval != 130 ]] || [[ $# -ne 0 ]] && return $exitval - done + exitval=$? + [[ $exitval != 130 ]] || [[ $# -ne 0 ]] && return $exitval + done } _forgit_rebase() { - _forgit_inside_work_tree || return 1 - local git_rebase cmd preview opts graph files target_commit prev_commit - git_rebase="git rebase -i $FORGIT_REBASE_GIT_OPTS" - graph=--graph - [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= - cmd="git log $graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" - files=$(sed -nE 's/.* -- (.*)/\1/p' <<<"$*") # extract files parameters for `git show` command - preview="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" + _forgit_inside_work_tree || return 1 + local git_rebase cmd preview opts graph files target_commit prev_commit + git_rebase="git rebase -i $FORGIT_REBASE_GIT_OPTS" + graph=--graph + [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= + cmd="git log $graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" + files=$(sed -nE 's/.* -- (.*)/\1/p' <<< "$*") # extract files parameters for `git show` command + preview="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s +m --tiebreak=index - --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" - --preview=\"$preview\" - $FORGIT_REBASE_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index + --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" + --preview=\"$preview\" + $FORGIT_REBASE_FZF_OPTS " - target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha") - if [[ -n "$target_commit" ]]; then - prev_commit=$(_forgit_previous_commit "$target_commit") + target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha") + if [[ -n "$target_commit" ]]; then + prev_commit=$(_forgit_previous_commit "$target_commit") - $git_rebase "$prev_commit" - fi + $git_rebase "$prev_commit" + fi } _forgit_fixup() { - _forgit_inside_work_tree || return 1 - git diff --cached --quiet && echo 'Nothing to fixup: there are no staged changes.' && return 1 - local git_fixup cmd preview opts graph files target_commit prev_commit - git_fixup="git commit --fixup $FORGIT_FIXUP_GIT_OPTS" - graph=--graph - [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= - cmd="git log $graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" - files=$(sed -nE 's/.* -- (.*)/\1/p' <<<"$*") - preview="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" + _forgit_inside_work_tree || return 1 + git diff --cached --quiet && echo 'Nothing to fixup: there are no staged changes.' && return 1 + local git_fixup cmd preview opts graph files target_commit prev_commit + git_fixup="git commit --fixup $FORGIT_FIXUP_GIT_OPTS" + graph=--graph + [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= + cmd="git log $graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" + files=$(sed -nE 's/.* -- (.*)/\1/p' <<< "$*") + preview="echo {} | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s +m --tiebreak=index - --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" - --preview=\"$preview\" - $FORGIT_FIXUP_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index + --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" + --preview=\"$preview\" + $FORGIT_FIXUP_FZF_OPTS " - target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha") - if [[ -n "$target_commit" ]] && $git_fixup "$target_commit"; then - prev_commit=$(_forgit_previous_commit "$target_commit") - # rebase will fail if there are unstaged changes so --autostash is needed to temporarily stash them - # GIT_SEQUENCE_EDITOR=: is needed to skip the editor - GIT_SEQUENCE_EDITOR=: git rebase --autostash -i --autosquash "$prev_commit" - fi + target_commit=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha") + if [[ -n "$target_commit" ]] && $git_fixup "$target_commit"; then + prev_commit=$(_forgit_previous_commit "$target_commit") + # rebase will fail if there are unstaged changes so --autostash is needed to temporarily stash them + # GIT_SEQUENCE_EDITOR=: is needed to skip the editor + GIT_SEQUENCE_EDITOR=: git rebase --autostash -i --autosquash "$prev_commit" + fi } # git checkout-file selector _forgit_checkout_file() { - _forgit_inside_work_tree || return 1 - local git_checkout cmd files opts - git_checkout="git checkout $FORGIT_CHECKOUT_FILE_GIT_OPTS" - [[ $# -ne 0 ]] && { - $git_checkout -- "$@" - return $? - } - cmd="git diff --color=always -- {} | $_forgit_diff_pager" + _forgit_inside_work_tree || return 1 + local git_checkout cmd files opts + git_checkout="git checkout $FORGIT_CHECKOUT_FILE_GIT_OPTS" + [[ $# -ne 0 ]] && { $git_checkout -- "$@"; return $?; } + cmd="git diff --color=always -- {} | $_forgit_diff_pager" opts=" - $FORGIT_FZF_DEFAULT_OPTS - -m -0 - --preview=\"$cmd\" - $FORGIT_CHECKOUT_FILE_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + -m -0 + --preview=\"$cmd\" + $FORGIT_CHECKOUT_FILE_FZF_OPTS " - files="$(git ls-files --modified "$(git rev-parse --show-toplevel)" | FZF_DEFAULT_OPTS="$opts" fzf)" - [[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | $git_checkout --pathspec-file-nul --pathspec-from-file - + files="$(git ls-files --modified "$(git rev-parse --show-toplevel)"| FZF_DEFAULT_OPTS="$opts" fzf)" + [[ -n "$files" ]] && echo "$files" | tr '\n' '\0' | $git_checkout --pathspec-file-nul --pathspec-from-file - } # git checkout-branch selector _forgit_checkout_branch() { - _forgit_inside_work_tree || return 1 - # if called with arguments, check if branch exists, else create a new one - if [[ $# -ne 0 ]]; then - if [[ "$*" == "-" ]] || git show-branch "$@" &>/dev/null; then - git switch "$@" - else - git switch -c "$@" - fi - checkout_status=$? - git status --short - return $checkout_status - fi + _forgit_inside_work_tree || return 1 + # if called with arguments, check if branch exists, else create a new one + if [[ $# -ne 0 ]]; then + if [[ "$*" == "-" ]] || git show-branch "$@" &>/dev/null; then + git switch "$@" + else + git switch -c "$@" + fi + checkout_status=$? + git status --short + return $checkout_status + fi - local git_checkout cmd preview opts branch - cmd="git branch --color=always ${FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS:---all} | LC_ALL=C sort -k1.1,1.1 -rs" - preview="git log {1} $_forgit_log_preview_options" + local git_checkout cmd preview opts branch + cmd="git branch --color=always ${FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS:---all} | LC_ALL=C sort -k1.1,1.1 -rs" + preview="git log {1} $_forgit_log_preview_options" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s +m --tiebreak=index --header-lines=1 - --preview=\"$preview\" - $FORGIT_CHECKOUT_BRANCH_FZF_OPTS - " - branch="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')" - [[ -z "$branch" ]] && return 1 + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index --header-lines=1 + --preview=\"$preview\" + $FORGIT_CHECKOUT_BRANCH_FZF_OPTS + " + branch="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}')" + [[ -z "$branch" ]] && return 1 - git_checkout="git checkout $FORGIT_CHECKOUT_BRANCH_GIT_OPTS" - # track the remote branch if possible - if [[ "$branch" == "remotes/origin/"* ]]; then - if git branch | grep -qw "${branch#remotes/origin/}"; then - # hack to force creating a new branch which tracks the remote if a local branch already exists - $git_checkout -b "track/${branch#remotes/origin/}" --track "$branch" - elif ! $git_checkout --track "$branch" 2>/dev/null; then - $git_checkout "$branch" - fi - else - $git_checkout "$branch" - fi + git_checkout="git checkout $FORGIT_CHECKOUT_BRANCH_GIT_OPTS" + # track the remote branch if possible + if [[ "$branch" == "remotes/origin/"* ]]; then + if git branch | grep -qw "${branch#remotes/origin/}"; then + # hack to force creating a new branch which tracks the remote if a local branch already exists + $git_checkout -b "track/${branch#remotes/origin/}" --track "$branch" + elif ! $git_checkout --track "$branch" 2>/dev/null; then + $git_checkout "$branch" + fi + else + $git_checkout "$branch" + fi } # git checkout-tag selector _forgit_checkout_tag() { - _forgit_inside_work_tree || return 1 - local git_checkout cmd opts preview - git_checkout="git checkout $FORGIT_CHECKOUT_TAG_GIT_OPTS" - [[ $# -ne 0 ]] && { - $git_checkout "$@" - return $? - } - cmd="git tag -l --sort=-v:refname" - preview="git log {1} $_forgit_log_preview_options" + _forgit_inside_work_tree || return 1 + local git_checkout cmd opts preview + git_checkout="git checkout $FORGIT_CHECKOUT_TAG_GIT_OPTS" + [[ $# -ne 0 ]] && { $git_checkout "$@"; return $?; } + cmd="git tag -l --sort=-v:refname" + preview="git log {1} $_forgit_log_preview_options" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s +m --tiebreak=index - --preview=\"$preview\" - $FORGIT_CHECKOUT_TAG_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index + --preview=\"$preview\" + $FORGIT_CHECKOUT_TAG_FZF_OPTS " - tag="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf)" - [[ -z "$tag" ]] && return 1 - $git_checkout "$tag" + tag="$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf)" + [[ -z "$tag" ]] && return 1 + $git_checkout "$tag" } # git checkout-commit selector _forgit_checkout_commit() { - _forgit_inside_work_tree || return 1 - local git_checkout cmd opts graph - git_checkout="git checkout $FORGIT_CHECKOUT_COMMIT_GIT_OPTS" - [[ $# -ne 0 ]] && { - $git_checkout "$@" - return $? - } - cmd="echo {} | $_forgit_extract_sha |xargs -I% git show --color=always % | $_forgit_show_pager" + _forgit_inside_work_tree || return 1 + local git_checkout cmd opts graph + git_checkout="git checkout $FORGIT_CHECKOUT_COMMIT_GIT_OPTS" + [[ $# -ne 0 ]] && { $git_checkout "$@"; return $?; } + cmd="echo {} | $_forgit_extract_sha |xargs -I% git show --color=always % | $_forgit_show_pager" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s +m --tiebreak=index - --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" - --preview=\"$cmd\" - $FORGIT_CHECKOUT_COMMIT_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + +s +m --tiebreak=index + --bind=\"ctrl-y:execute-silent(echo {} | $_forgit_extract_sha | ${FORGIT_COPY_CMD:-pbcopy})\" + --preview=\"$cmd\" + $FORGIT_CHECKOUT_COMMIT_FZF_OPTS " - graph=--graph - [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= - # shellcheck disable=2086 - eval "git log $graph --color=always --format='$_forgit_log_format' $_forgit_emojify" | - FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha" | xargs -I% $git_checkout % -- + graph=--graph + [[ $FORGIT_LOG_GRAPH_ENABLE == false ]] && graph= + # shellcheck disable=2086 + eval "git log $graph --color=always --format='$_forgit_log_format' $_forgit_emojify" | + FZF_DEFAULT_OPTS="$opts" fzf | eval "$_forgit_extract_sha" | xargs -I% $git_checkout % -- } _forgit_branch_delete() { - _forgit_inside_work_tree || return 1 - local git_branch preview opts cmd branches - git_branch="git branch $FORGIT_BRANCH_DELETE_GIT_OPTS" - [[ $# -ne 0 ]] && { - $git_branch -D "$@" - return $? - } - preview="git log {1} $_forgit_log_preview_options" + _forgit_inside_work_tree || return 1 + local git_branch preview opts cmd branches + git_branch="git branch $FORGIT_BRANCH_DELETE_GIT_OPTS" + [[ $# -ne 0 ]] && { $git_branch -D "$@"; return $?; } + preview="git log {1} $_forgit_log_preview_options" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s --multi --tiebreak=index --header-lines=1 - --preview=\"$preview\" - $FORGIT_BRANCH_DELETE_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + +s --multi --tiebreak=index --header-lines=1 + --preview=\"$preview\" + $FORGIT_BRANCH_DELETE_FZF_OPTS " - cmd="git branch --color=always | LC_ALL=C sort -k1.1,1.1 -rs" - branches=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}') - # shellcheck disable=2086 - echo -n "$branches" | tr '\n' '\0' | xargs -I{} -0 $git_branch -D {} + cmd="git branch --color=always | LC_ALL=C sort -k1.1,1.1 -rs" + branches=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $1}') + # shellcheck disable=2086 + echo -n "$branches" | tr '\n' '\0' | xargs -I{} -0 $git_branch -D {} } # git revert-commit selector _forgit_revert_commit() { - _forgit_inside_work_tree || return 1 - local git_revert cmd opts files preview commits IFS - git_revert="git revert $FORGIT_REVERT_COMMIT_GIT_OPTS" - [[ $# -ne 0 ]] && { - $git_revert "$@" - return $? - } + _forgit_inside_work_tree || return 1 + local git_revert cmd opts files preview commits IFS + git_revert="git revert $FORGIT_REVERT_COMMIT_GIT_OPTS" + [[ $# -ne 0 ]] && { $git_revert "$@"; return $?; } - cmd="git log --graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" + cmd="git log --graph --color=always --format='$_forgit_log_format' $* $_forgit_emojify" opts=" - $FORGIT_FZF_DEFAULT_OPTS - +s --tiebreak=index - --ansi --with-nth 2.. - $FORGIT_REVERT_COMMIT_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + +s --tiebreak=index + --ansi --with-nth 2.. + $FORGIT_REVERT_COMMIT_FZF_OPTS " - # in this function, we do something interesting to maintain proper ordering as it's assumed - # you generally want to revert newest->oldest when you multiselect - # The instances of "cut", "nl" and "sort" all serve this purpose - # Please see https://github.com/wfxr/forgit/issues/253 for more details + # in this function, we do something interesting to maintain proper ordering as it's assumed + # you generally want to revert newest->oldest when you multiselect + # The instances of "cut", "nl" and "sort" all serve this purpose + # Please see https://github.com/wfxr/forgit/issues/253 for more details - files=$(sed -nE 's/.* -- (.*)/\1/p' <<<"$*") # extract files parameters for `git show` command - preview="echo {} | cut -f2- | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" + files=$(sed -nE 's/.* -- (.*)/\1/p' <<< "$*") # extract files parameters for `git show` command + preview="echo {} | cut -f2- | $_forgit_extract_sha | xargs -I% git show --color=always % -- $files | $_forgit_show_pager" - ${IFS+"false"} && unset old_IFS || old_IFS="$IFS" - IFS=$'\n' - # shellcheck disable=2207 - commits=($(eval "$cmd" | - nl | - FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview" -m | - sort --numeric-sort --key=1 | - cut -f2- | - sed 's/^[^a-f^0-9]*\([a-f0-9]*\).*/\1/')) - ${old_IFS+"false"} && unset IFS || IFS="$old_IFS" + ${IFS+"false"} && unset old_IFS || old_IFS="$IFS" + IFS=$'\n' + # shellcheck disable=2207 + commits=($(eval "$cmd" | + nl | + FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview" -m | + sort --numeric-sort --key=1 | + cut -f2- | + sed 's/^[^a-f^0-9]*\([a-f0-9]*\).*/\1/')) + ${old_IFS+"false"} && unset IFS || IFS="$old_IFS" - [ ${#commits[@]} -eq 0 ] && return 1 + [ ${#commits[@]} -eq 0 ] && return 1 - $git_revert "${commits[@]}" + $git_revert "${commits[@]}" } # git blame viewer _forgit_blame() { - _forgit_inside_work_tree || return 1 - local git_blame opts flags preview file - git_blame="git blame $FORGIT_BLAME_GIT_OPTS" - _forgit_contains_non_flags "$@" && { - $git_blame "$@" - return $? - } + _forgit_inside_work_tree || return 1 + local git_blame opts flags preview file + git_blame="git blame $FORGIT_BLAME_GIT_OPTS" + _forgit_contains_non_flags "$@" && { $git_blame "$@"; return $?; } opts=" - $FORGIT_FZF_DEFAULT_OPTS - $FORGIT_BLAME_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + $FORGIT_BLAME_FZF_OPTS " - flags=$(git rev-parse --flags "$@") + flags=$(git rev-parse --flags "$@") preview=" - if $_forgit_is_file_tracked; then - git blame {} --date=short $FORGIT_BLAME_GIT_OPTS $flags | $_forgit_blame_pager - else - echo File not tracked - fi + if $_forgit_is_file_tracked; then + git blame {} --date=short $FORGIT_BLAME_GIT_OPTS $flags | $_forgit_blame_pager + else + echo File not tracked + fi " - file=$(FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview") - [[ -z "$file" ]] && return 1 - # shellcheck disable=2086 - eval $git_blame "$file" "$flags" + file=$(FZF_DEFAULT_OPTS="$opts" fzf --preview="$preview") + [[ -z "$file" ]] && return 1 + # shellcheck disable=2086 + eval $git_blame "$file" "$flags" } # git ignore generator @@ -651,72 +622,72 @@ export FORGIT_GI_REPO_LOCAL="${FORGIT_GI_REPO_LOCAL:-${XDG_CACHE_HOME:-$HOME/.ca export FORGIT_GI_TEMPLATES=${FORGIT_GI_TEMPLATES:-$FORGIT_GI_REPO_LOCAL/templates} _forgit_ignore() { - [ -d "$FORGIT_GI_REPO_LOCAL" ] || _forgit_ignore_update - local IFS cmd args opts - cmd="$_forgit_ignore_pager $FORGIT_GI_TEMPLATES/{2}{,.gitignore} 2>/dev/null" + [ -d "$FORGIT_GI_REPO_LOCAL" ] || _forgit_ignore_update + local IFS cmd args opts + cmd="$_forgit_ignore_pager $FORGIT_GI_TEMPLATES/{2}{,.gitignore} 2>/dev/null" opts=" - $FORGIT_FZF_DEFAULT_OPTS - -m --preview-window='right:70%' - --preview=\"eval $cmd\" - $FORGIT_IGNORE_FZF_OPTS + $FORGIT_FZF_DEFAULT_OPTS + -m --preview-window='right:70%' + --preview=\"eval $cmd\" + $FORGIT_IGNORE_FZF_OPTS " - ${IFS+"false"} && unset old_IFS || old_IFS="$IFS" - IFS=$'\n' - # shellcheck disable=SC2206,2207 - args=($@) && [[ $# -eq 0 ]] && args=($(_forgit_ignore_list | nl -nrn -w4 -s' ' | - FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $2}')) - ${old_IFS+"false"} && unset IFS || IFS="$old_IFS" - [ ${#args[@]} -eq 0 ] && return 1 - # shellcheck disable=SC2068 - _forgit_ignore_get ${args[@]} + ${IFS+"false"} && unset old_IFS || old_IFS="$IFS" + IFS=$'\n' + # shellcheck disable=SC2206,2207 + args=($@) && [[ $# -eq 0 ]] && args=($(_forgit_ignore_list | nl -nrn -w4 -s' ' | + FZF_DEFAULT_OPTS="$opts" fzf | awk '{print $2}')) + ${old_IFS+"false"} && unset IFS || IFS="$old_IFS" + [ ${#args[@]} -eq 0 ] && return 1 + # shellcheck disable=SC2068 + _forgit_ignore_get ${args[@]} } _forgit_ignore_update() { - if [[ -d "$FORGIT_GI_REPO_LOCAL" ]]; then - _forgit_info 'Updating gitignore repo...' - (cd "$FORGIT_GI_REPO_LOCAL" && git pull --no-rebase --ff) || return 1 - else - _forgit_info 'Initializing gitignore repo...' - git clone --depth=1 "$FORGIT_GI_REPO_REMOTE" "$FORGIT_GI_REPO_LOCAL" - fi + if [[ -d "$FORGIT_GI_REPO_LOCAL" ]]; then + _forgit_info 'Updating gitignore repo...' + (cd "$FORGIT_GI_REPO_LOCAL" && git pull --no-rebase --ff) || return 1 + else + _forgit_info 'Initializing gitignore repo...' + git clone --depth=1 "$FORGIT_GI_REPO_REMOTE" "$FORGIT_GI_REPO_LOCAL" + fi } _forgit_ignore_get() { - local item filename header - for item in "$@"; do - if filename=$(find -L "$FORGIT_GI_TEMPLATES" -type f \( -iname "${item}.gitignore" -o -iname "${item}" \) -print -quit); then - [[ -z "$filename" ]] && _forgit_warn "No gitignore template found for '$item'." && continue - header="${filename##*/}" && header="${header%.gitignore}" - echo "### $header" && cat "$filename" && echo - fi - done + local item filename header + for item in "$@"; do + if filename=$(find -L "$FORGIT_GI_TEMPLATES" -type f \( -iname "${item}.gitignore" -o -iname "${item}" \) -print -quit); then + [[ -z "$filename" ]] && _forgit_warn "No gitignore template found for '$item'." && continue + header="${filename##*/}" && header="${header%.gitignore}" + echo "### $header" && cat "$filename" && echo + fi + done } _forgit_ignore_list() { - find "$FORGIT_GI_TEMPLATES" -print | sed -e 's#.gitignore$##' -e 's#.*/##' | sort -fu + find "$FORGIT_GI_TEMPLATES" -print |sed -e 's#.gitignore$##' -e 's#.*/##' | sort -fu } _forgit_ignore_clean() { - setopt localoptions rmstarsilent - [[ -d "$FORGIT_GI_REPO_LOCAL" ]] && rm -rf "$FORGIT_GI_REPO_LOCAL" + setopt localoptions rmstarsilent + [[ -d "$FORGIT_GI_REPO_LOCAL" ]] && rm -rf "$FORGIT_GI_REPO_LOCAL" } valid_commands=( - "add" - "blame" - "branch_delete" - "checkout_branch" - "checkout_commit" - "checkout_file" - "checkout_tag" - "cherry_pick" - "cherry_pick_from_branch" - "clean" - "diff" - "fixup" - "ignore" - "log" - "rebase" - "reset_head" - "revert_commit" - "stash_show" - "stash_push" + "add" + "blame" + "branch_delete" + "checkout_branch" + "checkout_commit" + "checkout_file" + "checkout_tag" + "cherry_pick" + "cherry_pick_from_branch" + "clean" + "diff" + "fixup" + "ignore" + "log" + "rebase" + "reset_head" + "revert_commit" + "stash_show" + "stash_push" ) cmd="$1" @@ -724,14 +695,14 @@ shift # shellcheck disable=SC2076 if [[ ! " ${valid_commands[*]} " =~ " ${cmd} " ]]; then - if [[ -z "$cmd" ]]; then - printf "forgit: missing command\n\n" - else - printf "forgit: '%s' is not a valid forgit command.\n\n" "$cmd" - fi - printf "The following commands are supported:\n" - printf "\t%s\n" "${valid_commands[@]}" - exit 1 + if [[ -z "$cmd" ]]; then + printf "forgit: missing command\n\n" + else + printf "forgit: '%s' is not a valid forgit command.\n\n" "$cmd" + fi + printf "The following commands are supported:\n" + printf "\t%s\n" "${valid_commands[@]}" + exit 1 fi _forgit_"${cmd}" "$@" diff --git a/.config/fish/conf.d/fzf.fish b/.config/fish/conf.d/fzf.fish index f899dd53..8156c11b 100644 --- a/.config/fish/conf.d/fzf.fish +++ b/.config/fish/conf.d/fzf.fish @@ -3,7 +3,7 @@ if not status is-interactive && test "$CI" != true exit end -# Because of scoping rules, to capture the shell variables ezactly as they are, we must read +# Because of scoping rules, to capture the shell variables exactly as they are, we must read # them before even executing _fzf_search_variables. We use psub to store the # variables' info in temporary files and pass in the filenames as arguments. # This variable is global so that it can be referenced by fzf_configure_bindings and in tests