Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vim-open (Enter), checkout/switch to commit/branch (C-C), toogle preview (C-P) #60

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 11 additions & 86 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,25 @@
fzf-git.sh
==========

bash and zsh key bindings for Git objects, powered by [fzf][fzf].
**FORK** of [junegunn/fzf-git.sh](https://github.com/junegunn/fzf-git.sh)

<img width="1680" alt="image" src="https://user-images.githubusercontent.com/700826/185568470-20d70937-eea4-4274-aec5-14dfe7ee2de6.png">

Each binding will allow you to browse through Git objects of a certain type,
and select the objects you want to paste to your command-line.

[fzf]: https://github.com/junegunn/fzf

Installation
------------

1. Install the latest version of [fzf][fzf]
* (Optional) Install [bat](https://github.com/sharkdp/bat) for
syntax-highlighted file previews
1. Source [fzf-git.sh](https://raw.githubusercontent.com/junegunn/fzf-git.sh/main/fzf-git.sh) file from your .bashrc or .zshrc

Usage
-----

### List of bindings

* <kbd>CTRL-G</kbd><kbd>CTRL-F</kbd> for **F**iles
* <kbd>CTRL-G</kbd><kbd>CTRL-B</kbd> for **B**ranches
* <kbd>CTRL-G</kbd><kbd>CTRL-T</kbd> for **T**ags
* <kbd>CTRL-G</kbd><kbd>CTRL-R</kbd> for **R**emotes
* <kbd>CTRL-G</kbd><kbd>CTRL-H</kbd> for commit **H**ashes
* <kbd>CTRL-G</kbd><kbd>CTRL-S</kbd> for **S**tashes
* <kbd>CTRL-G</kbd><kbd>CTRL-L</kbd> for ref**l**ogs
* <kbd>CTRL-G</kbd><kbd>CTRL-W</kbd> for **W**orktrees
* <kbd>CTRL-G</kbd><kbd>CTRL-E</kbd> for **E**ach ref (`git for-each-ref`)

> [!WARNING]
> You may have issues with these bindings in the following cases:
>
> * <kbd>CTRL-G</kbd><kbd>CTRL-B</kbd> will not work if
> <kbd>CTRL-B</kbd> is used as the tmux prefix
> * <kbd>CTRL-G</kbd><kbd>CTRL-S</kbd> will not work if flow control is enabled,
> <kbd>CTRL-S</kbd> will freeze the terminal instead
> * (`stty -ixon` will disable it)
>
> To workaround the problems, you can use
> <kbd>CTRL-G</kbd><kbd>*{key}*</kbd> instead of
> <kbd>CTRL-G</kbd><kbd>CTRL-*{KEY}*</kbd>.
>

> [!WARNING]
> If zsh's `KEYTIMEOUT` is too small (e.g. 1), you may not be able
> to hit two keys in time.

### Inside fzf

* <kbd>TAB</kbd> or <kbd>SHIFT-TAB</kbd> to select multiple objects
* <kbd>CTRL-/</kbd> to change preview window layout
* <kbd>CTRL-O</kbd> to open the object in the web browser (in GitHub URL scheme)

Customization
-------------

```sh
# Redefine this function to change the options
_fzf_git_fzf() {
fzf --height=50% --tmux 90%,70% \
--layout=reverse --multi --min-height=20 --border \
--border-label-pos=2 \
--color='header:italic:underline,label:blue' \
--preview-window='right,50%,border-left' \
--bind='ctrl-/:change-preview-window(down,50%,border-top|hidden|)' "$@"
}
FZF_GIT_SCRIPT=~/fzf-git.sh/fzf-git.sh
[ ! -f "$FZF_GIT_SCRIPT" ] && \
cd $HOME && git clone https://github.com/juanMarinero/fzf-git.sh
source "$FZF_GIT_SCRIPT"
```

Defining shortcut commands
--------------------------

Each binding is backed by `_fzf_git_*` function so you can do something like
this in your shell configuration file.

```sh
gco() {
_fzf_git_each_ref --no-multi | xargs git checkout
}
Purpose
------------

gswt() {
cd "$(_fzf_git_worktrees --no-multi)"
}
```
Integrate **Vim** navigation alike [vimcast-34](http://vimcasts.org/episodes/fugitive-vim-browsing-the-git-object-database/) and [vimcast-35](http://vimcasts.org/episodes/fugitive-vim-exploring-the-history-of-a-git-repository/).

Environment Variables
---------------------
License
------------

| Variable | Description | Default |
| ----------------------- | -------------------------------------------------------- | ----------------------------------------------- |
| `BAT_STYLE` | Specifies the style for displaying files using `bat` | `full` |
| `FZF_GIT_CAT` | Defines the preview command used for displaying the file | `bat --style=$BAT_STYLE --color=$FZF_GIT_COLOR` |
| `FZF_GIT_COLOR` | Set to `never` to suppress colors in the list | `always` |
| `FZF_GIT_PAGER` | Specifies the pager command for the preview window | `$(git config --get core.pager)` |
| `FZF_GIT_PREVIEW_COLOR` | Set to `never` to suppress colors in the preview window | `always` |
MIT License (MIT)
103 changes: 99 additions & 4 deletions fzf-git.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,23 @@ if [[ $1 = --list ]]; then
}
case "$1" in
branches)
echo $'CTRL-O (open in browser) ╱ ALT-A (show all branches)\n'
echo $'CTRL-O (open in browser) ╱ ALT-A (show all branches)'
echo $'Enter (examine in Vim) / CTRL-C (checkout-switch)\n'
branches
;;
all-branches)
echo $'CTRL-O (open in browser)\n'
echo $'CTRL-O (open in browser)'
echo $'Enter (examine in Vim) / CTRL-C (checkout-switch)\n'
branches -a
;;
hashes)
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort) ╱ ALT-A (show all hashes)\n'
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort) ╱ ALT-A (show all hashes)'
echo $'Enter (examine in Vim) / CTRL-C (checkout) / CTRL-P (toogle preview)\n'
hashes
;;
all-hashes)
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort)\n'
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort)'
echo $'Enter (examine in Vim) / CTRL-C (checkout) / CTRL-P (toogle preview)\n'
hashes --all
;;
refs)
Expand Down Expand Up @@ -197,6 +201,8 @@ _fzf_git_branches() {
--bind 'ctrl-/:change-preview-window(down,70%|hidden|)' \
--bind "ctrl-o:execute-silent:bash \"$__fzf_git\" --list branch {}" \
--bind "alt-a:change-border-label(🌳 All branches)+reload:bash \"$__fzf_git\" --list all-branches" \
--bind "enter:execute:sed 's/^..//' <<< {} | cut -d' ' -f1 | xargs -I % sh -c 'vim -c \":Gedit %\" < /dev/tty'" \
--bind "ctrl-c:become:(echo {} | sed 's/^..//' | cut -d' ' -f1 | xargs git switch > /dev/tty)" \
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' \$(sed s/^..// <<< {} | cut -d' ' -f1) --" "$@" |
sed 's/^..//' | cut -d' ' -f1
}
Expand All @@ -212,14 +218,31 @@ _fzf_git_tags() {
}

_fzf_git_hashes() {

# ctrl-y and ctrl-z below not working
# aim is to update terminal prompt if checkouted to a commit
# without need to run any cmd in terminal (like date)
_fzf_git_checkout_commit() {
local commit_hash="$1" # Directly use the parameter passed to the function
git checkout "$commit_hash"
}
# workaround are sequence-widgets that overwrite this function call (bottom of file)

_fzf_git_check || return
bash "$__fzf_git" --list hashes |
_fzf_git_fzf --ansi --no-sort --bind 'ctrl-s:toggle-sort' \
--preview 'f() { set -- $(echo -- "$@" | grep -o "[a-f0-9]\{7\}"); [ $# -eq 0 ] || git show --color=always $1 ; }; f {}' \
--bind=ctrl-p:toggle-preview \
--border-label '🍡 Hashes' \
--header-lines 3 \
--preview-window right,border-left,50% \
--bind "ctrl-o:execute-silent:bash \"$__fzf_git\" --list commit {}" \
--bind "ctrl-c:become:(echo {} | grep -o '[a-f0-9]\{7\}' | head -1 | xargs git checkout > /dev/tty)" \
--bind "ctrl-y:execute:grep -o '[a-f0-9]\{7\}' <<< {} | head -n 1 | xargs _fzf_git_checkout_commit " \
--bind "ctrl-z:execute:(echo {} | grep -o '[a-f0-9]\{7\}' | head -1 | xargs -I % _fzf_git_checkout_commit %)" \
--bind "ctrl-d:execute:grep -o '[a-f0-9]\{7,\}' <<< {} | head -n 1 | xargs git diff --color=$(__fzf_git_color) > /dev/tty" \
--bind "alt-a:change-border-label(🍇 All hashes)+reload:bash \"$__fzf_git\" --list all-hashes" \
--bind "enter:execute:grep -o '[a-f0-9]\{7\}' <<< {} | head -n 1 | xargs -I % sh -c 'vim -c \":Gedit %\" < /dev/tty'" \
--color hl:underline,hl+:underline \
--preview "grep -o '[a-f0-9]\{7,\}' <<< {} | head -n 1 | xargs git show --color=$(__fzf_git_color .) | $(__fzf_git_pager)" "$@" |
awk 'match($0, /[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]*/) { print substr($0, RSTART, RLENGTH) }'
Expand Down Expand Up @@ -324,8 +347,80 @@ elif [[ -n "${ZSH_VERSION:-}" ]]; then
done
done
}

# --- Commit chekout ---
# To update terminal prompt if checkouted to a commit
# without need to run any cmd in terminal (like date)
# -- Workaround START --
# Define the widget to display the current commit-hash
zle -N git_echo_commit_hash_widget
git_echo_commit_hash_widget() {
echo -e "New commit hash is \e[30;44m $(git rev-parse HEAD) \e[0m"
}
# Create a ZLE widget to call _fzf_git_hashes
zle -N fzf_git_hashes_custome_widget
fzf_git_hashes_custome_widget() {
_fzf_git_hashes
}
# Define a new widget that chains the two widgets together
zle -N chain_fzf_git_hashes_custome_widgets
chain_fzf_git_hashes_custome_widgets() {
fzf_git_hashes_custome_widget
git_echo_commit_hash_widget
}
# Bind Ctrl+G
bindkey '^G' chain_fzf_git_hashes_custome_widgets
# Bind Ctrl+G Ctrl+H
__fzf_git_init_chain_fzf_git_hashes_custome_widgets() {
local m
for m in emacs vicmd viins; do
eval "bindkey -M $m '^g^h' chain_fzf_git_hashes_custome_widgets"
eval "bindkey -M $m '^gh' chain_fzf_git_hashes_custome_widgets"
done
}
# Initialize the binding: see EOF
# -- Workaround END --

# --- Branch chekout-switch ---
# To update terminal prompt if switched to a branch
# without need to run any cmd in terminal (like date)
# -- Workaround START --
# Define the widget to display the current branch
zle -N git_echo_commit_hash_widget
git_echo_branch_widget() {
echo -e "New branch is \e[30;44m $(git branch --show-current) \e[0m"
}
# Create a ZLE widget to call _fzf_git_branches
zle -N fzf_git_branches_custome_widget
fzf_git_branches_custome_widget() {
_fzf_git_branches
}
# Define a new widget that chains the two widgets together
zle -N chain_fzf_git_branches_custome_widgets
chain_fzf_git_branches_custome_widgets() {
fzf_git_branches_custome_widget
git_echo_branch_widget
}
# Bind Ctrl+B
bindkey '^B' chain_fzf_git_branches_custome_widgets
# Bind Ctrl+G Ctrl+B
__fzf_git_init_chain_fzf_git_branches_custome_widgets() {
local m
for m in emacs vicmd viins; do
eval "bindkey -M $m '^g^b' chain_fzf_git_branches_custome_widgets"
eval "bindkey -M $m '^gb' chain_fzf_git_branches_custome_widgets"
done
}
# Initialize the binding: see EOF
# -- Workaround END --

fi
__fzf_git_init files branches tags remotes hashes stashes lreflogs each_ref worktrees

# Initialize the binding after the default one to overwrite it
__fzf_git_init_chain_fzf_git_hashes_custome_widgets
__fzf_git_init_chain_fzf_git_branches_custome_widgets

# -----------------------------------------------------------------------------
fi