On Wed, 8 Jun 2011 08:58:00 -0400, Dave Reisner wrote:
On Wed, Jun 08, 2011 at 01:32:36PM +0200, Andrwe wrote:
Hi,

I've improved the bash-completion of rc.d.
I created a patch for latest git
(https://github.com/seblu/arch-initscripts/tree/).

The patched version extracts all actions of an initscript and adds
them to the list of possible actions and only list initscripts
supporting the given action.


Kind regards,
Andrwe

diff --git a/bash-completion b/bash-completion
index 5151972..03ce0e6 100644
--- a/bash-completion
+++ b/bash-completion
@@ -1,22 +1,50 @@
-# rc.d bash completion by Seblu <[email protected]>
-
-_rc.d ()
+# rc.d completion
+#
+#  Author: Andrwe Lord Weber
+#  Mail: lord-weber-andrwe <at> andrwe <dot> org
+#

Ouch. Really? Not going to leave _any_ credit behind for the original
author?

Sorry, forgot to add credits but will definitely.

+which rc.d >/dev/null 2>&1 &&

'type -P', never which.

Thanks for this hint.

+_rc_d()
 {
-       local action="help list start stop reload restart"
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       local caction="${COMP_WORDS[1]}"
-       if ((${COMP_CWORD} == 1)); then
-               COMPREPLY=($(compgen -W "${action}" -- "$cur"))
-       elif [[ "$caction" =~ help|list ]]; then
-               COMPREPLY=()
-       elif [[ "$caction" == start ]]; then
- COMPREPLY=($(comm -23 <(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort) <(cd /run/daemons/ && compgen -f "$cur"|sort)))
-       elif [[ "$caction" =~ stop|restart|reload ]]; then
-               COMPREPLY=($(cd /run/daemons/ && compgen -f "$cur"|sort))
-       elif ((${COMP_CWORD} > 1)); then
- COMPREPLY=($(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort))
+       local cur prev initdir long_opts cmds shoptExtglob
+
+       shoptExtglob="$(shopt -p | grep extglob)"

No grep needed here:

  shopt -p extglob

Thanks for this hint.

We don't use camel case, either.

Didn't know but will respect it now.

+       shopt -s extglob
+
+       long_opts='list help'
+       initdir=/etc/rc.d
+ cmds="$(sed '/#.*sh/,/^.*case\s*"*\${*1}*"*.*/ { /^.*case\s*"*\${*1}*"*.*/!d };s/^.*case\s*"*\${*1}*"*.*/;;/g;/;;/,/^\s*.*)\s*$/ !d;/^\s*.*)\s*$/ !d;/\*/d;/;;/d;s/\s*//g;s/)//g;s/|/ /g' ${initdir}/!(*functions*) | LANG=C sort -u | tr '\n' ' ')"

The default IFS is '\n\t ', so the final tr isn't needed here. This
really should be an array, too.

Done.

+
+       _get_comp_words_by_ref cur prev
+
+       cmd="${COMP_WORDS[1]}"
+
+ if [[ "${cmd}" =~ ^(${cmds// /|}|${long_opts// /|})$ ]] && [ -n "${cmd}" ]; then
+               daemons="$(ls -1 /run/daemons/ | tr '\n' '|')"

Never parse ls. The need for the pipe delimiter isn't obvious either.

pushd /run/daemons &>/dev/null && { daemons=(*); popd &>/dev/null; }

If you really need the pipe delimiter, you can then later:

  ( IFS='|'; echo "${daemons[*]}" )


Is needed for the regex-based check whether it's a valid action and to decrease the amount of listed initscripts.
For now I've removed this functionality.

+               case "${cmd}" in
+                       start)
+ COMPREPLY+=( $( compgen -W '`grep -El "^[ ]*[^ ]*${cmd}[|\)][^ ]*\)*[ ]*$" ${initdir}/* | sed 's#${initdir}/##' | grep -vE "^(${daemons})$"`' -- "$cur" ) )
+                               ;;
+                       stop|restart|reload)
+ COMPREPLY+=( $( compgen -W '`grep -El "^[ ]*[^ ]*${cmd}[|\)][^ ]*\)*[ ]*$" ${initdir}/* | sed 's#${initdir}/##' | grep -E "^(${daemons})$"`' -- "$cur" ) )
+                               ;;
+                       *)
+ COMPREPLY+=( $( compgen -W '`grep -El "^[ ]*[^ ]*${cmd}[|\)][^ ]*\)*[ ]*$" ${initdir}/* | sed 's#${initdir}/##'`' -- "$cur" ) )

We use $() for command substitution, not backticks.

Thanks for the hint.

+                               ;;
+               esac
+       else
+               COMPREPLY=( $( compgen -W '${long_opts} ${cmds}' -- "$cur" ) )
        fi
-}
-complete -F _rc.d rc.d

-# vim: set ts=2 sw=2 ft=sh noet:
+       ${shoptExtglob}
+       return 0
+} &&
+complete -F _rc_d rc.d
+
+# Local variables:
+# mode: shell-script
+# sh-basic-offset: 4
+# sh-indent-comment: t
+# indent-tabs-mode: nil
+# End:
+# vim: ts=2 sw=2 et filetype=sh

A general lack of commenting and an overbearing sense of overcomplicating
things gets a NACK from me.

d

So here is a version which should satisfy your hints.
Why should I always use an array?
It's easier to manipulate a string using bash internals than manipulating an array. Because of that I had to remove a functionality of the script because I don't know how I can merge two arrays by removing all elemts which can be found in both arrays without using multiple for-loops.


Kind regards,
Andrwe
diff --git a/bash-completion b/bash-completion
index 5151972..e751c8c 100644
--- a/bash-completion
+++ b/bash-completion
@@ -1,22 +1,59 @@
-# rc.d bash completion by Seblu <[email protected]>
+# rc.d completion
+#
+#  Author: Andrwe Lord Weber
+#  Mail: lord-weber-andrwe <at> andrwe <dot> org
+#  Credits: Seblu <[email protected]>
+#
 
-_rc.d ()
+# check wheather rc.d command exists
+type -P rc.d >/dev/null 2>&1 &&
+_rc_d()
 {
-	local action="help list start stop reload restart"
-	local cur="${COMP_WORDS[COMP_CWORD]}"
-	local caction="${COMP_WORDS[1]}"
-	if ((${COMP_CWORD} == 1)); then
-		COMPREPLY=($(compgen -W "${action}" -- "$cur"))
-	elif [[ "$caction" =~ help|list ]]; then
-		COMPREPLY=()
-	elif [[ "$caction" == start ]]; then
-		COMPREPLY=($(comm -23 <(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort) <(cd /run/daemons/ && compgen -f "$cur"|sort)))
-	elif [[ "$caction" =~ stop|restart|reload ]]; then
-		COMPREPLY=($(cd /run/daemons/ && compgen -f "$cur"|sort))
-	elif ((${COMP_CWORD} > 1)); then
-		COMPREPLY=($(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort))
+	local cur prev action actions shoptextglob
+
+	# get current extglob status
+	shoptextglob="$(shopt -p extglob)"
+	# set extglob for extended directory listing
+	shopt -s extglob
+
+	# get all possible actions also the initscript specific ones
+	pushd /etc/rc.d/ &>/dev/null && { actions=($(sed '/#.*sh/,/^.*case\s*"*\${*1}*"*.*/ { /^.*case\s*"*\${*1}*"*.*/!d };s/^.*case\s*"*\${*1}*"*.*/;;/g;/;;/,/^\s*.*)\s*$/ !d;/^\s*.*)\s*$/ !d;/\*/d;/;;/d;s/\s*//g;s/)//g;s/|/ /g' !(*functions*) | LANG=C sort -u) list help); popd &>/dev/null; } 
+
+	_get_comp_words_by_ref cur prev
+
+	# get first argument to whether it's a valid action
+	action="${COMP_WORDS[1]}"
+
+	# check if action is is valid/completed
+	if ( IFS='|'; [[ "${action}" =~ ^(${actions[*]})$ ]] ) && [ -n "${action}" ]; then
+
+		# get all running daemons
+		pushd /run/daemons &>/dev/null && { daemons=(*); popd &>/dev/null; }
+
+		# get all initscripts supporting chosen action
+		pushd /etc/rc.d/&>/dev/null && { inits=($(grep -El "^[ ]*[^ ]*${action}[|\)][^ ]*\)*[ ]*$" !(*functions*))); popd &>/dev/null; }
+
+		# set completion list
+		COMPREPLY+=( $( compgen -W '${inits[*]}' -- "$cur" ) )
+
+	# if not complete using detected actions
+	else 
+
+		# set completion list
+		COMPREPLY=( $( compgen -W '${actions[*]}' -- "$cur" ) )
+
 	fi
-}
-complete -F _rc.d rc.d
 
-# vim: set ts=2 sw=2 ft=sh noet:
+	# restore extglob status
+	${shoptextglob}
+	return 0
+} &&
+complete -F _rc_d rc.d
+
+# Local variables:
+# mode: shell-script
+# sh-basic-offset: 4
+# sh-indent-comment: t
+# indent-tabs-mode: nil
+# End:
+# vim: ts=2 sw=2 et filetype=sh

Reply via email to