Indent string diffs lines (#2648)

I noticed that the failure messages are a little easier to read if the
lines showing the point in the string that deviates are indented
relative to the "Which" header.

Before

    Expected: a String that:
      equals 'some other String'
    Actual: 'some String'
    Which: differs at offset 5:
    some other Stri ...
    some String
         ^

After

    Expected: a String that:
      equals 'some other String'
    Actual: 'some String'
    Which: differs at offset 5:
      some other Stri ...
      some String
           ^
diff --git a/pkgs/checks/CHANGELOG.md b/pkgs/checks/CHANGELOG.md
index b53ccc4..9626e53 100644
--- a/pkgs/checks/CHANGELOG.md
+++ b/pkgs/checks/CHANGELOG.md
@@ -3,6 +3,8 @@
 - Require Dart 3.7
 - Improve speed of pretty printing for large collections.
 - Improve formatting for failures involving unexpected exceptions.
+- Improve formatting for failed String equality checks - indent string diff
+  lines.
 - Fix a bug when using asynchronous conditions with `mayEmit` or
   `mayEmitMultiple`. Note that extensions using `nestAsync` should synchronously
   forward exceptions from that call.
diff --git a/pkgs/checks/lib/src/extensions/string.dart b/pkgs/checks/lib/src/extensions/string.dart
index f41fe0b..a6b746f 100644
--- a/pkgs/checks/lib/src/extensions/string.dart
+++ b/pkgs/checks/lib/src/extensions/string.dart
@@ -208,15 +208,17 @@
       );
     }
   } else {
-    final indentation = ' ' * (i > 10 ? 14 : i);
+    final markerIndent = ' ' * (i > 10 ? 14 : i);
     return Rejection(
       which: [
         'differs at offset $i:',
-        '${_leading(escapedExpectedDisplay, i)}'
-            '${_trailing(escapedExpectedDisplay, i)}',
-        '${_leading(escapedActualDisplay, i)}'
-            '${_trailing(escapedActualDisplay, i)}',
-        '$indentation^',
+        ...indent([
+          '${_leading(escapedExpectedDisplay, i)}'
+              '${_trailing(escapedExpectedDisplay, i)}',
+          '${_leading(escapedActualDisplay, i)}'
+              '${_trailing(escapedActualDisplay, i)}',
+          '$markerIndent^',
+        ]),
       ],
     );
   }
diff --git a/pkgs/checks/test/extensions/string_test.dart b/pkgs/checks/test/extensions/string_test.dart
index 0fbca2d..5202674 100644
--- a/pkgs/checks/test/extensions/string_test.dart
+++ b/pkgs/checks/test/extensions/string_test.dart
@@ -147,7 +147,7 @@
       test('reports index of different character', () {
         check('hit').isRejectedBy(
           (it) => it.equals('hat'),
-          which: ['differs at offset 1:', 'hat', 'hit', ' ^'],
+          which: ['differs at offset 1:', '  hat', '  hit', '   ^'],
         );
       });
       test(
@@ -157,9 +157,9 @@
             (it) => it.equals('blah blah blah hat blah blah blah'),
             which: [
               'differs at offset 16:',
-              '... lah blah hat blah bl ...',
-              '... lah blah hit blah bl ...',
-              '              ^',
+              '  ... lah blah hat blah bl ...',
+              '  ... lah blah hit blah bl ...',
+              '                ^',
             ],
           );
         },
@@ -186,7 +186,7 @@
       test('reports index of different character with original characters', () {
         check('HiT').isRejectedBy(
           (it) => it.equalsIgnoringCase('hAt'),
-          which: ['differs at offset 1:', 'hAt', 'HiT', ' ^'],
+          which: ['differs at offset 1:', '  hAt', '  HiT', '   ^'],
         );
       });
     });
@@ -216,7 +216,7 @@
       test('reports index of different character with original characters', () {
         check('x  hit  x').isRejectedBy(
           (it) => it.equalsIgnoringWhitespace('x hat x'),
-          which: ['differs at offset 3:', 'x hat x', 'x hit x', '   ^'],
+          which: ['differs at offset 3:', '  x hat x', '  x hit x', '     ^'],
         );
       });
     });