Better diff hunk headers with Swift

When you run git diff — or look at diffs in at least Fork — on a modified Swift project you see things like this:

@@ -251,7 +251,7 @@ extension AppUITests {
         let container = app.scrollViews["scroll"]
         XCTAssertTrue(container.waitForExistence(timeout: 2))
-        XCTAssertTrue(container.buttons["Restore"].exists)
+        XCTAssertTrue(container.buttons["Restore Purchases"].exists)
         XCTAssertTrue(container.buttons["View Subscriptions"].exists)
     }

While staring at a bunch of these today I realized just how unhelpful that line with @@s and extension is. The name of the extension where these lines live is not the most relevant context; the name of the function is.

This article on improving diff output for a bunch of other languages was helpful. I'll adapt its guidance for Swift here.

Step 1: Diff driver

Define a diff driver in your $HOME/.gitconfig. The xfuncname configuration specifies a regular expression that is used to match a line you want to see in the hunk header after the @@ bit. Covering all possible options with a regexp probably isn't possible, but this should cover most of the cases:

[diff "swift"]
    xfuncname = ^[ \t]*(((private |public |internal |final |open )*class|(private |public |internal )*struct|(private |public |internal )*actor|(private |public |internal )*func|(private |public |internal )*extension|(private |public |internal )*enum)[ \t].*)$

Step 2: Global git attributes

If you don't have a global git attributes file configured, set one up:

git config --global core.attributesfile ~/.gitattributes

Step 3: Configure the swift driver for Swift files

Edit the ~/.gitattributes file to make Git use your newly defined diff driver for Swift files. Add the following line:

*.swift diff=swift

After these changes, the above diff will look like this:

@@ -251,7 +251,7 @@ func testButtons() {
         let container = app.scrollViews["scroll"]
         XCTAssertTrue(container.waitForExistence(timeout: 2))
-        XCTAssertTrue(container.buttons["Restore"].exists)
+        XCTAssertTrue(container.buttons["Restore Purchases"].exists)
         XCTAssertTrue(container.buttons["View Subscriptions"].exists)
     }

That's a lot more helpful.

© Juri Pakaste 2023