Skip to content

Commit a04a4e0

Browse files
committed
Allow dragging files out of diffs into external apps
1 parent b764099 commit a04a4e0

File tree

1 file changed

+74
-1
lines changed

1 file changed

+74
-1
lines changed

GitUpKit/Components/GIDiffFilesViewController.m

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,18 @@ @interface GIFilesTableView : GITableView
3232
@property(nonatomic, assign) GIDiffFilesViewController* controller;
3333
@end
3434

35-
@interface GIDiffFilesViewController ()
35+
@interface GIDiffFilesViewController () <NSFilePromiseProviderDelegate>
3636
@property(nonatomic, weak) IBOutlet GIFilesTableView* tableView;
3737
@property(nonatomic, weak) IBOutlet NSTextField* emptyTextField;
3838
@property(nonatomic, readonly) NSArray* items;
3939
@end
4040

41+
/// Allows augmenting a file promise with custom intra-app data.
42+
API_AVAILABLE(macos(10.12))
43+
@interface GIDiffFileProvider : NSFilePromiseProvider
44+
@property(strong) id<NSPasteboardWriting> overridePasteboardWriter;
45+
@end
46+
4147
@implementation GIFileCellView
4248
@end
4349

@@ -204,6 +210,20 @@ - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
204210
NSURL* url = [NSURL fileURLWithPath:path isDirectory:NO];
205211
[pasteboardItem setString:url.absoluteString forType:GIPasteboardTypeFileURL];
206212

213+
if (@available(macOS 10.12, *)) {
214+
if (GC_FILE_MODE_IS_FILE(delta.oldFile.mode) || GC_FILE_MODE_IS_FILE(delta.newFile.mode)) {
215+
NSString* pathExtension = delta.canonicalPath.pathExtension;
216+
NSString* utType = (__bridge_transfer NSString*)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)pathExtension, kUTTypeData);
217+
218+
if (utType) {
219+
GIDiffFileProvider* provider = [[GIDiffFileProvider alloc] initWithFileType:utType delegate:self];
220+
provider.userInfo = delta;
221+
provider.overridePasteboardWriter = pasteboardItem;
222+
return provider;
223+
}
224+
}
225+
}
226+
207227
return pasteboardItem;
208228
}
209229

@@ -301,4 +321,57 @@ - (void)tableViewSelectionDidChange:(NSNotification*)notification {
301321
}
302322
}
303323

324+
#pragma mark - NSFilePromiseProviderDelegate
325+
326+
- (NSString*)_SHA1ForDelta:(GCDiffDelta*)delta {
327+
switch (delta.change) {
328+
case kGCFileDiffChange_Deleted:
329+
case kGCFileDiffChange_Unmodified:
330+
case kGCFileDiffChange_Ignored:
331+
case kGCFileDiffChange_Untracked:
332+
case kGCFileDiffChange_Unreadable:
333+
return delta.oldFile.SHA1;
334+
case kGCFileDiffChange_Added:
335+
case kGCFileDiffChange_Modified:
336+
case kGCFileDiffChange_Renamed:
337+
case kGCFileDiffChange_Copied:
338+
case kGCFileDiffChange_TypeChanged:
339+
case kGCFileDiffChange_Conflicted:
340+
return delta.newFile.SHA1;
341+
}
342+
}
343+
344+
- (NSString*)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider fileNameForType:(NSString*)fileType API_AVAILABLE(macos(10.12)) {
345+
GCDiffDelta* delta = filePromiseProvider.userInfo;
346+
NSString* SHA1 = [[self _SHA1ForDelta:delta] substringToIndex:7];
347+
NSString* basename = delta.canonicalPath.stringByDeletingPathExtension.lastPathComponent;
348+
NSString* pathExtension = delta.canonicalPath.pathExtension;
349+
NSString* filename = [[NSString stringWithFormat:@"%@ (%@)", basename, SHA1] stringByAppendingPathExtension:pathExtension];
350+
return filename;
351+
}
352+
353+
- (void)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider writePromiseToURL:(NSURL*)url completionHandler:(void (^)(NSError* errorOrNil))completionHandler API_AVAILABLE(macos(10.12)) {
354+
GCDiffDelta* delta = filePromiseProvider.userInfo;
355+
NSString* SHA1 = [self _SHA1ForDelta:delta];
356+
NSError* error;
357+
BOOL success = [delta.diff.repository exportBlobWithSHA1:SHA1 toPath:url.path error:&error];
358+
completionHandler(success ? nil : error);
359+
}
360+
361+
@end
362+
363+
@implementation GIDiffFileProvider
364+
365+
- (NSArray<NSPasteboardType>*)writableTypesForPasteboard:(NSPasteboard*)pasteboard {
366+
return [[self.overridePasteboardWriter writableTypesForPasteboard:pasteboard] arrayByAddingObjectsFromArray:[super writableTypesForPasteboard:pasteboard]];
367+
}
368+
369+
- (NSPasteboardWritingOptions)writingOptionsForType:(NSPasteboardType)type pasteboard:(NSPasteboard*)pasteboard {
370+
return [self.overridePasteboardWriter writingOptionsForType:type pasteboard:pasteboard] ?: [super writingOptionsForType:type pasteboard:pasteboard];
371+
}
372+
373+
- (id)pasteboardPropertyListForType:(NSPasteboardType)type {
374+
return [self.overridePasteboardWriter pasteboardPropertyListForType:type] ?: [super pasteboardPropertyListForType:type];
375+
}
376+
304377
@end

0 commit comments

Comments
 (0)