diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf64124 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.directory +*.zwc +*.old +*~ diff --git a/functions/zbnc_default_npm_completion b/functions/zbnc_default_npm_completion new file mode 100644 index 0000000..1e0b4c5 --- /dev/null +++ b/functions/zbnc_default_npm_completion @@ -0,0 +1,7 @@ +#!/usr/bin/env zsh + +compadd -- $(COMP_CWORD=$((CURRENT-1)) \ + COMP_LINE=$BUFFER \ + COMP_POINT=0 \ + npm completion -- "${words[@]}" \ + 2>/dev/null) diff --git a/functions/zbnc_get_package_json_property_object b/functions/zbnc_get_package_json_property_object new file mode 100644 index 0000000..16cd429 --- /dev/null +++ b/functions/zbnc_get_package_json_property_object @@ -0,0 +1,8 @@ +#!/usr/bin/env zsh + +local package_json="$1" +local property="$2" +cat "$package_json" | +sed -nE "/^ \"$property\": \{$/,/^ \},?$/p" | # Grab scripts object +sed '1d;$d' | # Remove first/last lines +sed -E 's/ "([^"]+)": "(.+)",?/\1=>\2/' # Parse into key=>value diff --git a/functions/zbnc_get_package_json_property_object_keys b/functions/zbnc_get_package_json_property_object_keys new file mode 100644 index 0000000..64f76f5 --- /dev/null +++ b/functions/zbnc_get_package_json_property_object_keys @@ -0,0 +1,5 @@ +#!/usr/bin/env zsh + +local package_json="$1" +local property="$2" +zbnc_get_package_json_property_object "$package_json" "$property" | cut -f 1 -d "=" diff --git a/functions/zbnc_list_cached_modules b/functions/zbnc_list_cached_modules new file mode 100644 index 0000000..01ce9a6 --- /dev/null +++ b/functions/zbnc_list_cached_modules @@ -0,0 +1,3 @@ +#!/usr/bin/env zsh + +ls ~/.npm 2>/dev/null diff --git a/functions/zbnc_no_of_npm_args b/functions/zbnc_no_of_npm_args new file mode 100644 index 0000000..2af0fd8 --- /dev/null +++ b/functions/zbnc_no_of_npm_args @@ -0,0 +1,3 @@ +#!/usr/bin/env zsh + +echo "$#words" diff --git a/functions/zbnc_npm_command b/functions/zbnc_npm_command new file mode 100644 index 0000000..0845457 --- /dev/null +++ b/functions/zbnc_npm_command @@ -0,0 +1,3 @@ +#!/usr/bin/env zsh + +echo "${words[2]}" diff --git a/functions/zbnc_npm_command_arg b/functions/zbnc_npm_command_arg new file mode 100644 index 0000000..ea3c01c --- /dev/null +++ b/functions/zbnc_npm_command_arg @@ -0,0 +1,3 @@ +#!/usr/bin/env zsh + +echo "${words[3]}" diff --git a/functions/zbnc_npm_install_completion b/functions/zbnc_npm_install_completion new file mode 100644 index 0000000..a56f05d --- /dev/null +++ b/functions/zbnc_npm_install_completion @@ -0,0 +1,13 @@ +#!/usr/bin/env zsh + +# Only run on `npm install ?` +[[ ! "$(zbnc_no_of_npm_args)" = "3" ]] && return + +# Return if we don't have any cached modules +[[ "$(zbnc_list_cached_modules)" = "" ]] && return + +# If we do, recommend them +_values $(zbnc_list_cached_modules) + +# Make sure we don't run default completion +custom_completion=true diff --git a/functions/zbnc_npm_run_completion b/functions/zbnc_npm_run_completion new file mode 100644 index 0000000..eec52b9 --- /dev/null +++ b/functions/zbnc_npm_run_completion @@ -0,0 +1,23 @@ +#!/usr/bin/env zsh + +# Only run on `npm run ?` +[[ ! "$(zbnc_no_of_npm_args)" = "3" ]] && return + +# Look for a package.json file +local package_json="$(zbnc_recursively_look_for package.json)" + +# Return if we can't find package.json +[[ "$package_json" = "" ]] && return + +# Parse scripts in package.json +local -a options +options=(${(f)"$(zbnc_parse_package_json_for_script_suggestions $package_json)"}) + +# Return if we can't parse it +[[ "$#options" = 0 ]] && return + +# Load the completions +_describe 'values' options + +# Make sure we don't run default completion +custom_completion=true diff --git a/functions/zbnc_npm_uninstall_completion b/functions/zbnc_npm_uninstall_completion new file mode 100644 index 0000000..94cb1d1 --- /dev/null +++ b/functions/zbnc_npm_uninstall_completion @@ -0,0 +1,15 @@ +#!/usr/bin/env zsh + +# Use default npm completion to recommend global modules +[[ "$(zbnc_npm_command_arg)" = "-g" ]] || [[ "$(zbnc_npm_command_arg)" = "--global" ]] && return + +# Look for a package.json file +local package_json="$(zbnc_recursively_look_for package.json)" + +# Return if we can't find package.json +[[ "$package_json" = "" ]] && return + +_values $(zbnc_parse_package_json_for_deps "$package_json") + +# Make sure we don't run default completion +custom_completion=true diff --git a/functions/zbnc_parse_package_json_for_deps b/functions/zbnc_parse_package_json_for_deps new file mode 100644 index 0000000..694893b --- /dev/null +++ b/functions/zbnc_parse_package_json_for_deps @@ -0,0 +1,5 @@ +#!/usr/bin/env zsh + +local package_json="$1" +zbnc_get_package_json_property_object_keys "$package_json" dependencies +zbnc_get_package_json_property_object_keys "$package_json" devDependencies diff --git a/functions/zbnc_parse_package_json_for_script_suggestions b/functions/zbnc_parse_package_json_for_script_suggestions new file mode 100644 index 0000000..91585b3 --- /dev/null +++ b/functions/zbnc_parse_package_json_for_script_suggestions @@ -0,0 +1,7 @@ +#!/usr/bin/env zsh + +local package_json="$1" +zbnc_get_package_json_property_object "$package_json" scripts | +sed -E 's/(.+)=>(.+)/\1:$ \2/' | # Parse commands into suggestions +sed 's/\(:\)[^$]/\\&/g' | # Escape ":" in commands +sed 's/\(:\)$[^ ]/\\&/g' # Escape ":$" without a space in commands diff --git a/functions/zbnc_recursively_look_for b/functions/zbnc_recursively_look_for new file mode 100644 index 0000000..26ea495 --- /dev/null +++ b/functions/zbnc_recursively_look_for @@ -0,0 +1,9 @@ +#!/usr/bin/env zsh + +local filename="$1" +local dir=$PWD +while [ ! -e "$dir/$filename" ]; do + dir=${dir%/*} + [[ "$dir" = "" ]] && break +done +[[ ! "$dir" = "" ]] && echo "$dir/$filename" diff --git a/functions/zbnc_zsh_better_npm_completion b/functions/zbnc_zsh_better_npm_completion new file mode 100644 index 0000000..cef2358 --- /dev/null +++ b/functions/zbnc_zsh_better_npm_completion @@ -0,0 +1,20 @@ +#!/usr/bin/env zsh + +# Store custom completion status +local custom_completion=false + +# Load custom completion commands +case "$(zbnc_npm_command)" in + i|install) + zbnc_npm_install_completion + ;; + r|uninstall) + zbnc_npm_uninstall_completion + ;; + run) + zbnc_npm_run_completion + ;; +esac + +# Fall back to default completion if we haven't done a custom one +[[ $custom_completion = false ]] && zbnc_default_npm_completion diff --git a/zsh-better-npm-completion.plugin.zsh b/zsh-better-npm-completion.plugin.zsh index 38a8d68..ce6c88b 100644 --- a/zsh-better-npm-completion.plugin.zsh +++ b/zsh-better-npm-completion.plugin.zsh @@ -1,143 +1,27 @@ -_zbnc_npm_command() { - echo "${words[2]}" -} - -_zbnc_npm_command_arg() { - echo "${words[3]}" -} - -_zbnc_no_of_npm_args() { - echo "$#words" -} - -_zbnc_list_cached_modules() { - ls ~/.npm 2>/dev/null -} - -_zbnc_recursively_look_for() { - local filename="$1" - local dir=$PWD - while [ ! -e "$dir/$filename" ]; do - dir=${dir%/*} - [[ "$dir" = "" ]] && break - done - [[ ! "$dir" = "" ]] && echo "$dir/$filename" -} - -_zbnc_get_package_json_property_object() { - local package_json="$1" - local property="$2" - cat "$package_json" | - sed -nE "/^ \"$property\": \{$/,/^ \},?$/p" | # Grab scripts object - sed '1d;$d' | # Remove first/last lines - sed -E 's/ "([^"]+)": "(.+)",?/\1=>\2/' # Parse into key=>value -} - -_zbnc_get_package_json_property_object_keys() { - local package_json="$1" - local property="$2" - _zbnc_get_package_json_property_object "$package_json" "$property" | cut -f 1 -d "=" -} - -_zbnc_parse_package_json_for_script_suggestions() { - local package_json="$1" - _zbnc_get_package_json_property_object "$package_json" scripts | - sed -E 's/(.+)=>(.+)/\1:$ \2/' | # Parse commands into suggestions - sed 's/\(:\)[^$]/\\&/g' | # Escape ":" in commands - sed 's/\(:\)$[^ ]/\\&/g' # Escape ":$" without a space in commands -} - -_zbnc_parse_package_json_for_deps() { - local package_json="$1" - _zbnc_get_package_json_property_object_keys "$package_json" dependencies - _zbnc_get_package_json_property_object_keys "$package_json" devDependencies -} - -_zbnc_npm_install_completion() { - - # Only run on `npm install ?` - [[ ! "$(_zbnc_no_of_npm_args)" = "3" ]] && return - - # Return if we don't have any cached modules - [[ "$(_zbnc_list_cached_modules)" = "" ]] && return - - # If we do, recommend them - _values $(_zbnc_list_cached_modules) - - # Make sure we don't run default completion - custom_completion=true -} - -_zbnc_npm_uninstall_completion() { - - # Use default npm completion to recommend global modules - [[ "$(_zbnc_npm_command_arg)" = "-g" ]] || [[ "$(_zbnc_npm_command_arg)" = "--global" ]] && return - - # Look for a package.json file - local package_json="$(_zbnc_recursively_look_for package.json)" - - # Return if we can't find package.json - [[ "$package_json" = "" ]] && return - - _values $(_zbnc_parse_package_json_for_deps "$package_json") - - # Make sure we don't run default completion - custom_completion=true -} - -_zbnc_npm_run_completion() { - - # Only run on `npm run ?` - [[ ! "$(_zbnc_no_of_npm_args)" = "3" ]] && return - - # Look for a package.json file - local package_json="$(_zbnc_recursively_look_for package.json)" - - # Return if we can't find package.json - [[ "$package_json" = "" ]] && return - - # Parse scripts in package.json - local -a options - options=(${(f)"$(_zbnc_parse_package_json_for_script_suggestions $package_json)"}) - - # Return if we can't parse it - [[ "$#options" = 0 ]] && return - - # Load the completions - _describe 'values' options - - # Make sure we don't run default completion - custom_completion=true -} - -_zbnc_default_npm_completion() { - compadd -- $(COMP_CWORD=$((CURRENT-1)) \ - COMP_LINE=$BUFFER \ - COMP_POINT=0 \ - npm completion -- "${words[@]}" \ - 2>/dev/null) -} - -_zbnc_zsh_better_npm_completion() { - - # Store custom completion status - local custom_completion=false - - # Load custom completion commands - case "$(_zbnc_npm_command)" in - i|install) - _zbnc_npm_install_completion - ;; - r|uninstall) - _zbnc_npm_uninstall_completion - ;; - run) - _zbnc_npm_run_completion - ;; - esac - - # Fall back to default completion if we haven't done a custom one - [[ $custom_completion = false ]] && _zbnc_default_npm_completion -} - -compdef _zbnc_zsh_better_npm_completion npm +# Standarized ZSH polyfills, following: +# https://github.com/zdharma/Zsh-100-Commits-Club/blob/master/Zsh-Plugin-Standard.adoc +0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" +0="${${(M)0:#/*}:-$PWD/$0}" + +if [[ $PMSPEC != *f* ]] { + fpath+=( "${0:h}/functions" ) +} + +autoload -Uz \ + zbnc_default_npm_completion \ + zbnc_get_package_json_property_object \ + zbnc_get_package_json_property_object_keys \ + zbnc_list_cached_modules \ + zbnc_no_of_npm_args \ + zbnc_npm_command \ + zbnc_npm_command_arg \ + zbnc_npm_install_completion \ + zbnc_npm_run_completion \ + zbnc_npm_uninstall_completion \ + zbnc_parse_package_json_for_deps \ + zbnc_parse_package_json_for_script_suggestions \ + zbnc_recursively_look_for \ + zbnc_zsh_better_npm_completion + + +compdef zbnc_zsh_better_npm_completion npm