5 # Jump to custom directories in terminal
6 # because `cd` takes too long...
8 # @github.com/mfaerevaag/wd
11 readonly WD_VERSION=0.5.0
14 readonly WD_BLUE="\033[96m"
15 readonly WD_GREEN="\033[92m"
16 readonly WD_YELLOW="\033[93m"
17 readonly WD_RED="\033[91m"
18 readonly WD_NOC="\033[m"
27 local prompt="${question} "
38 case ${answer:=${default}} in
39 "Y"|"y"|"YES"|"yes"|"Yes" )
40 RETVAL=${yes_RETVAL} && \
43 "N"|"n"|"NO"|"no"|"No" )
44 RETVAL=${no_RETVAL} && \
48 echo "Please provide a valid answer (y or n)"
58 if [[ -z $wd_quiet_mode ]]
63 if [[ $color == "" || $msg == "" ]]
65 print " ${WD_RED}*${WD_NOC} Could not print message. Sorry!"
67 print " ${color}*${WD_NOC} ${msg}"
75 Usage: wd [command] [point]
78 <point> Warps to the directory specified by the warp point
79 <point> <path> Warps to the directory specified by the warp point with path appended
80 add <point> Adds the current working directory to your warp points
81 add Adds the current working directory to your warp points with current directory's name
82 rm <point> Removes the given warp point
83 rm Removes the given warp point with current directory's name
84 show <point> Print path to given warp point
85 show Print warp points to current directory
86 list Print all stored warp points
87 ls <point> Show files from given warp point (ls)
88 path <point> Show the path to given warp point (pwd)
89 clean Remove points warping to nonexistent directories (will prompt unless --force is used)
91 -v | --version Print version
92 -d | --debug Exit after execution with exit codes (for testing)
93 -c | --config Specify config file (default ~/.warprc)
94 -q | --quiet Suppress all output
95 -f | --force Allows overwriting without warning (for add & clean)
97 help Show this extremely helpful text
105 wd_print_msg "$WD_RED" "$msg"
113 wd_print_msg "$WD_YELLOW" "$msg"
121 point=$(wd_show "$name_arg")
122 dir=${point:28+$#name_arg+7}
124 if [[ -z $name_arg ]]; then
125 wd_exit_fail "You must enter a warp point"
127 elif [[ -z $dir ]]; then
128 wd_exit_fail "Unknown warp point '${name_arg}'"
140 if [[ $point =~ "^\.+$" ]]
144 wd_exit_warn "Warping to current directory?"
149 elif [[ ${points[$point]} != "" ]]
153 cd ${points[$point]/#\~/$HOME}/$sub
155 cd ${points[$point]/#\~/$HOME}
158 wd_exit_fail "Unknown warp point '${point}'"
167 if [[ $point == "" ]]
169 point=$(basename "$PWD")
172 if [[ $point =~ "^[\.]+$" ]]
174 wd_exit_fail "Warp point cannot be just dots"
175 elif [[ $point =~ "[[:space:]]+" ]]
177 wd_exit_fail "Warp point should not contain whitespace"
178 elif [[ $point =~ : ]] || [[ $point =~ / ]]
180 wd_exit_fail "Warp point contains illegal character (:/)"
181 elif [[ ${points[$point]} == "" ]] || [ ! -z "$force" ]
183 wd_remove "$point" > /dev/null
184 printf "%q:%s\n" "${point}" "${PWD/#$HOME/~}" >> "$WD_CONFIG"
185 if (whence sort >/dev/null); then
186 local config_tmp=$(mktemp "${TMPDIR:-/tmp}/wd.XXXXXXXXXX")
187 # use 'cat' below to ensure we respect $WD_CONFIG as a symlink
188 command sort -o "${config_tmp}" "$WD_CONFIG" && command cat "${config_tmp}" > "$WD_CONFIG" && command rm "${config_tmp}"
191 wd_export_static_named_directories
193 wd_print_msg "$WD_GREEN" "Warp point added"
195 # override exit code in case wd_remove did not remove any points
196 # TODO: we should handle this kind of logic better
199 wd_exit_warn "Warp point '${point}' already exists. Use 'add --force' to overwrite."
207 if [[ "$point_list" == "" ]]
209 point_list=$(basename "$PWD")
212 for point_name in $point_list ; do
213 if [[ ${points[$point_name]} != "" ]]
215 local config_tmp=$(mktemp "${TMPDIR:-/tmp}/wd.XXXXXXXXXX")
216 # Copy and delete in two steps in order to preserve symlinks
217 if sed -n "/^${point_name}:.*$/!p" "$WD_CONFIG" > "$config_tmp" && command cp "$config_tmp" "$WD_CONFIG" && command rm "$config_tmp"
219 wd_print_msg "$WD_GREEN" "Warp point removed"
221 wd_exit_fail "Something bad happened! Sorry."
224 wd_exit_fail "Warp point was not found"
231 wd_print_msg "$WD_BLUE" "All warp points:"
233 entries=$(sed "s:${HOME}:~:g" "$WD_CONFIG")
235 max_warp_point_length=0
236 while IFS= read -r line
242 if [[ length -gt max_warp_point_length ]]
244 max_warp_point_length=$length
248 while IFS= read -r line
256 if [[ -z $wd_quiet_mode ]]
258 printf "%${max_warp_point_length}s -> %s\n" "$key" "$val"
267 ls "${dir/#\~/$HOME}"
273 echo "$(echo "$dir" | sed "s:~:${HOME}:g")"
279 # if there's an argument we look up the value
280 if [[ -n $name_arg ]]
282 if [[ -z $points[$name_arg] ]]
284 wd_print_msg "$WD_BLUE" "No warp point named $name_arg"
286 wd_print_msg "$WD_GREEN" "Warp point: ${WD_GREEN}$name_arg${WD_NOC} -> $points[$name_arg]"
289 # hax to create a local empty array
292 # do a reverse lookup to check whether PWD is in $points
294 if [[ ${points[(r)$PWD]} == "$PWD" ]]
296 for name in ${(k)points}
298 if [[ $points[$name] == "$PWD" ]]
300 wd_matches[$(($#wd_matches+1))]=$name
304 wd_print_msg "$WD_BLUE" "$#wd_matches warp point(s) to current directory: ${WD_GREEN}$wd_matches${WD_NOC}"
306 wd_print_msg "$WD_YELLOW" "No warp point to $(echo "$PWD" | sed "s:$HOME:~:")"
324 if [ -d "${val/#\~/$HOME}" ]
326 wd_tmp=$wd_tmp"\n"`echo "$line"`
328 wd_print_msg "$WD_YELLOW" "Nonexistent directory: ${key} -> ${val}"
334 if [[ $count -eq 0 ]]
336 wd_print_msg "$WD_BLUE" "No warp points to clean, carry on!"
338 if [ ! -z "$force" ] || wd_yesorno "Removing ${count} warp points. Continue? (y/n)"
340 echo "$wd_tmp" >! "$WD_CONFIG"
341 wd_print_msg "$WD_GREEN" "Cleanup complete. ${count} warp point(s) removed"
343 wd_print_msg "$WD_BLUE" "Cleanup aborted"
348 wd_export_static_named_directories() {
349 if [[ ! -z $WD_EXPORT ]]
351 command grep '^[0-9a-zA-Z_-]\+:' "$WD_CONFIG" | sed -e "s,~,$HOME," -e 's/:/=/' | while read -r warpdir ; do
357 local WD_CONFIG=${WD_CONFIG:-$HOME/.warprc}
362 # Parse 'meta' options first to avoid the need to have them before
363 # other commands. The `-D` flag consumes recognized options so that
364 # the actual command parsing won't be affected.
367 c:=wd_alt_config -config:=wd_alt_config \
368 q=wd_quiet_mode -quiet=wd_quiet_mode \
369 v=wd_print_version -version=wd_print_version \
370 d=wd_debug_mode -debug=wd_debug_mode \
371 f=wd_force_mode -force=wd_force_mode
373 if [[ ! -z $wd_print_version ]]
375 echo "wd version $WD_VERSION"
378 if [[ ! -z $wd_alt_config ]]
380 WD_CONFIG=$wd_alt_config[2]
383 # check if config file exists
384 if [ ! -e "$WD_CONFIG" ]
386 # if not, create config file
389 wd_export_static_named_directories
398 # join the rest, in case the path contains colons
399 val=${(j,:,)arr[2,-1]}
405 args=$(getopt -o a:r:c:lhs -l add:,rm:,clean,list,ls:,path:,help,show -- $*)
407 # check if no arguments were given, and that version is not set
408 if [[ ($? -ne 0 || $#* -eq 0) && -z $wd_print_version ]]
412 # check if config file is writeable
413 elif [ ! -w "$WD_CONFIG" ]
416 # can't run `exit`, as this would exit the executing shell
417 wd_exit_fail "\'$WD_CONFIG\' is not writeable."
420 # parse rest of options
427 wd_add "$2" "$wd_force_mode"
431 wd_export_static_named_directories
434 "-r"|"--remove"|"rm")
435 # Passes all the arguments as a single string separated by whitespace to wd_remove
447 "-p"|"--path"|"path")
451 "-h"|"--help"|"help")
455 "-s"|"--show"|"show")
459 "-c"|"--clean"|"clean")
460 wd_clean "$wd_force_mode"
474 ## garbage collection
475 # if not, next time warp will pick up variables from this run
476 # remember, there's no sub shell
488 unset wd_print_version
489 unset wd_export_static_named_directories
494 unset val &> /dev/null # fixes issue #1
496 if [[ -n $wd_debug_mode ]]