ENH: use bash associative array for on-the-fly completion (issue #551)

- this reduces the number of functions and allows lazy loading of
  completion options, which makes it easy to quickly add any other
  OpenFOAM application in completion.

  The generic '_of_complete_' function handles (bash) completion for
  any OpenFOAM application. On the first call for any particular
  application, it retrieves the available options from the application
  help output and adds this information to its environmental cache for
  subsequent use.

- Tcsh completion uses the same function via a bash wrapper.
  But since its wrapper is transient, the on-the-fly generation would
  be less efficient. For this case, a pre-generated completion_cache
  can be used, which is generated with

      bin/tools/foamCreateCompletionCache
This commit is contained in:
Mark Olesen
2017-08-08 13:17:36 +02:00
parent e0ebc8e973
commit ce0868106a
9 changed files with 732 additions and 2812 deletions

View File

@ -1,59 +0,0 @@
#!bash
# A bash -*- sh -*- adapter for re-using OpenFOAM bash completions with tcsh
#
# Called with appName and COMMAND_LINE
#
# Source the bash completions
. $WM_PROJECT_DIR/etc/config.sh/bash_completion
appName=$1
# Ensure COMP_LINE is available for bash function
if [ "$#" -eq 2 ]
then
COMP_LINE=$2
else
COMP_LINE=$COMMAND_LINE
fi
# Remove the colon as a completion separator because tcsh cannot handle it
COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
# Set COMP_WORDS in a way that can be handled by the bash script.
COMP_WORDS=($COMP_LINE)
# The cursor is at the end of parameter #1.
# We must check for a space as the last character which will
# tell us that the previous word is complete and the cursor
# is on the next word.
if [ "${COMP_LINE: -1}" = " " ]
then
# The last character is a space, so our location is at the end
# of the command-line array
COMP_CWORD=${#COMP_WORDS[@]}
else
# The last character is not a space, so our location is on the
# last word of the command-line array, so we must decrement the
# count by 1
COMP_CWORD=$((${#COMP_WORDS[@]}-1))
fi
# bash completions are "complete ... -F _of_APPNAME APPNAME
_of_${appName} \
"$appName" "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD-1]}"
# Need slash on the end of directories for tcsh
reply=($(for i in ${COMPREPLY[@]}
do
if [ -d "$i" -a "${i#/}" = "$i" ]
then
echo "$i/"
else
echo "$i"
fi
done
))
echo ${reply[@]}
#------------------------------------------------------------------------------

View File

@ -0,0 +1,93 @@
#!bash
#----------------------------------*-sh-*--------------------------------------
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
# \\ / O peration |
# \\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
# \\/ M anipulation |
#------------------------------------------------------------------------------
# This file is part of OpenFOAM, licensed under the GNU General Public License
# <http://www.gnu.org/licenses/>.
#
# File
# etc/config.csh/complete-wrapper
#
# Description
# A wrapper for using OpenFOAM bash completions with tcsh.
#
# Arguments
# appName = the application name
#
# Environment
# The tcsh COMMAND_LINE is passed in via the environment.
# This corresponds to the bash COMP_LINE variable
#
#------------------------------------------------------------------------------
[ "$#" -ge 1 ] || exit 1
# Preload completion cache
if [ -f $WM_PROJECT_DIR/etc/config.sh/completion_cache ]
then . $WM_PROJECT_DIR/etc/config.sh/completion_cache
fi
# Use the bash completion function, but retain cache etc.
_of_complete_tcsh=true
if [ -f $WM_PROJECT_DIR/etc/config.sh/bash_completion ]
then . $WM_PROJECT_DIR/etc/config.sh/bash_completion
else
# Could warn about missing file, or treat silently
echo
exit 1
fi
appName=$1
# Ensure COMP_LINE is available for bash function
if [ "$#" -eq 2 ]
then
COMP_LINE=$2
else
COMP_LINE=$COMMAND_LINE
fi
# Remove the colon as a completion separator because tcsh cannot handle it
COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
# Set COMP_WORDS in a way that can be handled by the bash script.
COMP_WORDS=($COMP_LINE)
# The cursor is at the end of parameter #1.
# We must check for a space as the last character which will
# tell us that the previous word is complete and the cursor
# is on the next word.
if [ "${COMP_LINE: -1}" = " " ]
then
# The last character is a space, so our location is at the end
# of the command-line array
COMP_CWORD=${#COMP_WORDS[@]}
else
# The last character is not a space, so our location is on the
# last word of the command-line array, so we must decrement the
# count by 1
COMP_CWORD=$((${#COMP_WORDS[@]}-1))
fi
# Call _of_complete_ APPNAME Current Previous
_of_complete_ \
"$appName" "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD-1]}"
# Tcsh needs slash on the end of directories
reply=($(for i in ${COMPREPLY[@]}
do
if [ -d "$i" -a "${i#/}" = "$i" ]
then
echo "$i/"
else
echo "$i"
fi
done
))
echo ${reply[@]}
#------------------------------------------------------------------------------

View File

@ -3,15 +3,23 @@
# Using bash_completion functions for the hard work
if ($?tcsh) then # tcsh only
if ( -f $WM_PROJECT_DIR/etc/config.sh/bash_completion \
&& -f $WM_PROJECT_DIR/etc/config.csh/complete) then
foreach appName (`sed -ne 's/^complete.* //p' $WM_PROJECT_DIR/etc/config.sh/bash_completion`)
# Remove old completions, which look like:
# complete APPNAME 'p,*,`bash $WM_PROJECT_DIR/etc/ ...
foreach appName (`complete | sed -ne '/WM_PROJECT/s/\t.*$//p'`)
uncomplete $cleaned
end
# Generate completions for predefined directories
foreach dirName ("$FOAM_APPBIN")
if ( ! -d $dirName || ! -f $WM_PROJECT_DIR/etc/config.csh/complete-wrapper ) continue
foreach appName (`find $dirName -maxdepth 1 -executable -type f`)
# Pass explicitly
## complete $appName 'p,*,`bash $WM_PROJECT_DIR/etc/config.csh/complete '$appName' "${COMMAND_LINE}"`,'
## complete $appName:t 'p,*,`bash $WM_PROJECT_DIR/etc/config.csh/complete-wrapper '$appName:t' "${COMMAND_LINE}"`,'
# Pass via environment
complete $appName 'p,*,`bash $WM_PROJECT_DIR/etc/config.csh/complete '$appName'`,'
complete $appName:t 'p,*,`bash $WM_PROJECT_DIR/etc/config.csh/complete-wrapper '$appName:t'`,'
end
endif
end
endif
#------------------------------------------------------------------------------

View File

@ -196,11 +196,10 @@ unalias wmRefresh
unalias foamVersion
unalias foamPV
# Cleanup completions, which look like this:
# complete blockMesh 'p,*,`bash $WM_PROJECT_DIR/etc/ ...
# Remove old completions, which look like:
# complete APPNAME 'p,*,`bash $WM_PROJECT_DIR/etc/ ...
if ($?prompt && $?tcsh) then # Interactive tcsh only
foreach cleaned (`complete | sed -n -e '/WM_PROJECT/s/\t.*$//p'`)
foreach cleaned (`complete | sed -ne '/WM_PROJECT/s/\t.*$//p'`)
uncomplete $cleaned
end
endif