浏览代码

[wd] New minor version (v0.4)

Markus Faerevaag 9 年之前
父节点
当前提交
6855dd4727
共有 3 个文件被更改,包括 355 次插入79 次删除
  1. 105 5
      plugins/wd/README.md
  2. 5 1
      plugins/wd/_wd.sh
  3. 245 73
      plugins/wd/wd.sh

+ 105 - 5
plugins/wd/README.md

@@ -1,8 +1,60 @@
-## wd
+wd
+==
+
+[![Build Status](https://travis-ci.org/mfaerevaag/wd.png?branch=master)](https://travis-ci.org/mfaerevaag/wd)
+
+`wd` (*warp directory*) lets you jump to custom directories in zsh, without using `cd`. Why? Because `cd` seems ineffecient when the folder is frequently visited or has a long path.
+
+
+### Setup
+
+### oh-my-zsh
+
+`wd` comes bundles with [oh-my-zshell](https://github.com/robbyrussell/oh-my-zsh)!
+
+Just add the plugin in your `~/.zshrc` file:
+
+    plugins=(... wd)
+
+
+#### Automatic
+
+Run either in terminal:
+
+ * `curl -L https://github.com/mfaerevaag/wd/raw/master/install.sh | sh`
+
+ * `wget --no-check-certificate https://github.com/mfaerevaag/wd/raw/master/install.sh -O - | sh`
+
+
+#### Manual
+
+ * Clone this repo to your liking
+
+ * Add `wd` function to `.zshrc` (or `.profile` etc.):
+
+        wd() {
+            . ~/paht/to/wd/wd.sh
+        }
+
+ * Install manpage. From `wd`'s base directory (requires root permissions):
+
+        # cp wd.1 /usr/share/man/man1/wd.1
+        # chmod 644 /usr/share/man/man1/wd.1
+
+    Note, when pulling and updating `wd`, you'll need to do this again in case of changes to the manpage.
+
+
+#### Completion
+
+If you're NOT using [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh) and you want to utelize the zsh-completion feature, you will also need to add the path to your `wd` installation (`~/bin/wd` if you used the automatic installer) to your `fpath`. E.g. in your `~/.zshrc`:
+
+    fpath=(~/path/to/wd $fpath)
+
+Also, you may have to force a rebuild of `zcompdump` by running:
+
+    $ rm -f ~/.zcompdump; compinit
 
-**Maintainer:** [mfaerevaag](https://github.com/mfaerevaag)
 
-`wd` (*warp directory*) lets you jump to custom directories in zsh, without using `cd`. Why? Because `cd` seems ineffecient when the folder is frequently visited or has a long path. [Source](https://github.com/mfaerevaag/wd)
 
 ### Usage
 
@@ -24,6 +76,7 @@
         $ wd ...
 
     This is a wrapper for the zsh `dirs` function.
+    (You might need `setopt AUTO_PUSHD` in your `.zshrc` if you hare not using [oh-my-zshell](https://github.com/robbyrussell/oh-my-zsh)).
 
  * Remove warp point test point:
 
@@ -33,8 +86,55 @@
 
         $ wd ls
 
- * List warp points to current directory
+ * List warp points to current directory, or optionally, path to given warp point:
 
         $ wd show
 
- * Print usage with no opts or the `help` argument.
+ * Remove warp points to non-existent directories.
+
+        $ wd clean
+
+    Use `clean!` to not be prompted with confirmation (force).
+
+ * Print usage with no opts or the `help` argument:
+
+        $ wd help
+
+ * Print the running version of `wd`:
+
+        $ wd --version
+
+ * Specifically set the config file (default `~/.warprc`), which is useful when testing:
+
+        $ wd --config ./file <action>
+
+ * Force `exit` with return code after running. This is not default, as it will *exit your terminal*, though required when testing/debugging.
+
+        $ wd --debug <action>
+
+ * Silence all output:
+
+        $ wd --quiet <action>
+
+
+### Testing
+
+`wd` comes with a small test suite, run with [shunit2](https://code.google.com/p/shunit2/). This can be used to confirm that things are working as it should on your setup, or to demonstrate an issue.
+
+To run, simply `cd` into the `test` directory and run the `tests.sh`.
+
+    $ ./tests.sh
+
+
+### License
+
+The project is licensed under the [MIT-license](https://github.com/mfaerevaag/wd/blob/master/LICENSE).
+
+
+### Finally
+
+If you have issues, feedback or improvements, don't hesitate to report it or submit a pull-request. In the case of an issue, we would much appreciate if you would include a failing test in `test/tests.sh`. Explanation on how to run the tests, read the section "Testing" in this README.
+
+Credit to [altschuler](https://github.com/altschuler) for awesome idea.
+
+Hope you enjoy!

+ 5 - 1
plugins/wd/_wd.sh

@@ -21,7 +21,8 @@ function _wd() {
     'add!:Overwrites existing warp point'
     'rm:Removes the given warp point'
     'ls:Outputs all stored warp points'
-    'show:Outputs all warp points that point to the current directory'
+    'show:Outputs all warp points that point to the current directory or shows a specific target directory for a point'
+    'show:Outputs all warp points that point to the current directory or shows a specific target directory for a point'
     'help:Show this extremely helpful text'
     '..:Go back to last directory'
   )
@@ -43,6 +44,9 @@ function _wd() {
         add)
           _message 'Write the name of your warp point' && ret=0
           ;;
+        show)
+          _describe -t points "Warp points" warp_points && ret=0
+          ;;
       esac
       ;;
   esac

+ 245 - 73
plugins/wd/wd.sh

@@ -7,40 +7,108 @@
 #
 # @github.com/mfaerevaag/wd
 
-
-## variables
-readonly CONFIG=$HOME/.warprc
+# version
+readonly WD_VERSION=0.4
 
 # colors
-readonly BLUE="\033[96m"
-readonly GREEN="\033[92m"
-readonly YELLOW="\033[93m"
-readonly RED="\033[91m"
-readonly NOC="\033[m"
+readonly WD_BLUE="\033[96m"
+readonly WD_GREEN="\033[92m"
+readonly WD_YELLOW="\033[93m"
+readonly WD_RED="\033[91m"
+readonly WD_NOC="\033[m"
 
+## functions
 
-## init
+# helpers
+wd_yesorno()
+{
+    # variables
+    local question="${1}"
+    local prompt="${question} "
+    local yes_RETVAL="0"
+    local no_RETVAL="3"
+    local RETVAL=""
+    local answer=""
+
+    # read-eval loop
+    while true ; do
+        printf $prompt
+        read -r answer
+
+        case ${answer:=${default}} in
+            Y|y|YES|yes|Yes )
+                RETVAL=${yes_RETVAL} && \
+                    break
+                ;;
+            N|n|NO|no|No )
+                RETVAL=${no_RETVAL} && \
+                    break
+                ;;
+            * )
+                echo "Please provide a valid answer (y or n)"
+                ;;
+        esac
+    done
 
-# check if config file exists
-if [ ! -e $CONFIG ]
-then
-    # if not, create config file
-    touch $CONFIG
-fi
+    return ${RETVAL}
+}
 
-# load warp points
-typeset -A points
-while read -r line
-do
-    arr=(${(s,:,)line})
-    key=${arr[1]}
-    val=${arr[2]}
+wd_print_msg()
+{
+    if [[ -z $wd_quiet_mode ]]
+    then
+        local color=$1
+        local msg=$2
 
-    points[$key]=$val
-done < $CONFIG
+        if [[ $color == "" || $msg == "" ]]
+        then
+            print " ${WD_RED}*${WD_NOC} Could not print message. Sorry!"
+        else
+            print " ${color}*${WD_NOC} ${msg}"
+        fi
+    fi
+}
 
+wd_print_usage()
+{
+    cat <<- EOF
+Usage: wd [command] <point>
 
-## functions
+Commands:
+	add <point>	Adds the current working directory to your warp points
+	add! <point>	Overwrites existing warp point
+	rm <point>	Removes the given warp point
+	show		Print warp points to current directory
+	show <point>	Print path to given warp point
+	ls		Print all stored warp points
+	clean!		Remove points warping to nonexistent directories
+
+	-v | --version	Print version
+	-d | --debug	Exit after execution with exit codes (for testing)
+	-c | --config	Specify config file (default ~/.warprc)
+	-q | --quiet	Suppress all output
+
+	help		Show this extremely helpful text
+EOF
+}
+
+wd_exit_fail()
+{
+    local msg=$1
+
+    wd_print_msg $WD_RED $1
+    WD_EXIT_CODE=1
+}
+
+wd_exit_warn()
+{
+    local msg=$1
+
+    wd_print_msg $WD_YELLOW $msg
+    WD_EXIT_CODE=1
+}
+
+# core
 
 wd_warp()
 {
@@ -50,7 +118,7 @@ wd_warp()
     then
         if [ $#1 < 2 ]
         then
-            wd_print_msg $YELLOW "Warping to current directory?"
+            wd_exit_warn "Warping to current directory?"
         else
             (( n = $#1 - 1 ))
             cd -$n > /dev/null
@@ -59,7 +127,7 @@ wd_warp()
     then
         cd ${points[$point]}
     else
-        wd_print_msg $RED "Unknown warp point '${point}'"
+        wd_exit_fail "Unknown warp point '${point}'"
     fi
 }
 
@@ -70,24 +138,28 @@ wd_add()
 
     if [[ $point =~ "^[\.]+$" ]]
     then
-        wd_print_msg $RED "Warp point cannot be just dots"
+        wd_exit_fail "Warp point cannot be just dots"
     elif [[ $point =~ "(\s|\ )+" ]]
     then
-        wd_print_msg $RED "Warp point should not contain whitespace"
+        wd_exit_fail "Warp point should not contain whitespace"
     elif [[ $point == *:* ]]
     then
-        wd_print_msg $RED "Warp point cannot contain colons"
+        wd_exit_fail "Warp point cannot contain colons"
     elif [[ $point == "" ]]
     then
-        wd_print_msg $RED "Warp point cannot be empty"
+        wd_exit_fail "Warp point cannot be empty"
     elif [[ ${points[$2]} == "" ]] || $force
     then
         wd_remove $point > /dev/null
-        printf "%q:%q\n" "${point}" "${PWD}" >> $CONFIG
+        printf "%q:%q\n" "${point}" "${PWD}" >> $WD_CONFIG
+
+        wd_print_msg $WD_GREEN "Warp point added"
 
-        wd_print_msg $GREEN "Warp point added"
+        # override exit code in case wd_remove did not remove any points
+        # TODO: we should handle this kind of logic better
+        WD_EXIT_CODE=0
     else
-        wd_print_msg $YELLOW "Warp point '${point}' already exists. Use 'add!' to overwrite."
+        wd_exit_warn "Warp point '${point}' already exists. Use 'add!' to overwrite."
     fi
 }
 
@@ -97,20 +169,21 @@ wd_remove()
 
     if [[ ${points[$point]} != "" ]]
     then
-        if sed -i.bak "s,^${point}:.*$,,g" $CONFIG
+        local config_tmp=$WD_CONFIG.tmp
+        if sed -n "/^${point}:.*$/!p" $WD_CONFIG > $config_tmp && mv $config_tmp $WD_CONFIG
         then
-            wd_print_msg $GREEN "Warp point removed"
+            wd_print_msg $WD_GREEN "Warp point removed"
         else
-            wd_print_msg $RED "Something bad happened! Sorry."
+            wd_exit_fail "Something bad happened! Sorry."
         fi
     else
-        wd_print_msg $RED "Warp point was not found"
+        wd_exit_fail "Warp point was not found"
     fi
 }
 
 wd_list_all()
 {
-    wd_print_msg $BLUE "All warp points:"
+    wd_print_msg $WD_BLUE "All warp points:"
 
     while IFS= read -r line
     do
@@ -120,66 +193,146 @@ wd_list_all()
             key=${arr[1]}
             val=${arr[2]}
 
-            printf "%20s  ->  %s\n" $key $val
+            if [[ -z $wd_quiet_mode ]]
+            then
+                printf "%20s  ->  %s\n" $key $val
+            fi
         fi
-    done <<< $(sed "s:${HOME}:~:g" $CONFIG)
+    done <<< $(sed "s:${HOME}:~:g" $WD_CONFIG)
 }
 
 wd_show()
 {
-    local cwd=$(print $PWD | sed "s:^${HOME}:~:")
-
-    wd_print_msg $BLUE "Warp points to current directory:"
-    wd_list_all | grep -e "${cwd}$"
+    local name_arg=$1
+    # if there's an argument we look up the value
+    if [[ ! -z $name_arg ]]
+    then
+        if [[ -z $points[$name_arg] ]]
+        then
+            wd_print_msg $WD_BLUE "No warp point named $name_arg"
+        else
+            wd_print_msg $WD_GREEN "Warp point: ${WD_GREEN}$name_arg${WD_NOC} -> $points[$name_arg]"
+        fi
+    else
+        # hax to create a local empty array
+        local wd_matches
+        wd_matches=()
+        # do a reverse lookup to check whether PWD is in $points
+        if [[ ${points[(r)$PWD]} == $PWD ]]
+        then
+            for name in ${(k)points}
+            do
+                if [[ $points[$name] == $PWD ]]
+                then
+                    wd_matches[$(($#wd_matches+1))]=$name
+                fi
+            done
+
+            wd_print_msg $WD_BLUE "$#wd_matches warp point(s) to current directory: ${WD_GREEN}$wd_matches${WD_NOC}"
+        else
+            wd_print_msg $WD_BLUE "No warp points to $cwd"
+        fi
+    fi
 }
 
-wd_print_msg()
-{
-    local color=$1
-    local msg=$2
+wd_clean() {
+    local force=$1
+    local count=0
+    local wd_tmp=""
+
+    while read line
+    do
+        if [[ $line != "" ]]
+        then
+            arr=(${(s,:,)line})
+            key=${arr[1]}
+            val=${arr[2]}
 
-    if [[ $color == "" || $msg == "" ]]
+            if [ -d "$val" ]
+            then
+                wd_tmp=$wd_tmp"\n"`echo $line`
+            else
+                wd_print_msg $WD_YELLOW "Nonexistent directory: ${key} -> ${val}"
+                count=$((count+1))
+            fi
+        fi
+    done < $WD_CONFIG
+
+    if [[ $count -eq 0 ]]
     then
-        print " ${RED}*${NOC} Could not print message. Sorry!"
+        wd_print_msg $WD_BLUE "No warp points to clean, carry on!"
     else
-        print " ${color}*${NOC} ${msg}"
+        if $force || wd_yesorno "Removing ${count} warp points. Continue? (Y/n)"
+        then
+            echo $wd_tmp >! $WD_CONFIG
+            wd_print_msg $WD_GREEN "Cleanup complete. ${count} warp point(s) removed"
+        else
+            wd_print_msg $WD_BLUE "Cleanup aborted"
+        fi
     fi
 }
 
-wd_print_usage()
-{
-    cat <<- EOF
-Usage: wd [add|-a|--add] [rm|-r|--remove] <point>
+local WD_CONFIG=$HOME/.warprc
+local WD_QUIET=0
+local WD_EXIT_CODE=0
+local WD_DEBUG=0
 
-Commands:
-	add	Adds the current working directory to your warp points
-	add!	Overwrites existing warp point
-	rm	Removes the given warp point
-	show	Outputs warp points to current directory
-	ls	Outputs all stored warp points
-	help	Show this extremely helpful text
-EOF
-}
+# Parse 'meta' options first to avoid the need to have them before
+# other commands. The `-D` flag consumes recognized options so that
+# the actual command parsing won't be affected.
 
+zparseopts -D -E \
+    c:=wd_alt_config -config:=wd_alt_config \
+    q=wd_quiet_mode -quiet=wd_quiet_mode \
+    v=wd_print_version -version=wd_print_version \
+    d=wd_debug_mode -debug=wd_debug_mode
 
-## run
+if [[ ! -z $wd_print_version ]]
+then
+    echo "wd version $WD_VERSION"
+fi
+
+if [[ ! -z $wd_alt_config ]]
+then
+    WD_CONFIG=$wd_alt_config[2]
+fi
+
+# check if config file exists
+if [ ! -e $WD_CONFIG ]
+then
+    # if not, create config file
+    touch $WD_CONFIG
+fi
+
+# load warp points
+typeset -A points
+while read -r line
+do
+    arr=(${(s,:,)line})
+    key=${arr[1]}
+    val=${arr[2]}
+
+    points[$key]=$val
+done < $WD_CONFIG
 
 # get opts
-args=$(getopt -o a:r:lhs -l add:,rm:,ls,help,show -- $*)
+args=$(getopt -o a:r:c:lhs -l add:,rm:,clean\!,ls,help,show -- $*)
 
-# check if no arguments were given
-if [[ $? -ne 0 || $#* -eq 0 ]]
+# check if no arguments were given, and that version is not set
+if [[ ($? -ne 0 || $#* -eq 0) && -z $wd_print_version ]]
 then
     wd_print_usage
 
-# check if config file is writeable
-elif [ ! -w $CONFIG ]
+    # check if config file is writeable
+elif [ ! -w $WD_CONFIG ]
 then
     # do nothing
     # can't run `exit`, as this would exit the executing shell
-    wd_print_msg $RED "\'$CONFIG\' is not writeable."
+    wd_exit_fail "\'$WD_CONFIG\' is not writeable."
 
 else
+
+    # parse rest of options
     for o
     do
         case "$o"
@@ -205,7 +358,15 @@ else
                 break
                 ;;
             -s|--show|show)
-                wd_show
+                wd_show $2
+                break
+                ;;
+            -c|--clean|clean)
+                wd_clean false
+                break
+                ;;
+            -c!|--clean!|clean!)
+                wd_clean true
                 break
                 ;;
             *)
@@ -229,8 +390,19 @@ unset wd_remove
 unset wd_show
 unset wd_list_all
 unset wd_print_msg
+unset wd_yesorno
 unset wd_print_usage
+unset wd_alt_config
+unset wd_quiet_mode
+unset wd_print_version
 
 unset args
 unset points
 unset val &> /dev/null # fixes issue #1
+
+if [[ ! -z $wd_debug_mode ]]
+then
+    exit $WD_EXIT_CODE
+else
+    unset wd_debug_mode
+fi