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

My funky cd replacement



The attached file my own version of "cd" with all the recent
changes and fixes.  On to of a plain cd it does:

When invoked with one directory argument:

 * If the path is a directory, cd into it (the obvious)
 * If it's not:
   - If the path does not exist, strip a trailing ":" (This is
     meant to simplyfy pasting a path from grep or gcc output to
     the shell).
   - If the path ends in one of archive the suffixes
     .tar .tar.gz .tar.bz2 .tgz .TGZ .zip .ZIP .7z .7Z
     strip the suffix and if the rest is a directory, cd into it.
   - If the path is just a file, cd into the containing directory.

When invoked with two arguments:

 * Try replacing all occurances of the first argument with the
   second argument in $PWD.  If any of the results is a directory,
   cd into the first of them.

   E.g. if you are in /aa/bb/aa/dd and there is a directory
   /aa/bb/ac/dd a simple

     cd a c

   will switch to it.  This also works with a blank first argument
   like

     cd "" .1

  to switch from e.g. ~/foo to ~/foo.1

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany
function cd ()
{
	local CDOPTS
	local SHELLOPTS
	local SUFFIXES
	local SUFFIX
	local STRIPCHARS
	local DIR

	SHELLOPTS=(${(Oa)${${(kv)options[(I)*pushd*|cd*|*cd]/off/+o}/on/-o}})
	emulate -L zsh
	set $SHELLOPTS
	setopt EXTENDED_GLOB

	# suffixes of various archives
	SUFFIXES=(.tar .tar.gz .tar.bz2 .tgz .TGZ .zip .ZIP .7z .7Z)
	# characters to strip from the end of the path; this is meant for
	# pasting file names from grep and gcc output without the need to edit
	# them
	STRIPCHARS=":"

	# remove the command options
	while [[ $# > 0 ]]; do
		case "$1" in
			-[qsLP]##)
				CDOPTS=($CDOPTS[@] "$1")
				shift
				;;
			--)
				# end of options
				shift
				break
				;;
			*)
				break
				;;
		esac
	done
	if [[ $# = 1 ]]; then
		if [[ "$1" = "" ]]; then
			# don't handle an empty argument specially
			builtin cd $CDOPTS[@] -- "$1"
			return
		elif [[ "${1#[+-]<0->}" = "" ]]; then
			# don't handle +<n> and -<n> specially
			builtin cd $CDOPTS[@] -- "$1"
			return
		elif [[ -d "$1" ]]; then
			# if it's a directory, cd into it
			builtin cd $CDOPTS[@] -- "$1"
			return
		fi
	fi
	case $# in
	0)
		builtin cd $CDOPTS[@]
		return
		;;
	1)
		local ARG
		ARG="$1"
		if [[ ! -e "$ARG" ]]; then
			# remove trailing garbage
			ARG="${1%[${(q)STRIPCHARS}]}"
			if [[ -d "$ARG" ]]; then
				builtin cd $CDOPTS[@] -- "$ARG"
				return
			fi
		fi
		for SUFFIX in "$SUFFIXES[@]"; do
			# if $ARG has one of the suffixes in the list, strip
			# the suffix and check whether there's a dir with that
			# name
			DIR="${ARG%%${(q)SUFFIX}}"
			if [[ "$DIR" != "$ARG" ]] && [[ -d "$DIR" ]]; then
				builtin cd $CDOPTS[@] -- "$DIR"
				return
			fi
		done
		if [[ -f "$ARG" ]]; then
			# cd into the containing dir
			builtin cd $CDOPTS[@] -- "$(dirname "${ARG:A}")"
			return
		else
			# just try cd
			builtin cd $CDOPTS[@] -- "$ARG"
			return
		fi
		;;
	2)
		# note: the pattern below fails to match the end of the string
		# so it's necessary to handle this separately
		if [[ "$1" = "" ]]; then
			DIR="$PWD$2"
			if [[ -d "$DIR" ]]; then
				builtin cd $CDOPTS[@] -- "$DIR"
				return
			fi
		fi
		integer I
		while DIR="${(I:${I}:)PWD/$1/$2}" && [[ "$DIR" != "$PWD" ]]; do
			if [[ -d "$DIR" ]]; then
				builtin cd $CDOPTS[@] -- "$DIR"
				return
			fi
			I="$[I + 1]"
		done
		builtin cd $CDOPTS[@] "$@"
		return
		;;
	*)
		builtin cd $CDOPTS[@] "$@"
		return
		;;
	esac
}


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