Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Two directory navigation facilities
- X-seq: zsh-users 9981
- From: Jean-Rene David <jrdavid@xxxxxxxx>
- To: Zsh User <zsh-users@xxxxxxxxxx>
- Subject: Two directory navigation facilities
- Date: Thu, 2 Mar 2006 13:34:25 -0500
- Mail-followup-to: Zsh User <zsh-users@xxxxxxxxxx>
- Mailing-list: contact zsh-users-help@xxxxxxxxxx; run by ezmlm
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