In my previous blog post, we discussed adding fuzzy search for curl options using fzf.
In this post, we will add fuzzy completion to the npm run
command by reading “scripts” from package.json
in the current directory. This requires jq, to available on PATH
.
Helpers for sub-command
Fzf _fzf_complete_COMMAND
function will trigger on main command and not for sub commands like npm run
. To support this, we need some helper functions.
_fzf_complete_get_command_pos() {
local arguments=("${(Q)${(z)@}[@]}")
local cmd=$(__fzf_extract_command "$@")
echo ${arguments[(i)$cmd]}
}
_fzf_complete_trim_env() {
local command_pos=$1
shift 1
local arguments=("${(Q)${(z)@}[@]}")
echo ${(q)arguments[$command_pos, -1]}
}
_fzf_complete_get_env() {
local command_pos=$1
shift 1
local arguments=("${${(z)@}[@]}")
echo ${arguments[1, $command_pos - 1]}
}
fzf complete NPM run
Now, using the above helper functions, we can add _fzf_complete_npm
and _fzf_complete_npm_run
as below.
_fzf_complete_npm() {
setopt local_options no_aliases
local command_pos=$(_fzf_complete_get_command_pos "$@")
local arguments=("${(Q)${(z)"$(_fzf_complete_trim_env "$command_pos" "$@")"}[@]}")
local subcommand=${arguments[2]}
if (( $command_pos > 1 )); then
local -x "${(e)${(z)"$(_fzf_complete_get_env "$command_pos" "$@")"}[@]}"
fi
if (( $+functions[_fzf_complete_npm_${subcommand}] )) && _fzf_complete_npm_${subcommand} "$@"; then
return
fi
_fzf_path_completion "$prefix" "$@"
}
_fzf_complete_npm_run() {
local package=${npm_directory-$(dirname -- $(npm root))}/package.json
if [[ ! -f $package ]]; then
return
fi
local scriptContent=$(cat package.json | jq -r '.scripts')
_fzf_complete --prompt="npm run> " --preview="echo '$scriptContent' | jq -r '.\"{}\"'" -- "$@" < <(
echo $scriptContent | jq -r 'keys[]'
)
}
Here is a small preview of the above script in action.
Versions of Language/packages used in this post.
| Library/Language | Version |
| ---------------- |---------|
| jq | 1.7 |
| fzf | 0.45.0 |
| zsh | 5.9 |