This patch prevents the plaintext display of files with binary content in tree-view by connecting the content to the textContents attribute.
PBGitTree is extended with the method textContents, which returns the textual representation of a PBGitTree-object. The methods first checks the output of "git check-attr binary <file>" to see if the user set/unset the binary attribute manually. Then it checks for common binary file-extensions. If this method can't determine whether the file is binary, the file-content is loaded and Unix "file" is run on the first 100 bytes of the file to make a decision. Signed-off-by: Johannes Gilger <[email protected]> --- Hey Pieter, I implemented your advice. My textContents doesn't return nil though, since I think people could mistake that for a file with no content (i.e. only whitespaces). I think the view is something we're going to replace anyway, since it is very limited in its capacity to display stuff. What fell out of the patch is the checking for file-size, but this can easily be added again later on. I edited the XIB by hand since my IB generated a huge diff again. It seems to work fine this way. I'm also pushing this to jg/showBinary on github. I think for 0.7 I still need to rewrite the 02 of the UserManual since it includes a passage about auto-refresh. PBGitHistoryView.xib | 6 ++-- PBGitTree.h | 1 + PBGitTree.m | 66 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/PBGitHistoryView.xib b/PBGitHistoryView.xib index 10b884e..71d7413 100644 --- a/PBGitHistoryView.xib +++ b/PBGitHistoryView.xib @@ -2049,15 +2049,15 @@ </object> <object class="IBConnectionRecord"> <object class="IBBindingConnection" key="connection"> - <string key="label">value: selection.contents</string> + <string key="label">value: selection.textContents</string> <reference key="source" ref="75600241"/> <reference key="destination" ref="69733037"/> <object class="NSNibBindingConnector" key="connector"> <reference key="NSSource" ref="75600241"/> <reference key="NSDestination" ref="69733037"/> - <string key="NSLabel">value: selection.contents</string> + <string key="NSLabel">value: selection.textContents</string> <string key="NSBinding">value</string> - <string key="NSKeyPath">selection.contents</string> + <string key="NSKeyPath">selection.textContents</string> <object class="NSDictionary" key="NSOptions"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSMutableArray" key="dict.sortedKeys"> diff --git a/PBGitTree.h b/PBGitTree.h index 9f4334b..612f24b 100644 --- a/PBGitTree.h +++ b/PBGitTree.h @@ -36,5 +36,6 @@ @property(readonly) NSArray* children; @property(readonly) NSString* fullPath; @property(readonly) NSString* contents; +...@property(readonly) NSString* textContents; @end diff --git a/PBGitTree.m b/PBGitTree.m index 51fadd2..e49e528 100644 --- a/PBGitTree.m +++ b/PBGitTree.m @@ -63,27 +63,83 @@ - (BOOL) isLocallyCached return NO; } +- (BOOL)hasBinaryHeader:(NSString *)fileHeader +{ + if(!fileHeader) + return NO; + + NSString* filetype = [PBEasyPipe outputForCommand:@"/usr/bin/file" withArgs:[NSArray arrayWithObjects:@"-b", @"-N", @"-", nil] inDir:[repository workingDirectory] inputString:fileHeader retValue:nil]; + if([filetype rangeOfString:@"text"].location == NSNotFound) + return YES; + else + return NO; +} + +- (BOOL)hasBinaryAttributes +{ + NSFileHandle* handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"check-attr", @"binary", [self fullPath], nil]]; + NSData* data = [handle readDataToEndOfFile]; + NSString* string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; + + if(string) { + string = [string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + if([string hasSuffix:@"binary: set"]) { + return YES; + } else if([string hasSuffix:@"binary: unset"]) { + return NO; + } else if([string hasSuffix:@"binary: unspecified"]) { + // try common filename-extensions + for (NSString* extension in [NSArray arrayWithObjects:@".pdf", @".jpg", @".jpeg", @".png", @".bmp", @".gif", @".o", nil]) { + if([[self fullPath] hasSuffix:extension]) + return YES; + } + } + } + + return NO; +} + - (NSString*) contents { if (!leaf) - return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]]; + return nil; NSData* data = nil; - + if ([self isLocallyCached]) data = [NSData dataWithContentsOfFile: localFileName]; else { NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]]; data = [handle readDataToEndOfFile]; } - + NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (!string) { + if (!string) string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; - } + return string; } +- (NSString*)textContents +{ + if (!leaf) + return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]]; + + NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"cat-file", @"-s", [self refSpec], nil]]; + NSString* fileSize = [[NSString alloc] initWithData:[handle readDataToEndOfFile] encoding:NSISOLatin1StringEncoding]; + [handle closeFile]; + + if([self hasBinaryAttributes]) + return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [fileSize longLongValue]]; + + NSString* contents = [self contents]; + + if([self hasBinaryHeader:[contents length] >= 100 ? [contents substringToIndex:99] : contents]) + return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [fileSize longLongValue]]; + + return contents; +} + - (void) saveToFolder: (NSString *) dir { NSString* newName = [dir stringByAppendingPathComponent:path]; -- 1.6.4.2.236.gf324c
