Notes & TILs
Searchโ€ฆ
FZF: Tips and Tricks
Posted on 23 Mar, 2021
โ€‹fzf is a recent addition to my CLI utilities, below are some common use-cases.

Ignoring unnecessary directories

Following bash script helps ignoring some directory paths while searching files via fzf.
1
#!/usr/bin/env bash
2
โ€‹
3
EXCLUDE_DIRS=(
4
"! -path /*.git/*"
5
"! -path /*go/*"
6
"! -path /*.bundle/*"
7
"! -path /*.cache/*"
8
"! -path /*.local/*"
9
"! -path /*.themes/*"
10
"! -path /*.config/*"
11
"! -path /*.codeintel/*"
12
"! -path /*python2.7/*"
13
"! -path /*python3.6/*"
14
"! -path /*__pycache__/*"
15
)
16
โ€‹
17
find $HOME -type f ${EXCLUDE_DIRS[@]} | fzf --height 40% --reverse
Copied!
Note that for some reason you won't able to ignore bin directory paths (like in python venv's etc).
If you prefer the locate command instead, make sure to update your /etc/updatedb.conf file with following PRUNENAMES
1
PRUNE_BIND_MOUNTS="yes"
2
PRUNENAMES=".git .cache .bundle .local .config node_modules __pycache__ python3.6 go"
3
PRUNEPATHS="/tmp /var/spool /media /var/lib/os-prober /var/lib/ceph /home/.ecryptfs /var/lib/schroot"
4
PRUNEFS="NFS nfs nfs4 rpc_pipefs afs binfmt_misc proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs devtmpfs fuse.mfs shfs sysfs cifs lustre tmpfs usbfs udf fuse.glusterfs fuse.sshfs curlftpfs ceph fuse.ceph fuse.rozofs ecryptfs fusesmb"
Copied!
or include any other directories you don't want like .DS_Store etc. Then run sudo updatedb to update the mlocate database. After that you can just pipe the output to fzf.
1
# look for any path in you $HOME directory
2
locate -ei "$HOME" | fzf --height 40% --reverse
Copied!
In vim you can create a custom command, make sure you have fzf.vim installed.
1
command! -nargs=1 -bang Locate call fzf#run(fzf#wrap({'source': 'locate -ei $HOME'}, <bang>0))
Copied!

Changing Directories.

If you followed the previous tip then using this is a no brainer
1
# faster but limited
2
cd "$(locate "$HOME" | fzf --height 40% --reverse)"
3
# bit slower but better
4
cd "$(find ~ -maxdepth 5 -not -path '*/\.git/*' -type d | fzf --height 40% --reverse)"
Copied!
Save this in your .bashrc:
1
fcd() {
2
cd "$(find ~ -maxdepth 5 -not -path '*/\.git/*' -type d | fzf --height 40% --reverse)"
3
}
Copied!

Opening files from terminal using your file-manager ๐Ÿ—ƒ๏ธ

1
# xdg-open for X11
2
# open for Mac
3
browse "$(locate -ei "$HOME" | fzf --height 40% --reverse)"
Copied!
A better version using xargs
1
alias bro="locate -ei "$HOME" | fzf --height 40% --reverse | xargs browse 2>/dev/null"
Copied!

Switching Git branches

fzf can be used as a nice prompt for showing git branches:
1
#!/usr/bin/env sh
2
โ€‹
3
choice=$(git for-each-ref --format='%(refname:short)' refs/heads/* | fzf \
4
--prompt="Switch branch: " \
5
--header="Select a branch to switch to" \
6
--height 40% --reverse
7
)
8
โ€‹
9
git switch $choice
Copied!

Interactively stage files in Git

1
#!/usr/bin/env bash
2
โ€‹
3
readarray -t choices < <(git ls-files --other --modified --exclude-standard | fzf \
4
--prompt="Stage Files: " \
5
--height 40% --reverse --multi \
6
--header="Choose files to stage (TAB to select multiple files)"
7
)
8
โ€‹
9
git add "${choices[@]}"
Copied!

Deleting unused branches interactively

1
#!/usr/bin/env sh
2
โ€‹
3
header="Select branches to delete"
4
โ€‹
5
choices=$(git for-each-ref --format='%(refname:short)' refs/heads/* | fzf \
6
--prompt="Delete Branches: " --pointer='๐Ÿก†'\
7
--header="Press TAB to select choices" \
8
--multi --height 30% --reverse
9
)
10
โ€‹
11
git branch -d $choices
Copied!

Diff(ing) files across branches

Useful in cases when your working with multiple people and want to compare files that are changed while building a feature.
1
#!/usr/bin/env bash
2
โ€‹
3
# FZF Wrapper over git to interactively diff files across branches
4
โ€‹
5
readarray -t git_files < <(git ls-files | fzf \
6
--prompt="Choose File(s): " \
7
--height 40% --reverse --multi \
8
--header="Choose files to diff (TAB to select multiple files)"
9
)
10
โ€‹
11
target_branch=$(git for-each-ref --format='%(refname:short)' refs/heads/* | fzf \
12
--prompt="Select target branch: " \
13
--header="Select branch to compare the files against" \
14
--height 40% --reverse
15
)
16
โ€‹
17
# get current branch
18
current_branch=$(git branch | grep \\* | cut -d ' ' -f2)
19
โ€‹
20
printf "%s\n" "Viewing diff for following files against $(tput bold)$target_branch$(tput sgr0)"
21
printf "$(tput bold)$(tput setaf 208)%s$(tput sgr0)\n" "${git_files[@]}"
22
echo
23
โ€‹
24
git diff "$current_branch".."$target_branch" -- "${git_files[@]}"
Copied!

Replacing gitmoji-cli with fzf

I like the idea of using emojis in commit messages but I am not ready to install node/npm and 10 other dependencies for a CLI.
We can use fzf to create a nice gitmoji like prompt. Here is a simple bash script that does the job. First download the gimojis.csv file and change the path to the csv file in the script.
1
#!/usr/bin/env bash
2
โ€‹
3
gitmoji_path="$HOME/.config/gitmojis.csv"
4
โ€‹
5
emoji=$(cat $gitmoji_path | fzf --prompt="Choose gitmoji: " --height 40% --reverse | awk '{print $1}')
6
printf "Emoji: %s\n" "$emoji"
7
โ€‹
8
read -erp "Enter Commit Title: " title
9
echo -e "Enter Commit Message (Ctrl+d when done):"
10
msg=$(</dev/stdin)
11
echo
12
read -erp "Issue / PR ref #: " issue_ref
13
if [[ "$issue_ref" ]]; then
14
git commit -m "$emoji $title (#$issue_ref)" -m "$msg"
15
else
16
git commit -m "$emoji $title" -m "$msg"
17
fi
Copied!
ofc credits goes to gitmoji ๐Ÿ’š๏ธ

Preview files & directories ๐Ÿ“‚๏ธ

For files you may want to check the filetype, size & permissions.
First create a bash function like this
1
fino () {
2
declare filepath=${1:-$(</dev/stdin)};
3
if [[ -f "$filepath" ]]; then
4
echo -e "$(basename "$filepath")";
5
info=$(file "$filepath" | awk -F ":" '{print $2}');
6
echo -e "$info";
7
ls -alh "$filepath" | awk '{print $1 "\nSize: " $5 "\nLast Modify: " $6 " " $7 " " $8}';
8
fi
9
}
10
export -f fino
Copied!
Now just use the --preview option in fzf.
1
locate -ei "$HOME" | fzf --preview "fino {}" --height 40% --reverse
Copied!
Previewing directories may include listing its contents
1
# Notice the [[ -d ... ]] means only run when the path is a directory
2
locate -ei "$HOME" | fzf --preview "[[ -d {} ]] && tree -C {} | head -200" --height 40% --reverse
Copied!

Beautifying fzf?

fzf offers very minimal but satisfying enough features to tweak around
  1. 1.
    Changing pointers (default '>'). Below are some valid pointer styles
    1
    fzf --prompt='Open File: ' --pointer='แ…'
    2
    fzf --prompt='Open File: ' --pointer='๐Ÿก†'
    3
    fzf --prompt='Open File: ' --pointer='๐Ÿ ฒ'
    4
    fzf --prompt='Open File: ' --pointer='โฎž'
    5
    fzf --prompt='Open File: ' --pointer='๐Ÿข‚'
    6
    fzf --prompt='Open File: ' --pointer='โžก'
    Copied!
  2. 2.
    Colors ๐Ÿ’…๏ธ (WIP)
    A full list of color rules can be found here or on man fzf. Below are some nice colorscheme combinations you might like
    1
    # Inspired from ayu colorscheme Vim
    2
    --color 'fg:#E6E1CF,fg+:#ddeeff,bg:#0F1419,pointer:#FF8400,header:#70B650,query:#FCD363'
    3
    # Inspired from afterglow theme Vim
    4
    --color 'fg:#E6E1CF,fg+:#ddeeff,bg:#1A1A1A,bg+:#393939,pointer:#FF8400,header:#717879'
    5
    # Inspired from sonokai theme Vim
    6
    --color 'fg:#E6E1CF,fg+:#ddeeff,bg:#2C2E34,bg+:#3C3E48,pointer:#EB4B48,header:#7F8490'
    7
    # Inspired from Monokai Pro
    8
    --color 'fg:#E6E1CF,fg+:#ddeeff,bg:#2B292E,bg+:#3D3B40,prompt:#A9DC76,pointer:#FF6188,header:#AB9DF2,query:#FFD866'
    Copied!
Last modified 1mo ago