Client:Bash tab completion for the CLI

Erik Massop edited this page Nov 4, 2017 · 1 revision

 $ xmms2 mlib searchadd artist=the 

Then some bash completion magic would do

 $ xmms2 mlib query "select value from Media where key='artist' and value like 'the%'     group by lower(value) order by lower(value)"|cut -c 9-  The chemical brothers  The KLF  the knife  The Mitchell Bros.

And then present the alternatives and let the user press tab to select the correct one. Perhaps warn if the result is very big.

Places that would benefit of tab completion

 $ xmms2 config out 

by values from xmms2 configlist|grep 'out'

 $ xmms2 jump the 

by values from xmms2 list|grep name, and translate to playlist id on exec (if this is possible)

 $ xmms2 addid the

by values from a xmms2 mlib query and translate to medialib id on exec (if this is possible)

 $ xmms2 sort a

by some predefined values, artist, title, duration, album etc etc


I started working on it. So command line get completed for:

  • commands
  • configuration options
  • configuration values
  • mlib commands
  • various file/directory completions
  • sort keys
  • search key options
  • search key values
  • export format

To have this working, copy attached shell script to /etc/bash_completion.d/xmms2 or have it invoked by bash in any way. Restart your bash and you're done :) There are some TODO/FIXME in the shell script to be worked on ...

#-*- mode: shell-script;-*-
# xmms2 client tab completion
#   -- Nicolas Collignon <tsointsoin@gmail.com>

have xmms2 &&
_xmms2()
{
   local cur cmds keys
   
#complete -f -X '!*.@(pls|PLS|m3u|M3U|mp3|MP3|ogg|OGG)' xmms2

   cur=${COMP_WORDS[COMP_CWORD]}
   cmds='add addid addpls clear config_list config current \
         help info jump list mlib move next pause play playlist \
         plugin_list prev quit radd remove seek shuffle sort \
         stats status stop volume_list volume'
         
   # mlib meta data keys
   keys='added album albumid artist artistid \
         bitrate duration laststarted lmod mime \
         title trackid tracknr url'
   
   # COMPREPLY=()

   # complete command (1st arg)
   if [[ $COMP_CWORD -eq 1 ]]; then
      COMPREPLY=( $( compgen -W "$cmds" -- $cur ))

   # complete option (2 args command)
   elif [[ $COMP_CWORD -eq 2 ]]; then
      case ${COMP_WORDS[1]} in
      add)    # add <url>
         # TODO
         ;;
      addid)  # addid <medialib_id> 
         COMPREPLY=( $( xmms2 mlib query \
                     "SELECT id FROM media WHERE key='url'" \
                     | sed -ne 's|^id = \('$cur'[^ ]*\)$|\1|p' ))
         ;;
      
      addpls) # addpl <url>
         # FIXME: handle URI proto
         _filedir
         ;;
      config) # config <key> <val>
         COMPREPLY=( $( xmms2 config_list \
                     | sed -ne 's|^\('$cur'[^ ]*\).*$|\1|p' ))
         ;;
      
      help) # help [cmd]
         COMPREPLY=( $( compgen -W "$cmds" -- $cur ))
         ;;
      
      jump|move) # move <playlist_position> <new_position>
                 # jump <playlist_position>
         # FIXME this is the ID not the position !
         COMPREPLY=( $( xmms2 mlib query \
                     "SELECT pos FROM PlaylistEntries WHERE playlist_id= \
                     (SELECT id FROM Playlist WHERE name='_xmms2cli')" \
                     | sed -ne 's|^pos = \('$cur'.*\).*$|\1|p' ))
         ;;

      mlib) # mlib <cmd> [options ...]
         COMPREPLY=( $( compgen -W \
                  'add addpath \
                   export_playlist \
                   import_playlist \
                   list_playlist loadall load_playlist \
                   playlists_list \
                   query queryadd \
                   rehash remove_playlist \
                   save_playlist \
                   search searchadd' \
                  -- $cur ))
         ;;
    
      playlist) # playlist cmd
     COMPREPLY=( $( compgen -W \
          'active create \
           list load \
           type remove' \
                  -- $cur ))
         ;;
      
      radd) # radd <directory>
         _filedir -d
         ;;
      
      remove) # remove <playlist_position>
         # TODO
         ;;
      
      seek)   # seek [+|-] <seconds>
         COMPREPLY=( $( compgen -W '+ -' -- $cur ))
         ;;
      sort)   # sort <property>
         COMPREPLY=( $( compgen -W "$keys" -- $cur ))
         ;;
      volume) # volume <channel> <level>
         # TODO : xmms2 volume_list
         ;;
      *)
         ;;
      esac
   
   # complete options (3 args command)
   elif [[ $COMP_CWORD -eq 3 ]]; then
      case ${COMP_WORDS[1]} in
      
      config) # config <key> <val>
         case ${COMP_WORDS[2]} in
         # complete boolean (0/1) keys
         effect.equalizer.enabled \
         |effect.replaygain.enabled \
         |medialib.dologging \
         |playlist.load_autosaved \
         |playlist.repeat_all \
         |playlist.repeat_one \
         |transport.curl_http.shoutcastinfo \
         |transport.curl_http.useproxy \
         |transport.curl_http.verbose)
            COMPREPLY=( $( compgen -W '0 1' -- $cur ))
            ;;
         # complete files
         core.ipcsocket|medialib.path)
            _filedir
            ;;
         
         # complete directories
         core.shutdownpath \
         |core.startuppath \
         |output.diskwrite.destination_directory)
            _filedir -d
            ;;
         # output plugin
         output.plugin)
            COMPREPLY=( $( xmms2 plugin_list \
                        | sed -ne 's|^\('$cur'[^ ]*\).*output.*$|\1|p' ))
            ;;
         
         # replaygain mode
         effect.replaygain.mode)
            COMPREPLY=( $( compgen -W 'track album' -- $cur ))
            ;;

         # add yours here ...
         *)
            ;;
         esac
         ;;

      mlib) # mlib <cmd> [options..]

         case ${COMP_WORDS[2]} in
         
         # export_playlist <name> <mime>
         # list_playlist <name>
         # load_playlist <name>
         # remove_playlist <name>
         # save_playlist <name>
         export_paylist \
         |list_playlist \
         |load_playlist \
         |remove_playlist\
         |save_playlist )
            # FIXME: add quotes + case insensitive
            local old_ifs
            old_ifs=$IFS
            IFS='
';
            COMPREPLY=( $( xmms2 mlib playlists_list \
                        | sed -ne 's|^\('$cur'.*\).*$|\1|p' ))
            IFS=old_ifs
            ;;
         add) # add <url>
            # FIXME: handle URI proto ?
            _filedir
            ;;
      
         addpath) # addpath <directory>
            _filedir -d
            ;;
         
         query|queryadd) # query <sql> <statement>
            # TODO ?
            ;;
         search|searchadd) # search[add] key=value
            if [[ "$cur" == *=\"* ]]; then
               local key sql old_ifs
        old_ifs=$IFS
        IFS='
';
               key=${cur%%=*}
               COMPREPLY=( $( xmms2 mlib query \
                           "SELECT value FROM Media WHERE  \
                            key='${key%\\*}' AND value LIKE '${cur#*=\"}%' " \
                           | sed -ne 's|^value = \(.*\)$|"\1"|p' ))
        IFS=$old_ifs
            else
               COMPREPLY=( $( compgen -S '="' -W "$keys" -- $cur ))
            fi
            ;;
         *)
            ;;
         esac
         ;;
         
      move) # move <playlist_position> <new_position>
         # TODO
# xmms2 mlib query "SELECT PlaylistEntries.pos FROM PlaylistEntries WHERE playlist_id=(SELECT id FROM Playlist WHERE name='_xmms2cli')"
         # FIXME LEFT JOIN ON() Playlist.name='_xmms2cli'
#COMPREPLY=( $( xmms2 mlib query \
#                    "SELECT pos FROM PlaylistEntries" \
#                    | sed -ne 's|^pos = \('$cur'.*\).*$|\1|p' ))
         ;;

      playlist) # complete playlist name
         case ${COMP_WORDS[2]} in
        load|remove|type)
            local old_ifs
        old_ifs=$IFS
        IFS='
';
            COMPREPLY=( $( xmms2 playlist list \
                  | sed -e 's,^  ,,' -e 's,\([ \\<>%$#*();?!&|]\),\\\1,g' | sed -ne 's|^\('$cur'.*\).*$|\1|p' ))
        IFS=old_ifs
        ;;
         *)
        ;;
    esac
    ;;

      *)
         ;;
      esac
   # complete options (4 args command)
   elif [[ $COMP_CWORD -eq 4 ]]; then
      case ${COMP_WORDS[1]} in
      mlib)
         case ${COMP_WORDS[2]} in
         import_playlist) # import_playlist <name> <url>
            # TODO: don't complete dir if it doesn't contain a pls
            # FIXME: quotes !
            _filedir '@(pls|PLS|m3u|M3U)'
            ;;
      
         export_playlist) # export_playlist <name> <mime>
            COMPREPLY=( $( xmms2 plugin_list \
                        | sed -ne 's|^\('$cur'[^ ]*\).*Playlist.*$|\1|p' ))
            ;;
         
         *)
            ;;
         esac
         ;;
      playlist)
        case ${COMP_WORDS[2]} in
      type)
            COMPREPLY=( $( compgen -W 'list queue pshuffle' -- $cur ))
        ;;  
      *)
        ;;
        esac
    ;;
      *)
         ;;
      esac
   fi

   return 0
}
#have xmms2 && complete -F _xmms2 -o plusdirs -o nospace xmms2
have xmms2 && complete -F _xmms2 -o nospace xmms2
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.