#!/bin/bash # ABOUT : BASH Shell auto completion for Drush - it auto-completes when you invoke drush with - 'd', 'dr', 'drush' or 'drush.php'. # WEB RESOURCES : See http://drupal.org/node/437568 - the issue that we use for this thing. # VERSION : 0.10 (now usably fast) # CHANGELOG : # : 0.10 - (--17jun2009 7h04--) basically a complete rewrite. # - made it a lot faster by avoiding calling drush whenever possible and by using sed instead of basename. # - works with option parameters # - cleaned up the code, putting stuff in functions. # - the script now creates a ~/.drush-complete directory where it stores a command cache. # - this rev courtesy of Ted Tibbetts (username "intuited" at the google mail location) # ! not tested for compatibility; please let me know if you have problems. I run ubuntu linux. # ! it won't work if the current directory is more than 6 levels below drupal root. this seems unlikely to be a problem. # : 0.9 - made it Mac OSX compatible I hope; renamed some vars # : 0.8 - changed the way drupal_root is determined # : 0.7 - we handle 'sql dump'-like commands correctly # DATE : 090617 # INSTALL : (valid for debian with bash) # : EITHER 1. cd /etc/bash_completion.d/; ln -s /path/to/drush/drush.completion # : OR 2. mcedit .bashrc; then write ". /path/to/drush/drush.completion" in it ('.' = source) # REQUIREMENTS : "drush" named symlink in your $PATH . It uses it to get some info by calling drush. # TODO : Limitations : # : 1. better modules/projects completion on dl/enable/disable ... for now we do a `find $drupal_root/modules/ $drupal_root/themes/ $drupal_root/sites/ -type f -name "*.info" -exec basename '{}' .info \; | tr '\n' ' '` ... which returns ALL present modules/themes # TODO : Roadmap : # : create an internal use --completion option for drush that will make smarter completion suggestions ##constants __DRC_SETTINGS_DIR="$HOME/.drush-complete"; __DRC_COMMAND_CACHE="$__DRC_SETTINGS_DIR/command-cache"; __DRC_COMMAND_CACHE_EXPIRE=86400; # expire the cache every 24 hours ##support functions #set up the settings directory where the command cache is stored function __drc_setup_settings_dir { if ! mkdir -p "$HOME/.drush-complete"; then echo "drush-complete: couldn't create settings directory." >&2; return -10; fi; } #get a word list from cache unless it's nonexistent or expired # word list is returned on stdout, one per line. function __drc_get_commands { if ! __drc_setup_settings_dir; then return $?; fi; if [[ ! -e "$__DRC_COMMAND_CACHE" ]] || (( $(stat -c %Y "$__DRC_COMMAND_CACHE") < $(date +%s) - $__DRC_COMMAND_CACHE_EXPIRE )); then drush help --pipe | sed 's/\"\ \"/\n/g' | sed 's/\"//g' | sort | tee "$__DRC_COMMAND_CACHE"; else cat "$__DRC_COMMAND_CACHE"; fi; } #find all directories containing .info files that start with $1 # list is returned one per line function __drc_get_modules { # if we can't find the drupal root, then return unsuccessfully -- we're not in a drupal directory. if ! drc_drupal_root="$(__drc_get_drupal_root)"; then return -1; fi; find $drc_drupal_root/modules/ $drc_drupal_root/themes/ $drc_drupal_root/sites/ -type f -name "$1*.info" | sed -r 's_.*/(.*).info_\1_'; } #get the path to the drupal root install. # ! assumes that the file called "index.php" that is closest to the current directory # (tracing upwards through the directory structure) # that contains '// $Id: index.php,' # is in the Drupal root install directory. # results to sth like "/var/www/vhosts/example.com" - no new line at its end function __drc_get_drupal_root { local root; INDEX_PHP_CANDIDATES=(./index.php ../index.php ../../index.php ../../../index.php ../../../../index.php ../../../../../index.php ../../../../../../index.php); if ! root="$(dirname $(grep -l '//\s*$Id:\s*index.php,' "${INDEX_PHP_CANDIDATES[@]}" 2>/dev/null) 2>/dev/null)"; then #if we did not find Drupal's index.php, return unsuccessfully -- we're not in a drupal directory. return -1; fi; echo "$root"; } ##The func that bash uses for drush completion. _drush_completion() { oldIFS="$IFS"; #set up completion data structures local word; local drc_word_list; # get drush command list IFS=$'\n'; drc_commands=("$(__drc_get_commands)"); drc_commands_re="($(echo "${drc_commands[*]}" |tr '\n' '|'))"; # init the array with the reply COMPREPLY=(); #parse existing command line -- parts of commands get precedence. set -- "${COMP_WORDS[@]}"; shift; # shift out the drush command if [[ $1 =~ -.* ]]; then shift; fi; #ignore option parameters # test for help request local help; if [[ $1 == help ]]; then help=1; shift; if [[ $1 =~ -.* ]]; then shift; fi; #shift and ignore option parameters fi; local prefix="$(echo "$@" |sed 's/\S*$//')"; local matching_commands=($(echo "${drc_commands[*]}" |grep "^$(echo "$@")" |if (( ${#prefix} > 0 )); then sed "s/$prefix//"; else cat -; fi;)); if (( ${#matching_commands[@]} == 0 )) && ! [ $help ]; then # if there are no matching command completions shopt -s extglob; case "$1" in @(enable|disable|uninstall|update|updatecode|info)) shift; if [[ $1 =~ -.* ]]; then shift; fi; #shift and ignore option parameters COMPREPLY=($(__drc_get_modules "$@" | grep "^$(echo "$@")" )) ; esac; else COMPREPLY=("${matching_commands[@]}"); fi; IFS="$oldIFS"; } complete -F _drush_completion d dr drush drush.php