mbox series

[v2,0/1,v2,0/1,GSOC,2025,Newbie] userdiff: add built-in pattern for shell scripts

Message ID 20250218153537.16320-1-dhar61595@gmail.com (mailing list archive)
Headers show
Series userdiff: add built-in pattern for shell scripts | expand

Message

Moumita Feb. 18, 2025, 3:35 p.m. UTC
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\"@',\\#}{~%]*).*$",
    + 	 /* -- */

Comments

Eric Sunshine Feb. 18, 2025, 5:30 p.m. UTC | #1
On Tue, Feb 18, 2025 at 10:36 AM Moumita <dhar61595@gmail.com> wrote:
> 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

Regarding this last point, for completeness, I had meant to respond to
j6t's review of your patch by saying that, according to POSIX, a
function body can be any compound command, which means the body does
not need to be encased in braces. For instance, this works:

    $ foo() echo nothing
    $ foo
    nothing
    $

That said, I doubt that this usage is common, thus is probably not
worth worrying about.