#!/bin/bash
#-------------------------- =+- Shell script -+= --------------------------
#
# @file      .bashrc_dirstack
# @date      Thu Dec 21 17:24:38 2006
# @brief
#
# CVS version control block - do not edit manually
#  $RCSfile: .bashrc_dyndirstack,v $
#  $Source: /home/cvs/yoh/public_html/Linux/.files/.bashrc_dyndirstack,v $
#
# Created: Thu Dec 21 17:24:38 2006
#  Commited: $Date: 2007/02/22 18:13:08 $
#  Revision: $Revision: 1.3 $
#
#  Yaroslav Halchenko                                      CS@UNM, CS@NJIT
#  web:     http://www.onerussian.com                      & PSYCH@RUTGERS
#  e-mail:  yoh@onerussian.com                              ICQ#: 60653192
#
# DESCRIPTION (NOTES):
#
# List of functions to implement dynamic DIRSTACK, so it always keeps
# last ${MAXDIRSTACK} entries (with no repeats). Appropriate
# completions are in place ;-)
#
# COPYRIGHT: Yaroslav Halchenko 2006
#
# LICENSE:
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the 
#  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
# On Debian system see /usr/share/common-licenses/GPL for the full license.
#
#-----------------\____________________________________/------------------


: ${MAXDIRSTACK:=30}

dir_list ()
# smth like dirs -lp should be
{
	# unfortunately spaces at the end of filenames will not be
	# treated correctly
	dirs -l 2>/dev/null | sed -e 's/ \//\n\//g'
# | sed 's/ /\\ /g'
}

dir_list_num ()
# smth like dirs -lv should be
{
	dir_list | nl -v0;
}

dir_addcurrent ()
# add current to the list if it is not there
{
	# we need to preserve OLDPWD for cd -
	OLDDIR="$OLDPWD"
	# remember old one
	# only iff we haven't seen it before
	dir_list  | tail -n +2 | \
		egrep -q -e "\B$PWD\>"  || \
		pushd . &>/dev/null
	OLDPWD="$OLDDIR"
}

dir_chdir ()
{

	# add current
	dir_addcurrent
	# actually cd
	builtin cd "$@"
	# lighten up stack if necessary
    [ ${#DIRSTACK[@]} -gt ${MAXDIRSTACK} ] && popd -0 > /dev/null
	# list context without files known to be comming in lots
    ls -I 'Rrun*.*' -I 's1r*.txt'
	# debugging
	# dirs -p
}

dir_popcd ()
# change directory and depending on DOPOP pop or not pop
{
	arg="$1"
	# descriminate if it was simply a directory or a pattern
	# to match
	if echo "$arg" | grep -q '^[0-9]\+$'; then
		newdir=`dir_list_num \
                | egrep "^[[:space:]]*$arg\>" | sed -e 's/^[ 0-9\t]*//g'`
	else
		# we need to shape it a bit in similar way to dir_bc_historycd_cat
		arg=`echo $arg | sed -e 's/^"\(.*\)"/\1/g' \
                             -e 's/\([^\]\) /\1\\\ /g'`
		newdir=`dir_list | tail -n +2 | egrep "^$arg\$" | head -n 1`
		#echo "Guessed name '$newdir'"
	fi
	dir_addcurrent
	[ -z $DOPOP ] || popd +$arg &>/dev/null
	[ -z "$newdir" ] \
		&& echo "Directory matching '$arg' was not found." \
		|| builtin cd "$newdir"
}

#
# callback for bash completions -- will search for appropriate directory
# to be chosen for completion
dir_bc_historycd_cat ()
{
	# shape argument a bit - so it could be specified as "a b" in case
	# if it has spaces
	arg=`echo $2| sed -e 's/^"\(.*\)"/\1/g' \
                      -e 's/\([^\]\) /\1\\\ /g'`
    dir_list | tail -n +2 | grep "$arg" | sed -e 's| |\\ |g'
	return 0
}


#
# This function aims to provide a completion for COMPLETE only iff
# there is a single variant. Otherwise we don't want to screw up the
# line, but we want just to present on the screen possible
# completions
dir_bc_historycd ()
{
	matches_num=`dir_bc_historycd_cat '$1' "$2"| wc -l`

	if [ $matches_num -eq 1 ]; then
		# so we have only 1 match - it is safe to substitute!

		COMPREPLY=( [0]="$(dir_bc_historycd_cat 'XXX' "$2")" )

	else
		# return original name (but not empty!) -- that seems to
		# forbid complition to get into the cmdline (which is what we
		# want since it would place the line which would not complete
		# anylonger to the same set as the original string)
		[ $1 == 'cd' ] || COMPREPLY=( "$2" )
	fi
	return 0
}

# try to complete from DIRSTACK and if not - from dirnames
# add  -o dirnames to include regular directories
complete -F dir_bc_historycd -C dir_bc_historycd_cat  popcd jumpcd jcd pcd

# or complement it any time for cd need to figure out how to make it
# include full names - not only dirnames but menu-complete actually
# does the right thing ;-)
# nevertheless it needs more thinking since otherwise it polutes regular 
# cd command so it doesn't select even if there is only 1 obvious completion
# among directories
#complete -F dir_bc_historycd -C dir_bc_historycd_cat -o plusdirs cd chdir


# the only difference for jump and pop cds is that when doing pop, the
# directory gets removed from stack but then later on inserted by
# dir_addcurrent, so it would move up in the stack
popcd () { DOPOP=1 dir_popcd "$*"; }
jumpcd () { DOPOP= dir_popcd "$*"; }

# quick shortcuts
alias jcd=jumpcd
alias pcd=popcd
alias d=dir_list_num


