## Copyright (C) 2005-2014 Deepayan Sarkar ### ### This file provides programmable completion for R under the bash ### shell. It is made available under the terms of the GNU General ### Public License, version 2, or at your option, any later version, ### incorporated herein by reference. ### ### This program is distributed in the hope that it will be ### useful, but WITHOUT ANY WARRANTY; without even the implied ### warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ### PURPOSE. See the GNU General Public License, available at ### http://www.gnu.org/licenses/licenses.html, for more details. ### NOTE: This does NOT provide completion for commands within R, only ### for R's command-line options. For example, ### ### R CMD build --f[TAB] ### ### will complete to --force and so on. In other words, this is ### potentially useful (for the most part) to package developers, not ### regular users. ### NEWS: Updated for R 2.4.0 (October 2006) ### BUGS: As it stands, this is far from perfect. Known bugs include: ### ### (1) Not all mutually exclusive options are properly handled ### ### (2) Doesn't test for the existence of R before defining the ### (2) completion function (not strictly a bug, but definitely not a ### (2) good feature) ### INSTALLATION AND USAGE: You need to first install and enable bash ### completion on your system to use this script. See ### ### http://www.caliban.org/bash/index.shtml#completion ### ### to learn more about bash completion. On a modern Debian system, ### all the necessary files are already installed by the bash package. ### To enable it, just uncomment the following lines in your .bashrc ### ### # if [ "$PS1" -a -f /etc/bash_completion ]; then ### # . /etc/bash_completion ### # fi ### ### or to try it out in your current shell, type ### ### . /etc/bash_completion ### ### Once you are using bash completion, you can enable completion for ### R by similarly sourcing this file. For permanent use, place it in ### your $BASH_COMPLETION_DIR (/etc/bash_completion.d in Debian). If ### you don't have access to do that, copy the contents of this file ### in it's entirety to your ~/.bash_completion, which is sourced by ### the bash_completion script. _R() { local cur loneOpts helpOpts stdOpts argOpts versOpts cmds cmd furtherOpts local fileNames dirNames i lastToken # local IFS=$'\t\n' COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} loneOpts='--version RHOME' versOpts='-v --version' # only on commands helpOpts='-h --help' stdOpts='--save --no-save --no-environ --no-site-file \ --no-init-file --restore --no-restore-data --no-restore-history \ --no-restore --vanilla --no-readline -q --quiet --silent --slave \ --interactive --verbose -d -g --args -f -e' ## these should end with a '=' and not be followed by a space. ## Unfortunately, I haven't figured out how to make that work. ## -nospace doesn't suppress the space, and if I add = at the end, ## they get completed as "--debugger\= " etc. Anyway, they are ## kept separate in anticipation of some future fix... argOpts='--min-vsize --max-vsize --min-nsize --max-nsize \ --encoding --max-ppsize --debugger --debugger-args \ --gui --arch --file' cmds='BATCH COMPILE SHLIB INSTALL REMOVE build check LINK Rprof \ Rdconv Rd2pdf Rd2txt Stangle Sweave Rdiff config javareconf rtags' fileNames='' # possible to have files in certain commands (e.g. BATCH) dirNames='' if [[ $COMP_CWORD -eq 1 ]] ; then COMPREPLY=( $( compgen -W "CMD $loneOpts $helpOpts $stdOpts" -- $cur ) $( compgen -o nospace -W "$argOpts" -- $cur ) ) return 0 fi ## certain tokens preclude further activity if [[ ${COMP_WORDS[$COMP_CWORD-1]} == @(-v|--version|RHOME|-h|--help) ]] ; then return 0 fi ## more complicated stuff ## keep last token for use later lastToken=${COMP_WORDS[$COMP_CWORD-1]} ## if [[ $COMP_CWORD -gt 1 ]] && (implied) if [[ ${COMP_WORDS[1]} == "CMD" ]] ; then if [[ $COMP_CWORD -eq 2 ]] ; then COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) return 0 else ## COMP_CWORD >= 3. cmd=${COMP_WORDS[2]} is (hopefully) ## one of $cmds. At this point, all further options ## (except -v|-h|RHOME etc handled above) will be assumed ## repeatable (except for duplicates and exclusives, to be ## handled later). In the next step, possible completions ## for each cmd will be derived. ## A largely similar derivation is also needed for the ## case when ${COMP_WORDS[2]} is not CMD. A similar ## completion list will be derived in that case. ## Afterwards, things will be removed from these as ## needed, before the final COMPREPLY is computed. cmd=${COMP_WORDS[2]} case $cmd in BATCH) ## if last word is a filename (not starting with ## -) then no more options are allowed, but can be ## followed by any file (outfile) if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken != -* ]] ; then furtherOpts="" fileNames=$( compgen -f -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) else furtherOpts="$versOpts $helpOpts $stdOpts $argOpts --no-timing" fileNames=$( compgen -f -X '!*.@(R|r|S|s)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) fi ;; COMPILE) if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken != -* ]] ; then furtherOpts="" fileNames=$( compgen -f -X '!*.@(c|cc|cpp|C|f)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) else furtherOpts="$versOpts $helpOpts -D" fileNames=$( compgen -f -X '!*.@(c|cc|cpp|C|f)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) fi ;; SHLIB) if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken != -* ]] ; then furtherOpts="" fileNames=$( compgen -f -X '!*.@(a|o)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) else furtherOpts="$versOpts $helpOpts -o --output -c --clean \ --preclean -n --dry-run" fileNames=$( compgen -f -X '!*.@(a|o)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) fi ;; INSTALL) if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken == @(-l|--library) ]] ; then furtherOpts="" dirNames=$( compgen -d -- "$cur" ) else furtherOpts="$versOpts $helpOpts \ --configure-args --configure-vars -c --clean --preclean -d --debug -l \ --library --no-configure --no-docs --html --no-html --latex --example \ --fake --no-lock --lock --pkglock --build --install-tests --no-R \ --no-libs --no-data --no-help --no-demo --no-exec --no-inst \ --no-multiarch --libs-only --data-compress --resave-data \ --compact-docs --with-keep.source --without-keep.source --byte-compile \ --no-byte-compile --no-test-load --no-clean-on-error --merge-multiarch \ --built-timestamp" fileNames=$( compgen -f -X '!*.@(tar.gz|tgz)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) fi ;; REMOVE) furtherOpts="$versOpts $helpOpts -l --library" if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken == @(-l|--library) ]] ; then dirNames=$( compgen -d -- "$cur" ) fi ;; build) furtherOpts="$versOpts $helpOpts \ --force --keep-empty-dirs --no-build-vignettes --no-manual --resave-data \ --no-resave-data --compact-vignettes --md5" dirNames=$( compgen -d -- "$cur" ) ;; check) furtherOpts="$versOpts $helpOpts \ -l --library -o --output \ --no-clean --no-codoc --no-examples --no-install --no-tests \ --no-manual --no-vignettes --no-build-vignettes --run-dontrun \ --run-donttest --use-gct --use-valgrind --timings \ --install-args --test-dir --check-subdirs --as-cran \ --extra-arch --multiarch --no-multiarch --force-multiarch" fileNames=$( compgen -f -X '!*.@(tar.gz|tgz)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) ;; LINK) furtherOpts="$versOpts $helpOpts" ;; Rprof) furtherOpts="$versOpts $helpOpts --lines --total --self --linesonly --min%total --min%self" fileNames=$( compgen -f -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) ;; Rdconv) furtherOpts="$versOpts $helpOpts -t --type \ --encoding --package -o --output --os --OS" fileNames=$( compgen -f -X '!*.@(Rd)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) ;; Rd2pdf) furtherOpts="$versOpts $helpOpts --batch \ --no-clean --no-preview --encoding --outputEncoding \ --os --OS -o --output --force --title \ --no-index --no-description --internals" fileNames=$( compgen -f -X '!*.@(Rd)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) ;; Rd2txt) furtherOpts="$versOpts $helpOpts -t --type --encoding --package -o --output --os --OS" fileNames=$( compgen -f -X '!*.@(Rd)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) ;; Sweave) ## if last word is a filename (not starting with ## -) then nothing more is allowed if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken != -* ]] ; then return 0 else furtherOpts="$versOpts $helpOpts --driver --engine --encoding --options --pdf --compact" fileNames=$( compgen -f -X '!*.@(Rnw|rnw|Snw|snw|Rmd|rmd)' -- "$cur" ) dirNames="" ## dirNames=$( compgen -d -- "$cur" ) fi ;; Stangle) ## if last word is a filename (not starting with ## -) then nothing more is allowed if [[ $COMP_CWORD -gt 3 ]] && \ [[ $lastToken != -* ]] ; then return 0 else furtherOpts="$versOpts $helpOpts --engine --encoding --options" fileNames=$( compgen -f -X '!*.@(Rnw|rnw|Snw|snw|Rmd|rmd)' -- "$cur" ) dirNames="" ## dirNames=$( compgen -d -- "$cur" ) fi ;; config) if [[ $COMP_CWORD -gt 3 ]] ; then return 0 else furtherOpts="$versOpts $helpOpts --ldflags --cppflags \ --no-user-files --no-site-files \ BLAS_LIBS CC CFLAGS CPICFLAGS CPP CPPFLAGS CXX CXXCPP CXXFLAGS \ CXXPICFLAGS DYLIB_EXT DYLIB_LD DYLIB_LDFLAGS F77 FFLAGS FLIBS \ FPICFLAGS FC FCFLAGS FCPICFLAGS JAR JAVA JAVAC JAVAH JAVA_HOME \ JAVA_LIBS JAVA_CPPFLAGS LAPACK_LIBS LIBnn LDFLAGS OBJC OBJCFLAGS MAKE \ SAFE_FFLAGS SHLIB_CFLAGS SHLIB_CXXLD SHLIB_CXXLDFLAGS SHLIB_EXT \ SHLIB_FFLAGS SHLIB_LD SHLIB_LDFLAGS SHLIB_FCLD SHLIB_FCLDFLAGS \ TCLTK_CPPFLAGS TCLTK_LIBS" fi ;; javareconf) furtherOpts="$versOpts $helpOpts -n --dry-run -e" ;; rtags) furtherOpts="$versOpts $helpOpts -o --output --no-c --no-R \ --no-Rd -a --append -V --verbose" dirNames=$( compgen -d -- "$cur" ) ;; esac fi elif [[ $lastToken == "<" ]] ; then ## R [options] < furtherOpts="" fileNames=$( compgen -f -X '!*.@(R|r|S|s)' -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) elif [[ $lastToken == ">" ]] ; then ## R [options] > furtherOpts="" fileNames=$( compgen -f -- "$cur" ) dirNames=$( compgen -d -- "$cur" ) else case $lastToken in -g|--gui) furtherOpts="X11 Tk" ;; -d|--debugger) ## allow commands furtherOpts=$( compgen -c -- "$cur" ) ;; -f|--file) fileNames=$( compgen -f -X '!*.@(R|r|S|s)' -- "$cur" ) dirNames="" ## dirNames=$( compgen -d -- "$cur" ) ;; *) ## NOT 'R CMD ': see comments above furtherOpts="$versOpts $helpOpts $stdOpts $argOpts" ;; esac fi ## need some removal ## take out options already given for (( i=1; i<=$COMP_CWORD-1; ++i )) ; do opt=${COMP_WORDS[$i]} case $opt in --*) optBase=${opt/=*/} ;; -*) optBase=${opt:0:2} ;; esac ## can't seem to do this using case if [[ $opt == "<" ]] ; then ## no more args allowed furtherOpts="" elif [[ $opt == ">" ]] ; then ## no more args allowed furtherOpts="" fi allOpts=" $furtherOpts " allOpts=${allOpts/ ${optBase} / } #echo $allOpts ## take out alternatives and mutually exclusives case $optBase in # not working # "<") ## only filenames allowed # echo "-----------" # allOpts=">" ;; # ">") ## only filenames allowed # allOpts="<" ;; -q|--quiet|--silent) allOpts=${allOpts/ -q / } allOpts=${allOpts/ --quiet / } allOpts=${allOpts/ --silent / } #echo $allOpts ;; --save|--no-save) allOpts=${allOpts/ --save / } allOpts=${allOpts/ --no-save / } ;; --vanilla) allOpts=${allOpts/ --no-save / } allOpts=${allOpts/ --no-restore / } allOpts=${allOpts/ --no-site-file / } allOpts=${allOpts/ --no-init-file / } allOpts=${allOpts/ --no-environ / } ;; -d) allOpts=${allOpts/ --debugger / } ;; --debugger) allOpts=${allOpts/ -d / } ;; --restore) allOpts=${allOpts/ --no-restore / } ;; --no-restore) allOpts=${allOpts/ --restore / } ;; -g|--gui) allOpts=${allOpts/ -g / } allOpts=${allOpts/ --gui / } ;; BATCH) allOpts=${allOpts/ --restore / } allOpts=${allOpts/ --save / } allOpts=${allOpts/ --no-readline / } ;; esac done ## and finally: COMPREPLY=( $( compgen -W "$allOpts $fileNames $dirNames" -- $cur ) ) return 0 } complete -F _R -o default R ## Add more aliases here, e.g. # for e in R-devel R-patched; do complete -F _R -o default ${e}; done ### Local variables: ### mode: shell-script ### End: