git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4 1/1][GSOC] userdiff: extend Bash pattern to cover more shell function forms

From
Moumita <dhar61595@gmail.com>
Date
Mar 30, 2025, 13:39 UTC
Message-ID
<20250330134018.9662-2-dhar61595@gmail.com>
In-Reply-To
<20250330134018.9662-1-dhar61595@gmail.com>
From: Moumita Dhar <dhar61595@gmail.com>

The previous function regex required explicit matching of function bodies using `{`, `(`, `((`, or `[[`, which caused several issues:

- It failed to capture valid functions where `{` was on the next line
  due to line continuation (`\`).
- It did not recognize functions with single  command body, such as
  `x () echo hello`.

Replacing the function body matching logic with `.*$`, ensures that everything on the function definition line is captured, aligning with other userdiff drivers and improving hunk headers in `git diff`.

Additionally, the word regex is refined to better recognize shell syntax, including additional parameter expansion operators and command-line options, improving syntax-aware diffs.

Signed-off-by: Moumita Dhar <dhar61595@gmail.com>
---
 t/t4018/bash-bashism-style-multiline-function |  4 +++
 t/t4018/bash-posix-style-multiline-function   |  4 +++
 .../bash-posix-style-single-command-function  |  3 ++
 t/t4034-diff-words.sh                         |  1 +
 t/t4034/bash/expect                           | 30 +++++++++++++++++++
 t/t4034/bash/post                             | 25 ++++++++++++++++
 t/t4034/bash/pre                              | 25 ++++++++++++++++
 userdiff.c                                    | 24 +++++++++++----
 8 files changed, 110 insertions(+), 6 deletions(-)
 create mode 100644 t/t4018/bash-bashism-style-multiline-function
 create mode 100644 t/t4018/bash-posix-style-multiline-function
 create mode 100644 t/t4018/bash-posix-style-single-command-function
 create mode 100644 t/t4034/bash/expect
 create mode 100644 t/t4034/bash/post
 create mode 100644 t/t4034/bash/pre
diff --git a/t/t4018/bash-bashism-style-multiline-function b/t/t4018/bash-bashism-style-multiline-function
new file mode 100644
index 0000000000..284d50dd99
--- /dev/null
+++ b/t/t4018/bash-bashism-style-multiline-function
@@ -0,0 +1,4 @@
+function RIGHT \
+{    
+    echo 'ChangeMe'
+}
diff --git a/t/t4018/bash-posix-style-multiline-function b/t/t4018/bash-posix-style-multiline-function
new file mode 100644
index 0000000000..cc8727cbcd
--- /dev/null
+++ b/t/t4018/bash-posix-style-multiline-function
@@ -0,0 +1,4 @@
+RIGHT() \
+{
+    ChangeMe
+}
diff --git a/t/t4018/bash-posix-style-single-command-function b/t/t4018/bash-posix-style-single-command-function
new file mode 100644
index 0000000000..398ae1c5d2
--- /dev/null
+++ b/t/t4018/bash-posix-style-single-command-function
@@ -0,0 +1,3 @@
+RIGHT() echo "hello"
+
+    ChangeMe
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index f51d3557f1..0be647c2fb 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -320,6 +320,7 @@ test_expect_success 'unset default driver' '
 
 test_language_driver ada
 test_language_driver bibtex
+test_language_driver bash
 test_language_driver cpp
 test_language_driver csharp
 test_language_driver css
diff --git a/t/t4034/bash/expect b/t/t4034/bash/expect
new file mode 100644
index 0000000000..a0f7cbd5a3
--- /dev/null
+++ b/t/t4034/bash/expect
@@ -0,0 +1,30 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 09ac008..60ba6a2 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,25 +1,25 @@<RESET>
+<RED>my_var<RESET><GREEN>new_var<RESET>=10
+x=<RED>123<RESET><GREEN>456<RESET>
+y=<RED>3.14<RESET><GREEN>2.71<RESET>
+z=<RED>.5<RESET><GREEN>.75<RESET>
+echo <RED>$USER<RESET><GREEN>$USERNAME<RESET>
+${<RED>HOME<RESET><GREEN>HOMEDIR<RESET>}
+if [ "<RED>$a<RESET><GREEN>$x<RESET>" == "<RED>$b<RESET><GREEN>$y<RESET>" ] || [ "<RED>$c<RESET><GREEN>$x<RESET>" != "<RED>$d<RESET><GREEN>$y<RESET>" ]; then echo "OK"; fi
+((<RED>a<RESET><GREEN>x<RESET>+=<RED>b<RESET><GREEN>y<RESET>))
+((<RED>a<RESET><GREEN>x<RESET>-=<RED>b<RESET><GREEN>y<RESET>))
+$((<RED>a<RESET><GREEN>x<RESET><<<RED>b<RESET><GREEN>y<RESET>))
+$((<RED>a<RESET><GREEN>x<RESET>>><RED>b<RESET><GREEN>y<RESET>))
+${<RED>a<RESET><GREEN>x<RESET>:-<RED>b<RESET><GREEN>y<RESET>}
+${<RED>a<RESET><GREEN>x<RESET>:=<RED>b<RESET><GREEN>y<RESET>}
+${<RED>a<RESET><GREEN>x<RESET>##*/}
+${<RED>a<RESET><GREEN>x<RESET>%.*}
+${<RED>a<RESET><GREEN>x<RESET>%%.*}
+${<RED>a<RESET><GREEN>x<RESET>^^}
+${<RED>a<RESET><GREEN>x<RESET>,}
+${<RED>a<RESET><GREEN>x<RESET>,,}
+${!<RED>a<RESET><GREEN>x<RESET>}
+${<RED>a<RESET><GREEN>x<RESET>[@]}
+${<RED>a<RESET><GREEN>x<RESET>:?error message}
+${<RED>a<RESET><GREEN>x<RESET>:2:3}
+ls <RED>-a<RESET><GREEN>-x<RESET>
+ls <RED>--a<RESET><GREEN>--x<RESET>
diff --git a/t/t4034/bash/post b/t/t4034/bash/post
new file mode 100644
index 0000000000..60ba6a2e75
--- /dev/null
+++ b/t/t4034/bash/post
@@ -0,0 +1,25 @@
+new_var=10
+x=456
+y=2.71
+z=.75
+echo $USERNAME
+${HOMEDIR}
+if [ "$x" == "$y" ] || [ "$x" != "$y" ]; then echo "OK"; fi
+((x+=y))
+((x-=y))
+$((x<<y))
+$((x>>y))
+${x:-y}
+${x:=y}
+${x##*/}
+${x%.*}
+${x%%.*}
+${x^^}
+${x,}
+${x,,}
+${!x}
+${x[@]}
+${x:?error message}
+${x:2:3}
+ls -x
+ls --x
diff --git a/t/t4034/bash/pre b/t/t4034/bash/pre
new file mode 100644
index 0000000000..09ac008a83
--- /dev/null
+++ b/t/t4034/bash/pre
@@ -0,0 +1,25 @@
+my_var=10
+x=123
+y=3.14
+z=.5
+echo $USER
+${HOME}
+if [ "$a" == "$b" ] || [ "$c" != "$d" ]; then echo "OK"; fi
+((a+=b))
+((a-=b))
+$((a << b))
+$((a >> b))
+${a:-b}
+${a:=b}
+${a##*/}
+${a%.*}
+${a%%.*}
+${a^^}
+${a,}
+${a,,}
+${!a}
+${a[@]}
+${a:?error message}
+${a:2:3}
+ls -a
+ls --a
diff --git a/userdiff.c b/userdiff.c
index 340c4eb4f7..4c77c7e0f6 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -64,15 +64,27 @@ PATTERNS("bash",
 	     /* Bashism identifier with optional parentheses */
 	     "(function[ \t]+[a-zA-Z_][a-zA-Z0-9_]*(([ \t]*\\([ \t]*\\))|([ \t]+))"
 	 ")"
-	 /* Optional whitespace */
-	 "[ \t]*"
-	 /* Compound command starting with `{`, `(`, `((` or `[[` */
-	 "(\\{|\\(\\(?|\\[\\[)"
+	 /* Everything after the function header is captured  */
+	 ".*$"
 	 /* End of captured text */
 	 ")",
 	 /* -- */
-	 /* 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]*)?|[-+]?\\.[0-9]+"
+	 /* Shell variables: $VAR, ${VAR} */
+	  "|\\$[a-zA-Z_][a-zA-Z0-9_]*|\\$\\{"
+	  /* Logical and comparison operators */
+	 "|\\|\\||&&|<<|>>|==|!=|<=|>="
+	 /* Assignment and arithmetic operators */
+	 "|[-+*/%&|^!=<>]=?"
+	 /* Additional parameter expansion operators */
+	 "|:?=|:-|:\\+|:\\?|:|#|##|%|%%|/[a-zA-Z0-9_-]+|\\^\\^?|,|,,?|!|@|:[0-9]+(:[0-9]+)?"
+	 /* Command-line options (to avoid splitting -option) */
+	 "|--?[a-zA-Z0-9_-]+"
+	 /* Brackets and grouping symbols */
+	 "|\\(|\\)|\\{|\\}|\\[|\\]"),
 PATTERNS("bibtex",
 	 "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
 	 /* -- */
-- 
2.48.0
Previous: MoumitaNext: Junio C Hamano
Message 17 of 37 in “[GSOC 2025] [Newbie] userdiff: add built-in pattern for shell scripts”
  1. 0/1 [GSOC 2025] [Newbie] userdiff: add built-in pattern for shell scriptsMoumita, Feb 11, 2025
  2. 1/1 Added built in function recognition for shellMoumita, Feb 11, 2025
  3. Johannes SixtFeb 15, 2025
  4. 0/1 [PATCH v2 0/1] [GSOC 2025] [Newbie] userdiff: add built-in pattern for shell scriptsMoumita, Feb 18, 2025
  5. 1/1 userdiff: extend Bash pattern to cover more shell function formsMoumita, Feb 18, 2025
  6. Junio C HamanoFeb 18, 2025
  7. Johannes SixtFeb 22, 2025
  8. Junio C HamanoFeb 24, 2025
  9. Junio C HamanoFeb 18, 2025
  10. Johannes SixtFeb 22, 2025
  11. Eric SunshineFeb 18, 2025
  12. 0/1 userdiff: improve Bash function and word regex patternsMoumita, Mar 28, 2025
  13. 1/1 userdiff: extend Bash pattern to cover more shell function formsMoumita, Mar 28, 2025
  14. Junio C HamanoMar 29, 2025
  15. MOUMITA DHARMar 30, 2025
  16. 0/1 [GSOC] userdiff:Added newlines at the end of the test casesMoumita, Mar 30, 2025
  17. 1/1 [GSOC] userdiff: extend Bash pattern to cover more shell function formsMoumita, Mar 30, 2025
  18. Junio C HamanoMay 2, 2025
  19. Johannes SixtMay 6, 2025
  20. MOUMITA DHARMay 10, 2025
  21. Johannes SixtMay 10, 2025
  22. 0/1 Added the closing ")" to make sure is not unbalanced and corrected the tests for word diffMoumita, May 11, 2025
  23. 1/1 userdiff: extend Bash pattern to cover more shell function formsMoumita, May 11, 2025
  24. Moumita, May 11, 2025
  25. Moumita, May 11, 2025
  26. Moumita, May 11, 2025
  27. 0/1 Added the newline after the test in t/4018Moumita, May 11, 2025
  28. 1/1 userdiff: extend Bash pattern to cover more shell function formsMoumita, May 11, 2025
  29. Junio C HamanoMay 13, 2025
  30. MOUMITA DHARMay 14, 2025
  31. Johannes SixtMay 16, 2025
  32. Junio C HamanoMay 17, 2025
  33. Johannes SixtMay 18, 2025
  34. 0/1 Updated the word diff regex for Bash scriptsMoumita, May 16, 2025
  35. 1/1 userdiff: extend Bash pattern to cover more shell function formsMoumita, May 16, 2025
  36. Johannes SixtMay 16, 2025
  37. Junio C HamanoMay 16, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.