{"thread":{"id":"66028","subject":"[PATCH] userdiff: add support for Swift","startedAt":"2026-07-17T14:02:44Z","lastAt":"2026-07-27T17:37:20Z","messageCount":12,"participants":["Shlok Kulshreshtha","Junio C Hamano","Johannes Sixt","Michael Montalbo"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"548509","messageId":"20260717140232.6722-1-diy2903@gmail.com","threadId":"66028","inReplyTo":null,"subject":"[PATCH] userdiff: add support for Swift","fromName":"Shlok Kulshreshtha","fromEmail":"diy2903@gmail.com","sentAt":"2026-07-17T14:02:29Z","receivedAt":"2026-07-17T14:02:44Z","isPatch":true,"body":"Add a built-in userdiff driver for the Swift programming language so that\ndiff hunk headers and word diffs work out of the box for \".swift\" files.\n\nThe funcname pattern is built for Swift's own declaration grammar: an\noptional run of attributes (\"@objc\", \"@available(iOS 13, *)\", ...),\nfollowed by an optional run of lowercase modifiers (\"public\", \"static\",\n\"final\", ...), followed by a declaration keyword (func, class, struct,\nenum, protocol, extension, actor, init, deinit, subscript). The keyword\nis followed by a boundary that allows whitespace, \"(\" (init/subscript),\n\"?\" or \"!\" (failable init), or \"<\" (generics), while still acting as a\nword boundary so e.g. \"initialize(\" does not match.\n\nThe word regex recognizes Swift identifiers, hexadecimal, octal, binary,\ninteger and floating-point literals, and the language's operators.\n\nSigned-off-by: Shlok Kulshreshtha <diy2903@gmail.com>\n---\nThis addresses the \"add a userdiff driver for a language\" microproject.\nSwift is not covered by a built-in driver yet, and I did not find an\nin-flight patch adding one on the list; please let me know if one exists.\n\nMotivation: without a Swift driver, \".swift\" files use the generic\nfuncname heuristic, so \"git diff\" hunk headers name the enclosing type\ninstead of the changed function.\n\nThe pattern is built directly from Swift's declaration grammar rather\nthan adapted from another language's driver, so it covers a few things\nthat a straight port would miss:\n\n - attributes, with or without arguments, whether on their own line\n   (\"@objc\" above a \"func\") or inline with the declaration\n   (\"@objc func foo()\", \"@available(iOS 13, *) public func bar()\");\n - modifiers (\"public\", \"static\", \"override\", \"mutating\", ...) in any\n   combination, before or after attributes;\n - failable initializers, \"init?\" and \"init!\";\n - generics, \"init<T>\" and \"subscript<T>\";\n - the keyword boundary still acts as a word boundary, so e.g.\n   \"initialize(\" is not mistaken for \"init\".\n\nI verified all of the above against a built binary, including generic\nfunctions with \"where\" clauses, multi-line signatures, and operator\nfunctions such as \"static func ==\". I did not find a real case this\npattern misses; the ones I intentionally left out are one-line\ndeclarations (\"typealias\", \"associatedtype\") and rarer forms\n(\"operator\", \"precedencegroup\", \"macro\"), which would not make useful\nsection headers anyway.\n\nThe word regex covers Swift identifiers; hexadecimal, octal, binary,\ninteger and floating-point literals; and operators including \"<<=\" /\n\">>=\", \"??\" and the range operators. All of t4018 passes, including the\nsorted builtin_drivers check and the new swift-* fixtures.\n\n Documentation/gitattributes.adoc  |  2 ++\n t/t4018/swift-actor               |  5 +++++\n t/t4018/swift-attribute-with-args |  7 +++++++\n t/t4018/swift-class               |  5 +++++\n t/t4018/swift-enum                |  5 +++++\n t/t4018/swift-extension           |  5 +++++\n t/t4018/swift-failable-init       |  7 +++++++\n t/t4018/swift-func                |  5 +++++\n t/t4018/swift-generic-subscript   |  7 +++++++\n t/t4018/swift-init                |  7 +++++++\n t/t4018/swift-inline-attribute    |  7 +++++++\n t/t4018/swift-modifiers           |  4 ++++\n t/t4018/swift-protocol            |  5 +++++\n t/t4018/swift-struct              |  5 +++++\n userdiff.c                        | 10 ++++++++++\n 15 files changed, 86 insertions(+)\n create mode 100644 t/t4018/swift-actor\n create mode 100644 t/t4018/swift-attribute-with-args\n create mode 100644 t/t4018/swift-class\n create mode 100644 t/t4018/swift-enum\n create mode 100644 t/t4018/swift-extension\n create mode 100644 t/t4018/swift-failable-init\n create mode 100644 t/t4018/swift-func\n create mode 100644 t/t4018/swift-generic-subscript\n create mode 100644 t/t4018/swift-init\n create mode 100644 t/t4018/swift-inline-attribute\n create mode 100644 t/t4018/swift-modifiers\n create mode 100644 t/t4018/swift-protocol\n create mode 100644 t/t4018/swift-struct\n\ndiff --git a/Documentation/gitattributes.adoc b/Documentation/gitattributes.adoc\nindex bd76167a45..9fea75f96f 100644\n--- a/Documentation/gitattributes.adoc\n+++ b/Documentation/gitattributes.adoc\n@@ -914,6 +914,8 @@ patterns are available:\n - `scheme` suitable for source code in most Lisp dialects,\n   including Scheme, Emacs Lisp, Common Lisp, and Clojure.\n \n+- `swift` suitable for source code in the Swift language.\n+\n - `tex` suitable for source code for LaTeX documents.\n \n \ndiff --git a/t/t4018/swift-actor b/t/t4018/swift-actor\nnew file mode 100644\nindex 0000000000..e4852f40a7\n--- /dev/null\n+++ b/t/t4018/swift-actor\n@@ -0,0 +1,5 @@\n+actor RIGHT {\n+    let a = 1\n+    // a comment\n+    let b = ChangeMe\n+}\ndiff --git a/t/t4018/swift-attribute-with-args b/t/t4018/swift-attribute-with-args\nnew file mode 100644\nindex 0000000000..22b1ee32f1\n--- /dev/null\n+++ b/t/t4018/swift-attribute-with-args\n@@ -0,0 +1,7 @@\n+struct View {\n+    @available(iOS 13, *) public func RIGHT() {\n+        let a = 1\n+        // a comment\n+        print(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-class b/t/t4018/swift-class\nnew file mode 100644\nindex 0000000000..c3a9336027\n--- /dev/null\n+++ b/t/t4018/swift-class\n@@ -0,0 +1,5 @@\n+class RIGHT {\n+    let a = 1\n+    // a comment\n+    let b = ChangeMe\n+}\ndiff --git a/t/t4018/swift-enum b/t/t4018/swift-enum\nnew file mode 100644\nindex 0000000000..0a84302993\n--- /dev/null\n+++ b/t/t4018/swift-enum\n@@ -0,0 +1,5 @@\n+enum RIGHT {\n+    case first\n+    // a comment\n+    case ChangeMe\n+}\ndiff --git a/t/t4018/swift-extension b/t/t4018/swift-extension\nnew file mode 100644\nindex 0000000000..cbc18ab6ef\n--- /dev/null\n+++ b/t/t4018/swift-extension\n@@ -0,0 +1,5 @@\n+extension RIGHT {\n+    static let a = 1\n+    // a comment\n+    static let b = ChangeMe\n+}\ndiff --git a/t/t4018/swift-failable-init b/t/t4018/swift-failable-init\nnew file mode 100644\nindex 0000000000..5e4091d97c\n--- /dev/null\n+++ b/t/t4018/swift-failable-init\n@@ -0,0 +1,7 @@\n+class Bar {\n+    init?(RIGHT: Int) {\n+        let value = RIGHT\n+        // a comment\n+        print(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-func b/t/t4018/swift-func\nnew file mode 100644\nindex 0000000000..1fecae0911\n--- /dev/null\n+++ b/t/t4018/swift-func\n@@ -0,0 +1,5 @@\n+func RIGHT(x: Int) -> Int {\n+    let y = x\n+    // a comment\n+    return ChangeMe\n+}\ndiff --git a/t/t4018/swift-generic-subscript b/t/t4018/swift-generic-subscript\nnew file mode 100644\nindex 0000000000..565f93cd6c\n--- /dev/null\n+++ b/t/t4018/swift-generic-subscript\n@@ -0,0 +1,7 @@\n+struct Container {\n+    subscript<RIGHT>(index: RIGHT) -> Int {\n+        let a = 0\n+        // a comment\n+        return ChangeMe\n+    }\n+}\ndiff --git a/t/t4018/swift-init b/t/t4018/swift-init\nnew file mode 100644\nindex 0000000000..f683e74794\n--- /dev/null\n+++ b/t/t4018/swift-init\n@@ -0,0 +1,7 @@\n+class Foo {\n+    init(RIGHT: Int) {\n+        let value = RIGHT\n+        // a comment\n+        print(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-inline-attribute b/t/t4018/swift-inline-attribute\nnew file mode 100644\nindex 0000000000..2374c4b603\n--- /dev/null\n+++ b/t/t4018/swift-inline-attribute\n@@ -0,0 +1,7 @@\n+class Service {\n+    @objc func RIGHT() {\n+        let path = \"/api\"\n+        // a comment\n+        log(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-modifiers b/t/t4018/swift-modifiers\nnew file mode 100644\nindex 0000000000..9d80685a78\n--- /dev/null\n+++ b/t/t4018/swift-modifiers\n@@ -0,0 +1,4 @@\n+public static func RIGHT() -> Int {\n+    // a comment\n+    return ChangeMe\n+}\ndiff --git a/t/t4018/swift-protocol b/t/t4018/swift-protocol\nnew file mode 100644\nindex 0000000000..07c39ec2a3\n--- /dev/null\n+++ b/t/t4018/swift-protocol\n@@ -0,0 +1,5 @@\n+protocol RIGHT {\n+    var first: Int { get }\n+    // a comment\n+    var second: ChangeMe { get }\n+}\ndiff --git a/t/t4018/swift-struct b/t/t4018/swift-struct\nnew file mode 100644\nindex 0000000000..e399ed7759\n--- /dev/null\n+++ b/t/t4018/swift-struct\n@@ -0,0 +1,5 @@\n+struct RIGHT {\n+    let a = 1\n+    // a comment\n+    let b = ChangeMe\n+}\ndiff --git a/userdiff.c b/userdiff.c\nindex b5412e6bc3..df37dd78a6 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -362,6 +362,16 @@ PATTERNS(\"scheme\",\n \t \"\\\\|([^|\\\\\\\\]|\\\\\\\\.)*\\\\|\"\n \t /* All other words should be delimited by spaces or parentheses. */\n \t \"|([^][)(}{ \\t])+\"),\n+PATTERNS(\"swift\",\n+\t \"^[ \\t]*((@[A-Za-z_][A-Za-z0-9_]*(\\\\([^()]*\\\\))?[ \\t]+)*([a-z]+[ \\t]+)*(func|init|deinit|subscript|class|struct|enum|protocol|extension|actor)[ \\t(?!<].*)$\",\n+\t /* -- */\n+\t \"[a-zA-Z_][a-zA-Z0-9_]*\"\n+\t /* hexadecimal, octal, and binary literals */\n+\t \"|0[xX][0-9a-fA-F_]+|0[oO][0-7_]+|0[bB][01_]+\"\n+\t /* integers and floating-point numbers */\n+\t \"|[0-9][0-9_]*([.][0-9_]+)?([eE][-+]?[0-9]+)?\"\n+\t /* unary and binary operators */\n+\t \"|[-+*/%<>=!&|^~?]=?|&&|\\\\|\\\\||<<=?|>>=?|\\\\?\\\\?|\\\\.\\\\.[.<]|->\"),\n PATTERNS(\"tex\", \"^(\\\\\\\\((sub)*section|chapter|part)\\\\*{0,1}\\\\{.*)$\",\n \t \"\\\\\\\\[a-zA-Z@]+|\\\\\\\\.|([a-zA-Z0-9]|[^\\x01-\\x7f])+\"),\n { .name = \"default\", .binary = -1 },\n-- \n2.52.0\n\n"},{"id":"548546","messageId":"xmqqy0f94m5l.fsf@gitster.g","threadId":"66028","inReplyTo":"20260717140232.6722-1-diy2903@gmail.com","subject":"Re: [PATCH] userdiff: add support for Swift","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-17T16:27:02Z","receivedAt":"2026-07-17T16:27:05Z","isPatch":true,"body":"Shlok Kulshreshtha <diy2903@gmail.com> writes:\n\n> Add a built-in userdiff driver for the Swift programming language so that\n> diff hunk headers and word diffs work out of the box for \".swift\" files.\n\nI do not work with this language myself, so I have no idea how well\nthe pattern proposed here matches real-world code.  Will queue, but\nit needs reviews and validaion from active Swift users before it can\nadvance to 'next' and eventually to a future Git release.\n\nThanks.\n"},{"id":"548590","messageId":"2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org","threadId":"66028","inReplyTo":"20260717140232.6722-1-diy2903@gmail.com","subject":"Re: [PATCH] userdiff: add support for Swift","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2026-07-18T18:11:30Z","receivedAt":"2026-07-18T18:11:42Z","isPatch":true,"body":"Am 17.07.26 um 16:02 schrieb Shlok Kulshreshtha:\n> Add a built-in userdiff driver for the Swift programming language so that\n> diff hunk headers and word diffs work out of the box for \".swift\" files.\n> \n> The funcname pattern is built for Swift's own declaration grammar: an\n> optional run of attributes (\"@objc\", \"@available(iOS 13, *)\", ...),\n> followed by an optional run of lowercase modifiers (\"public\", \"static\",\n> \"final\", ...), followed by a declaration keyword (func, class, struct,\n> enum, protocol, extension, actor, init, deinit, subscript). The keyword\n> is followed by a boundary that allows whitespace, \"(\" (init/subscript),\n> \"?\" or \"!\" (failable init), or \"<\" (generics), while still acting as a\n> word boundary so e.g. \"initialize(\" does not match.\n> \n> The word regex recognizes Swift identifiers, hexadecimal, octal, binary,\n> integer and floating-point literals, and the language's operators.\n> \n> Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com>\n> ---\n> This addresses the \"add a userdiff driver for a language\" microproject.\n\nI am mildly surprised that userdiff drivers can count as microproject.\nAt a minimum, they are on the challenging side of the spectrum.\n\n> Swift is not covered by a built-in driver yet, and I did not find an\n> in-flight patch adding one on the list; please let me know if one exists.\n> \n> Motivation: without a Swift driver, \".swift\" files use the generic\n> funcname heuristic, so \"git diff\" hunk headers name the enclosing type\n> instead of the changed function.\n> \n> The pattern is built directly from Swift's declaration grammar rather\n> than adapted from another language's driver, so it covers a few things\n> that a straight port would miss:\n> \n>  - attributes, with or without arguments, whether on their own line\n>    (\"@objc\" above a \"func\") or inline with the declaration\n>    (\"@objc func foo()\", \"@available(iOS 13, *) public func bar()\");\n\nAFAIC, the regular expression does not match attributes on their own\nline. What relevance does this statement have?\n\n>  - modifiers (\"public\", \"static\", \"override\", \"mutating\", ...) in any\n>    combination, before or after attributes;\n>  - failable initializers, \"init?\" and \"init!\";\n>  - generics, \"init<T>\" and \"subscript<T>\";\n>  - the keyword boundary still acts as a word boundary, so e.g.\n>    \"initialize(\" is not mistaken for \"init\".\n> \n> I verified all of the above against a built binary, including generic\n> functions with \"where\" clauses, multi-line signatures, and operator\n> functions such as \"static func ==\". I did not find a real case this\n> pattern misses; the ones I intentionally left out are one-line\n> declarations (\"typealias\", \"associatedtype\") and rarer forms\n> (\"operator\", \"precedencegroup\", \"macro\"), which would not make useful\n> section headers anyway.\n> \n> The word regex covers Swift identifiers; hexadecimal, octal, binary,\n> integer and floating-point literals; and operators including \"<<=\" /\n> \">>=\", \"??\" and the range operators. All of t4018 passes, including the\n> sorted builtin_drivers check and the new swift-* fixtures.\n> \n>  Documentation/gitattributes.adoc  |  2 ++\n>  t/t4018/swift-actor               |  5 +++++\n>  t/t4018/swift-attribute-with-args |  7 +++++++\n>  t/t4018/swift-class               |  5 +++++\n>  t/t4018/swift-enum                |  5 +++++\n>  t/t4018/swift-extension           |  5 +++++\n>  t/t4018/swift-failable-init       |  7 +++++++\n>  t/t4018/swift-func                |  5 +++++\n>  t/t4018/swift-generic-subscript   |  7 +++++++\n>  t/t4018/swift-init                |  7 +++++++\n>  t/t4018/swift-inline-attribute    |  7 +++++++\n>  t/t4018/swift-modifiers           |  4 ++++\n>  t/t4018/swift-protocol            |  5 +++++\n>  t/t4018/swift-struct              |  5 +++++\n>  userdiff.c                        | 10 ++++++++++\n>  15 files changed, 86 insertions(+)\n>  create mode 100644 t/t4018/swift-actor\n>  create mode 100644 t/t4018/swift-attribute-with-args\n>  create mode 100644 t/t4018/swift-class\n>  create mode 100644 t/t4018/swift-enum\n>  create mode 100644 t/t4018/swift-extension\n>  create mode 100644 t/t4018/swift-failable-init\n>  create mode 100644 t/t4018/swift-func\n>  create mode 100644 t/t4018/swift-generic-subscript\n>  create mode 100644 t/t4018/swift-init\n>  create mode 100644 t/t4018/swift-inline-attribute\n>  create mode 100644 t/t4018/swift-modifiers\n>  create mode 100644 t/t4018/swift-protocol\n>  create mode 100644 t/t4018/swift-struct\n> \n> diff --git a/Documentation/gitattributes.adoc b/Documentation/gitattributes.adoc\n> index bd76167a45..9fea75f96f 100644\n> --- a/Documentation/gitattributes.adoc\n> +++ b/Documentation/gitattributes.adoc\n> @@ -914,6 +914,8 @@ patterns are available:\n>  - `scheme` suitable for source code in most Lisp dialects,\n>    including Scheme, Emacs Lisp, Common Lisp, and Clojure.\n>  \n> +- `swift` suitable for source code in the Swift language.\n> +\n>  - `tex` suitable for source code for LaTeX documents.\n>  \n>  \n> diff --git a/t/t4018/swift-actor b/t/t4018/swift-actor\n> new file mode 100644\n> index 0000000000..e4852f40a7\n> --- /dev/null\n> +++ b/t/t4018/swift-actor\n> @@ -0,0 +1,5 @@\n> +actor RIGHT {\n> +    let a = 1\n> +    // a comment\n> +    let b = ChangeMe\n> +}\n> diff --git a/t/t4018/swift-attribute-with-args b/t/t4018/swift-attribute-with-args\n> new file mode 100644\n> index 0000000000..22b1ee32f1\n> --- /dev/null\n> +++ b/t/t4018/swift-attribute-with-args\n> @@ -0,0 +1,7 @@\n> +struct View {\n> +    @available(iOS 13, *) public func RIGHT() {\n> +        let a = 1\n> +        // a comment\n> +        print(ChangeMe)\n> +    }\n> +}\n\nSo, this doesn't pick up the \"struct View {\" line, but the line below.\nGood test.\n\n> diff --git a/t/t4018/swift-failable-init b/t/t4018/swift-failable-init\n> new file mode 100644\n> index 0000000000..5e4091d97c\n> --- /dev/null\n> +++ b/t/t4018/swift-failable-init\n> @@ -0,0 +1,7 @@\n> +class Bar {\n> +    init?(RIGHT: Int) {\n> +        let value = RIGHT\n> +        // a comment\n> +        print(ChangeMe)\n> +    }\n> +}\n\nThis test contains \"RIGHT\" twice. This is not good, because we do not\nknow which one is picked.\n\n> diff --git a/t/t4018/swift-generic-subscript b/t/t4018/swift-generic-subscript\n> new file mode 100644\n> index 0000000000..565f93cd6c\n> --- /dev/null\n> +++ b/t/t4018/swift-generic-subscript\n> @@ -0,0 +1,7 @@\n> +struct Container {\n> +    subscript<RIGHT>(index: RIGHT) -> Int {\n> +        let a = 0\n> +        // a comment\n> +        return ChangeMe\n> +    }\n> +}\n\nIt is strange to have \"RIGHT\" twice on the same line, but it does no\nharm. Still, there should be only one for consistency.\n\n> diff --git a/t/t4018/swift-init b/t/t4018/swift-init\n> new file mode 100644\n> index 0000000000..f683e74794\n> --- /dev/null\n> +++ b/t/t4018/swift-init\n> @@ -0,0 +1,7 @@\n> +class Foo {\n> +    init(RIGHT: Int) {\n> +        let value = RIGHT\n> +        // a comment\n> +        print(ChangeMe)\n> +    }\n> +}\n\nAgain \"RIGHT\" twice in a harmful way.\n\nAll other test cases look good.\n\n> diff --git a/userdiff.c b/userdiff.c\n> index b5412e6bc3..df37dd78a6 100644\n> --- a/userdiff.c\n> +++ b/userdiff.c\n> @@ -362,6 +362,16 @@ PATTERNS(\"scheme\",\n>  \t \"\\\\|([^|\\\\\\\\]|\\\\\\\\.)*\\\\|\"\n>  \t /* All other words should be delimited by spaces or parentheses. */\n>  \t \"|([^][)(}{ \\t])+\"),\n> +PATTERNS(\"swift\",\n> +\t \"^[ \\t]*((@[A-Za-z_][A-Za-z0-9_]*(\\\\([^()]*\\\\))?[ \\t]+)*([a-z]+[ \\t]+)*(func|init|deinit|subscript|class|struct|enum|protocol|extension|actor)[ \\t(?!<].*)$\",\n\nThis looks good.\n\nNotice, however, how the regular expression matcher has to backtrack on\neven simple lines such as\n\nclass foo {\n\nOn the first attempt, [a-z]+ matches \"class\", but then \"foo\" does not\nmatch. On the next attempt, the clause with [a-z]+ matches zero times\nand the next clause matches \"class\" and, in total, successfully.\n\nIt may be worth considering to enumerate all keywords and permit any run\nof them:\n\n\t(public|final|etc.|func|init|...|actor)[ \\t(?!<]+)+\n\nIt does not matter that this would match any assemblement of keywords;\nthey wouldn't occur in correct Swift code anyway. (Or would they?)\n\n> +\t /* -- */\n> +\t \"[a-zA-Z_][a-zA-Z0-9_]*\"\n> +\t /* hexadecimal, octal, and binary literals */\n> +\t \"|0[xX][0-9a-fA-F_]+|0[oO][0-7_]+|0[bB][01_]+\"\n\nYou could just throw all of them into a single pattern like this:\n\n\t0[xXoObB][0-9a-fA-F_]+\n\nexcept when, for example,\n\n\t0b1_abc\n\ncan occur in correct Swift code (perhaps the token 0b1 followd by the\ntoken _abc).\n\n> +\t /* integers and floating-point numbers */\n> +\t \"|[0-9][0-9_]*([.][0-9_]+)?([eE][-+]?[0-9]+)?\"\n\nOk. Is \".5\" a correct floating-point number? If so, it would not be\ncaught by this regular expression? But it wouldn't be particularly\nharmful, either, to leave it as is. The \".5\" would just be parsed as two\ntokens, \".\" and \"5\".\n\n> +\t /* unary and binary operators */\n> +\t \"|[-+*/%<>=!&|^~?]=?|&&|\\\\|\\\\||<<=?|>>=?|\\\\?\\\\?|\\\\.\\\\.[.<]|->\"),\n\nYou do not have to account for single-character operators; they are\nautomatic. Drop the \"?\" from the first \"=?\".\n\nThese are my comments on the technical side. Since I do not speak Swift,\nI cannot comment on how reasonable your choice which lines to pick out is.\n\n-- Hannes\n\n"},{"id":"548647","messageId":"xmqqldb6i7kp.fsf@gitster.g","threadId":"66028","inReplyTo":"2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org","subject":"Re: [PATCH] userdiff: add support for Swift","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-20T04:55:02Z","receivedAt":"2026-07-20T04:55:05Z","isPatch":true,"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 17.07.26 um 16:02 schrieb Shlok Kulshreshtha:\n>> Add a built-in userdiff driver for the Swift programming language so that\n>> diff hunk headers and word diffs work out of the box for \".swift\" files.\n>> \n>> The funcname pattern is built for Swift's own declaration grammar: an\n>> optional run of attributes (\"@objc\", \"@available(iOS 13, *)\", ...),\n>> followed by an optional run of lowercase modifiers (\"public\", \"static\",\n>> \"final\", ...), followed by a declaration keyword (func, class, struct,\n>> enum, protocol, extension, actor, init, deinit, subscript). The keyword\n>> is followed by a boundary that allows whitespace, \"(\" (init/subscript),\n>> \"?\" or \"!\" (failable init), or \"<\" (generics), while still acting as a\n>> word boundary so e.g. \"initialize(\" does not match.\n>> \n>> The word regex recognizes Swift identifiers, hexadecimal, octal, binary,\n>> integer and floating-point literals, and the language's operators.\n>> \n>> Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com>\n>> ---\n>> This addresses the \"add a userdiff driver for a language\" microproject.\n>\n> I am mildly surprised that userdiff drivers can count as microproject.\n> At a minimum, they are on the challenging side of the spectrum.\n\nI am, too ;-)  It is hard to get them right, even though thanks to\nyour earlier work long time ago, writing a test that demonstrates\nwhat is expected of the patterns is fairly easy to write.\n"},{"id":"548656","messageId":"7b541cd5-bd66-4675-818d-8e23eb1c9530@kdbg.org","threadId":"66028","inReplyTo":"2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org","subject":"Re: [PATCH] userdiff: add support for Swift","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2026-07-20T08:49:21Z","receivedAt":"2026-07-20T08:49:33Z","isPatch":true,"body":"Am 18.07.26 um 20:11 schrieb Johannes Sixt:\n> Am 17.07.26 um 16:02 schrieb Shlok Kulshreshtha:\n>> +PATTERNS(\"swift\",\n>> +\t \"^[ \\t]*((@[A-Za-z_][A-Za-z0-9_]*(\\\\([^()]*\\\\))?[ \\t]+)*([a-z]+[ \\t]+)*(func|init|deinit|subscript|class|struct|enum|protocol|extension|actor)[ \\t(?!<].*)$\",\n> \n> This looks good.\n> \n> Notice, however, how the regular expression matcher has to backtrack on\n> even simple lines such as\n[...]\n> It may be worth considering to enumerate all keywords and permit any run\n> of them:\n\nLet me back-paddle on this one. As I said, the original RE is good. I am\nmaking up a problem here without providing evidence. Modern RE matchers\nmay be clever enough that there is no problem. If it turns out there is\na problem, we can improve later something that already works.\n\n-- Hannes\n\n"},{"id":"548666","messageId":"20260720095335.66241-1-diy2903@gmail.com","threadId":"66028","inReplyTo":"2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org","subject":"Re: [PATCH] userdiff: add support for Swift","fromName":"Shlok Kulshreshtha","fromEmail":"diy2903@gmail.com","sentAt":"2026-07-20T09:52:28Z","receivedAt":"2026-07-20T09:53:57Z","isPatch":true,"body":"Johannes Sixt <j6t@kdbg.org> writes:\n>>  - attributes, with or without arguments, whether on their own line\n>>    (\"@objc\" above a \"func\") or inline with the declaration\n> AFAIC, the regular expression does not match attributes on their own\n> line. What relevance does this statement have?\n\nYou are right.  The pattern only matches attributes that are inline with\nthe declaration.  An attribute on its own line is not matched, and does\nnot need to be, because the declaration line below it matches on its own.\nI have reworded this.\n\n> This test contains \"RIGHT\" twice. This is not good, because we do not\n> know which one is picked.\n[...]\n> Again \"RIGHT\" twice in a harmful way.\n\nFixed in a coming v2: swift-init, swift-failable-init and\nswift-generic-subscript now contain \"RIGHT\" only once, on the\ndeclaration line.\n\n> It may be worth considering to enumerate all keywords and permit any\n> run of them:\n> \t(public|final|etc.|func|init|...|actor)[ \\t(?!<]+)+\n\nNoted, and thanks for the follow-up on this one.  I did check it anyway\nout of curiosity: with that shape, a line that is only modifiers and\nnever reaches a real declaration keyword, such as\n\n\tpublic var counter = 0\n\nwould still match, because it merges modifiers and declaration keywords\ninto one interchangeable run.  The current pattern requires a real\nkeyword at the end, so that line correctly gets no header.  I will keep\nthe current form for now, and can revisit if the backtracking turns out\nto matter in practice.\n\n> You could just throw all of them into a single pattern like this:\n> \t0[xXoObB][0-9a-fA-F_]+\n> except when, for example, 0b1_abc\n\nRight -- that is why I kept them as three separate patterns, so the\ndigit ranges stay correct (binary [01], octal [0-7]); merging would\nmis-tokenize \"0b1_abc\".\n\n> Is \".5\" a correct floating-point number?\n\nNo -- Swift requires a leading digit, so \".5\" is a syntax error (one must\nwrite \"0.5\").  Tokenizing it as \".\" and \"5\" is therefore fine, and it\ndoes not occur in valid Swift.\n\n> You do not have to account for single-character operators; they are\n> automatic. Drop the \"?\" from the first \"=?\".\n\nDone in a coming v2, thanks; I had not realized PATTERNS appends\n\"|[^[:space:]]\".  It is a nice simplification, and it only touches the\nword regex, not the funcname pattern.\n\nSince neither of us speaks Swift, for your ease of judgement I have also\nput together some coverage numbers, which the coming v2 cover note will\ninclude:\n\n - Grammar: I went through every declaration form listed in the \"Summary\n   of the Grammar\" in Swift's own language reference (func, init incl.\n   failable/generic, deinit, subscript incl. generic, class, struct,\n   enum, protocol, extension, actor, operator methods, stacked\n   modifiers, attributes with and without arguments, \"where\" clauses,\n   multi-line signatures -- 26 forms total) and wrote a case for each.\n   All 26 get the correct header.\n\n - Real-world code: I ran the driver over the last 200 commits touching\n   *.swift in seven different Swift projects -- Alamofire,\n   apple/swift-argument-parser, vapor, Kingfisher, RxSwift, SnapKit, and\n   pointfreeco/swift-composable-architecture -- and checked every hunk\n   header by hand. Out of 20454 hunks, 15310 got a header, and 15296 of\n   those (99.9%) named a real declaration. None of the empty-header\n   hunks turned out to be a real miss (they were things like file\n   comment blocks, imports, or Package.swift, which have nothing to\n   attach a header to).\n\nThese numbers are unaffected by the changes in this reply: the funcname\npattern is identical in v1 and v2 (only the word regex and the test\nfiles changed), and both measurements are of hunk headers, which come\nfrom the funcname pattern alone. So the coverage above still holds for\nv2.\n\nBesides the fixes above, v2 will also carry the reworded attribute\ndescription and the changelog explaining what changed since v1, so the\nfull picture is in one place when you look at it.\n\nThanks for the careful review.\nShlok\n"},{"id":"548715","messageId":"20260721065736.8747-1-diy2903@gmail.com","threadId":"66028","inReplyTo":"20260717140232.6722-1-diy2903@gmail.com","subject":"[PATCH v2] userdiff: add support for Swift","fromName":"Shlok Kulshreshtha","fromEmail":"diy2903@gmail.com","sentAt":"2026-07-21T06:57:36Z","receivedAt":"2026-07-21T06:57:46Z","isPatch":true,"body":"Add a built-in userdiff driver for the Swift programming language so that\ndiff hunk headers and word diffs work out of the box for \".swift\" files.\n\nThe funcname pattern is built for Swift's own declaration grammar: an\noptional run of attributes (\"@objc\", \"@available(iOS 13, *)\", ...),\nfollowed by an optional run of lowercase modifiers (\"public\", \"static\",\n\"final\", ...), followed by a declaration keyword (func, class, struct,\nenum, protocol, extension, actor, init, deinit, subscript). The keyword\nis followed by a boundary that allows whitespace, \"(\" (init/subscript),\n\"?\" or \"!\" (failable init), or \"<\" (generics), while still acting as a\nword boundary so e.g. \"initialize(\" does not match.\n\nThe word regex recognizes Swift identifiers, hexadecimal, octal, binary,\ninteger and floating-point literals, and the language's operators.\n\nSigned-off-by: Shlok Kulshreshtha <diy2903@gmail.com>\n---\nv2, addressing Johannes Sixt's review of v1\n(<2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org>).  Changes since v1:\n\n - t4018/swift-{init,failable-init,generic-subscript}: \"RIGHT\" now\n   appears only once, on the declaration line, so the expected header is\n   unambiguous.\n - word regex: dropped the redundant \"?\" after the single-character\n   operator class.  Single characters are already covered by the\n   \"|[^[:space:]]\" fallback that the PATTERNS macro appends, so only the\n   two-character forms need to be spelled out.\n\n(A couple of Hannes's other suggestions I kept as-is; I have explained\nthe reasoning in a reply to his review.)\n\nSome coverage evidence beyond the t4018 fixtures:\n\n - Grammar: a test over every declaration form in Swift's grammar\n   summary (26 forms -- func/class/struct/enum/protocol/extension/actor,\n   init incl. \"init?\"/\"init!\"/generic, deinit, subscript incl. generic,\n   operator methods, stacked modifiers, inline attributes with and\n   without arguments, \"where\" clauses, multi-line signatures) -- all 26\n   resolve to the correct declaration.\n\n - Corpus: run over the last 200 commits touching *.swift in seven\n   stylistically different projects (Alamofire, apple/\n   swift-argument-parser, vapor, Kingfisher, RxSwift, SnapKit,\n   pointfreeco/swift-composable-architecture): of 20454 hunks, 15310\n   produced a header and 15296 (99.9%) named a real declaration.  The\n   empty-header hunks are changes with no enclosing declaration (file\n   comment blocks, imports, Package.swift, top-level code); sampling\n   found no change inside a declaration that failed to get a header.\n   The handful of non-declaration headers are the selective-import form\n   (\"import class Foundation.Bundle\"), which reads \"import\" as a\n   modifier; rare and low-harm, and I can exclude it in a follow-up if\n   preferred.\n\n Documentation/gitattributes.adoc  |  2 ++\n t/t4018/swift-actor               |  5 +++++\n t/t4018/swift-attribute-with-args |  7 +++++++\n t/t4018/swift-class               |  5 +++++\n t/t4018/swift-enum                |  5 +++++\n t/t4018/swift-extension           |  5 +++++\n t/t4018/swift-failable-init       |  7 +++++++\n t/t4018/swift-func                |  5 +++++\n t/t4018/swift-generic-subscript   |  7 +++++++\n t/t4018/swift-init                |  7 +++++++\n t/t4018/swift-inline-attribute    |  7 +++++++\n t/t4018/swift-modifiers           |  4 ++++\n t/t4018/swift-protocol            |  5 +++++\n t/t4018/swift-struct              |  5 +++++\n userdiff.c                        | 10 ++++++++++\n 15 files changed, 86 insertions(+)\n create mode 100644 t/t4018/swift-actor\n create mode 100644 t/t4018/swift-attribute-with-args\n create mode 100644 t/t4018/swift-class\n create mode 100644 t/t4018/swift-enum\n create mode 100644 t/t4018/swift-extension\n create mode 100644 t/t4018/swift-failable-init\n create mode 100644 t/t4018/swift-func\n create mode 100644 t/t4018/swift-generic-subscript\n create mode 100644 t/t4018/swift-init\n create mode 100644 t/t4018/swift-inline-attribute\n create mode 100644 t/t4018/swift-modifiers\n create mode 100644 t/t4018/swift-protocol\n create mode 100644 t/t4018/swift-struct\n\ndiff --git a/Documentation/gitattributes.adoc b/Documentation/gitattributes.adoc\nindex bd76167a45..9fea75f96f 100644\n--- a/Documentation/gitattributes.adoc\n+++ b/Documentation/gitattributes.adoc\n@@ -914,6 +914,8 @@ patterns are available:\n - `scheme` suitable for source code in most Lisp dialects,\n   including Scheme, Emacs Lisp, Common Lisp, and Clojure.\n \n+- `swift` suitable for source code in the Swift language.\n+\n - `tex` suitable for source code for LaTeX documents.\n \n \ndiff --git a/t/t4018/swift-actor b/t/t4018/swift-actor\nnew file mode 100644\nindex 0000000000..e4852f40a7\n--- /dev/null\n+++ b/t/t4018/swift-actor\n@@ -0,0 +1,5 @@\n+actor RIGHT {\n+    let a = 1\n+    // a comment\n+    let b = ChangeMe\n+}\ndiff --git a/t/t4018/swift-attribute-with-args b/t/t4018/swift-attribute-with-args\nnew file mode 100644\nindex 0000000000..22b1ee32f1\n--- /dev/null\n+++ b/t/t4018/swift-attribute-with-args\n@@ -0,0 +1,7 @@\n+struct View {\n+    @available(iOS 13, *) public func RIGHT() {\n+        let a = 1\n+        // a comment\n+        print(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-class b/t/t4018/swift-class\nnew file mode 100644\nindex 0000000000..c3a9336027\n--- /dev/null\n+++ b/t/t4018/swift-class\n@@ -0,0 +1,5 @@\n+class RIGHT {\n+    let a = 1\n+    // a comment\n+    let b = ChangeMe\n+}\ndiff --git a/t/t4018/swift-enum b/t/t4018/swift-enum\nnew file mode 100644\nindex 0000000000..0a84302993\n--- /dev/null\n+++ b/t/t4018/swift-enum\n@@ -0,0 +1,5 @@\n+enum RIGHT {\n+    case first\n+    // a comment\n+    case ChangeMe\n+}\ndiff --git a/t/t4018/swift-extension b/t/t4018/swift-extension\nnew file mode 100644\nindex 0000000000..cbc18ab6ef\n--- /dev/null\n+++ b/t/t4018/swift-extension\n@@ -0,0 +1,5 @@\n+extension RIGHT {\n+    static let a = 1\n+    // a comment\n+    static let b = ChangeMe\n+}\ndiff --git a/t/t4018/swift-failable-init b/t/t4018/swift-failable-init\nnew file mode 100644\nindex 0000000000..4bbd6217c9\n--- /dev/null\n+++ b/t/t4018/swift-failable-init\n@@ -0,0 +1,7 @@\n+class Bar {\n+    init?(RIGHT: Int) {\n+        let x = 0\n+        // a comment\n+        print(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-func b/t/t4018/swift-func\nnew file mode 100644\nindex 0000000000..1fecae0911\n--- /dev/null\n+++ b/t/t4018/swift-func\n@@ -0,0 +1,5 @@\n+func RIGHT(x: Int) -> Int {\n+    let y = x\n+    // a comment\n+    return ChangeMe\n+}\ndiff --git a/t/t4018/swift-generic-subscript b/t/t4018/swift-generic-subscript\nnew file mode 100644\nindex 0000000000..423cb58941\n--- /dev/null\n+++ b/t/t4018/swift-generic-subscript\n@@ -0,0 +1,7 @@\n+struct Container {\n+    subscript<RIGHT>(index: Int) -> Int {\n+        let a = 0\n+        // a comment\n+        return ChangeMe\n+    }\n+}\ndiff --git a/t/t4018/swift-init b/t/t4018/swift-init\nnew file mode 100644\nindex 0000000000..dc7a298f38\n--- /dev/null\n+++ b/t/t4018/swift-init\n@@ -0,0 +1,7 @@\n+class Foo {\n+    init(RIGHT: Int) {\n+        let x = 0\n+        // a comment\n+        print(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-inline-attribute b/t/t4018/swift-inline-attribute\nnew file mode 100644\nindex 0000000000..2374c4b603\n--- /dev/null\n+++ b/t/t4018/swift-inline-attribute\n@@ -0,0 +1,7 @@\n+class Service {\n+    @objc func RIGHT() {\n+        let path = \"/api\"\n+        // a comment\n+        log(ChangeMe)\n+    }\n+}\ndiff --git a/t/t4018/swift-modifiers b/t/t4018/swift-modifiers\nnew file mode 100644\nindex 0000000000..9d80685a78\n--- /dev/null\n+++ b/t/t4018/swift-modifiers\n@@ -0,0 +1,4 @@\n+public static func RIGHT() -> Int {\n+    // a comment\n+    return ChangeMe\n+}\ndiff --git a/t/t4018/swift-protocol b/t/t4018/swift-protocol\nnew file mode 100644\nindex 0000000000..07c39ec2a3\n--- /dev/null\n+++ b/t/t4018/swift-protocol\n@@ -0,0 +1,5 @@\n+protocol RIGHT {\n+    var first: Int { get }\n+    // a comment\n+    var second: ChangeMe { get }\n+}\ndiff --git a/t/t4018/swift-struct b/t/t4018/swift-struct\nnew file mode 100644\nindex 0000000000..e399ed7759\n--- /dev/null\n+++ b/t/t4018/swift-struct\n@@ -0,0 +1,5 @@\n+struct RIGHT {\n+    let a = 1\n+    // a comment\n+    let b = ChangeMe\n+}\ndiff --git a/userdiff.c b/userdiff.c\nindex b5412e6bc3..7129bf1482 100644\n--- a/userdiff.c\n+++ b/userdiff.c\n@@ -362,6 +362,16 @@ PATTERNS(\"scheme\",\n \t \"\\\\|([^|\\\\\\\\]|\\\\\\\\.)*\\\\|\"\n \t /* All other words should be delimited by spaces or parentheses. */\n \t \"|([^][)(}{ \\t])+\"),\n+PATTERNS(\"swift\",\n+\t \"^[ \\t]*((@[A-Za-z_][A-Za-z0-9_]*(\\\\([^()]*\\\\))?[ \\t]+)*([a-z]+[ \\t]+)*(func|init|deinit|subscript|class|struct|enum|protocol|extension|actor)[ \\t(?!<].*)$\",\n+\t /* -- */\n+\t \"[a-zA-Z_][a-zA-Z0-9_]*\"\n+\t /* hexadecimal, octal, and binary literals */\n+\t \"|0[xX][0-9a-fA-F_]+|0[oO][0-7_]+|0[bB][01_]+\"\n+\t /* integers and floating-point numbers */\n+\t \"|[0-9][0-9_]*([.][0-9_]+)?([eE][-+]?[0-9]+)?\"\n+\t /* unary and binary operators */\n+\t \"|[-+*/%<>=!&|^~?]=|&&|\\\\|\\\\||<<=?|>>=?|\\\\?\\\\?|\\\\.\\\\.[.<]|->\"),\n PATTERNS(\"tex\", \"^(\\\\\\\\((sub)*section|chapter|part)\\\\*{0,1}\\\\{.*)$\",\n \t \"\\\\\\\\[a-zA-Z@]+|\\\\\\\\.|([a-zA-Z0-9]|[^\\x01-\\x7f])+\"),\n { .name = \"default\", .binary = -1 },\n\nRange-diff against v1:\n1:  1e7e199355 ! 1:  af48611565 userdiff: add support for Swift\n    @@ t/t4018/swift-failable-init (new)\n     @@\n     +class Bar {\n     +    init?(RIGHT: Int) {\n    -+        let value = RIGHT\n    ++        let x = 0\n     +        // a comment\n     +        print(ChangeMe)\n     +    }\n    @@ t/t4018/swift-func (new)\n      ## t/t4018/swift-generic-subscript (new) ##\n     @@\n     +struct Container {\n    -+    subscript<RIGHT>(index: RIGHT) -> Int {\n    ++    subscript<RIGHT>(index: Int) -> Int {\n     +        let a = 0\n     +        // a comment\n     +        return ChangeMe\n    @@ t/t4018/swift-init (new)\n     @@\n     +class Foo {\n     +    init(RIGHT: Int) {\n    -+        let value = RIGHT\n    ++        let x = 0\n     +        // a comment\n     +        print(ChangeMe)\n     +    }\n    @@ userdiff.c: PATTERNS(\"scheme\",\n     +\t /* integers and floating-point numbers */\n     +\t \"|[0-9][0-9_]*([.][0-9_]+)?([eE][-+]?[0-9]+)?\"\n     +\t /* unary and binary operators */\n    -+\t \"|[-+*/%<>=!&|^~?]=?|&&|\\\\|\\\\||<<=?|>>=?|\\\\?\\\\?|\\\\.\\\\.[.<]|->\"),\n    ++\t \"|[-+*/%<>=!&|^~?]=|&&|\\\\|\\\\||<<=?|>>=?|\\\\?\\\\?|\\\\.\\\\.[.<]|->\"),\n      PATTERNS(\"tex\", \"^(\\\\\\\\((sub)*section|chapter|part)\\\\*{0,1}\\\\{.*)$\",\n      \t \"\\\\\\\\[a-zA-Z@]+|\\\\\\\\.|([a-zA-Z0-9]|[^\\x01-\\x7f])+\"),\n      { .name = \"default\", .binary = -1 },\n-- \n2.52.0\n\n"},{"id":"548734","messageId":"xmqqmrvkw31z.fsf@gitster.g","threadId":"66028","inReplyTo":"20260721065736.8747-1-diy2903@gmail.com","subject":"Re: [PATCH v2] userdiff: add support for Swift","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-07-21T19:33:28Z","receivedAt":"2026-07-21T19:33:31Z","isPatch":true,"body":"Shlok Kulshreshtha <diy2903@gmail.com> writes:\n\n> Add a built-in userdiff driver for the Swift programming language so that\n> diff hunk headers and word diffs work out of the box for \".swift\" files.\n>\n> The funcname pattern is built for Swift's own declaration grammar: an\n> optional run of attributes (\"@objc\", \"@available(iOS 13, *)\", ...),\n> followed by an optional run of lowercase modifiers (\"public\", \"static\",\n> \"final\", ...), followed by a declaration keyword (func, class, struct,\n> enum, protocol, extension, actor, init, deinit, subscript). The keyword\n> is followed by a boundary that allows whitespace, \"(\" (init/subscript),\n> \"?\" or \"!\" (failable init), or \"<\" (generics), while still acting as a\n> word boundary so e.g. \"initialize(\" does not match.\n>\n> The word regex recognizes Swift identifiers, hexadecimal, octal, binary,\n> integer and floating-point literals, and the language's operators.\n>\n> Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com>\n> ---\n> v2, addressing Johannes Sixt's review of v1\n> (<2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org>).  Changes since v1:\n>\n>  - t4018/swift-{init,failable-init,generic-subscript}: \"RIGHT\" now\n>    appears only once, on the declaration line, so the expected header is\n>    unambiguous.\n>  - word regex: dropped the redundant \"?\" after the single-character\n>    operator class.  Single characters are already covered by the\n>    \"|[^[:space:]]\" fallback that the PATTERNS macro appends, so only the\n>    two-character forms need to be spelled out.\n>\n> (A couple of Hannes's other suggestions I kept as-is; I have explained\n> the reasoning in a reply to his review.)\n\nThanks for an update.\n\nLet's wait for a few days to see if we hear more comments and\notherwise mark the topic for 'next'.\n"},{"id":"548803","messageId":"d3337806-f044-4571-90f2-aaebb2e295ce@kdbg.org","threadId":"66028","inReplyTo":"xmqqmrvkw31z.fsf@gitster.g","subject":"Re: [PATCH v2] userdiff: add support for Swift","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2026-07-23T08:00:27Z","receivedAt":"2026-07-23T08:00:39Z","isPatch":true,"body":"Am 21.07.26 um 21:33 schrieb Junio C Hamano:\n> Shlok Kulshreshtha <diy2903@gmail.com> writes:\n> \n>> Add a built-in userdiff driver for the Swift programming language so that\n>> diff hunk headers and word diffs work out of the box for \".swift\" files.\n>>\n>> The funcname pattern is built for Swift's own declaration grammar: an\n>> optional run of attributes (\"@objc\", \"@available(iOS 13, *)\", ...),\n>> followed by an optional run of lowercase modifiers (\"public\", \"static\",\n>> \"final\", ...), followed by a declaration keyword (func, class, struct,\n>> enum, protocol, extension, actor, init, deinit, subscript). The keyword\n>> is followed by a boundary that allows whitespace, \"(\" (init/subscript),\n>> \"?\" or \"!\" (failable init), or \"<\" (generics), while still acting as a\n>> word boundary so e.g. \"initialize(\" does not match.\n>>\n>> The word regex recognizes Swift identifiers, hexadecimal, octal, binary,\n>> integer and floating-point literals, and the language's operators.\n>>\n>> Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com>\n>> ---\n>> v2, addressing Johannes Sixt's review of v1\n>> (<2a3a73c5-5e90-44a3-bf6a-6e98ce5e5a59@kdbg.org>).  Changes since v1:\n>>\n>>  - t4018/swift-{init,failable-init,generic-subscript}: \"RIGHT\" now\n>>    appears only once, on the declaration line, so the expected header is\n>>    unambiguous.\n>>  - word regex: dropped the redundant \"?\" after the single-character\n>>    operator class.  Single characters are already covered by the\n>>    \"|[^[:space:]]\" fallback that the PATTERNS macro appends, so only the\n>>    two-character forms need to be spelled out.\n>>\n>> (A couple of Hannes's other suggestions I kept as-is; I have explained\n>> the reasoning in a reply to his review.)\n> \n> Thanks for an update.\n> \n> Let's wait for a few days to see if we hear more comments and\n> otherwise mark the topic for 'next'.\n\nThis round looks good to me.\n\nAcked-by: Johannes Sixt <j6t@kdbg.org>\n\n-- Hannes\n\n"},{"id":"549064","messageId":"CAC2QwmK7HVma7HMxmXvC7qa4XQVomteC0x7PpX61MjpDLbvDzA@mail.gmail.com","threadId":"66028","inReplyTo":"20260721065736.8747-1-diy2903@gmail.com","subject":"Re: [PATCH v2] userdiff: add support for Swift","fromName":"Michael Montalbo","fromEmail":"mmontalbo@gmail.com","sentAt":"2026-07-27T05:03:54Z","receivedAt":"2026-07-27T05:04:07Z","isPatch":true,"body":"On Tue, Jul 21, 2026 at 12:06 AM Shlok Kulshreshtha <diy2903@gmail.com> wrote:\n>\n> Add a built-in userdiff driver for the Swift programming language so that\n> diff hunk headers and word diffs work out of the box for \".swift\" files.\n>\n\nI noticed other languages add a test_language_driver entry to\nt/t4034-diff-words.sh with corresponding pre/post/expect\nfixtures. Should we add something similar for Swift?\n"},{"id":"549069","messageId":"734cf745-ff32-4681-be2f-ad3225c80bec@kdbg.org","threadId":"66028","inReplyTo":"CAC2QwmK7HVma7HMxmXvC7qa4XQVomteC0x7PpX61MjpDLbvDzA@mail.gmail.com","subject":"Re: [PATCH v2] userdiff: add support for Swift","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2026-07-27T06:44:24Z","receivedAt":"2026-07-27T06:44:35Z","isPatch":true,"body":"Am 27.07.26 um 07:03 schrieb Michael Montalbo:\n> On Tue, Jul 21, 2026 at 12:06 AM Shlok Kulshreshtha <diy2903@gmail.com> wrote:\n>>\n>> Add a built-in userdiff driver for the Swift programming language so that\n>> diff hunk headers and word diffs work out of the box for \".swift\" files.\n>>\n> \n> I noticed other languages add a test_language_driver entry to\n> t/t4034-diff-words.sh with corresponding pre/post/expect\n> fixtures. Should we add something similar for Swift?\n\nWe could that. But since the words are basically run-of-the-mill and\nnothing exotic (like we had for the scheme driver), I gladly forgo a\ntest script at this time. In the past, these test scripts turned out to\nbe non-trivial to get correct and it was a burden for both the author\nand the reviewers. It would certainly exceed the scope of a microproject.\n\n\n-- Hannes\n\n"},{"id":"549098","messageId":"CAC2QwmKuNEnFHraKTUkaskW4aeEWJvS68SyMfxMnhwMEoJuhrQ@mail.gmail.com","threadId":"66028","inReplyTo":"734cf745-ff32-4681-be2f-ad3225c80bec@kdbg.org","subject":"Re: [PATCH v2] userdiff: add support for Swift","fromName":"Michael Montalbo","fromEmail":"mmontalbo@gmail.com","sentAt":"2026-07-27T17:37:06Z","receivedAt":"2026-07-27T17:37:20Z","isPatch":true,"body":"On Sun, Jul 26, 2026 at 11:44 PM Johannes Sixt <j6t@kdbg.org> wrote:\n>\n> Am 27.07.26 um 07:03 schrieb Michael Montalbo:\n> > On Tue, Jul 21, 2026 at 12:06 AM Shlok Kulshreshtha <diy2903@gmail.com> wrote:\n> >>\n> >> Add a built-in userdiff driver for the Swift programming language so that\n> >> diff hunk headers and word diffs work out of the box for \".swift\" files.\n> >>\n> >\n> > I noticed other languages add a test_language_driver entry to\n> > t/t4034-diff-words.sh with corresponding pre/post/expect\n> > fixtures. Should we add something similar for Swift?\n[snip]\n> In the past, these test scripts turned out to\n> be non-trivial to get correct and it was a burden for both the author\n> and the reviewers. It would certainly exceed the scope of a microproject.\n>\n\nGot it, thanks for the context.\n\nFWIW, I tested the changes against a recent WWDC 2026 sample\nproject[1] I was playing around with, and the new user driver appears\nto work well.\n\n[1] https://developer.apple.com/documentation/FoundationModels/origami-crafting-a-dynamic-tutorial-for-apple-intelligence\n"}]}