Skip to content

Instantly share code, notes, and snippets.

@nathanshelly
Last active June 20, 2022 14:54
Show Gist options
  • Save nathanshelly/4b7020d09d413cab823914b06162145a to your computer and use it in GitHub Desktop.
Save nathanshelly/4b7020d09d413cab823914b06162145a to your computer and use it in GitHub Desktop.
scripts & .files for opendoor

o/uutalk - Useful Utilities

Intro

Today I want to talk about a few utilities to supercharge your shell workflows!

Skimmable list of topics

  • zsh - a modern shell replacement for Bash with better tab-completion, complex globbing and plugins
  • ripgrep - a faster grep with friendlier defaults
  • fd - a faster find with friendlier defaults
  • exa - a prettier ls with friendlier defaults
  • bat - a prettier cat with syntax highlighting, line numbers, git highlights and paging
  • hub - enables GitHub.com features like creating pull requests from the command line
  • fzf - easily fuzzily filter any list (files, directories, git branches, etc.)

Install all of these tools in a single command (zsh & fzf benefit from additional configuration that we'll discuss):

brew install zsh ripgrep fd exa bat hub fzf

See the Cut for time section for a few more helpful utilities that I couldn't squeeze into this talk!

Utilities

🐚 Shell - zsh

If you work at Opendoor view the up-to-date living guide here

A superset of Bash with modern bells and whistles. These include better tab-completion, more complex globbing support, a plugin system, and more!

zsh will be the default shell in macOS Catalina so might as well start getting used to it 😃

Set up:

brew install zsh
sudo sh -c "echo $(command -v zsh) >> /etc/shells"
chsh -s "$(command -v zsh)"

Don't have time to discuss everything that's different but I do want to highlight tab completion. We need to add two lines to our .zshrc to turn this on (the onboarding tutorial has an option to do this). Add the following lines to ~/.zshrc:

autoload -Uz compinit
compinit

Now source it to use our changes - source ~/.zshrc. Okay, let's walk through two (by no means comprehensive) examples of zsh tab completion vs bash tab completion:

ls -<TAB>
# bash does nothing
# zsh displays flags

git add <TAB>
# bash displays files in the directory
# zsh displays unstaged files

# additional note: repeatedly hitting Tab cycles through
# options in zsh, in bash it just redisplays all options

Plugins

Plugins add functionality to zsh. There are many different plugin managers, I use zplugin which is the fastest plugin manager I've found and supports loading plugins asynchronously.

Run the installation script:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/zdharma/zplugin/master/doc/install.sh)"

The install script should add the below lines to your ~/.zshrc. If it doesn't, add them manually.

source "$HOME/.zplugin/bin/zplugin.zsh"
autoload -Uz _zplugin
(( ${+_comps} )) && _comps[zplugin]=_zplugin

To install the three plugins I'll discuss add the following snippet to ~/.zshrc:

# ref - search zsh-autosuggestions
# http://zdharma.org/zplugin/wiki/GALLERY/#plugins
zplugin ice wait lucid atload'_zsh_autosuggest_start'
zplugin light zsh-users/zsh-autosuggestions

# note: any plugins that define widgets the syntax highlighting might need to
# color (such as `zsh-autosuggestions`) must be loaded prior
# ref - search fast-syntax-highlighting
# http://zdharma.org/zplugin/wiki/GALLERY/#plugins
zplugin ice wait lucid atinit"ZPLGM[COMPINIT_OPTS]=-C; zpcompinit; zpcdreplay"
zplugin light zdharma/fast-syntax-highlighting

# prompt
# ref - https://github.com/romkatv/powerlevel10k#zplugin
zplugin ice depth=1
zplugin light romkatv/powerlevel10k
  • Context aware prompt - display context of current directory (e.g. git status, executable versions, virtual environments, etc.)

    Install by adding the following line to ~/.zshrc - zplugin light romkatv/powerlevel10k

  • Syntax highlighting - highlight your commands as you type them

    Install by adding the following lines to ~/.zshrc:

    zplugin ice wait lucid atinit"ZPLGM[COMPINIT_OPTS]=-C; zpcompinit; zpcdreplay"
    zplugin light zdharma/fast-syntax-highlighting
  • History autocompletions - suggest previous commands from history as you type

    Install by adding the following lines to ~/.zshrc:

    zplugin ice wait lucid atload'_zsh_autosuggest_start'
    zplugin light zsh-users/zsh-autosuggestions

    This plugin benefits from configuring a few shortcuts:

    # Ctrl-e accepts until end of line (same as right arrow)
    bindkey '^e' autosuggest-accept
    # Ctrl-Space accepts until end of line and immediately execute
    bindkey '^ ' autosuggest-execute
    # Ctrl-w accepts next word
    bindkey '^w' forward-word
    # count only alphanumeric characters as part of a word
    WORDCHARS=

🔎 ripgrep

A faster and generally more user friendly replacement for grep. It searches recursively by default, respects .gitignore (and .ignore) files, and skips hidden and binary files.

Here's a writeup of more details on the tool by it's creator including detailed benchmarks.

Here is a heads up comparison on an arbitrary query:

# takes ~30 seconds w/o `--exlude-dir` (this exclude also wouldn't cover all
# files ignored by ripgrep, e.g. go build files, python virtualenvironments, etc.)
grep -r TradeInStep . --exclude-dir=node_modules --color -n

rg TradeInStep

Here are some usage examples:

# recursively search current directory for pattern
rg pattern

# include .gitignored and hidden files
rg -uu pattern

# search for whole word matches in files matching the given glob
rg -w @types/lodash -g 'package.json'

🔎 fd

A simpler, faster find (fd is to find what ripgrep is to grep). Skips hidden directories, respects .gitignore files, colorized terminal output, smart case (case-insensitive by default, case sensitive if pattern includes a capital).

Here is a heads up comparison on an arbitrary query:

find . -iname '*TradeInStep*' -not -path '*/node_modules/*'
# or
fd TradeInStep

A few other usage examples:

# search for files matching pattern (no more `find . -iname '*PATTERN*'`)
fd pattern

# include hidden and ignored files
fd --hidden --no-ignore pattern

💎 exa

A prettier ls that comes with friendlier defaults and adds extra contextual information (like git info with --git).

Add the following line to ~/.zshrc to alias ls to exa: alias ls=exa

Note: if you do alias ls to exa you can always use regular ls with /bin/ls

🦇 bat

A prettier cat with syntax highlighting, line numbers, git highlights and paging.

bat

🐙🐈 hub

Augments git when using GitHub (the tool itself is developed by GitHub). hub supports PR creation, easier repo cloning, viewing CI status & more!

hub is a strict superset of git and GitHub suggests aliasing git to hub for easier usage (anecdotally I've had git aliased to hub for over a year now without any issues).

By far the most useful feature of hub for me is pull request creation:

# `-p` pushes branch if not pushed, `-o` opens PR in browser, `-c` copies PR link to clipboard
# first `-m` specifies PR title, second `-m` specific PR body, `-l` adds the given label (can
# specify multiple separated by commas - `-l label-one,label-two`), `-r` adds the given reviewer
# (again can specify multiple separated by commas - `-r username-one,username-two`)
hub pull-request -poc -m 'title here' -m 'body here' -l merge-when-green -r bmalehorn

Here a few other usage examples:

# clone a repository without the full url (omit the username for your own repos)
hub clone username/repo_name

# create a repository on GitHub (optional organization and repo name)
hub create organization/repo_name

# compare the current branch to master (or given base branch)
hub compare <optional-base-branch>

# view status of GitHub CI checks
hub ci-status -v

# open repo in browser
hub browse

🌸🚀 fzf

A fantastic fuzzy finder for fun coding and my personal favorite of these utilities!

fzf enables interactive fuzzy filtering of a list of strings (file paths, lines of code, git commits, etc.) with previews!

To set up fzf let's run it's setup script:

$(brew --prefix)/opt/fzf/install

We now have completions and key bindings. First, let's talk completions:

# fuzzily cd to a directory
cd **<Tab>

# kill processes
kill -9 <Tab>

# fuzzily open file in your editor
vim **<Tab>

Next, key bindings. The setup script adds three bindings. These can be triggered at any time, not just the start of a shell command!

  • Ctrl-r - shell history
  • Ctrl-t - all files under the current directory
  • Alt-c - cd to selected directory under the current one

My personal fzf config

Finally, I have my own configuration that adds a few other handy shortcuts along with configuring previews. This can be added by copying and pasting the config from the fzf.zsh file in this gist to the end of your ~/.zshrc or by running the command below which curls the file down and appends it.

# install preview dependencies (can use the older versions
# (e.g. `grep` instead of `rg`, `find` instead of `fd`) of
# each of these if you prefer by editing `~/.zshrc`)
brew install bat exa fd

# append fzf.zsh from this gist to ~/.zshrc
curl https://gist.githubusercontent.com/nathanshelly/4b7020d09d413cab823914b06162145a/raw/de3a42bb78be18336ffc0c81878028c94894f72d/fzf.zsh >> ~/.zshrc

Here are the new shortcuts this config adds:

  • Ctrl-p - open selected file(s) in $EDITOR
  • Alt-h - list commits
  • Alt-f - list unstaged files
  • Alt-r - list branches (local & remote)

More information on fzf

Additional utilities cut for time

Skimmable list

  • fasd - quickly access files and folders based on frequency and recency of access
  • tldr - a cliff-notes man page
  • tmux - a terminal multiplexer to replace endless terminal tabs
  • trash - replacement for rm that moves files to the trash so you can recover them

Install all of these tools in a single command - brew install fasd tldr tmux trash

💨 fasd

Quickly access files and folders from anywhere on your machine based on frequency and recency of access ("frecency").

v def conf       =>     vim /some/awkward/path/to/type/default.conf
j abc            =>     cd /hell/of/a/awkward/path/to/get/to/abcdef
m movie          =>     mplayer /whatever/whatever/whatever/awesome_movie.mp4
o eng paper      =>     xdg-open /you/dont/remember/where/english_paper.pdf
vim `f rc lo`    =>     vim /etc/rc.local
vim `f rc conf`  =>     vim /etc/rc.conf

See the repo for more details including setup instructions! Note: the README doesn't mention using Homebrew but it's there - brew install fasd

📖 tldr

A cliff notes man page. Provides quick high-level documentation of a tool with some examples.

Run on tar:

tldr

🗑 trash

A replacement for rm. Files deleted with trash are moved to the system Trash folder so you can easily recover them if you accidentally delete something. Bonus, it works on files and directories (no need to ever type -r again).

🤹 tmux

Ripped shamelessly from the tmux README:

tmux is a terminal multiplexer.

It enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.

See any of these guides for a great primer on why you might want to use it and how to get started!

# <<<<<<<<<<<<<<<<<<< start of fzf config >>>>>>>>>>>>>>>>>>>
# fuzzy finder
# ref - https://github.com/junegunn/fzf
#
# helpful sources
# refs:
# - https://github.com/junegunn/fzf/wiki/examples
# - https://medium.com/@sidneyliebrand/how-fzf-and-ripgrep-improved-my-workflow-61c7ca212861
# - http://owen.cymru/fzf-ripgrep-navigate-with-bash-faster-than-ever-before/
# <<<< completion >>>>
brew_prefix="$(brew --prefix)"
# Note: `$-` lists options set in current shell
# ref - https://stackoverflow.com/questions/5163144/what-are-the-special-dollar-sign-shell-variables
[[ $- == *i* ]] && {
source "$brew_prefix/opt/fzf/shell/completion.zsh" 2>/dev/null
}
# use `fd` for `**` path completion
# `$1` is the base path to start traversal
_fzf_compgen_path() {
fd --hidden --follow --exclude ".git" . "$1"
}
# use `fd` for `**` directory completion
# `$1` is the base path to start traversal
_fzf_compgen_dir() {
fd --type directory --hidden --follow --exclude ".git" . "$1"
}
# <<<< config >>>>
# << shared >>
_fzf_bat_preview="--preview='bat --style=numbers --color=always {}'"
_fzf_preview_window="--preview-window=down:75%"
_fzf_hidden_preview_window="${_fzf_preview_window}:hidden"
export FZF_DEFAULT_COMMAND="fd --type file --hidden --follow --exclude .git"
export FZF_DEFAULT_OPTS="--height 99% --reverse --no-mouse --cycle --ansi --multi\
$_fzf_preview_window\
--bind ctrl-k:down,ctrl-l:up,ctrl-space:toggle-preview,\
ctrl-d:preview-page-down,ctrl-u:preview-page-up,ctrl-a:select-all+accept"
# << list files >>
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_CTRL_T_OPTS="$_fzf_bat_preview $_fzf_hidden_preview_window"
# << navigate to directory (`cd` into selected folder) >>
export FZF_ALT_C_COMMAND="fd --type directory --hidden --follow --exclude .git"
export FZF_ALT_C_OPTS="--preview='exa --color always {}'"
# << edit w/ $EDITOR >>
# edit selected file (same as `e <c-f>`)
bindkey '^p' fzf-edit-widget
export FZF_EDIT_OPTS="$_fzf_bat_preview"
# <<<< widgets >>>>
# << zsh functions -> widgets >>
# zsh requires explicit marking of functions that will be mapped as widgets
zle -N fzf-edit-widget
# edit selected file
# lightly adapted from `fzf-cd-widget`
fzf-edit-widget() {
setopt localoptions pipefail 2> /dev/null
local file="$(
eval "$FZF_DEFAULT_COMMAND" \
| FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS $FZF_EDIT_OPTS" $(__fzfcmd) +m
)"
if [[ -z "$file" ]]; then
zle redisplay
return 0
fi
"${EDITOR:-nvim}" "$file"
local ret=$?
zle fzf-redraw-prompt
return $ret
}
# fzf ❤️ git
# useful combinations of git & fzf
# refs:
# - https://junegunn.kr/2016/07/fzf-git
# - https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236
# join multi-line output from fzf
join-lines() {
local item
while read item; do
echo -n "${(q)item} "
done
}
bind-git-helper() {
local c
for c in $@; do
eval "fzf-g$c-widget() {\
zle reset-prompt;\
local result=\$(fzf_g$c | join-lines);\
zle reset-prompt;\
LBUFFER+=\$result\
}"
eval "zle -N fzf-g$c-widget"
eval "bindkey '\e$c' fzf-g$c-widget"
done
}
# f - list files (what `git status` would list)
# r - list branches (including remotes)
# h - list hashes (commits)
bind-git-helper f r h
unset -f bind-git-helper
path=(/usr/local/opt/fzf/bin $path)
# will return non-zero status if the current directory is not managed by git
is_in_git_repo() {
git rev-parse HEAD > /dev/null 2>&1
}
fzf_gf() {
is_in_git_repo || return
local preview
preview='(git diff --color=always -- {-1} | sed 1,4d; cat {-1}) | bat'
git -c color.status=always status --short |
fzf -m --ansi --nth 2..,.. --preview "$preview" |
cut -c4- | sed 's/.* -> //'
}
fzf_gr() {
is_in_git_repo || return
local bindings preview
bindings='ctrl-space:toggle-preview'
preview='git log --oneline --graph --date=short --color=always'
preview+=' --pretty="format:%C(auto)%cd %h%d %s"'
preview+=' $(sed s/^..// <<< {} | cut -d" " -f1) | bat'
git branch -a --color=always | grep -v '/HEAD\s' | sort |
fzf --ansi --multi --tac --preview-window right:70% --bind="$bindings" \
--preview "$preview" |
sed 's/^..//' | cut -d' ' -f1 |
sed 's#^remotes/##'
}
fzf_gh() {
is_in_git_repo || return
local format bindings preview
format='%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)'
bindings='ctrl-s:toggle-sort,ctrl-space:toggle-preview'
preview='grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | bat'
git log --date=short --format="$format" --graph --color=always |
fzf --ansi --no-sort --reverse --multi --bind "$bindings" \
--header 'Press CTRL-S to toggle sort' \
--preview "$preview" |
grep -o "[a-f0-9]\{7,\}"
}
# <<<<<<<<<<<<<<<<<<< end of fzf config >>>>>>>>>>>>>>>>>>>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment