#----------------------------------*-sh-*-------------------------------------- # ========= | # \\ / F ield | OpenFOAM: The Open Source CFD Toolbox # \\ / O peration | # \\ / A nd | www.openfoam.com # \\/ M anipulation | #------------------------------------------------------------------------------ # Copyright (C) 2017-2023 OpenCFD Ltd. #------------------------------------------------------------------------------ # License # This file is part of OpenFOAM, distributed under GPL-3.0-or-later. # # File # etc/config.sh/bash_completion # - sourced by OpenFOAM-*/etc/bashrc # # Description # Bash completion handler for OpenFOAM applications and automatic # generation of completion associations # # Provides # foamAddCompletion # _of_complete_ # # Uses # _of_complete_cache_ # # Requires # bash 4.2 or newer # #------------------------------------------------------------------------------ # Remove old completions (skip for tcsh wrapper), which look like: # "complete ... -F _of_complete_ APPNAME if [ -z "$_of_complete_tcsh" ] then # 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 fi # Add completion for commands, directories of commands # -clear # -list # -quiet # -verbose # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ unset -f foamAddCompletion 2>/dev/null foamAddCompletion() { [ "$#" -gt 0 ] || \ echo "Usage: foamAddCompletion -clear | -list | dir(s) | app(s)" 1>&2 local appName choices local verboseOnMissing=true for appName do if [ "$appName" = "-quiet" ] then # No message for missing applications unset verboseOnMissing elif [ "$appName" = "-verbose" ] then # Report for missing applications verboseOnMissing="true" elif [ "$appName" = "-clear" ] then # Clear cached values echo "Clear cached values" 1>&2 _of_complete_cache_=() elif [ "$appName" = "-list" ] then # List cached keys choices="${#_of_complete_cache_[@]}" echo "$choices cached values:" 1>&2 [ "$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 then complete -o filenames -F _of_complete_ "${appName##*/}" # echo "complete ${appName##*/}" 1>&2 elif [ -n "$appName" ] && [ -n "$verboseOnMissing" ] then echo "No completions for $appName" 1>&2 echo "[ignore if OpenFOAM is not yet compiled]" 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-full output and cached to the _of_complete_cache_ global associative # array with entries formatted as "argOpts.. | boolOpts ..". # The '|' character separates options with/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 | -help-compat | -help-full | -help-man | -doc | -doc-source) # 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) # Or: $(find system -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sed -e 's%.*/%%') choices=$(\ls -d system/*/ 2>/dev/null | sed -e 's%/$%%; s%^.*/%%') COMPREPLY=($(compgen -W "$choices" -- ${cur})) ;; -fileHandler) choices="collated uncollated hostCollated hostUncollated masterUncollated" COMPREPLY=($(compgen -W "$choices" -- ${cur})) ;; *) # All options choices="${_of_complete_cache_[$appName]}" # Not in cache, obtain by parsing application -help-full # Extract all options of the format # -opt1 descrip # -opt2 descrip # -help-full # Ignore -help-man (internal option). # Begin parsing after first appearance of "^[Oo]ptions:" # Terminate parsing on first appearance of "-help-full" # - options with '=' (eg, -mode=ugo) are not handled very well at all. # - alternatives (eg, -a, -all) are not handled nicely either, # for these treat ',' like a space to catch the worst of them. # # Remove anything that starts with more than 8 spaces to avoid parsing # any of the option description text if [ -z "$choices" ] then local helpText helpText=$("$appName" -help-full 2>/dev/null | \ sed -ne '1,/^[Oo]ptions:/d' \ -e '/^ \{8\}/d;' \ -e 's/^ *//; /^$/d; /^[^-]/d; /^--/d; /^-help-man/d;' \ -e 'y/,/ /; s/=.*$/=/;' \ -e '/^-[^ ]* &2 choices="false" # Mark failure to prevent repeating again else # Array of options with args local argOpts=($(awk '/&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" ] && [ "${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 } #------------------------------------------------------------------------------ # Uses 'declare -gA' for the implementation # The '-A' requires bash >= 4.0 and the '-g' requires bash >= 4.2 if [ "${BASH_VERSINFO[0]:-0}${BASH_VERSINFO[1]:-0}" -ge 42 ] then # 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_=() # Completions for predefined directories foamAddCompletion "$FOAM_APPBIN" # Completions for a few common scripts (allowed to be missing) foamAddCompletion -quiet paraFoam wmake fi else # Bash version is too old. ## echo "No bash completions - requires bash >= 4.2" 1>&2 unset -f foamAddCompletion 2>/dev/null foamAddCompletion() { echo "foamAddCompletion disabled - requires bash >= 4.2" 1>&2 } unset -f _of_complete_ 2>/dev/null fi #------------------------------------------------------------------------------ # Intermediate variables (do as last for a clean exit code) unset cleaned foamOldDirs #------------------------------------------------------------------------------