OS X GUI access to a shared directory stack

gdirs

screenshot


pushd just doesn't cut it in a multi-terminal session GUI environment. I never could get used to the directory stack idea, especially when each shell session is isolated from all of the others.  But I wanted a way of returning to previously visited directories with a minimum of typing.  I also wanted a way of getting there easily with the finder.  Hence  gdirs which is very loosly modelled after the dirs command associated with pushd.  Along the way I had to make several functions and aliases to get it all to work properly.


If you want to use this with zsh on OS X, by FAR the easiest thing to do is to install my zsh template scripts, as this will work right out of the box (starting with version 0.4.0).  This page is to explain a bit of what I made, so that you can understand it and hopefully modify and improve it.



How to use it:


Type gdirs and you will get a pop-up window that displays up to twenty previoiusly visited directories.  Pick whatever directory you want and hit "OK" and the terminal will cd to that directory.  Type
gdirs -f and both the terminal and Finder will change to the newly selected directory.  Type gdirs -F and only the Finder will change to the newly selected directory.

The non-gui version is (at present) a bit more flexible and fully-featured.  Type dirstack [n] where n is an integer [defaults to 20] and you will get the n most recent directories visited, listed with numbers next to them.  The command cd? is the same.  Then you can type (eg) cd7 and the terminal will change directory to that listed on line 7 of the dirstack output. cp7 or cpath7 copies the directory path in line 7 into the clipboard copy/paste buffer.



I have defined the following aliases in my aliases.local file:

alias dirstack="dirdump; typeset -U dirs_shared ; dirstack"

alias cd\?="dirdump; typeset -U dirs_shared; dirstack"

alias gdirs="dirdump; typeset -U dirs_shared; dirstack > /dev/null ; _guidirs"




I also autoload the following functions in my functions.local file:

dirdump:

#!/bin/zsh

# use this in conjunction with the local functions
# called chpwd and dirstack

# In an attempt to have a shared directory stack (i.e.,
# shared between different shell sessions), this appends
# the pwd onto the bottom of a file called ~/.zdirdump

print $PWD | perl -pi -e 's| |_SPACE_|g'  >>| ~/.zdirdump

# Now create an array called global_dirs.  It is generated
# from the entries in the above file.

 junk=()
 junk=( $(cat ~/.zdirdump ) )

lines=${#junk}

for (( i = 1; i <=$lines; i++ )) do 
    if [[ -n $junk[i] ]];then
invjunk[i]=$junk[-i]
fi
done

 dirs_shared=( $invjunk )
 export dirs_shared




dirstack:


#!/bin/zsh

# usage:   dirsize [n]

# n = # of lines of directory stack printed
# if n is not given, default to 20

# command to update and then print out the shared directory stack

# aliases a series of cd-type commands corresponding to the line
# number in the directory stack printout

# eg:
#     cd7  will cd to the directory in line #7 of the dirstack printout
#     cd? is aliased to the dirstack command (in the file aliases.local)

#  The commands cp7 and cpath7 are aliases to the same string of commands
#  that copies the directory in line #7 into the clipboard cut/paste buffer

#  cd# and cp# / cpath#  are updated dynamically each time this function is invoked,
#  so always invoke it first with cd? or dirstack


# Here you can change the default 20 most recent directories to
# whatever number suits you.


if [[ -n $1 ]]; then
 GLOBALDIRSIZE=$1
else
 GLOBALDIRSIZE=20
fi

 

 global_dirs=()
 global_dirs=(  $dirs_shared[1,$GLOBALDIRSIZE]  )
 export global_dirs


for ((i = 1; i <= $GLOBALDIRSIZE; i++ )) do        
        if [[ -n $global_dirs[i] ]];then
                print $i $global_dirs[i] | perl -pi -e 's|_SPACE_|\\\ |g'
                dir_index=$(print $global_dirs[i] | perl -pi -e 's|_SPACE_|\\\ |g' )
                alias cd$i="cd $dir_index ; command pwd "
                dir_index_chomp=$(print -n $global_dirs[i] | perl -pi -e 's|_SPACE_|\\\ |g' )

                alias cp$i="echo -n $dir_index_chomp |perl -pi -e 's; ;\\\ ;g' | pbcopy "
                alias cpath$i="echo -n $dir_index_chomp |perl -pi -e 's; ;\\\ ;g' | pbcopy "

        else
                return 0
        fi
done




 _guidirs:

#!/bin/zsh -f

# usage:  gdirs [-fF]

#  gdirs -f cd's both terminal and finder to chosen directory
#  gdirs -F cd's only the Finder to the chosen directory
#  gdirs with no argument changes only the terminal directory

if [[ $1 == '-f' ]];then
 CDD=ON
elif [[ $1 == '-F' ]];then
 CDF=ON
fi

 
# function ChooseFile allows picking from filtered list of files in $PWD
# returns name of chosen file as a string

function ChooseFromStack {
#
# Change this first line for particular filtering needs:
#
# =========>
#

        filelist=($(print $global_dirs | perl -pi -e 's| |\n|g' | perl -pi -e 's|_SPACE_|\*|g' ) )

        item_list=""

        for item in "${filelist[@]}"
        do
                item_list="$item_list""\"${item}\","
        done

        function filepicker {
                osascript << eof
                        tell app "Finder"
                                activate
                                choose from list {${item_list%,}} with prompt "Choose a recent directory: "
                        end tell
eof
        }

        SelectedFile=$(filepicker)

  if [[ $CDD == ON ]];then
    cd "$SelectedFile"; open . ; pwd
  elif [[ $CDF == ON ]];then
    cd "$SelectedFile"; open . ; cd $OLDPWD
  else
        cd  "$SelectedFile"; pwd
  fi
}

ChooseFromStack


chpwd:
   

#!/bin/zsh -f
# chpwd:  when you cd, this runs functions settitle and settab to update title bar and tab in iterm
#
function chpwd {
settab
settitle
dirdump
}


(Note that unless you are using my settitle and settab functions, you only need the dirdump entry between the curly brackets.)



Run these commands on login from somewhere (I use functions.local):
    
    autoload -U dirstack dirdump _guidirs chpwd

    chpwd   #run this command upon login
   
    # keep the ~/.zdirdump file from growing too long (250 entries seems ok)
    tmp_timestamp=$(date | awk '{print $4}')
    command touch ~/.zdirdump
    command cp ~/.zdirdump /tmp/$tmp_timestamp.zdirdump
    command tail -250 /tmp/$tmp_timestamp.zdirdump >| ~/.zdirdump
    command rm -f /tmp/$tmp_timestamp.zdirdump





Click here for web site index Valid HTML 4.01!