Commit dafb232e authored by Mark OLESEN's avatar Mark OLESEN
Browse files

Merge branch 'feature-bash-completion' into 'develop'

Feature bash completion

See merge request !137
parents 5f538909 ce086810
#!/bin/sh
#!/bin/bash
#------------------------------------------------------------------------------
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
......@@ -23,12 +23,15 @@
# along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
#
# Script
# foamCreateBashCompletions
# foamCreateCompletionCache
#
# Description
# Create bash completions for OpenFOAM applications
# Create cache of bash completion values for OpenFOAM applications
# The cached values are typically used by the tcsh completion wrapper.
#
#------------------------------------------------------------------------------
defaultOutputFile="$WM_PROJECT_DIR/etc/config.sh/completion_cache"
usage() {
exec 1>&2
while [ "$#" -ge 1 ]; do echo "$1"; shift; done
......@@ -36,141 +39,107 @@ usage() {
Usage: ${0##*/} [OPTION] [appName .. [appNameN]]
options:
-d dir | -dir dir Directory to process
-u | -user Add \$FOAM_USER_APPBIN to the search directories
-head | -header Generate header
-h | -help Print the usage
-d dir | -dir dir Directory to process
-u | -user Add \$FOAM_USER_APPBIN to the search directories
-no-header Suppress header generation
-o FILE Write to alternative output
-h | -help Print the usage
Create cache of bash completion values for OpenFOAM applications.
The cached values are typically used by the tcsh completion wrapper.
Default search: \$FOAM_APPBIN only.
Default output: $defaultOutputFile
Create bash completions for OpenFOAM applications and write to stdout.
By default searches \$FOAM_APPBIN only.
Alternatively, scan the output from individual applications for single completion
commands (using the '_of_complete_' backend).
Uses the search directory if applications are specified.
USAGE
exit 1
}
# Report error and exit
die()
{
exec 1>&2
echo
echo "Error encountered:"
while [ "$#" -ge 1 ]; do echo " $1"; shift; done
echo
echo "See '${0##*/} -help' for usage"
echo
exit 1
}
#-------------------------------------------------------------------------------
searchDirs="$FOAM_APPBIN"
unset optHeader
optHeader=true
unset outputFile
while [ "$#" -gt 0 ]
do
case "$1" in
-h | -help)
usage
;;
-d | -dir)
searchDirs="$2"
[ -d $searchDirs ] || usage "directory not found '$searchDirs'"
shift
;;
-u | -user)
searchDirs="$searchDirs $FOAM_USER_APPBIN"
;;
-head | -header)
optHeader=true
;;
-*)
usage "unknown option: '$1'"
;;
*)
break
;;
-h | -help)
usage
;;
-d | -dir)
[ "$#" -ge 2 ] || die "'$1' option requires an argument"
searchDirs="$2"
[ -d "$searchDirs" ] || die "directory not found '$searchDirs'"
shift
;;
-u | -user)
searchDirs="$searchDirs $FOAM_USER_APPBIN"
;;
-no-head*)
optHeader=false
;;
-o | -output)
[ "$#" -ge 2 ] || die "'$1' option requires an argument"
outputFile="$2"
shift
;;
-*)
usage "unknown option: '$1'"
;;
*)
break
;;
esac
shift
done
# No applications given, then always generate a header
if [ "$#" -eq 0 ]
: ${outputFile:=$defaultOutputFile}
# Verify that output is writeable
if [ -e "$outputFile" ]
then
optHeader=true
[ -f "$outputFile" ] || \
die "Cannot overwrite $outputFile" "Not a file"
[ -w "$outputFile" ] || \
die "Cannot overwrite $outputFile" "No permission?"
else
[ -w "$(dirname $outputFile)" ] || \
die "Cannot write $outputFile" "directory is not writeble"
fi
# Header requested or required
exec 1>| $outputFile || exit $?
echo "Writing $outputFile" 1>&2
echo 1>&2
# Header not disabled
[ "$optHeader" = true ] && cat << HEADER
#----------------------------------*-sh-*--------------------------------------
# Bash completions for OpenFOAM applications
# Recreate with "${0##*/}"
# Cached options for bash completion of OpenFOAM applications.
# These are the values expected by the '_of_complete_' function
#
# Formatted as "complete ... -F _of_APPNAME APPNAME
# Recreate with "${0##*/}"
#
# Generic completion handler for OpenFOAM applications
# - arg1 = command-name
# - arg2 = current word
# - arg3 = previous word
# - arg4 = options with args
# - arg5 = boolean options
#
unset -f _of_complete_ 2>/dev/null
_of_complete_()
{
# Unused: local cmd=\$1
local cur=\$2
local prev=\$3
local optsWithArgs="\$4 " # Trailing space added for easier matching
local opts="\$5 "
local choices
# Global associative array (cached options for OpenFOAM applications)
declare -gA _of_complete_cache_;
case \${prev} in
-help|-doc|-srcDoc)
# These options are usage and we can stop here.
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}))
;;
*Dict)
# local dirs=\$(\ls -d s*/)
# local files=\$(\ls -f | grep Dict)
# COMPREPLY=(\$(compgen -W \"\$dirs \$files\" -- \${cur}))
COMPREPLY=(\$(compgen -f -- \${cur}))
;;
*)
if [ "\${optsWithArgs/\${prev} /}" != "\${optsWithArgs}" ]
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,
# use files 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 \${opts} \${optsWithArgs}
do
[ "\${COMP_LINE/\$o/}" = "\${COMP_LINE}" ] && echo \$o
done
)
COMPREPLY=(\$(compgen -W "\$choices" -- \${cur}))
fi
;;
esac
return 0
}
# Clear existing cache.
_of_complete_cache_=()
#------------------------------------------------------------------------------
HEADER
#-------------------------------------------------------------------------------
......@@ -178,92 +147,48 @@ HEADER
# Scans the output of the application -help to detect options with/without
# arguments. Dispatch via _of_complete_
#
generateCompletion()
extractOptions()
{
local fullName="$1"
local appName="${1##*/}"
local appHelp
[ -f "$fullName" -a -x "$fullName" ] || {
echo "skip $fullName" 1>&2
return 1
}
if [ "$appName" = "complete_" ]
then
echo "skip $appName ... reserved name?" 1>&2
return 1
fi
local appName="$1"
local helpText=$($appName -help 2>/dev/null | sed -ne '/^ *-/p')
appHelp=$($fullName -help) || {
echo "error calling $fullName" 1>&2
[ -n "$helpText" ] || {
echo "Error calling $appName" 1>&2
return 1
}
# Options with args - as array
local optsWithArgs=($(awk '/^ {0,4}-[a-z]/ && /</ {print $1}' <<< "$appHelp"))
# Array of options with args
local argOpts=($(awk '/^ {0,4}-[a-z]/ && /</ {print $1}' <<< "$helpText"))
# Options without args - as array
local opts=($(awk '/^ {0,4}-[a-z]/ && !/</ {print $1}' <<< "$appHelp"))
# See bash(1) for some details. Completion functions are called with
# arg1 = command-name, arg2 = current word, arg3 = previous word
#
# Append known option types and dispatch to _of_complete_
echo " $appName" 1>&2
cat << COMPLETION
# [$appName]
unset -f _of_${appName} 2>/dev/null
_of_${appName}() {
_of_complete_ "\$@" \\
"${optsWithArgs[@]}" \\
"${opts[@]}"
}
complete -o filenames -F _of_${appName} $appName
# Array of options without args
local boolOpts=($(awk '/^ {0,4}-[a-z]/ && !/</ {print $1}' <<< "$helpText"))
COMPLETION
appName="${appName##*/}"
echo "$appName" 1>&2
echo "_of_complete_cache_[${appName}]=\"${argOpts[@]} | ${boolOpts[@]}\""
}
#------------------------------------------------------------------------------
[ "$#" -gt 0 ] || set -- ${searchDirs}
if [ "$#" -eq 0 ]
then
for dir in ${searchDirs}
do
if [ -d "$dir" ]
then
echo "Processing directory $dir" 1>&2
else
echo "No such directory: $dir" 1>&2
continue
fi
# Sort with ignore-case
set -- $(\ls $dir | sort -f)
for appName
for item
do
if [ -d "$item" ]
then
# Process directory for applications - sort with ignore-case
echo "[directory] $item" 1>&2
choices="$(find $item -maxdepth 1 -executable -type f | sort -f 2>/dev/null)"
for appName in $choices
do
generateCompletion "$dir/$appName"
extractOptions $appName
done
done
else
for appName
do
if [ -f "$appName" -a -x "$appName" ]
then
generateCompletion "$appName"
elif fullName=$(command -v $appName 2>/dev/null)
then
generateCompletion "$fullName"
else
echo "No application found: $appName" 1>&2
fi
done
fi
elif command -v "$item" > /dev/null 2>&1
then
extractOptions $item
else
echo "No such file or directory: $item" 1>&2
fi
done
# Generate footer
[ "$optHeader" = true ] && cat << FOOTER
......
#!bash
# A bash -*- sh -*- adapter for re-using OpenFOAM bash completions with tcsh
#----------------------------------*-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.
#
# Called with appName and COMMAND_LINE
# Arguments
# appName = the application name
#
# Source the bash completions
. $WM_PROJECT_DIR/etc/config.sh/bash_completion
# 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
......@@ -38,11 +72,11 @@ else
COMP_CWORD=$((${#COMP_WORDS[@]}-1))
fi
# bash completions are "complete ... -F _of_APPNAME APPNAME
_of_${appName} \
# Call _of_complete_ APPNAME Current Previous
_of_complete_ \
"$appName" "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD-1]}"
# Need slash on the end of directories for tcsh
# Tcsh needs slash on the end of directories
reply=($(for i in ${COMPREPLY[@]}
do
if [ -d "$i" -a "${i#/}" = "$i" ]
......
......@@ -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
#------------------------------------------------------------------------------
......@@ -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
......
This diff is collapsed.
This diff is collapsed.
......@@ -181,16 +181,21 @@ unset -f wmRefresh 2>/dev/null
unset -f foamVersion 2>/dev/null
unset -f foamPV 2>/dev/null
# Cleanup bash completions, which look like this:
# "complete ... -F _of_APPNAME APPNAME
# For economy, obtain list first but also remove the 'of_complete_' backend
foamClean="$(complete 2>/dev/null | sed -n -e 's/complete.*-F _of_.* \(..*\)$/\1/p')"
for cleaned in $foamClean complete_
# 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
unset -f _of_$cleaned 2>/dev/null
complete -r $cleaned 2>/dev/null
complete -r $cleaned 2>/dev/null
done
# Completion functions
unset -f foamAddCompletion 2>/dev/null
unset -f _of_complete_ 2>/dev/null
# Completion cache
unset _of_complete_cache_
#------------------------------------------------------------------------------
# Intermediate variables (do as last for a clean exit code)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment