Skip to content

Commit

Permalink
bin/tools/foamGenerateBashCompletion: Improved robustness of bracket …
Browse files Browse the repository at this point in the history
…parsing

Also minor formatting changes
  • Loading branch information
Will Bainbridge committed Jul 30, 2020
1 parent 074dbec commit e603417
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 155 deletions.
316 changes: 166 additions & 150 deletions bin/tools/foamGenerateBashCompletion
Original file line number Diff line number Diff line change
Expand Up @@ -92,44 +92,35 @@ banner () {
EOF
}

header_start () {
declareLocals () {
cat <<EOF
{
local cur="\${COMP_WORDS[COMP_CWORD]}"
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
local line=\${COMP_LINE}
local used=\$(echo "\$line" | grep -oE "\-[a-zA-Z]+ ")
EOF
}

header_end () {
caseStart () {
cat <<EOF
[ "\$COMP_CWORD" = 1 ] || \\
case "\$prev" in
EOF
}

footer () {
caseEnd () {
cat <<EOF
esac
COMPREPLY=( \$(compgen -W "\${opts}" \$extra -- \${cur}) )
}
EOF
}

close () {
cat<<EOF
#------------------------------------------------------------------------------
EOF
}

# shellcheck disable=SC2154
_foamGet () {
cat <<EOF
_foamGet_ ()
$(header_start)
{
$(declareLocals)
_searchDirs () {
_dirs="\\
Expand All @@ -156,7 +147,8 @@ $(header_start)
for o in \$used ; do opts="\${opts/\$o/}" ; done
extra=""
opts="\${opts} \$(_searchDirs)"
$(header_end)
$(caseStart)
-case|-target)
opts="" ; extra="-d" ;;
-ext)
Expand All @@ -168,7 +160,8 @@ $(header_end)
*) opts=""; extra="" ;;
esac
;;
$(footer)
$(caseEnd)
}
complete -o filenames -o nospace -F _foamGet_ foamGet
EOF
Expand All @@ -178,13 +171,16 @@ EOF
_foamCloneCase () {
cat <<EOF
_foamCloneCase_ ()
$(header_start)
{
$(declareLocals)
opts="-add -help -latestTime -no-orig -no-scripts -processor -template"
for o in \$used ; do opts="\${opts/\$o/}" ; done
extra="-d"
$(header_end)
$(footer)
$(caseStart)
$(caseEnd)
}
complete -o filenames -o nospace -F _foamCloneCase_ foamCloneCase
EOF
Expand All @@ -208,156 +204,176 @@ do

echo "Configuring $appName"

# Check for special configurations
echo "$specialApps" | grep -qsw "$appName" && "_$appName" >> "$file" && continue

# ARGUMENTS between <> and []
usage=$($app -help | grep ^Usage)
args=$(echo "$usage" | awk -F '[]<>[]' '{for(i=2;i<=NF;++i)print $i}' | sed '/^[\t ]*$/d')

# Entries without "output", ending "file"
input_file_args=$(echo "$args" | while read -r line
do
echo "$line" | grep -v output | grep -E "file$"
done)
n_input_file_args=$(echo "$input_file_args" | sed '/^$/d' | wc -l)
# Entries without "output", including "case" or "dir*"
input_dir_args=$(echo "$args" | while read -r line
do
echo "$line" | grep -v output | grep -Ei "(case|dir).*"
done)
n_input_dir_args=$(echo "$input_dir_args" | sed '/^$/d' | wc -l)
# OPTIONS
opt_list=$($app -help | \
sed -n '/^options/,/^$/p' | \
grep -E "^[\t ]*-" | \
tr -s " ")
argless_opts="" # options without arguments
dir_opts="" # options with directory arguments
file_opts="" # options with file arguments
handler_opts="" # file handler options -fileHandler
ranges_opts="" # ranges options -time
arg_opts="" # options with unspecified arguments
# If a special configurations is defined for this app, use it and continue
echo "$specialApps" | \
grep -qsw "$appName" && "_$appName" >> "$file" && continue

# Get arguments. Anything on the usage line in <> or [] brackets.
argList=$($app -help | \
grep ^Usage | \
awk -F '[]>]' '{for(i=1;i<=NF;++i) print $i}' | \
awk -F ' [<[]' '{print $2}')

# Categorise arguments ...

# File arguments. Entries without "output", ending in "file".
inputFileArgs=$(echo "$argList" | while read -r line
do
echo "$line" | grep -v output | grep -E "file$"
done)
nInputFileArgs=$(echo "$inputFileArgs" | sed '/^$/d' | wc -l)
# Directory arguments. Entries without "output", including "case" or "dir*".
inputDirArgs=$(echo "$argList" | while read -r line
do
echo "$line" | grep -v output | grep -Ei "(case|dir).*"
done)
nInputDirArgs=$(echo "$inputDirArgs" | sed '/^$/d' | wc -l)
# Options. Anything in the between "options" and the next empty line.
optList=$($app -help | \
sed -n '/^options/,/^$/p' | \
grep -E "^[\t ]*-" | \
tr -s " ")
# Categorise options ...
arglessOpts="" # options without arguments
dirOpts="" # options with directory arguments
fileOpts="" # options with file arguments
handlerOpts="" # file handler options -fileHandler
rangesOpts="" # ranges options -time
argOpts="" # options with unspecified arguments
while read -r line
do
# Get the option
opt=$(echo "$line" | cut -d " " -f1 | tr -d " ")
# Get the string in <>. Hack cuts beyond field 5 to avoid (fvPatchField<vector>)
# Get the adjacent string in <> brackets
next=$(echo "$line" | \
cut -d " " -f1-5 | \
awk -F '[<>]' '{print $2}' | \
tr -d \) | tr -d \()
sed 's/ \<.*\>.*//g' | \
awk -F '>' '{print $1}' | \
awk -F ' <' '{print $2}' |
tr -d \) | \
tr -d \()
# Check the last word in string
# Categorise by the the last word in the string
case "${next##* }" in
"") argless_opts="$argless_opts $opt" ;;
dir) dir_opts="$dir_opts $opt" ;;
file) file_opts="$file_opts $opt";;
handler) handler_opts="$handler_opts $opt";;
ranges) ranges_opts="$ranges_opts $opt";;
*) arg_opts="$arg_opts $opt";;
"") arglessOpts="$arglessOpts $opt" ;;
dir) dirOpts="$dirOpts $opt" ;;
file) fileOpts="$fileOpts $opt";;
handler) handlerOpts="$handlerOpts $opt";;
ranges) rangesOpts="$rangesOpts $opt";;
*) argOpts="$argOpts $opt";;
esac
done<<< "$opt_list"
done<<< "$optList"
# Combine options into a single list
# shellcheck disable=SC2086
all_opts=$(printf '%s\n' $argless_opts $dir_opts $file_opts $handler_opts $ranges_opts $arg_opts | sort)
allOpts=$(printf '%s\n' \
$arglessOpts $dirOpts $fileOpts $handlerOpts $rangesOpts $argOpts | \
sort)
# WRITE FUNCTION
# Write the completion function ...
# shellcheck disable=SC2086
{
echo "_${appName}_ ()"
echo "{"
declareLocals
echo ""
# shellcheck disable=SC2027,SC2086
echo " opts=\""$allOpts"\""
echo " for o in \$used ; do opts=\"\${opts/\$o/}\" ; done"
if [ ! "$nInputFileArgs" = 0 ]
then
echo " extra=\"-d -f\""
elif [ ! "$nInputDirArgs" = 0 ]
then
echo " extra=\"-d\""
else
echo " extra=\"\""
fi
echo ""
caseStart
if [ -n "$dirOpts" ]
then
printf " %s)\n" "$(echo $dirOpts | tr " " "|")"
echo " opts=\"\" ; extra=\"-d\" ;;"
fi
if [ -n "$fileOpts" ]
then
printf " %s)\n" "$(echo $fileOpts | tr " " "|")"
echo " opts=\"\" ; extra=\"-d -f\" ;;"
fi
if [ -n "$handlerOpts" ]
then
printf " %s)\n" "$(echo $handlerOpts | tr " " "|")"
echo " opts=\"uncollated collated masterUncollated\" ; extra=\"\" ;;"
fi
if [ -n "$rangesOpts" ]
then
printf " %s)\n" "$(echo $rangesOpts | tr " " "|")"
echo " opts=\"\$(foamListTimes -withZero 2> /dev/null)\" ; extra=\"\" ;;"
fi
if [ -n "$argOpts" ]
then
printf " %s)\n" "$(echo $argOpts | tr " " "|")"
echo " opts=\"\" ; extra=\"\" ;;"
fi
# Set argOpts to all options with arguments
argOpts="$argOpts $dirOpts $fileOpts $handlerOpts $rangesOpts"
# Get the max of nInputFileArgs and nInputDirArgs
nMaxFileDirArgs=$nInputFileArgs
[ "$nInputDirArgs" -gt "$nMaxFileDirArgs" ] && \
nMaxFileDirArgs=$nInputDirArgs
# Stop optional arguments once mandatory arguments are entered
case "$nMaxFileDirArgs" in
0) echo " *) ;;" ;;
1)
echo " -*) ;;"
echo " *)"
if [ -z "${argOpts// }" ]
then
echo " opts=\"\"; extra=\"\""
else
echo " case \"\${COMP_WORDS[COMP_CWORD-2]}\" in"
printf " %s) ;;\n" \
"$(echo $argOpts | tr " " "|")"
echo " *) opts=\"\"; extra=\"\" ;;"
echo " esac"
fi
echo " ;;"
;;
*)
echo " -*) ;;"
echo " *) opts=\"\";;"
;;
esac
echo "_${appName}_ ()"
header_start
# shellcheck disable=SC2027,SC2086
echo " opts=\""$all_opts"\""
echo " for o in \$used ; do opts=\"\${opts/\$o/}\" ; done"
if [ ! "$n_input_file_args" = 0 ]
then
echo " extra=\"-d -f\""
elif [ ! "$n_input_dir_args" = 0 ]
then
echo " extra=\"-d\""
else
echo " extra=\"\""
fi
header_end
if [ -n "$dir_opts" ]
then
printf " %s)\n" "$(echo $dir_opts | tr " " "|")"
echo " opts=\"\" ; extra=\"-d\" ;;"
fi
if [ -n "$file_opts" ]
then
printf " %s)\n" "$(echo $file_opts | tr " " "|")"
echo " opts=\"\" ; extra=\"-d -f\" ;;"
fi
if [ -n "$handler_opts" ]
then
printf " %s)\n" "$(echo $handler_opts | tr " " "|")"
echo " opts=\"uncollated collated masterUncollated\" ; extra=\"\" ;;"
fi
if [ -n "$ranges_opts" ]
then
printf " %s)\n" "$(echo $ranges_opts | tr " " "|")"
echo " opts=\"\$(foamListTimes -withZero 2> /dev/null)\" ; extra=\"\" ;;"
fi
if [ -n "$arg_opts" ]
then
printf " %s)\n" "$(echo $arg_opts | tr " " "|")"
echo " opts=\"\" ; extra=\"\" ;;"
fi
# Set arg_opts to all options with arguments
arg_opts="$arg_opts $dir_opts $file_opts $handler_opts $ranges_opts"
# Get the max of n_input_file_args and n_input_dir_args
n_max_file_dir_args=$n_input_file_args
[ "$n_input_dir_args" -gt "$n_max_file_dir_args" ] && \
n_max_file_dir_args=$n_input_dir_args
# Stop optional arguments once mandatory arguments are entered
case "$n_max_file_dir_args" in
0) echo " *) ;;" ;;
1)
echo " -*) ;;"
echo " *)"
if [ -z "${arg_opts// }" ]
then
echo " opts=\"\"; extra=\"\""
else
echo " case \"\${COMP_WORDS[COMP_CWORD-2]}\" in"
printf " %s) ;;\n" "$(echo $arg_opts | tr " " "|")"
echo " *) opts=\"\"; extra=\"\" ;;"
echo " esac"
fi
echo " ;;"
;;
*)
echo " -*) ;;"
echo " *) opts=\"\";;"
;;
esac
footer
caseEnd
echo "}"
echo "complete -o filenames -o nospace -F _${appName}_ ${appName}"
echo ""
echo "complete -o filenames -o nospace -F _${appName}_ ${appName}"
echo ""
} >> "$file"
done
close >> "$file"
cat<<\EOF >> "$file"
#------------------------------------------------------------------------------
EOF
#------------------------------------------------------------------------------
Loading

0 comments on commit e603417

Please sign in to comment.