From 65dfcde0ee400d5a32a06122eb47d03d2139212c Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Fri, 9 Sep 2011 01:58:35 +0200 Subject: [PATCH] Rewrite bash completion. Now that para_client and para_audioc gained the --completion option for completing a partially entered command line, we can use this feature in the bash completion script. This allows to avoid duplicating the available commands in the completion script. --- audioc.c | 1 + bash_completion | 230 +++++++++++++++++------------------------------- configure.ac | 2 +- 3 files changed, 85 insertions(+), 148 deletions(-) diff --git a/audioc.c b/audioc.c index 73bc2cf3..e12d6e98 100644 --- a/audioc.c +++ b/audioc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "audioc.cmdline.h" #include "para.h" diff --git a/bash_completion b/bash_completion index a9947b74..51bbc68e 100644 --- a/bash_completion +++ b/bash_completion @@ -1,165 +1,101 @@ -# Copyright (C) 2007 Andre Noll +# Copyright (C) 2007-2011 Andre Noll # # Licensed under the GPL v2. For licencing details see COPYING. -PC="para_client -l error -- " - -__para_commandlist= -__para_sender_list= -__para_table_list= -__para_mood_list= -__para_lyrics_list= -__para_image_list= -__para_playlist_list= -__para_attributes_list= - -__paracomp() -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - if [ $# -gt 2 ]; then - cur="$3" - fi - COMPREPLY=($(compgen -P "$2" -W "$1" -- "$cur")) -} - -__para_complete_file() -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - local sed_cmd="-e s|^\($cur[^/]\+/\).*|\1|1" - $PC ls -p -sp "${cur}*" | sed $sed_cmd | uniq -} - -__para_complete_command() -{ - if test -z "$__para_command_list"; then - __para_command_list="$($PC help | cut -f 1)" - fi - echo "$__para_command_list" -} - -__para_complete_table() -{ - if test -z "$__para_table_list"; then - __para_table_list="$(ls $HOME/.paraslash/afs_database-0.4/)" - fi - echo "$__para_table_list" -} -__para_complete_sender() -{ - if test -z "$__para_sender_list"; then - __para_sender_list="$($PC si | grep '^.* sender:$' | sed -e 's/ sender://')" - fi - echo "$__para_sender_list" -} -__para_complete_attribute() -{ - if test -z "$__para_attributes_list"; then - __para_attributes_list="$($PC lsatt)" - fi - echo "$__para_attributes_list" -} -__para_complete_playlist() -{ - if test -z "$__para_playlist_list"; then - __para_playlist_list="$($PC lspl)" - fi - echo "$__para_playlist_list" -} -__para_complete_mood() -{ - if test -z "$__para_mood_list"; then - __para_mood_list="$($PC lsmood)" - fi - echo "$__para_mood_list" -} -__para_complete_image() +_para_complete() { - if test -z "$__para_image_list"; then - __para_image_list="$($PC lsimg)" + local prg="$1" # the program to execute + local cur=${COMP_WORDS[$COMP_CWORD]} + local line="$COMP_LINE" OLD_IFS="$IFS" + local opts n + + if [[ "$COMP_WORDBREAKS" != ' ' ]]; then + COMP_WORDBREAKS=' ' + return 124 # try again with proper value fi - echo "$__para_imagelist" -} -__para_complete_lyrics() -{ - if test -z "$__para_lyrics_list"; then - __para_lyrics_list="$($PC lslyr)" + # This extracts short and long options from the help output + local script='{ + if ($1 ~ "-[a-zA-Z]," && $2 ~ "--[a-zA-Z]") { + print substr($1, 0, 2); + gsub("=.*", "", $2) + print $2 + } else if ($1 ~ "--[a-zA-Z]") { + gsub("=.*", "", $1) + print $1 + } + }' + + if [[ "$cur" == -* ]]; then # option + # Depending on whether '--' is one of the previous words we + # complete either on local options, i.e. those of the program + # to execute, or call the program to print possible completions + # (to a subcommand). + local_opts=true + for ((i=0; i < $COMP_CWORD; i++)); do + [[ "${COMP_WORDS[$i]}" != '--' ]] && continue + local_opts=false + break + done + if [[ "$local_opts" == "true" ]]; then + result="-- $($prg --help | awk "$script")" + COMPREPLY=($(compgen -W "$result" -- $cur)) + return + fi fi - echo "$__para_lyrics_list" -} - -__para_select() -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - *) - __paracomp "$($PC lspl "${cur}*" | sed -e 's|^|p/|1') $($PC lsmood | sed -e 's|^|m/|1')" - ;; - esac -} - -__para_setatt() -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - if [ $COMP_CWORD -lt 3 ]; then - __paracomp "$(__para_complete_attribute)" + # We need to call the program with --complete to get the possible + # completions. Before that, all local options must be discarded. + IFS=' ' + n=0 + for word in $line; do + ((n > 0)) && ! [[ "$word" == -* ]] && break + line="${line##*( )}" # remove leading whitespace + line="${line##+([^ ])}" + line="${line##*( )}" + let n++ + [[ "$word" == '--' ]] && break + done + IFS="$OLD_IFS" + s=$((${#COMP_LINE} - ${#line})) # how many characters have been cut + if (($COMP_POINT > $s)); then + COMP_POINT=$(($COMP_POINT - $s)) else - if test -z "$cur" -o "$cur" = "${cur#/}"; then - __paracomp "$(__para_complete_attribute)" - else - __paracomp "$(__para_complete_file)" - fi + COMP_POINT=0 fi + COMP_LINE="$line" + #echo "line: $COMP_LINE, point: $COMP_POINT" + export COMP_LINE COMP_POINT + result=($($prg --complete)) + + # the last line of the output contains the options for compopt, + # prefixed with '-o='. + n=${#result[@]} + (($n == 0)) && return # oops, $prg did not write any output + let n-- + opts="${result[$n]}" + result[$n]= + opts="${opts#-o=}" + IFS=',' + compopt +o nospace + for opt in $opts; do + #echo "opt: $opt" + case "$opt" in + filenames) compopt -o filenames;; + nospace) compopt -o nospace;; + esac + done + IFS="$OLD_IFS" + COMPREPLY=(${result[@]}) } -__para_sender() +_para_audioc() { - if test $COMP_CWORD -eq 2; then - __paracomp "$(__para_complete_sender)" - elif test $COMP_CWORD -eq 3; then - __paracomp "on off add delete allow deny help" - else - COMPREPLY=() - fi + _para_complete ~maan/para/para_audioc } +complete -F _para_audioc para_audioc _para_client() { - local i c=1 command - - - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" - case "$i" in - --*) ;; - *) command="$i"; break ;; - esac - c=$((++c)) - done - - if [ $c -eq $COMP_CWORD ]; then - case "${COMP_WORDS[COMP_CWORD]}" in - --*=*) COMPREPLY=();; - *) __paracomp "$(__para_complete_command)";; - esac - return - fi - - case "$command" in - stop|play|term|hup|pause|nomore|si|version) COMPREPLY=();; - setatt) __para_setatt;; - select) __para_select;; - touch|ls|rm|cpsi) __paracomp "$(__para_complete_file)";; - mvatt|lsatt|rmatt) __paracomp "$(__para_complete_attribute)";; - help) __paracomp "$(__para_complete_command)";; - sender) __para_sender;; - init) __paracomp __paracomp "$(__para_complete_table)";; - mvmood|lsmood|rmmood) __paracomp "$(__para_complete_mood)";; - mvlyr|lslyr|rmlyr) __paracomp "$(__para_complete_lyrics)";; - mvimg|lsimg|rmimg) __paracomp "$(__para_complete_image)";; - mvpl|lspl|rmpl) __paracomp "$(__para_complete_playlist)";; - esac - + _para_complete ~maan/para/para_client } complete -o default -o nospace -F _para_client para_client complete -o default -o nospace -F _para_client para - diff --git a/configure.ac b/configure.ac index f51c44e6..66541fe4 100644 --- a/configure.ac +++ b/configure.ac @@ -916,7 +916,7 @@ if test "$have_readline" = "yes"; then all_errlist_objs="$all_errlist_objs interactive" client_errlist_objs="$client_errlist_objs interactive" client_ldflags="$client_ldflags $readline_libs" - audioc_errlist_objs="$audioc_errlist_objs buffer_tree interactive sched" + audioc_errlist_objs="$audioc_errlist_objs buffer_tree interactive sched time" audioc_ldflags="$audioc_ldflags $readline_libs" AC_SUBST(readline_cppflags) AC_DEFINE(HAVE_READLINE, 1, define to 1 to turn on readline support) -- 2.39.5