11
11
#import < ObjectiveGit/GTConfiguration.h>
12
12
#import " PBGitRef.h"
13
13
#import " PBGitRevSpecifier.h"
14
+ #import < stdatomic.h>
15
+
16
+ @interface PBWebHistoryController ()
17
+ @property (nonatomic ) atomic_ulong commitSummaryGeneration;
18
+ @end
14
19
15
20
@implementation PBWebHistoryController
16
21
@@ -83,6 +88,8 @@ - (void) changeContentToMultipleSelectionMessage {
83
88
}
84
89
}
85
90
91
+ static NSDictionary *loadCommitSummary (GTRepository *repo, GTCommit *commit, BOOL (^isCanceled)());
92
+
86
93
- (void ) changeContentToCommit: (PBGitCommit *)commit
87
94
{
88
95
// The sha is the same, but refs may have changed. reload it lazy
@@ -101,29 +108,76 @@ - (void) changeContentToCommit:(PBGitCommit *)commit
101
108
}
102
109
currentOID = commit.OID ;
103
110
111
+ unsigned long gen = atomic_fetch_add (&_commitSummaryGeneration, 1 ) + 1 ;
112
+
113
+ // Open a new repo instance for the background queue
114
+ NSError *err = nil ;
115
+ GTRepository *repo =
116
+ [GTRepository repositoryWithURL: [repository gtRepo ].gitDirectoryURL error: &err];
117
+ if (!repo) {
118
+ NSLog (@" Failed to open repository: %@ " , err);
119
+ return ;
120
+ }
121
+ GTCommit *queueCommit = [repo lookUpObjectByOID: commit.OID error: &err];
122
+ if (!queueCommit) {
123
+ NSLog (@" Failed to find commit: %@ " , err);
124
+ return ;
125
+ }
126
+
127
+ dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0 ), ^{
128
+ NSDictionary *summary = loadCommitSummary (repo, queueCommit, ^BOOL {
129
+ return gen != atomic_load (&_commitSummaryGeneration);
130
+ });
131
+ if (!summary) return ;
132
+ NSError *err = nil ;
133
+ NSString *summaryJSON =
134
+ [[NSString alloc ] initWithData: [NSJSONSerialization dataWithJSONObject: summary
135
+ options: 0
136
+ error: &err]
137
+ encoding: NSUTF8StringEncoding];
138
+ if (!summaryJSON) {
139
+ NSLog (@" Commit summary JSON error: %@ " , err);
140
+ return ;
141
+ }
142
+ dispatch_async (dispatch_get_main_queue (), ^{
143
+ [self commitSummaryLoaded: summaryJSON forOID: commit.OID];
144
+ });
145
+ });
146
+ }
147
+
148
+ static NSDictionary *loadCommitSummary (GTRepository *repo, GTCommit *commit, BOOL (^isCanceled)()) {
149
+ if (isCanceled ()) return nil ;
104
150
GTDiffFindOptionsFlags flags = GTDiffFindOptionsFlagsFindRenames;
105
151
if (![PBGitDefaults showWhitespaceDifferences ]) {
106
152
flags |= GTDiffFindOptionsFlagsIgnoreWhitespace;
107
153
}
108
154
NSError *err = nil ;
109
- GTDiff *d = // TODO async?
110
- [GTDiff diffOldTree: commit.gtCommit.parents.firstObject.tree
111
- withNewTree: commit.gtCommit.tree
112
- inRepository: [repository gtRepo ]
113
- options: @{
114
- GTDiffFindOptionsFlagsKey : @(flags)
115
- }
116
- error: &err];
155
+ GTDiff *d = [GTDiff diffOldTree: commit.parents.firstObject.tree
156
+ withNewTree: commit.tree
157
+ inRepository: repo
158
+ options: @{
159
+ GTDiffFindOptionsFlagsKey : @(flags)
160
+ }
161
+ error: &err];
117
162
if (!d) {
118
163
NSLog (@" Commit summary diff error: %@ " , err);
119
- return ;
164
+ return nil ;
120
165
}
166
+ if (isCanceled ()) return nil ;
121
167
NSMutableArray *fileDeltas = [NSMutableArray array ];
122
168
[d enumerateDeltasUsingBlock: ^(GTDiffDelta *_Nonnull delta, BOOL *_Nonnull stop) {
169
+ if (isCanceled ()) {
170
+ *stop = YES ;
171
+ return ;
172
+ }
123
173
NSUInteger numLinesAdded = 0 ;
124
174
NSUInteger numLinesRemoved = 0 ;
125
175
NSError *err = nil ;
126
176
GTDiffPatch *patch = [delta generatePatch: &err];
177
+ if (isCanceled ()) {
178
+ *stop = YES ;
179
+ return ;
180
+ }
127
181
if (patch) {
128
182
numLinesAdded = patch.addedLinesCount ;
129
183
numLinesRemoved = patch.deletedLinesCount ;
@@ -141,20 +195,20 @@ - (void) changeContentToCommit:(PBGitCommit *)commit
141
195
[NSNumber numberWithBool: (delta.flags & GTDiffFileFlagBinary) != 0 ],
142
196
}];
143
197
}];
144
- NSDictionary *summaryDict = @{
198
+ if (isCanceled ()) return nil ;
199
+ return @{
145
200
@" filesInfo" : fileDeltas,
146
201
};
147
- NSString *summary =
148
- [[NSString alloc ] initWithData: [NSJSONSerialization dataWithJSONObject: summaryDict
149
- options: 0
150
- error: &err]
151
- encoding: NSUTF8StringEncoding];
152
- if (!summary) {
153
- NSLog (@" Commit summary JSON error: %@ " , err);
202
+ }
203
+
204
+ - (void )commitSummaryLoaded: (NSString *)summaryJSON forOID: (GTOID *)summaryOID
205
+ {
206
+ if (![currentOID isEqual: summaryOID]) {
207
+ // a different summary finished loading late
154
208
return ;
155
209
}
156
210
157
- [self .view.windowScriptObject callWebScriptMethod: @" loadCommitSummary" withArguments: @[summary ]];
211
+ [self .view.windowScriptObject callWebScriptMethod: @" loadCommitSummary" withArguments: @[summaryJSON ]];
158
212
159
213
// Now load the full diff
160
214
NSMutableArray *taskArguments = [NSMutableArray arrayWithObjects: @" show" , @" --pretty=raw" , @" -M" , @" --no-color" , currentOID.SHA, nil ];
0 commit comments