@leroysheep / CrazyWebTemps / commits / 113d62b141

userdiff: add support for Swift

Add a built-in userdiff driver for the Swift programming language so that diff hunk headers and word diffs work out of the box for ".swift" files. The funcname pattern is built for Swift's own declaration grammar: an optional run of attributes ("@objc", "@available(iOS 13, *)", ...), followed by an optional run of lowercase modifiers ("public", "static", "final", ...), followed by a declaration keyword (func, class, struct, enum, protocol, extension, actor, init, deinit, subscript). The keyword is followed by a boundary that allows whitespace, "(" (init/subscript), "?" or "!" (failable init), or "<" (generics), while still acting as a word boundary so e.g. "initialize(" does not match. The word regex recognizes Swift identifiers, hexadecimal, octal, binary, integer and floating-point literals, and the language's operators. Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shlok Kulshreshtha committed Jul 21, 2026 at 12:27 UTC 113d62b141a80bf136268df51b4597dbec4355d0
15 files changed +86
Documentation/gitattributes.adoc
+2
index bd76167a45..9fea75f96f 100644 --- a/Documentation/gitattributes.adoc +++ b/Documentation/gitattributes.adoc @@ -914,6 +914,8 @@ patterns are available: - `scheme` suitable for source code in most Lisp dialects, including Scheme, Emacs Lisp, Common Lisp, and Clojure. +- `swift` suitable for source code in the Swift language. + - `tex` suitable for source code for LaTeX documents.
t/t4018/swift-actor
+5
new file mode 100644 index 0000000000..e4852f40a7 --- /dev/null +++ b/t/t4018/swift-actor @@ -0,0 +1,5 @@ +actor RIGHT { + let a = 1 + // a comment + let b = ChangeMe +}
t/t4018/swift-attribute-with-args
+7
new file mode 100644 index 0000000000..22b1ee32f1 --- /dev/null +++ b/t/t4018/swift-attribute-with-args @@ -0,0 +1,7 @@ +struct View { + @available(iOS 13, *) public func RIGHT() { + let a = 1 + // a comment + print(ChangeMe) + } +}
t/t4018/swift-class
+5
new file mode 100644 index 0000000000..c3a9336027 --- /dev/null +++ b/t/t4018/swift-class @@ -0,0 +1,5 @@ +class RIGHT { + let a = 1 + // a comment + let b = ChangeMe +}
t/t4018/swift-enum
+5
new file mode 100644 index 0000000000..0a84302993 --- /dev/null +++ b/t/t4018/swift-enum @@ -0,0 +1,5 @@ +enum RIGHT { + case first + // a comment + case ChangeMe +}
t/t4018/swift-extension
+5
new file mode 100644 index 0000000000..cbc18ab6ef --- /dev/null +++ b/t/t4018/swift-extension @@ -0,0 +1,5 @@ +extension RIGHT { + static let a = 1 + // a comment + static let b = ChangeMe +}
t/t4018/swift-failable-init
+7
new file mode 100644 index 0000000000..4bbd6217c9 --- /dev/null +++ b/t/t4018/swift-failable-init @@ -0,0 +1,7 @@ +class Bar { + init?(RIGHT: Int) { + let x = 0 + // a comment + print(ChangeMe) + } +}
t/t4018/swift-func
+5
new file mode 100644 index 0000000000..1fecae0911 --- /dev/null +++ b/t/t4018/swift-func @@ -0,0 +1,5 @@ +func RIGHT(x: Int) -> Int { + let y = x + // a comment + return ChangeMe +}
t/t4018/swift-generic-subscript
+7
new file mode 100644 index 0000000000..423cb58941 --- /dev/null +++ b/t/t4018/swift-generic-subscript @@ -0,0 +1,7 @@ +struct Container { + subscript<RIGHT>(index: Int) -> Int { + let a = 0 + // a comment + return ChangeMe + } +}
t/t4018/swift-init
+7
new file mode 100644 index 0000000000..dc7a298f38 --- /dev/null +++ b/t/t4018/swift-init @@ -0,0 +1,7 @@ +class Foo { + init(RIGHT: Int) { + let x = 0 + // a comment + print(ChangeMe) + } +}
t/t4018/swift-inline-attribute
+7
new file mode 100644 index 0000000000..2374c4b603 --- /dev/null +++ b/t/t4018/swift-inline-attribute @@ -0,0 +1,7 @@ +class Service { + @objc func RIGHT() { + let path = "/api" + // a comment + log(ChangeMe) + } +}
t/t4018/swift-modifiers
+4
new file mode 100644 index 0000000000..9d80685a78 --- /dev/null +++ b/t/t4018/swift-modifiers @@ -0,0 +1,4 @@ +public static func RIGHT() -> Int { + // a comment + return ChangeMe +}
t/t4018/swift-protocol
+5
new file mode 100644 index 0000000000..07c39ec2a3 --- /dev/null +++ b/t/t4018/swift-protocol @@ -0,0 +1,5 @@ +protocol RIGHT { + var first: Int { get } + // a comment + var second: ChangeMe { get } +}
t/t4018/swift-struct
+5
new file mode 100644 index 0000000000..e399ed7759 --- /dev/null +++ b/t/t4018/swift-struct @@ -0,0 +1,5 @@ +struct RIGHT { + let a = 1 + // a comment + let b = ChangeMe +}
userdiff.c
+10
index b5412e6bc3..7129bf1482 100644 --- a/userdiff.c +++ b/userdiff.c @@ -362,6 +362,16 @@ PATTERNS("scheme", "\\|([^|\\\\]|\\\\.)*\\|" /* All other words should be delimited by spaces or parentheses. */ "|([^][)(}{ \t])+"), +PATTERNS("swift", + "^[ \t]*((@[A-Za-z_][A-Za-z0-9_]*(\\([^()]*\\))?[ \t]+)*([a-z]+[ \t]+)*(func|init|deinit|subscript|class|struct|enum|protocol|extension|actor)[ \t(?!<].*)$", + /* -- */ + "[a-zA-Z_][a-zA-Z0-9_]*" + /* hexadecimal, octal, and binary literals */ + "|0[xX][0-9a-fA-F_]+|0[oO][0-7_]+|0[bB][01_]+" + /* integers and floating-point numbers */ + "|[0-9][0-9_]*([.][0-9_]+)?([eE][-+]?[0-9]+)?" + /* unary and binary operators */ + "|[-+*/%<>=!&|^~?]=|&&|\\|\\||<<=?|>>=?|\\?\\?|\\.\\.[.<]|->"), PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", "\\\\[a-zA-Z@]+|\\\\.|([a-zA-Z0-9]|[^\x01-\x7f])+"), { .name = "default", .binary = -1 },