Advertisement
Yunga

commacd.bash

Oct 11th, 2014
312
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 5.52 KB | None | 0 0
  1. # from:     https://raw.githubusercontent.com/shyiko/commacd/master/commacd.bash
  2. # see also: http://shyiko.com/2014/10/10/commacd/
  3. # ---------------------------------------------------------------------------
  4. # commacd - a faster way to move around (Bash 3+).
  5. # https://github.com/shyiko/commacd
  6. #
  7. # ENV variables that can be used to control commacd:
  8. #   COMMACD_CD - function to change the directory (by default commacd uses builtin cd and pwd)
  9. #   COMMACD_NOTTY - set it to "on" when you want to suppress user input (= print multiple matches and exit)
  10. #
  11. # @version 0.1.0
  12. # @author Stanley Shyiko <stanley.shyiko@gmail.com>
  13. # @license MIT
  14.  
  15. # turn on case-insensitive search by default
  16. shopt -s nocaseglob
  17.  
  18. _commacd_split() { echo "$1" | sed $'s|/|\\\n/|g' | sed '/^[[:space:]]*$/d'; }
  19. _commacd_join() { local IFS="$1"; shift; echo "$*"; }
  20. _commacd_expand() ( shopt -s extglob nullglob; local ex=($1); printf "%s\n" "${ex[@]}"; )
  21.  
  22. _command_cd() {
  23.   local dir=$1
  24.   if [[ -z "$COMMACD_CD" ]]; then
  25.     builtin cd "$dir" && pwd
  26.   else
  27.     $COMMACD_CD "$dir"
  28.   fi
  29. }
  30.  
  31. # show match selection menu
  32. _commacd_choose_match() {
  33.   local matches=("$@")
  34.   for i in "${!matches[@]}"; do
  35.     printf "%s\t%s\n" "$i" "${matches[$i]}" >&2
  36.   done
  37.   local selection;
  38.   read -e -p ': ' selection >&2
  39.   if [[ -n "$selection" ]]; then
  40.     echo -n "${matches[$selection]}"
  41.   else
  42.     echo -n "$PWD"
  43.   fi
  44. }
  45.  
  46. _commacd_forward_by_prefix() {
  47.   local path="${*%/}/" IFS=$'\n'
  48.   # shellcheck disable=SC2046
  49.   local matches=($(_commacd_expand "$(_commacd_join \* $(_commacd_split "$path"))"))
  50.   case ${#matches[@]} in
  51.     0) echo -n "$PWD";;
  52.     *) printf "%s\n" "${matches[@]}"
  53.   esac
  54. }
  55.  
  56. # jump forward (`,`)
  57. _commacd_forward() {
  58.   if [[ -z "$*" ]]; then return 1; fi
  59.   local IFS=$'\n'
  60.   local dir=($(_commacd_forward_by_prefix "$@"))
  61.   if [[ "$COMMACD_NOTTY" == "on" ]]; then
  62.     printf "%s\n" "${dir[@]}"
  63.     return
  64.   fi
  65.   if [[ ${#dir[@]} -gt 1 ]]; then
  66.     dir=$(_commacd_choose_match "${dir[@]}")
  67.   fi
  68.   _command_cd "$dir"
  69. }
  70.  
  71. # search backward for the vcs root (`,,`)
  72. _commacd_backward_vcs_root() {
  73.   local dir="$PWD"
  74.   while [[ ! -d "$dir/.git" && ! -d "$dir/.hg" && ! -d "$dir/.svn" ]]; do
  75.     dir="${dir%/*}"
  76.     if [[ -z "$dir" ]]; then
  77.       echo -n "$PWD"
  78.       return
  79.     fi
  80.   done
  81.   echo -n "$dir"
  82. }
  83.  
  84. # search backward for the directory whose name begins with $1 (`,, $1`)
  85. _commacd_backward_by_prefix() {
  86.   local prev_dir dir="${PWD%/*}" matches match IFS=$'\n'
  87.   while [[ -n "$dir" ]]; do
  88.     prev_dir="$dir"
  89.     dir="${dir%/*}"
  90.     matches=($(_commacd_expand "$dir/${1}*/"))
  91.     for match in "${matches[@]}"; do
  92.         if [[ "$match" == "$prev_dir/" ]]; then
  93.           echo -n "$prev_dir"
  94.           return
  95.         fi
  96.     done
  97.   done
  98.   # at this point there is still a possibility that $1 is an actual path (passed in
  99.   # by completion or whatever), so let's check that one out
  100.   if [[ -d "$1" ]]; then echo -n "$1"; return; fi
  101.   # otherwise fallback to pwd
  102.   echo -n "$PWD"
  103. }
  104.  
  105. # replace $1 with $2 in $PWD (`,, $1 $2`)
  106. _commacd_backward_substitute() {
  107.   echo -n "${PWD/$1/$2}"
  108. }
  109.  
  110. # choose `,,` strategy based on a number of arguments
  111. _commacd_backward() {
  112.   local dir=
  113.   case $# in
  114.     0) dir=$(_commacd_backward_vcs_root);;
  115.     1) dir=$(_commacd_backward_by_prefix "$@");;
  116.     2) dir=$(_commacd_backward_substitute "$@");;
  117.     *) return 1
  118.   esac
  119.   if [[ "$COMMACD_NOTTY" == "on" ]]; then
  120.     echo -n "${dir}"
  121.     return
  122.   fi
  123.   _command_cd "$dir"
  124. }
  125.  
  126. _commacd_backward_forward_by_prefix() {
  127.   local dir="$PWD" path="${*%/}/" matches match IFS=$'\n'
  128.   if [[ "${path:0:1}" == "/" ]]; then
  129.     # assume that we've been brought here by the completion
  130.     dir=(${path%/}*)
  131.     printf "%s\n" "${dir[@]}"
  132.     return
  133.   fi
  134.   while [[ -n "$dir" ]]; do
  135.     dir="${dir%/*}"
  136.     # shellcheck disable=SC2046
  137.     matches=($(_commacd_expand "$dir/$(_commacd_join \* $(_commacd_split "$path"))"))
  138.     case ${#matches[@]} in
  139.       0) ;;
  140.       *) printf "%s\n" "${matches[@]}"
  141.          return;;
  142.     esac
  143.   done
  144.   echo -n "$PWD"
  145. }
  146.  
  147. # combine backtracking with `, $1` (`,,, $1`)
  148. _commacd_backward_forward() {
  149.   if [[ -z "$*" ]]; then return 1; fi
  150.   local IFS=$'\n'
  151.   local dir=($(_commacd_backward_forward_by_prefix "$@"))
  152.   if [[ "$COMMACD_NOTTY" == "on" ]]; then
  153.     printf "%s\n" "${dir[@]}"
  154.     return
  155.   fi
  156.   if [[ ${#dir[@]} -gt 1 ]]; then
  157.     dir=$(_commacd_choose_match "${dir[@]}")
  158.   fi
  159.   _command_cd "$dir"
  160. }
  161.  
  162. _commacd_completion() {
  163.   local pattern=${COMP_WORDS[COMP_CWORD]} IFS=$'\n'
  164.   # shellcheck disable=SC2088
  165.   if [[ "${pattern:0:2}" == "~/" ]]; then
  166.     # shellcheck disable=SC2116
  167.     pattern=$(echo ~/"${pattern:2}")
  168.   fi
  169.   local completion=($(COMMACD_NOTTY=on $1 "$pattern"))
  170.   if [[ "$completion" == "$PWD" || "${completion// /\\ }" == "$pattern" ]]; then
  171.     return
  172.   fi
  173.   # remove trailing / (if any)
  174.   for i in "${!completion[@]}"; do
  175.     completion[$i]="${completion[$i]%/}";
  176.   done
  177.   COMPREPLY=($(compgen -W "$(printf "%s\n" "${completion[@]}")" -- ''))
  178. }
  179.  
  180. _commacd_forward_completion() {
  181.   _commacd_completion _commacd_forward
  182. }
  183.  
  184. _commacd_backward_completion() {
  185.   _commacd_completion _commacd_backward
  186. }
  187.  
  188. _commacd_backward_forward_completion() {
  189.   _commacd_completion _commacd_backward_forward
  190. }
  191.  
  192. alias ,=_commacd_forward
  193. alias ,,=_commacd_backward
  194. alias ,,,=_commacd_backward_forward
  195.  
  196. complete -o filenames -F _commacd_forward_completion ,
  197. complete -o filenames -F _commacd_backward_completion ,,
  198. complete -o filenames -F _commacd_backward_forward_completion ,,,
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement