Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Two directory navigation facilities



I made up two little facilities to navigate
directories:

1. directory marks. These are similar to named
   directories but are dynamically defined, have
   one letter mnemonics and are automatically
   saved to a file. 

2. directory jump-list. Go back to previous
   directories in cd-history and go forward again.

I'm sure I've duplicated some existing
functionality but it works just as I like and I
learned a lot in the process of doing it.

Just thought I'd share that. Hope someone finds it
useful. Improvements welcome...

**********************************************
 Directory marks
 i.e. This is similar to vi's marks functionality.
      In vicmd mode, type 'ma' to assign marks 'a'
      to the current directory. Then from
      anywhere, in vicmd mode, type ;a to go back
      to the marked directory.
      Type 'marks' to see all marks currently
      defined.
      Marks are saved in a file so persist between
      shell sessions.
**********************************************
ZSH_CONFIG_DIR=~/.zsh
MARKS_FILE=$ZSH_CONFIG_DIR/marks
typeset -A dir_marks
# load marks
if [ -r $MARKS_FILE ] ; then
   while read key value ; do
      dir_marks[$key]=$value
   done < $MARKS_FILE
fi

usage() {
}

marks() { 
   if [ $# -eq 0 ] ; then
      for k in ${(k)dir_marks}; do
         print -r "$k ${(vq)dir_marks[$k]}"
      done
   fi

   while getopts "hld:gs" arg
   do
      case "$arg" in
         l) # Load marks file 
            if [ -r $MARKS_FILE ] ; then
               while read key value ; do
                  dir_marks[$key]=$value
               done < $MARKS_FILE
               return 0
            else
               print -u2 "$MARKS_FILE doesn\'t exist."
               return 1
            fi
            ;;
         d) # Delete marks
            if [ $OPTARG = "ALL" ] ; then
               set -A dir_marks
               rm -f $MARKS_FILE
            elif [ $dir_marks[$OPTARG] ] ; then
               unset "dir_marks[$OPTARG]"
            else
               print -u2 "$0: No such mark \'$OPTARG\'"
            fi
            return 0
            ;;
         g) # Go to mark, let cd handle errors
            builtin cd $dir_marks[$2]
            return 0
            ;;
         s) # Set mark
            if [ $2 -a -z $3 ] ; then
               dir_marks[$2]=${PWD}
            elif [ $2 -a $3 ]  ; then
               dir_marks[$2]=$3
            else
               print -u2 "which mark?"
               return 1
            fi
            for k in ${(k)dir_marks}; do
               print -r "$k ${(vq)dir_marks[$k]}"
            done >| $MARKS_FILE
            ;;

         : ) ;;
      esac
   done
}

zle -N set-dir-mark
zle -N goto-dir-mark
bindkey -M vicmd 'm'   set-dir-mark
bindkey -M vicmd \;    goto-dir-mark

********************
set-dir-mark widget:
********************
read -k mark
if [ $mark = '?' ] ; then
   cat $MARKS_FILE
else
   [ ${mark%
} ] || { print -u2 "$0: Empty mark is illegal."; return 1; }
   dir_marks[$mark]=${PWD}
   print "$mark -> $dir_marks[$mark]"
   marks >| $MARKS_FILE
fi
zle accept-line

********************
goto-dir-mark widget:
********************
read -k mark
builtin cd $dir_marks[$mark]
zle accept-line

*************************************************
 Directory jumplist
 i.e. this is similar to vim's jump functionality.
      typing "ju" or "jumps" will show you all the
      places you've 'cd' to, preceded by a count.
      Type that count and ^o (in vicmd mode) and
      you are back to that directory.

      The difference with directory stacks is that
      when you go back in the 'cd history' (if I
      may call it that), nothing gets popped off
      the stack so you can go forward again to
      where you came from, also using a count.

      Uses a separate directory stack (called
      'jumplist') so all the normal stack
      manipulation functions work normally.
*************************************************
JUMPS_FILE=$ZSH_CONFIG_DIR/jumps
JUMPLIST_SIZE=50
set -A jumplist
integer jumppos=1

_pushd() {
   integer i;
   integer len;

   len=${#jumplist}
   if [ $len -eq $JUMPLIST_SIZE ] ; 
   then 
      len=$JUMPLIST_SIZE-1
   fi

   if [ $len -eq 0 ]
   then
      jumplist[1]=${PWD}
   else
      for ((i=$len; i>0; i--))
      do
         jumplist[(($i+1))]=$jumplist[$i]
      done
      jumplist[1]=${PWD}
   fi
}

_popd() {
   local i;

   [ ${#jumplist} -eq 0 ]        && return 1;
   for ((i=1; i<${#jumplist}; i++))
   do
      jumplist[$i]=$jumplist[(($i+1))]
   done
   jumplist[$i]=()
   return 0;
}

jump_to() {
   local i;

   builtin cd $1
   [ $? -eq 0 ] || return 1;
   if [ $jumppos -gt 1 ] ; then
      for ((i=$jumppos; i>1; i--))
      do
         _popd;
      done
      jumppos=1
   fi
   _pushd
}

jumps() {
   integer i

   # With no argument, print jump list
   if [ $# -eq 0 ] ; then
      for ((i=${#jumplist}; i>0; i--))
      do
         if [ $i -eq $jumppos ] 
         then
            print "$(($i-1)) > $jumplist[$i]"
         else
            print "$(($i-1))   $jumplist[$i]"
         fi
      done
      return 0
   fi

   while getopts "d" arg
   do
      case "$arg" in
         d ) set -A jumplist
             return 0
             ;;
         ? ) ;;
      esac
   done
}

zle -N jump_back
zle -N jump_forward
bindkey -M vicmd '\Co' jump_back
bindkey -M viins '\Co' jump_back
# Can't bind c-i in viins because it's too useful for completion
# (i.e. 'tab') but it works in vicmd mode.
bindkey -M vicmd '\Ci' jump_forward
alias cd=jump_to
alias ju=jumps

********************
jump_back widget:
********************
[ ${#jumplist} -eq 0 ]        && return 1;
if [ ! $NUMERIC ] ; then
   count=1;
else
   count=$NUMERIC
fi

# make sure we don't jump beyond end if list
if [ $(($jumppos+$count)) -gt ${#jumplist} ] ; then
   jumppos=$((${#jumplist}));
else
   jumppos=$(($jumppos+$count));
fi
builtin cd $jumplist[$jumppos]
zle accept-line

********************
jump_forward widget:
********************
[ ${#jumplist} -eq 0 ] && return 1;
if [ ! $NUMERIC ] ; then
   count=1;
else
   count=$NUMERIC
fi

if [ $(($jumppos-$count)) -lt 1 ] ; then
   jumppos=1
else
   jumppos=$(($jumppos-$count));
fi
builtin cd $jumplist[$jumppos]
zle accept-line

-- 
JR



Messages sorted by: Reverse Date, Date, Thread, Author