userdiff: support Bash

Support POSIX, bashism and mixed function declarations, all four compound command types, trailing comments and mixed whitespace. Even though Bash allows locale-dependent characters in function names <https://unix.stackexchange.com/a/245336/3645>, only detect function names with characters allowed by POSIX.1-2017 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_235> for simplicity. This should cover the vast majority of use cases, and produces system-agnostic results. Since a word pattern has to be specified, but there is no easy way to know the default word pattern, use the default `IFS` characters for a starter. A later patch can improve this. Signed-off-by: Victor Engmark <victor@engmark.name> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Victor Engmark committed Oct 22, 2020 at 12:45 UTC 2ff6c34612057baccbd841524106c5a05f6be6d6
18 files changed +91
Documentation/gitattributes.txt
+3
@@ -802,6 +802,9 @@ patterns are available:
802
803 - `ada` suitable for source code in the Ada language.
804
805 +- `bash` suitable for source code in the Bourne-Again SHell language.
806 + Covers a superset of POSIX shell function definitions.
807 +
808 - `bibtex` suitable for files with BibTeX coded references.
809
810 - `cpp` suitable for source code in the C and C++ languages.
t/t4018-diff-funcname.sh
+1
@@ -27,6 +27,7 @@ test_expect_success 'setup' '
27
28 diffpatterns="
29 ada
30 + bash
31 bibtex
32 cpp
33 csharp
t/t4018/bash-arithmetic-function new
+4
@@ -0,0 +1,4 @@
1 +RIGHT() ((
2 +
3 + ChangeMe = "$x" + "$y"
4 +))
t/t4018/bash-bashism-style-compact new
+6
@@ -0,0 +1,6 @@
1 +function RIGHT {
2 + function InvalidSyntax{
3 + :
4 + echo 'ChangeMe'
5 + }
6 +}
t/t4018/bash-bashism-style-function new
+4
@@ -0,0 +1,4 @@
1 +function RIGHT {
2 + :
3 + echo 'ChangeMe'
4 +}
t/t4018/bash-bashism-style-whitespace new
+4
@@ -0,0 +1,4 @@
1 + function RIGHT ( ) {
2 +
3 + ChangeMe
4 + }
t/t4018/bash-conditional-function new
+4
@@ -0,0 +1,4 @@
1 +RIGHT() [[ \
2 +
3 + "$a" > "$ChangeMe"
4 +]]
t/t4018/bash-missing-parentheses new
+6
@@ -0,0 +1,6 @@
1 +function RIGHT {
2 + functionInvalidSyntax {
3 + :
4 + echo 'ChangeMe'
5 + }
6 +}
t/t4018/bash-mixed-style-compact new
+4
@@ -0,0 +1,4 @@
1 +function RIGHT(){
2 + :
3 + echo 'ChangeMe'
4 +}
t/t4018/bash-mixed-style-function new
+4
@@ -0,0 +1,4 @@
1 +function RIGHT() {
2 +
3 + ChangeMe
4 +}
t/t4018/bash-nested-functions new
+6
@@ -0,0 +1,6 @@
1 +outer() {
2 + RIGHT() {
3 + :
4 + echo 'ChangeMe'
5 + }
6 +}
t/t4018/bash-other-characters new
+4
@@ -0,0 +1,4 @@
1 +_RIGHT_0n() {
2 +
3 + ChangeMe
4 +}
t/t4018/bash-posix-style-compact new
+4
@@ -0,0 +1,4 @@
1 +RIGHT(){
2 +
3 + ChangeMe
4 +}
t/t4018/bash-posix-style-function new
+4
@@ -0,0 +1,4 @@
1 +RIGHT() {
2 +
3 + ChangeMe
4 +}
t/t4018/bash-posix-style-whitespace new
+4
@@ -0,0 +1,4 @@
1 + RIGHT ( ) {
2 +
3 + ChangeMe
4 + }
t/t4018/bash-subshell-function new
+4
@@ -0,0 +1,4 @@
1 +RIGHT() (
2 +
3 + ChangeMe=2
4 +)
t/t4018/bash-trailing-comment new
+4
@@ -0,0 +1,4 @@
1 +RIGHT() { # Comment
2 +
3 + ChangeMe
4 +}
userdiff.c
+21
@@ -23,6 +23,27 @@ IPATTERN("ada",
23 "[a-zA-Z][a-zA-Z0-9_]*"
24 "|[-+]?[0-9][0-9#_.aAbBcCdDeEfF]*([eE][+-]?[0-9_]+)?"
25 "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"),
26 +PATTERNS("bash",
27 + /* Optional leading indentation */
28 + "^[ \t]*"
29 + /* Start of captured text */
30 + "("
31 + "("
32 + /* POSIX identifier with mandatory parentheses */
33 + "[a-zA-Z_][a-zA-Z0-9_]*[ \t]*\\([ \t]*\\))"
34 + "|"
35 + /* Bashism identifier with optional parentheses */
36 + "(function[ \t]+[a-zA-Z_][a-zA-Z0-9_]*(([ \t]*\\([ \t]*\\))|([ \t]+))"
37 + ")"
38 + /* Optional whitespace */
39 + "[ \t]*"
40 + /* Compound command starting with `{`, `(`, `((` or `[[` */
41 + "(\\{|\\(\\(?|\\[\\[)"
42 + /* End of captured text */
43 + ")",
44 + /* -- */
45 + /* Characters not in the default $IFS value */
46 + "[^ \t]+"),
47 PATTERNS("dts",
48 "!;\n"
49 "!=\n"