Files
openfoam/etc/config.sh/bash_completion
Mark Olesen ce0868106a 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
2017-08-08 13:17:36 +02:00

204 lines
6.5 KiB
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.sh/bash_completion
#
# Description
# Bash completion handler for OpenFOAM applications and automatic
# generation of completion associations
#
# Provides
# foamAddCompletion
# _of_complete_
#
# Uses
# _of_complete_cache_
#
#------------------------------------------------------------------------------
# Add completion for command or directory of commands
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unset -f foamAddCompletion 2>/dev/null
foamAddCompletion()
{
[ "$#" -gt 0 ] || \
echo "Usage: foamAddCompletion -clear | -list | dir(s) | app(s)" 1>&2
local appName choices
for appName
do
if [ "$appName" = "-clear" ]
then
# Clear cached values
echo "clear cached values"
_of_complete_cache_=()
elif [ "$appName" = "-list" ]
then
# List cached keys
choices="${#_of_complete_cache_[@]}"
echo "$choices cached values:"
[ "$choices" = 0 ] || echo ${!_of_complete_cache_[@]} # keys
elif [ -d "$appName" ]
then
# Process directory for applications
choices="$(find $appName -maxdepth 1 -executable -type f 2>/dev/null)"
for appName in $choices
do
complete -o filenames -F _of_complete_ "${appName##*/}"
# echo "complete ${appName##*/}" 1>&2
done
elif command -v "$appName" > /dev/null 2>&1
then
complete -o filenames -F _of_complete_ "${appName##*/}"
# echo "complete ${appName##*/}" 1>&2
else
echo "No completion added for $appName" 1>&2
fi
done
}
# Generic completion handler for OpenFOAM applications
#
# Dispatch via "complete ... -F _of_complete_ APPNAME
# - arg1 = command-name
# - arg2 = current word
# - arg3 = previous word
#
# The respective options are generated on-the-fly from the application's -help
# output and cached to the _of_complete_cache_ global associative array with
# entries formatted as "argOpts.. | boolOpts ..".
# The '|' character separates options with and without arguments.
#
unset -f _of_complete_ 2>/dev/null
_of_complete_()
{
local appName=$1
local cur=$2
local prev=$3
local choices
case ${prev} in
-help|-doc|-srcDoc)
# These options are usage - we can stop now.
COMPREPLY=()
return 0
;;
-case)
COMPREPLY=($(compgen -d -- ${cur}))
;;
-time)
# Could use "foamListTimes -withZero", but still doesn't address ranges
COMPREPLY=($(compgen -d -X '![-0-9]*' -- ${cur}))
;;
-region)
choices=$(\ls -d system/*/ 2>/dev/null | sed -e 's#/$##' -e 's#^.*/##')
COMPREPLY=($(compgen -W "$choices" -- ${cur}))
;;
-fileHandler)
choices="collated uncollated masterUncollated"
COMPREPLY=($(compgen -W "$choices" -- ${cur}))
;;
*)
# All options
choices="${_of_complete_cache_[$appName]}"
# Not in cache, obtain by parsing application -help
if [ -z "$choices" ]
then
local helpText=$($appName -help 2>/dev/null | sed -ne '/^ *-/p')
if [ -n "$helpText" ]
then
# Array of options with args
local argOpts=($(awk '/^ {0,4}-[a-z]/ && /</ {print $1}' <<< "$helpText"))
# Array of options without args
local boolOpts=($(awk '/^ {0,4}-[a-z]/ && !/</ {print $1}' <<< "$helpText"))
choices="${argOpts[@]} | ${boolOpts[@]}"
else
echo "Error calling $appName" 1>&2
choices="false" # Mark failure to prevent repeating again
fi
_of_complete_cache_[$appName]="$choices"
## echo "generated $appName = $choices" 1>&2 # Debugging
fi
if [ "${choices:-false}" = false ]
then
COMPREPLY=($(compgen -f -- ${cur}))
else
# Everything before the '|' ==> options with args.
local argOpts="${choices%|*}"
if [ "${argOpts/${prev} /}" != "${argOpts}" ]
then
# Option with unknown type of arg - set to files.
# Not always correct but can still navigate path if needed...
COMPREPLY=($(compgen -f -- ${cur}))
elif [ -n "$cur" -a "${cur#-}" = "${cur}" ]
then
# Already started a (non-empty) word that isn't an option,
# in which case revert to filenames.
COMPREPLY=($(compgen -f -- ${cur}))
else
# Catchall
# - Present remaining options (not already seen in $COMP_LINE)
choices=$(
for o in ${choices}
do
[ "${COMP_LINE/$o/}" = "${COMP_LINE}" ] && echo "${o#|}"
done
)
COMPREPLY=($(compgen -W "$choices" -- ${cur}))
fi
fi
;;
esac
return 0
}
#------------------------------------------------------------------------------
# Global associative array (cached options for OpenFOAM applications)
declare -gA _of_complete_cache_;
# Clear existing cache and reassign bash completions.
# But for tcsh wrapper make use of caching and avoid this overhead.
if [ -z "$_of_complete_tcsh" ]
then
_of_complete_cache_=()
# Remove old completions, which look like:
# "complete ... -F _of_complete_ APPNAME
# For economy, obtain list first
foamOldDirs="$(complete 2>/dev/null | sed -ne 's/^.*-F _of_.* \(..*\)$/\1/p')"
for cleaned in $foamOldDirs
do
complete -r $cleaned 2>/dev/null
done
# Generate completions for predefined directories
foamAddCompletion $FOAM_APPBIN
fi
#------------------------------------------------------------------------------
# Intermediate variables (do as last for a clean exit code)
unset cleaned foamOldDirs
#------------------------------------------------------------------------------