From e603417ef7bdcd1fd605c8d5b0ab5ef079aaa62d Mon Sep 17 00:00:00 2001 From: Will Bainbridge Date: Thu, 30 Jul 2020 16:46:51 +0100 Subject: [PATCH] bin/tools/foamGenerateBashCompletion: Improved robustness of bracket parsing Also minor formatting changes --- bin/tools/foamGenerateBashCompletion | 316 ++++++++++++++------------- etc/config.sh/bash_completion | 2 +- wmake/wmakeCheckPwd | 4 +- wmake/wmakeLnInclude | 4 +- 4 files changed, 171 insertions(+), 155 deletions(-) diff --git a/bin/tools/foamGenerateBashCompletion b/bin/tools/foamGenerateBashCompletion index ca53184038..dd62679dfa 100755 --- a/bin/tools/foamGenerateBashCompletion +++ b/bin/tools/foamGenerateBashCompletion @@ -92,36 +92,26 @@ banner () { EOF } -header_start () { +declareLocals () { cat <> "$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) + # 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 + #------------------------------------------------------------------------------ diff --git a/etc/config.sh/bash_completion b/etc/config.sh/bash_completion index 68851daaff..869bece7b9 100644 --- a/etc/config.sh/bash_completion +++ b/etc/config.sh/bash_completion @@ -5509,7 +5509,7 @@ _foamInfo_ () [ "$COMP_CWORD" = 1 ] || \ case "$prev" in - -browser|-keyword) + -browser) opts="" ; extra="" ;; *) ;; esac diff --git a/wmake/wmakeCheckPwd b/wmake/wmakeCheckPwd index 2112ef7be0..befd3580b2 100755 --- a/wmake/wmakeCheckPwd +++ b/wmake/wmakeCheckPwd @@ -3,7 +3,7 @@ # ========= | # \\ / F ield | OpenFOAM: The Open Source CFD Toolbox # \\ / O peration | Website: https://openfoam.org -# \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation +# \\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation # \\/ M anipulation | #------------------------------------------------------------------------------ # License @@ -39,7 +39,7 @@ unset quietOpt usage() { cat<