diff --git a/LICENSE b/LICENSE index e2db8f2..a7c1a5e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,10 @@ MIT License -Copyright (c) 2016 Luke Childs +Copyright (c) 2016 Luke Childs, 2017-present Ulysse Buonomo + +Copyright for portions of yarn-completion are held by Luke Childs (2016) as +part of project zsh-better-npm-completion. All other copyright for project +yarn-completion are held by Ulysse Buonomo (2017). Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 0ff46a4..ab9edea 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,20 @@ -# zsh-better-npm-completion +# yarn-extra-completion -> Better completion for `npm` +This plugin is greatly inspired by [zsh-better-npm-completion](https://github.com/lukechilds/zsh-better-npm-completion). It works the same way, as you can see with `npm` demo: -* Makes `npm install` recommendations from npm cache -* Makes `npm uninstall` recommendations from `dependencies`/`devDependencies` -* Shows detailed information on script contents for `npm run` -* Falls back to default npm completions if we don't have anything better +* Makes `yarn add` recommendations from npm cache, +* Makes `yarn remove` recommendations from `dependencies`/`devDependencies`, +* Shows detailed information on script contents for `npm run`, +* Calls already installed yarn completion for any other command. + +# Pre-requisites + +You'll need [jq](https://stedolan.github.io/jq/download/). + +It is strongly suggested that you also have the default yarn suggestion under +the name of `_yarn`. Or that you set `YARN_EXTRA_COMPLETION_DEFAULT=_your_default_function`. ## Installation @@ -16,14 +23,14 @@ Bundle `zsh-better-npm-completion` in your `.zshrc` ```shell -antigen bundle lukechilds/zsh-better-npm-completion +antigen bundle buonomo/yarn-completion ``` ### Using [zplug](https://github.com/b4b4r07/zplug) Load `zsh-better-npm-completion` as a plugin in your `.zshrc` ```shell -zplug "lukechilds/zsh-better-npm-completion", nice:10 +zplug "buonomo/yarn-completion", defer:2 ``` ### Using [zgen](https://github.com/tarjoilija/zgen) @@ -31,39 +38,34 @@ zplug "lukechilds/zsh-better-npm-completion", nice:10 Include the load command in your `.zshrc` ```shell -zgen load lukechilds/zsh-better-npm-completion +zgen load buonomo/yarn-completion ``` ### As an [Oh My ZSH!](https://github.com/robbyrussell/oh-my-zsh) custom plugin -Clone `zsh-better-npm-completion` into your custom plugins repo +Clone `yarn-completion` into your custom plugins repo ```shell -git clone https://github.com/lukechilds/zsh-better-npm-completion ~/.oh-my-zsh/custom/plugins/zsh-better-npm-completion +git clone https://github.com/buonomo/yarn-completion ~/.oh-my-zsh/custom/plugins/yarn-completion ``` Then load as a plugin in your `.zshrc` ```shell -plugins+=(zsh-better-npm-completion) +plugins+=(yarn-completion) ``` ### Manually -Clone this repository somewhere (`~/.zsh-better-npm-completion` for example) +Clone this repository somewhere (`~/.yarn-completion` for example) ```shell -git clone https://github.com/lukechilds/zsh-better-npm-completion.git ~/.zsh-better-npm-completion +git clone https://github.com/buonomo/yarn-completion.git ~/.yarn-completion ``` Then source it in your `.zshrc` ```shell -source ~/.zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh +source ~/.yarn-completion/yarn-completion.plugin.zsh ``` -## Related - -- [`zsh-nvm`](https://github.com/lukechilds/zsh-nvm) - Zsh plugin for installing, updating and loading `nvm` -- [`gifgen`](https://github.com/lukechilds/gifgen) - Simple high quality GIF encoding - ## License -MIT © Luke Childs +MIT © Ulysse Buonomo diff --git a/yarn-extra-completion.plugin.zsh b/yarn-extra-completion.plugin.zsh new file mode 100644 index 0000000..9d9ad86 --- /dev/null +++ b/yarn-extra-completion.plugin.zsh @@ -0,0 +1,112 @@ +#compdef yarn + +_yc_run_default() { + if (( ${+YARN_EXTRA_COMPLETION_DEFAULT} )); then + $YARN_EXTRA_COMPLETION_DEFAULT "$@" + elif (( ${+commands[_yarn]} )); then + _yarn "$@" + fi +} + +_yc_yarn_command() { + echo "${words[2]}" +} + +_yc_yarn_command_arg() { + echo "${words[3]}" +} + +_yc_no_of_yarn_args() { + echo "$#words" +} + +_yc_check_jq() { + (( ${+commands[jq]} )) || echo "\nyarn-completion needs jq\n" +} + +_yc_recursively_look_for() { + local filename="$1" + local dir=$PWD + while [ ! -e "$dir/$filename" ]; do + dir=${dir%/*} + [[ "$dir" = "" ]] && break + done + [[ ! "$dir" = "" ]] && echo "$dir/$filename" +} + +_yc_yarn_add_completion() { + # Only run on `yarn add ?` + [[ ! "$(_yc_no_of_yarn_args)" = "3" ]] && return + + local packages=($(yarn cache list --json | jq --raw-output '.data.body[] | .[0]' 2> /dev/null)) + + # Return if we don't have any cached modules + [[ "$#packages" = 0 ]] && return + + # If we do, recommend them + _values 'packages' $packages +} + +_yc_yarn_remove_completion() { + # Use default yarn completion to recommend global modules + [[ "$(_yc_yarn_command_arg)" = "-g" ]] || [[ "$(_yc_yarn_command_arg)" = "--global" ]] && return + + # Look for a package.json file + local package_json="$(_yc_recursively_look_for package.json)" + + # Return if we can't find package.json + [[ "$package_json" = "" ]] && return + + local values=($(jq --raw-output '(.devDependencies, .dependencies) | keys[]' $package_json 2> /dev/null)) + + [[ "$#values" = 0 ]] && return + + _values 'installed' $values +} + +_yc_yarn_run_completion() { + # Only run on `yarn run ?` + [[ ! "$(_yc_no_of_yarn_args)" = "3" ]] && return + + # Look for a package.json file + local package_json="$(_yc_recursively_look_for package.json)" + + # Return if we can't find package.json + [[ "$package_json" = "" ]] && return + + local -a scripts + scripts=(${(f)"$( + jq --raw-output ' + .scripts | to_entries[] | "\(.key):\(.value | gsub("\n";"\\\\n"))" + ' $package_json 2> /dev/null + )"}) + + [[ "$#scripts" = 0 ]] && return + + _describe 'scripts' scripts +} + +_yc_zsh_yarn_extra_completion() { + # Show yarn commands if not typed yet + [[ $(_yc_no_of_yarn_args) -le 2 ]] && _yc_run_default "$@" && return + + # Load custom completion commands + case "$(_yc_yarn_command)" in + add) + _yc_check_jq + _yc_yarn_add_completion + ;; + remove) + _yc_check_jq + _yc_yarn_remove_completion + ;; + run) + _yc_check_jq + _yc_yarn_run_completion + ;; + *) + _yc_run_default "$@" + esac +} + +_yc_zsh_yarn_extra_completion "$@" diff --git a/zsh-better-npm-completion.plugin.zsh b/zsh-better-npm-completion.plugin.zsh deleted file mode 100644 index 38a8d68..0000000 --- a/zsh-better-npm-completion.plugin.zsh +++ /dev/null @@ -1,143 +0,0 @@ -_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