which + vim = wvim
Over the years I’ve collected an array of one-off scripts, shell aliases, git
subcommands, etc., and I often find myself wanting to reference or edit of one
of them. Sometimes I know where to look, but not always, and when in doubt I
rely on the which
command to point me in the right direction.
wvim
is a script that I’ve built to streamline these sort of edits. It started
as a simple wrapper around which
— function wvim() { vim "$(which $1)" }
—
but over time I’ve added support for shell functions & aliases, as well as git
aliases and scripts. The thing that tipped this into the “oh wow, that’s pretty
cool” space for me was the addition of tab completion by leveraging the existing
tab completion for which
via compdef wvim=which
.
Using it looks something like this:
Show Me The Code!
You can check out my current version of this script in my dotfiles
repo,
but for completeness, I’ve included the contents of the file below. You can use
it by including the code in your ~/.zshrc
file (or by splitting it out into
its own file for organization purposes if you share my penchant for clean config
files).
Note - the compdef
completion line is zsh-specific, but I believe the rest
should be reasonably portable to bash or other similar shells.
# top-level command. Determines the type of the requested command and then
# attempts to open it in vim
wvim() {
command_name="$1"
case "$(_definition_type "$command_name")" in
"alias") _edit_shell_alias "$command_name";;
"function") _edit_shell_function "$command_name";;
"script") _edit_script "$command_name";;
"git-alias") _edit_git_alias "$command_name";;
"not found") _handle_unknown_command "$command_name"
esac
}
# This line configures zsh tab completion for `wvim` by reusing the tab completion
# for `which`
compdef wvim=which
# Use the `type` command to determine the type of the provided command
_definition_type() {
arg_type_string=$(type -a "$1")
if [[ "$arg_type_string" == *"is an alias"* ]]; then
echo "alias"
elif [[ "$arg_type_string" == *"is a shell function"* ]]; then
echo "function"
elif which "$1" > /dev/null 2>&1; then
echo "script"
elif _is_git_alias "$1"; then
echo "git-alias"
else
echo "not found"
fi
}
# Special handling for git aliases since `type` doesn't know about them
_is_git_alias() {
echo "$1" | grep -q 'git-.*' && _git_aliases | grep -qF $(_git_alias_name "$1")
}
_handle_unknown_command() {
echo "\"$1\" is not recognized as a script, function, or alias" >&2
return 1
}
_git_alias_name() {
echo "$1" | sed 's/^git-//'
}
_git_aliases() {
git config --get-regexp ^alias\. |\
sed -e s/^alias\.// -e s/\ /\ =\ / |\
awk '{print $1}'
}
_edit_git_alias() {
line=$(grep -En "^\s+$(_git_alias_name "$1") =" ~/.gitconfig | cut -d ":" -f 1)
vim ~/.gitconfig "+$line"
}
_edit_script() {
vim "$(which "$1")"
}
_definition_field_for_pattern() {
definition=$(grep -En "$2" ~/.zshrc ~/.zshenv ~/.zsh/**/*.zsh 2>/dev/null)
echo "$definition" | cut -d ":" -f "$1"
}
_edit_based_on_pattern() {
file=$(_definition_field_for_pattern 1 "$1")
line=$(_definition_field_for_pattern 2 "$1")
vim "$file" "+$line"
}
_edit_shell_function() {
_edit_based_on_pattern "(^function $1)|(^$1\(\))"
}
_edit_shell_alias() {
_edit_based_on_pattern "alias $1="
}
Caveats and Limitations
Given that wvim
is built out of various regex checks and heuristic searching
logic, I’ve been impressed by how well wvim
has worked for me.
That said, there are a few assumptions baked into this script, most notably that
I have it configured to look in both ~/.zshenv
and ~/.zshrc
. If you don’t
have both those files, you’ll want to update that to only reference the file you
have.