The modifications that I made were -
"^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*\\([ \t]*\\)[ \t]*" - so that is allows foo() and foo ( ).
"^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*\\([ \t]*\\)[ \t]*(\\{|\\(|\\[\\[)" - so that it recognises {, (, or [[ as function bodies
"^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*\\([ \t]*\\)[ \t]*(\\{|\\(|\\[\\[)|\\\\\n"- so that it matches "function foo \
{ echo "hello"; }"
"(?:function[ \t]+(?=[a-zA-Z_]))?[a-zA-Z_][a-zA-Z0-9_]*(([ \t]*\\([ \t]*\\))|([ \t]+))?" - so that it matches function foo() { echo "hello"; }
and also function bar { echo "no parens"; }
"|\\$[a-zA-Z_][a-zA-Z0-9_]*|\\$\\{[^}]+\\}"- It seperates ${} expansions
"|--?[a-zA-Z0-9_-]+" - It ensures -opt and --long-opt are treated as whole tokens.
"|[0-9]+(\\.[0-9]*)?" - It matches numbers without +/-Moumita Dhar (1):
userdiff: extend Bash pattern to cover more shell function forms
userdiff.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
Range-diff against v1:
1: 683ea08819 ! 1: de2e8f9792 userdiff : Added built in function recognition for shell
@@
## Metadata ##
-Author: Moumita <dhar61595@gmail.com>
+Author: Moumita Dhar <dhar61595@gmail.com>
## Commit message ##
- userdiff : Added built in function recognition for shell
+ userdiff: extend Bash pattern to cover more shell function forms
- Introduced a built-in userdiff driver for shell scripts, enabling
- accurate function name recognition in `git diff` hunk headers.
+ The existing Bash userdiff pattern misses some shell function forms, such as
+ `function foo()`, multi-line definitions, and extra whitespace.
- Enhancements include:
- - Function name detection for both POSIX and Bash/Ksh-style functions:
- - `function_name() { ... }`
- - `function function_name { ... }`
- - Exclusion of shell keywords that can resemble function names,
- preventing false matches (e.g., `if`, `for`, `while`, `return`, etc.).
- - Improved tokenization support for:
- - Identifiers (variable and function names)
- - Numeric constants (integers and decimals)
- - Shell variables (`$VAR`, `${VAR}`)
- - Logical (`&&`, `||`, `==`, `!=`, `<=`, `>=`) and arithmetic operators
- - Assignment and redirection operators
- - Brackets and grouping symbols
+ Extend the pattern to:
+ - Support `function foo()` syntax.
+ - Allow spaces in `foo ( )` definitions.
+ - Recognize multi-line definitions with backslashes.
+ - Broaden function body detection.
- This update improves Git’s diff readability for shell scripts,
- bringing it in line with existing built-in userdiff drivers.
-
- Signed-off-by: Moumita <dhar61595@gmail.com>
+ Signed-off-by: Moumita Dhar <dhar61595@gmail.com>
## userdiff.c ##
-@@ userdiff.c: PATTERNS("scheme",
- "\\|([^\\\\]*)\\|"
- /* All other words should be delimited by spaces or parentheses */
- "|([^][)(}{[ \t])+"),
-+PATTERNS("shell",
-+ /* Negate shell keywords that can look like functions */
-+ "!^[ \t]*(if|elif|else|fi|for|while|until|case|esac|then|do|done|return|break|continue)\\b\n"
-+ /* POSIX-style shell functions: function_name() { ... } */
-+ "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*\\(\\)[ \t]*\\{\n"
-+ /* Bash/Ksh-style functions: function function_name { ... } */
-+ "^[ \t]*function[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*\\{\n",
-+ /* -- */
+@@ userdiff.c: IPATTERN("ada",
+ "|[-+]?[0-9][0-9#_.aAbBcCdDeEfF]*([eE][+-]?[0-9_]+)?"
+ "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"),
+ PATTERNS("bash",
+- /* Optional leading indentation */
++ /* Optional leading indentation */
+ "^[ \t]*"
+- /* Start of captured text */
++ /* Start of captured function name */
+ "("
+ "("
+- /* POSIX identifier with mandatory parentheses */
+- "[a-zA-Z_][a-zA-Z0-9_]*[ \t]*\\([ \t]*\\))"
++ /* POSIX identifier with mandatory parentheses (allow spaces inside) */
++ "[a-zA-Z_][a-zA-Z0-9_]*[ \t]*\\([ \t]*\\)"
+ "|"
+- /* Bashism identifier with optional parentheses */
+- "(function[ \t]+[a-zA-Z_][a-zA-Z0-9_]*(([ \t]*\\([ \t]*\\))|([ \t]+))"
++ /* Bash-style function definitions, allowing optional `function` keyword */
++ "(?:function[ \t]+(?=[a-zA-Z_]))?[a-zA-Z_][a-zA-Z0-9_]*(([ \t]*\\([ \t]*\\))|([ \t]+))?"
+ ")"
+ /* Optional whitespace */
+ "[ \t]*"
+- /* Compound command starting with `{`, `(`, `((` or `[[` */
+- "(\\{|\\(\\(?|\\[\\[)"
+- /* End of captured text */
++ /* Allow function body to start with `{`, `(` (subshell), `[[` */
++ "(\\{|\\(|\\[\\[)"
++ /* End of captured function name */
+ ")",
+ /* -- */
+- /* Characters not in the default $IFS value */
+- "[^ \t]+"),
+ /* Identifiers: variable and function names */
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ /* Numeric constants: integers and decimals */
-+ "|[-+]?[0-9]+(\\.[0-9]*)?"
-+ /* Shell variables: $VAR and ${VAR} */
++ "|[-+]?[0-9]+(\\.[0-9]*)?|[-+]?\\.[0-9]+"
++ /* Shell variables: `$VAR`, `${VAR}` */
+ "|\\$[a-zA-Z_][a-zA-Z0-9_]*|\\$\\{[^}]+\\}"
+ /* Logical and comparison operators */
+ "|\\|\\||&&|<<|>>|==|!=|<=|>="
+ /* Assignment and arithmetic operators */
+ "|[-+*/%&|^!=<>]=?"
++ /* Command-line options (to avoid splitting `-option`) */
++ "|--?[a-zA-Z0-9_-]+"
+ /* Brackets and grouping symbols */
+ "|\\(|\\)|\\{|\\}|\\[|\\]"),
- PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
- "\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"),
- { .name = "default", .binary = -1 },
+ PATTERNS("bibtex",
+ "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
+ /* -- */