@@ -36,11 +36,25 @@ extension GitClient {
3636 /// - Throws: Can throw ``GitClient/GitClientError`` errors if it finds unexpected output.
3737 func getStatus( ) async throws -> Status {
3838 let output = try await run ( " status -z --porcelain=2 -u " )
39+ return try parseStatusString ( output)
40+ }
41+
42+ /// Parses a status string from ``getStatus()`` and returns a ``Status`` object if possible.
43+ /// - Parameter output: The git output from running `status`. Expects a porcelain v2 string.
44+ /// - Returns: A status object if parseable.
45+ func parseStatusString( _ output: borrowing String ) throws -> Status {
46+ let endsInNull = output. last == Character ( UnicodeScalar ( 0 ) )
47+ let endIndex : String . Index
48+ if endsInNull && output. count > 1 {
49+ endIndex = output. index ( before: output. endIndex)
50+ } else {
51+ endIndex = output. endIndex
52+ }
3953
4054 var status = Status ( changedFiles: [ ] , unmergedChanges: [ ] , untrackedFiles: [ ] )
4155
4256 var index = output. startIndex
43- while index < output . endIndex {
57+ while index < endIndex {
4458 let typeIndex = index
4559
4660 // Move ahead no matter what.
@@ -100,7 +114,11 @@ extension GitClient {
100114 }
101115 index = newIndex
102116 }
103- index = output. index ( after: index)
117+ defer {
118+ if index < output. index ( before: output. endIndex) {
119+ index = output. index ( after: index)
120+ }
121+ }
104122 return output [ startIndex..< index]
105123 }
106124
@@ -147,7 +165,8 @@ extension GitClient {
147165 try moveToNextSpace ( from: & index, output: output)
148166 }
149167 try moveOneChar ( from: & index, output: output)
150- let filename = String ( try substringToNextNull ( from: & index, output: output) )
168+ let substring = try substringToNextNull ( from: & index, output: output)
169+ let filename = String ( substring)
151170 return GitChangedFile (
152171 status: status,
153172 stagedStatus: stagedStatus,
0 commit comments