public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: Zach Forrest <zach@disinformation.ca>
To: gentoo-dev@gentoo.org
Subject: [gentoo-dev] latest and greatest gentoo.completion
Date: Tue, 12 Mar 2002 17:05:15 -0800	[thread overview]
Message-ID: <3C8EA5CB.5070108@disinformation.ca> (raw)

[-- Attachment #1: Type: text/plain, Size: 136 bytes --]

I've made some significant changes incorporating the latest available 
options and making the completion more intelligent. Enjoy!

Zach

[-- Attachment #2: gentoo.completion --]
[-- Type: text/plain, Size: 13297 bytes --]

# -*- shell-script -*-
#
# Gentoo Linux command completion.
#
# Copyright 1999-2002 Gentoo Technologies, Inc.
# Distributed under the terms of the GNU General Public License, v2 or later
#
# Author: Geert Bevin  <gbevin@theleaf.be>
# Author: Zach Forrest <zach@disinformation.ca>
#

# Turn on extended globbing and programmable completion
shopt -s extglob progcomp


#
# emerge completion command
#
_emerge()
{
	local cur prev grepcmd sedcmd systemactions setsma setbig portagedir origdir
	local mode words opts curword numwords pkgdbdir

	origdir="${PWD}"
	portagedir=/usr/portage
	pkgdbdir=/var/db/pkg
	COMPREPLY=()
	cur="${COMP_WORDS[COMP_CWORD]}"
	prev="${COMP_WORDS[COMP_CWORD-1]}"
	words="${COMP_WORDS[*]}"
	numwords=${#COMP_WORDS[*]}
	curword=${COMP_CWORD}
	mode='ALL'

	# Determine which mode we're running in.

	if [ ${curword} -eq 1 ] && [ ${numwords} -eq 2 ]; then
		# This is set when we nothing but the command name has been given.
		mode='ALL'
	elif [[ " ${words} " == *" --unmerge "* ]]; then
		mode='UNMERGE'
	elif [[ " ${words} " == *" --safe "* ]]; then
		mode='SAFE'
	elif [[ " ${words} " == *" --search "* ]]; then
		mode='SEARCH'
	elif [[ " ${words} " == *" --world "* ]]; then
		mode='WORLD'
	elif [[ " ${words} " == *" --help "* ]]; then
		mode='HELP'
	elif [[ " ${words} " == *" --clean "* ]]; then
		mode='CLEAN'
	elif [[ " ${words} " == *" --pretend "* ]]; then
		mode='PRETEND'
	else
		# All except '--clean'
		mode='NOCLEAN'
	fi

	if [[ "${cur}" == -* ]]; then

		# Process Options

		case "${mode}" in
			"ALL")
				opts='--clean --help --verbose --debug --fetchonly \
					--onlydeps --noreplace --usepkg --buildpkg \
					--autoclean --pretend --unmerge --safe \
					--search --world'
				;;

			"UNMERGE")
				opts='--clean --verbose --debug --pretend \
					--unmerge --safe'
				;;

			"SAFE")
				opts='--unmerge --verbose --debug'
				;;

			"SEARCH")
				opts='--verbose --debug'
				;;

			"WORLD")
				opts='--verbose --debug --pretend --world'
				;;

			"HELP")
				opts=''
				;;

			"CLEAN")
				opts='--verbose --debug --clean'
				;;

			"PRETEND")
				opts='--verbose --debug --fetchonly --onlydeps \
					--noreplace --usepkg --buildpkg \
					--autoclean --pretend --unmerge --safe \
					--world'
				;;

			"NOCLEAN")
				opts='--help --verbose --debug --fetchonly \
					--onlydeps --noreplace --usepkg --buildpkg \
					--autoclean --pretend --unmerge --safe \
					--search --world'
				;;
			*)
				# Same as ALL
				opts='--clean --help --verbose --debug --fetchonly \
					--onlydeps --noreplace --usepkg --buildpkg \
					--autoclean --pretend --unmerge --safe \
					--search --world'
				;;

		esac
		
		# Generate the reply.
		COMPREPLY=($(compgen -W "${opts}" | grep ^$cur))

	elif [ "${mode}" == "CLEAN" ]; then
		# "rsync" is the only option that can follow "--clean"
		COMPREPLY=($(compgen -W 'rsync'))

	elif [ "${mode}" == "WORLD" ]; then
		# "update" is the only option that can follow "--world"
		#COMPREPLY=($(compgen -W 'update'))
		COMPREPLY=($(compgen -W 'update' | grep ^${cur}))

	elif [ "${mode}" == "HELP" ]; then
		if [[ ! " ${words} " == *" "@(system|rsync)" "* ]]; then
			COMPREPLY=($(compgen -W 'rsync system' | grep ^${cur}))
		else
			COMPREPLY=''
		fi

	elif [ "${mode}" == "SEARCH" ]; then
		# We don't need to interfere here as the search string is a
		# regular expression. (But wouldn't intelligent, dynamic,
		# commandline completion of regular expressions be great!)
		COMPREPLY=''

	elif [ "${mode}" == "UNMERGE" ]; then
		# Ignore >, >=, <, <=, and = for the purpose of completion.
		sedcmd="sed -e s:=:: -e s:>:: -e s:<::"
		cur=$(echo "${cur}" | ${sedcmd})

		# If the current completion (minus conditional characters)
		# starts with one of the following characters, then complete
		# on filenames (i.e. an ebuild file) rather than referencing
		# the package database.
		if [[ "${cur} " == @('/'|'.'|'~'|'$')* ]]; then
			# Setting this to nothing with tell bash to use default
			# completion (i.e. pathname completion).
			COMPREPLY=''
		else
			cd "${pkgdbdir}"
			grepcmd="grep -E ^$cur.*"

			if [ "${cur}" ]; then
				if [ $(echo "${cur}" | grep '/') ]; then
					setbig=$(compgen -G "${cur}*")
					COMPREPLY=($(echo "${setbig}" | ${grepcmd}))
				else
					setsma=$(compgen -S '/' -G "${cur}*")
					if [ $(echo "${setsma}" | ${grepcmd} | grep '/' | wc -l) = 1 ]; then
						setbig=$(compgen -G "*/*")
						COMPREPLY=($(echo "${setbig}" | ${grepcmd}))
					else
						COMPREPLY=($(echo "${setsma}" | ${grepcmd}))
					fi
				fi
			else
				setsma=$(compgen -S '/' -G "${cur}*")
				COMPREPLY=($(echo "${setsma}"))
			fi

			cd "${origdir}"
		fi

	elif [ "${mode}" == "SAFE" ]; then
		COMPREPLY=($(compgen -W '--unmerge' | grep ^${cur}))

	elif [[ " ${words} " == *" "@(update|system|rsync)" "* ]]; then
 		# syncing the portage tree is a lonely job
 		# updating should be done by itself (also lonely)
  		COMPREPLY=''

	elif [[ " ${words} " == *" --usepkg "* ]] && [[ "${cur} " == @('/'|'.'|'~'|'$')* ]]; then
		# In order to complete on a package file, the name must be
		# an absolute or realative pathname (even if it is in the
		# current directory). This allows completion on both package
		# names in /usr/portage and on arbitrary *.tbz2 packages.
		#
		# I'm planning to come up with a more elegant solution, but
		# that will have to wait for another update. (The only thing
		# that is really annoying right now is when specifying a
		# *.tbz2 file in or below the current directory, you have
		# to prefix the path with "./".)
		COMPREPLY=''

	else
		cd "${portagedir}"
		grepcmd="grep -E ^${cur}.*"
		sedcmd="sed -e /CVS/d \
			-e /BUGS-TODO/d \
			-e /ChangeLog.*/d \
			-e /header.txt/d \
			-e /skel.build/d \
			-e /skel.ebuild/d \
			-e /distfiles/d \
			-e /eclass/d \
			-e /files/d \
			-e /incoming/d \
			-e /packages/d \
			-e /profiles/d \
			-e /scripts/d \
			-e /virtual-update/d \
			-e /current-packages/d"

		if [ ${COMP_CWORD} -eq 1 ]; then
			# If emerge hasn't been given any args yet, include "rsync"
			# among the system actions. The case where the "--clean" flag
			# has been specified is handled above.
			systemactions=$'\n'"system"$'\n'"update"$'\n'"rsync"
		else
			# Only allow these actions if no packages have been specified.
			if [[ ! " ${words} " == *" "*[/]*" "* ]]; then
				systemactions=$'\n'"system"$'\n'"update"
			else
				systemactions=''
			fi
		fi

		if [ "${cur}" ]; then
			if [ $(echo "${cur}" | grep '/') ]; then
				setbig=$(compgen -G "${cur}*" | ${sedcmd})"${systemactions}"
				COMPREPLY=($(echo "${setbig}" | $grepcmd))
			else
				setsma=$(compgen -S '/' -G "${cur}*" | ${sedcmd})"${systemactions}"
				if [ $(echo "${setsma}" | ${grepcmd} | grep '/' | wc -l) = 1 ]; then
					setbig=$(compgen -G "*/*" | ${sedcmd})"${systemactions}"
					COMPREPLY=($(echo "${setbig}" | ${grepcmd}))
				else
					COMPREPLY=($(echo "${setsma}" | ${grepcmd}))
				fi
			fi
		else
                        setsma=$(compgen -S '/' -G "${cur}*" | ${sedcmd})"${systemactions}"
                        COMPREPLY=($(echo "${setsma}"))
		fi

		cd "${origdir}"
	fi

	# (Adapted from bash_completion by Ian Macdonald <ian@caliban.org>)
	# This removes any options from the list of completions that have
	# already been specified on the command line.
	COMPREPLY=($(echo "${COMP_WORDS[@]}" | \
			(while read -d ' ' i; do
				[ "${i}" == "" ] && continue
				# flatten array with spaces on either side,
				# otherwise we cannot grep on word boundaries of
				# first and last word
				COMPREPLY=" ${COMPREPLY[@]} "
				# remove word from list of completions
				COMPREPLY=(${COMPREPLY/ ${i%% *} / })
			done
			echo ${COMPREPLY[@]})))
		
	return 0
}
complete -o default -F _emerge emerge

#
# ebuild completion command
#
_ebuild()
{
	local cur prev

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}
	prev=${COMP_WORDS[COMP_CWORD-1]}
		
	if [ $COMP_CWORD -eq 1 ]; then
		#COMPREPLY=( $( compgen -o filenames -X '!*.ebuild' $cur ) )
		COMPREPLY=( $( compgen -o filenames ) )

	elif [ $COMP_CWORD -eq 2 ]; then
		COMPREPLY=( $( compgen -W 'clean \
			compile \
			digest \
			fetch \
			install \
			merge \
			package \
			qmerge \
			remerge \
			rpm \
			unmerge \
			unpack' $cur ) )
	fi

	return 0
}
complete -o default -F _ebuild ebuild

#
# rc-update completion command
#
_rc-update()
{
	local cur prev initdir runlvdir origdir

	origdir=${PWD}
	initdir=/etc/init.d
	runlvdir=/etc/runlevels

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}
	prev=${COMP_WORDS[COMP_CWORD-1]}
		
	if [ $COMP_CWORD -eq 1 ]; then
		COMPREPLY=( $( compgen -W 'add del' ${cur} ) )
	elif [ $COMP_CWORD -eq 2 ]; then
		cd ${initdir}
		COMPREPLY=( $( compgen -G "${cur}*" ) )
		cd ${origdir}
	elif [ $COMP_CWORD -eq 3 ]; then
		cd ${runlvdir}
		COMPREPLY=( $( compgen -G "${cur}*" ) )
		cd ${origdir}
	fi

	return 0
}
complete -F _rc-update rc-update

#
# This function loosely emulates emerge, but, as the name implies,
# it _unmerges_. It is useful for unmerging multiple, existing packages
# with a lot less typing. It looks in /var/db/pkg.
#
epurge() {
	local pkg pkgdb pkgfile usage pretend red yellow off
	local pkgnover pkgcount depend

	red="\033[31;01m"      # Red
	yellow="\033[33;01m"  # Yellow
	off="\033[0m"           # Default

	pkgdb="/var/db/pkg"
	usage="Usage: ${FUNCNAME} [ --pretend ] cat/pkg [ [ cat2/pkg2 ] ... ]"
	count=0

	# We need at least one package
	if [ -z "${1}" ]; then
		echo "${usage}"
		return 1
	fi

	if [ "${1}" = "--pretend" ]; then
		# We need at least one package
		if [ -z "${2}" ]; then
			echo "${usage}"
			return 1
		else
			shift # move "--pretend" out of the way
			pretend="TRUE"
			echo
			echo "These are the packages that I would unmerge, in order."
		fi
	fi

	# The following may seem a little overzealous. After all, why not just check
	# for the existence of the files during the main loop? My rationale is this:
	# because unmerging has the potential to do serious damage (e.g. unmerging your
	# only glibc entry), any problems should be addressed _before_ any packages are
	# unmerged. This will provide one extra sanity check for the user; if there
	# is one mistake, there may be others. Also, because this function isn't the
	# most sophisticated piece of code in the world, if a package was specified
	# more than once on the command line, the main loop can now assume (with a
	# reasonable degree of certainty) that any missing ebuild files are from
	# packages that have already been unmerged  (i.e. if the file doesn't exist,
	# it must have been unmerged with a previous call to ebuild).
	# Enough talk....

	for pkg in $*
	do
		pkgfile="${pkgdb}/${pkg}/$( basename ${pkg} ).ebuild"
		if [ ! -f "${pkgfile}"  ]; then
			echo
			echo -e "${red}!!!${off} Cannot find database entry for $pkg:"
			echo -e "${red}!!!${off} $pkgfile not found"
			echo
			return 1
		fi
	done

	# Make some room.
	echo

	for pkg in $*
	do
		if [ "${pretend}" = "TRUE" ]; then
			echo -e "[ebuild ${red}UNMERGE${off}] $pkg"

			# Calculate dependencies
			#
			# Note: This doesn't (yet) account for version numbers 
			# in calculating dependencies. So, if a package requires
			# a specific version of the one being unmerged, and this
			# is that version, then you may end up with a broken
			# package/dependency. Also, dependency checking is only
			# performed when using "--pretend". When actually
			# unmerging packages, it is assumed that you know what
			# you are doing.
			# 
			# TODO: make version aware
			# TODO: check for PROVIDES (i.e. virtual dependencies)

			pkgnover="${pkg%%-[0-9]*}"
			pkgcount=$( ls "${pkgdb}/${pkg%%/*}" | grep -c ${pkgnover##*/} )

			# If there exists another installed version of the package,
			# then assume any dependencies are taken care of (see note
			# above). Otherwise, check for packages dependent on this
			# one.
			if [ ${pkgcount} -eq 1 ]; then
				for depend in $( egrep -l ${pkgnover} $( find ${pkgdb} -name RDEPEND ) \
					| sed -e "s|/RDEPEND||" -e "s|${pkgdb}/||" )
				do
					echo -e "${yellow}!!! WARNING:${off} $depend depends on $pkgnover"
				done
			fi
		else
			pkgfile=${pkgdb}/${pkg}/$( basename ${pkg} ).ebuild
			if [ -f "${pkgfile}" ]; then
				echo ">>> Unmerging ${pkg}...."
				echo ">>> ebuild ${pkgfile} unmerge"
				ebuild ${pkgfile} unmerge
				echo ">>> ${pkg} unmerged"
			else
				echo
				echo "!!! Ignoring ${pkg} (already unmerged)" # most likely, anyway
				echo
			fi
		fi
	done

	echo

	return 0
}

#
# epurge completion command
#
_epurge()
{
	local cur origdir pkgdb grepcmd setsma setbig

	origdir="${PWD}"
	pkgdb=/var/db/pkg

	COMPREPLY=()
	cur=${COMP_WORDS[COMP_CWORD]}

	if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
		COMPREPLY=( $( compgen -W '--pretend' | grep ^$cur ) )
	else
		cd ${pkgdb}
		grepcmd="grep -E ^${cur}.*"

		setsma=$( compgen -S '/' -G "*" )
		setbig=$( compgen -G "*/*" )

		if [ ${cur} ]; then
			if [ `echo ${cur} | grep '/'` ]; then
				COMPREPLY=( $( echo "${setbig}" | ${grepcmd} ) )
			else
				if [ `echo "${setsma}" | ${grepcmd} | grep '/' | wc -l` = 1 ]; then
					COMPREPLY=( $( echo "${setbig}" | ${grepcmd} ) )
				else
					COMPREPLY=( $( echo "${setsma}" | ${grepcmd} ) )
				fi
			fi
		else
			COMPREPLY=( $( echo "${setsma}" ) )
		fi

		cd ${origdir}
	fi

	return 0
}
complete -F _epurge epurge

             reply	other threads:[~2002-03-13  0:59 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-03-13  1:05 Zach Forrest [this message]
2002-03-13  6:48 ` [gentoo-dev] latest and greatest gentoo.completion Thilo Bangert
2002-03-13 18:30   ` Zach Forrest
2002-03-13 18:56     ` Thilo Bangert
2002-03-14 22:38     ` jboyens
2002-03-16 17:56 ` Ian Smith
2002-03-16 18:05   ` Gerald Schneider
2002-03-16 18:27     ` Ian Smith

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3C8EA5CB.5070108@disinformation.ca \
    --to=zach@disinformation.ca \
    --cc=gentoo-dev@gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox