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>
This commit is contained in:
Shlok Kulshreshtha authored and Junio C Hamano committed 2026-07-23 07:14:34 -07:00
1 parent 41365c2a9b
commit 113d62b141
15 files changed
+86

No files matched your search

+2
View File
@@ -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.
+5
View File
@@ -0,0 +1,5 @@
actor RIGHT {
let a = 1
// a comment
let b = ChangeMe
}
+7
View File
@@ -0,0 +1,7 @@
struct View {
@available(iOS 13, *) public func RIGHT() {
let a = 1
// a comment
print(ChangeMe)
}
}
+5
View File
@@ -0,0 +1,5 @@
class RIGHT {
let a = 1
// a comment
let b = ChangeMe
}
+5
View File
@@ -0,0 +1,5 @@
enum RIGHT {
case first
// a comment
case ChangeMe
}
+5
View File
@@ -0,0 +1,5 @@
extension RIGHT {
static let a = 1
// a comment
static let b = ChangeMe
}
+7
View File
@@ -0,0 +1,7 @@
class Bar {
init?(RIGHT: Int) {
let x = 0
// a comment
print(ChangeMe)
}
}
+5
View File
@@ -0,0 +1,5 @@
func RIGHT(x: Int) -> Int {
let y = x
// a comment
return ChangeMe
}
+7
View File
@@ -0,0 +1,7 @@
struct Container {
subscript<RIGHT>(index: Int) -> Int {
let a = 0
// a comment
return ChangeMe
}
}
+7
View File
@@ -0,0 +1,7 @@
class Foo {
init(RIGHT: Int) {
let x = 0
// a comment
print(ChangeMe)
}
}
+7
View File
@@ -0,0 +1,7 @@
class Service {
@objc func RIGHT() {
let path = "/api"
// a comment
log(ChangeMe)
}
}
+4
View File
@@ -0,0 +1,4 @@
public static func RIGHT() -> Int {
// a comment
return ChangeMe
}
+5
View File
@@ -0,0 +1,5 @@
protocol RIGHT {
var first: Int { get }
// a comment
var second: ChangeMe { get }
}
+5
View File
@@ -0,0 +1,5 @@
struct RIGHT {
let a = 1
// a comment
let b = ChangeMe
}
+10
View File
@@ -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 },