From: <ho...@us...> - 2007-04-28 20:14:32
|
Revision: 1925 http://skim-app.svn.sourceforge.net/skim-app/?rev=1925&view=rev Author: hofman Date: 2007-04-28 13:14:20 -0700 (Sat, 28 Apr 2007) Log Message: ----------- Parse and lookup pdfsync in background using a DO. Modified Paths: -------------- trunk/SKApplication.m trunk/SKDocument.m trunk/SKPDFSynchronizer.h trunk/SKPDFSynchronizer.m trunk/SKPDFView.m Modified: trunk/SKApplication.m =================================================================== --- trunk/SKApplication.m 2007-04-28 17:13:26 UTC (rev 1924) +++ trunk/SKApplication.m 2007-04-28 20:14:20 UTC (rev 1925) @@ -114,14 +114,9 @@ if ([[NSFileManager defaultManager] fileExistsAtPath:[file path]] && [[NSFileManager defaultManager] fileExistsAtPath:source]) { SKDocument *document = [[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:file display:YES error:NULL]; - unsigned int pageIndex; - NSPoint point; - if ([document respondsToSelector:@selector(synchronizer)] && [document respondsToSelector:@selector(pdfView)] && - [[document synchronizer] getPageIndex:&pageIndex location:&point forLine:[lineNumber intValue] inFile:source]) { - - [[document pdfView] displayLineAtPoint:point inPageAtIndex:pageIndex]; - } + if ([document respondsToSelector:@selector(synchronizer)]) + [[document synchronizer] findPageLocationForLine:[lineNumber intValue] inFile:source]; } else { [command setScriptErrorNumber:NSArgumentsWrongScriptError]; Modified: trunk/SKDocument.m =================================================================== --- trunk/SKDocument.m 2007-04-28 17:13:26 UTC (rev 1924) +++ trunk/SKDocument.m 2007-04-28 20:14:20 UTC (rev 1925) @@ -76,6 +76,8 @@ - (void)dealloc { [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKey:SKAutoCheckFileUpdateKey]; [[NSNotificationCenter defaultCenter] removeObserver:self]; + [synchronizer stopDOServer]; + [synchronizer release]; [fileUpdateTimer invalidate]; [fileUpdateTimer release]; [lastChangedDate release]; @@ -83,7 +85,6 @@ [pdfData release]; [noteDicts release]; [readNotesAccessoryView release]; - [synchronizer release]; [super dealloc]; } @@ -599,11 +600,46 @@ - (SKPDFSynchronizer *)synchronizer { if (synchronizer == nil) { synchronizer = [[SKPDFSynchronizer alloc] init]; + [synchronizer setDelegate:self]; [synchronizer setFileName:[[[self fileName] stringByDeletingPathExtension] stringByAppendingPathExtension:@"pdfsync"]]; } return synchronizer; } +- (void)synchronizer:(SKPDFSynchronizer *)synchronizer foundLine:(int)line inFile:(NSString *)file { + if ([[NSFileManager defaultManager] fileExistsAtPath:file]) { + + NSString *editorPreset = [[NSUserDefaults standardUserDefaults] objectForKey:SKTeXEditorPresetKey]; + NSString *editorCmd = [[NSUserDefaults standardUserDefaults] objectForKey:SKTeXEditorCommandKey]; + NSMutableString *cmdString = [[[[NSUserDefaults standardUserDefaults] objectForKey:SKTeXEditorArgumentsKey] mutableCopy] autorelease]; + + if ([editorPreset isEqualToString:@""] == NO) { + NSString *appPath = [[NSWorkspace sharedWorkspace] fullPathForApplication:editorPreset]; + NSString *toolPath = appPath ? [NSBundle pathForResource:editorCmd ofType:nil inDirectory:appPath] : nil; + if (toolPath) { + editorCmd = toolPath; + } else { + // Emacs has its tool in Emacs.app/Contents/MacOS/bin/ + toolPath = [[[[NSBundle bundleWithPath:appPath] executablePath] stringByAppendingPathComponent:@"bin"] stringByAppendingPathComponent:cmdString]; + if ([[NSFileManager defaultManager] isExecutableFileAtPath:toolPath]) + editorCmd = toolPath; + } + } + + [cmdString replaceOccurrencesOfString:@"%file" withString:file options:NSLiteralSearch range: NSMakeRange(0, [cmdString length] )]; + [cmdString replaceOccurrencesOfString:@"%line" withString:[NSString stringWithFormat:@"%d", line] options:NSLiteralSearch range:NSMakeRange(0, [cmdString length])]; + [cmdString insertString:@" " atIndex:0]; + [cmdString insertString:editorCmd atIndex:0]; + + [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", cmdString, nil]]; + } +} + +- (void)synchronizer:(SKPDFSynchronizer *)synchronizer foundLocation:(NSPoint)point atPageIndex:(unsigned int)pageIndex { + [[self pdfView] displayLineAtPoint:point inPageAtIndex:pageIndex]; +} + + #pragma mark Accessors - (SKMainWindowController *)mainWindowController { Modified: trunk/SKPDFSynchronizer.h =================================================================== --- trunk/SKPDFSynchronizer.h 2007-04-28 17:13:26 UTC (rev 1924) +++ trunk/SKPDFSynchronizer.h 2007-04-28 20:14:20 UTC (rev 1925) @@ -37,6 +37,7 @@ */ #import <Cocoa/Cocoa.h> +#import <libkern/OSAtomic.h> @interface SKPDFSynchronizer : NSObject { @@ -44,20 +45,40 @@ NSDate *lastModDate; NSMutableArray *pages; NSMutableDictionary *lines; + + id delegate; + + NSLock *lock; + + id serverOnMainThread; + id serverOnServerThread; + NSConnection *mainThreadConnection; + NSConnection *localThreadConnection; + + volatile int32_t shouldKeepRunning __attribute__ ((aligned (4))); } + +- (id)delegate; +- (void)setDelegate:(id)newDelegate; + - (NSString *)fileName; - (void)setFileName:(NSString *)newFileName; -- (BOOL)parsePdfsyncFile; -- (BOOL)parsePdfsyncFileIfNeeded; +- (void)findLineForLocation:(NSPoint)point inRect:(NSRect)rect atPageIndex:(unsigned int)pageIndex; +- (void)findPageLocationForLine:(int)line inFile:(NSString *)file; -- (BOOL)getLine:(int *)line file:(NSString **)file forLocation:(NSPoint)point inRect:(NSRect)rect atPageIndex:(unsigned int)pageIndex; -- (BOOL)getPageIndex:(unsigned int *)pageIndex location:(NSPoint *)point forLine:(int)line inFile:(NSString *)file; +- (void)stopDOServer; @end +@interface NSObject (SKPDFSynchronizerDelegate) +- (void)synchronizer:(SKPDFSynchronizer *)synchronizer foundLine:(int)line inFile:(NSString *)file; +- (void)synchronizer:(SKPDFSynchronizer *)synchronizer foundLocation:(NSPoint)point atPageIndex:(unsigned int)pageIndex; +@end + + @interface NSMutableDictionary (SKExtensions) - (void)setIntValue:(int)value forKey:(id)key; - (void)setFloatValue:(float)value forKey:(id)key; Modified: trunk/SKPDFSynchronizer.m =================================================================== --- trunk/SKPDFSynchronizer.m 2007-04-28 17:13:26 UTC (rev 1924) +++ trunk/SKPDFSynchronizer.m 2007-04-28 20:14:20 UTC (rev 1925) @@ -39,8 +39,96 @@ #import "SKPDFSynchronizer.h" #import "NSCharacterSet_SKExtensions.h" #import "NSScanner_SKExtensions.h" +#import <Carbon/Carbon.h> +// NSFileManager is not thread safe +static BOOL SKFileExistsAtPath(NSString *path) { + if (path == nil) + return NO; + + FSRef ref; + + return noErr == FSPathMakeRef((UInt8 *)[path fileSystemRepresentation], &ref, NULL); +} + +static NSDate *SKFileModificationDateAtPath(NSString *path) { + static NSDate* jan1904 = nil; + if (jan1904 == nil) + jan1904 = [[NSDate dateWithString:@"1904-01-01 00:00:00 +0000"] retain]; + + FSCatalogInfo info; + FSRef fileRef; + + if (NO == CFURLGetFSRef((CFURLRef)[NSURL fileURLWithPath:path], &fileRef)) + return nil; + + if (noErr == FSGetCatalogInfo( &fileRef, kFSCatInfoContentMod, &info, NULL,NULL, NULL )) + return nil; + + union { + UTCDateTime local; + UInt64 shifted; + } time; + + time.local = info.contentModDate; + if (time.shifted) + return [[[NSDate alloc] initWithTimeInterval:time.shifted / 65536 sinceDate:jan1904] autorelease]; + else + return nil; +} + +static NSString *SKTeXSourceFile(NSString *file, NSString *base) { + if ([[file pathExtension] caseInsensitiveCompare:@"tex"] != NSOrderedSame) + file = [file stringByAppendingPathExtension:@"tex"]; + if ([file hasPrefix:@"/"] == NO) + file = [base stringByAppendingPathComponent:file]; + return file; +} + +static NSMutableDictionary *SKRecordForRecordIndex(NSMutableDictionary *records, int recordIndex) { + NSNumber *recordNumber = [[NSNumber alloc] initWithInt:recordIndex]; + NSMutableDictionary *record = [records objectForKey:recordNumber]; + if (record == nil) { + record = [[NSMutableDictionary alloc] initWithObjectsAndKeys:recordNumber, @"recordIndex", nil]; + [records setObject:record forKey:recordNumber]; + [record release]; + } + [recordNumber release]; + return record; +} + +#pragma mark - + +@protocol SKPDFSynchronizerServerThread +- (oneway void)cleanup; +- (oneway void)serverFindLineForLocation:(NSPoint)point inRect:(NSRect)rect atPageIndex:(unsigned int)pageIndex; +- (oneway void)serverFindPageLocationForLine:(int)line inFile:(bycopy NSString *)file; +@end + +@protocol SKPDFSynchronizerMainThread +- (oneway void)setLocalServer:(byref id)anObject; +- (oneway void)serverFoundLine:(int)line inFile:(bycopy NSString *)file; +- (oneway void)serverFoundLocation:(NSPoint)point atPageIndex:(unsigned int)pageIndex; +@end + +#pragma mark - + +@interface SKPDFSynchronizer (Private) + +- (NSDate *)lastModDate; +- (void)setLastModDate:(NSDate *)date; + +- (void)runDOServerForPorts:(NSArray *)ports; + +// these following methods only be called on the server thread +- (BOOL)parsePdfsyncFile; +- (BOOL)parsePdfsyncFileIfNeeded; + +@end + +#pragma mark - + @implementation SKPDFSynchronizer // Offset of coordinates in PDFKit and what pdfsync tells us. Don't know what they are; is this implementation dependent? @@ -52,11 +140,32 @@ lines = [[NSMutableDictionary alloc] init]; fileName = nil; lastModDate = nil; + + lock = [[NSLock alloc] init]; + + NSPort *port1 = [NSPort port]; + NSPort *port2 = [NSPort port]; + + mainThreadConnection = [[NSConnection alloc] initWithReceivePort:port1 sendPort:port2]; + [mainThreadConnection setRootObject:self]; + [mainThreadConnection enableMultipleThreads]; + + // these will be set when the background thread sets up + localThreadConnection = nil; + serverOnMainThread = nil; + serverOnServerThread = nil; + + shouldKeepRunning = 1; + + // run a background thread to connect to the remote server + // this will connect back to the connection we just set up + [NSThread detachNewThreadSelector:@selector(runDOServerForPorts:) toTarget:self withObject:[NSArray arrayWithObjects:port2, port1, nil]]; } return self; } - (void)dealloc { + [lock release]; [pages release]; [lines release]; [fileName release]; @@ -64,11 +173,28 @@ [super dealloc]; } +#pragma mark Accessors + +- (id)delegate { + return [[delegate retain] autorelease]; +} + +- (void)setDelegate:(id)newDelegate { + if (delegate != newDelegate) { + [delegate release]; + delegate = [newDelegate retain]; + } +} + - (NSString *)fileName { - return [[fileName retain] autorelease]; + [lock lock]; + NSString *file = [[fileName retain] autorelease]; + [lock unlock]; + return file; } - (void)setFileName:(NSString *)newFileName { + [lock lock]; if (fileName != newFileName) { if ([fileName isEqualToString:newFileName] == NO && lastModDate) { [lastModDate release]; @@ -77,58 +203,169 @@ [fileName release]; fileName = [newFileName retain]; } + [lock unlock]; } +- (NSDate *)lastModDate { + [lock lock]; + NSDate *date = [[lastModDate retain] autorelease]; + [lock unlock]; + return date; +} + +- (void)setLastModDate:(NSDate *)date { + [lock lock]; + if (date != lastModDate) { + [lastModDate release]; + lastModDate = [date retain]; + } + [lock unlock]; +} + +#pragma mark API +#pragma mark | DO server + +- (void)stopDOServer { + // this cleans up the connections, ports and proxies on both sides + [serverOnServerThread cleanup]; + // we're in the main thread, so set the stop flag + OSAtomicCompareAndSwap32Barrier(1, 0, (int32_t *)&shouldKeepRunning); + + // clean up the connection in the main thread; don't invalidate the ports, since they're still in use + [mainThreadConnection setRootObject:nil]; + [mainThreadConnection invalidate]; + [mainThreadConnection release]; + mainThreadConnection = nil; + + [serverOnServerThread release]; + serverOnServerThread = nil; +} + +#pragma mark | Finding + +- (void)findLineForLocation:(NSPoint)point inRect:(NSRect)rect atPageIndex:(unsigned int)pageIndex { + while (serverOnServerThread == nil) + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [serverOnServerThread serverFindLineForLocation:point inRect:rect atPageIndex:pageIndex]; +} + +- (void)findPageLocationForLine:(int)line inFile:(NSString *)file { + while (serverOnServerThread == nil) + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [serverOnServerThread serverFindPageLocationForLine:line inFile:file]; +} + +#pragma mark Main thread +#pragma mark | DO server + +- (oneway void)setLocalServer:(byref id)anObject { + [anObject setProtocolForProxy:@protocol(SKPDFSynchronizerServerThread)]; + serverOnServerThread = [anObject retain]; +} + +#pragma mark | Finding + +- (oneway void)serverFoundLine:(int)line inFile:(bycopy NSString *)file { + if (shouldKeepRunning && [delegate respondsToSelector:@selector(synchronizer:foundLine:inFile:)]) + [delegate synchronizer:self foundLine:line inFile:file]; +} + +- (oneway void)serverFoundLocation:(NSPoint)point atPageIndex:(unsigned int)pageIndex { + if (shouldKeepRunning && [delegate respondsToSelector:@selector(synchronizer:foundLocation:atPageIndex:)]) + [delegate synchronizer:self foundLocation:point atPageIndex:pageIndex]; +} + +#pragma mark Server thread +#pragma mark | DO server + +- (oneway void)cleanup { + // clean up the connection in the server thread + [localThreadConnection setRootObject:nil]; + + // this frees up the CFMachPorts created in -init + [[localThreadConnection receivePort] invalidate]; + [[localThreadConnection sendPort] invalidate]; + [localThreadConnection invalidate]; + [localThreadConnection release]; + localThreadConnection = nil; + + [serverOnMainThread release]; + serverOnMainThread = nil; +} + +- (void)runDOServerForPorts:(NSArray *)ports { + // detach a new thread to run this + NSAssert(localThreadConnection == nil, @"server is already running"); + + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + + OSAtomicCompareAndSwap32Barrier(0, 1, (int32_t *)&shouldKeepRunning); + + @try { + // we'll use this to communicate between threads on the localhost + localThreadConnection = [[NSConnection alloc] initWithReceivePort:[ports objectAtIndex:0] sendPort:[ports objectAtIndex:1]]; + if(localThreadConnection == nil) + @throw @"Unable to get default connection"; + [localThreadConnection setRootObject:self]; + + serverOnMainThread = [[localThreadConnection rootProxy] retain]; + [serverOnMainThread setProtocolForProxy:@protocol(SKPDFSynchronizerMainThread)]; + // handshake, this sets the proxy at the other side + [serverOnMainThread setLocalServer:self]; + + NSRunLoop *rl = [NSRunLoop currentRunLoop]; + BOOL didRun; + + // see http://lists.apple.com/archives/cocoa-dev/2006/Jun/msg01054.html for a helpful explanation of NSRunLoop + do { + [pool release]; + pool = [NSAutoreleasePool new]; + didRun = [rl runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } while (shouldKeepRunning == 1 && didRun); + } + @catch(id exception) { + NSLog(@"Discarding exception \"%@\" raised in object %@", exception, self); + // reset the flag so we can start over; shouldn't be necessary + OSAtomicCompareAndSwap32Barrier(0, 1, (int32_t *)&shouldKeepRunning); + } + + @finally { + [pool release]; + } +} + - (BOOL)parsePdfsyncFileIfNeeded { - NSFileManager *fm = [NSFileManager defaultManager]; + NSString *theFileName = [self fileName]; - if (fileName == nil || [fm fileExistsAtPath:fileName] == NO) + if (theFileName == nil || SKFileExistsAtPath(theFileName) == NO) return NO; - NSDate *modDate = [[fm fileAttributesAtPath:fileName traverseLink:NO] fileModificationDate]; - - if (lastModDate == nil || [modDate compare:lastModDate] == NSOrderedDescending) + NSDate *modDate = SKFileModificationDateAtPath(theFileName); + NSDate *currentModDate = [self lastModDate]; + + if (currentModDate == nil || [modDate compare:currentModDate] == NSOrderedDescending) return [self parsePdfsyncFile]; return YES; } -static NSString *SKTeXSourceFile(NSString *file, NSString *base) { - if ([[file pathExtension] caseInsensitiveCompare:@"tex"] != NSOrderedSame) - file = [file stringByAppendingPathExtension:@"tex"]; - if ([file hasPrefix:@"/"] == NO) - file = [base stringByAppendingPathComponent:file]; - return file; -} +#pragma mark | Parsing and Finding -static NSMutableDictionary *SKRecordForRecordIndex(NSMutableDictionary *records, int recordIndex) { - NSNumber *recordNumber = [[NSNumber alloc] initWithInt:recordIndex]; - NSMutableDictionary *record = [records objectForKey:recordNumber]; - if (record == nil) { - record = [[NSMutableDictionary alloc] initWithObjectsAndKeys:recordNumber, @"recordIndex", nil]; - [records setObject:record forKey:recordNumber]; - [record release]; - } - [recordNumber release]; - return record; -} - - (BOOL)parsePdfsyncFile { - NSFileManager *fm = [NSFileManager defaultManager]; + NSString *theFileName = [self fileName]; [pages removeAllObjects]; [lines removeAllObjects]; - if ([fm fileExistsAtPath:fileName] == NO) + if (SKFileExistsAtPath(theFileName) == NO) return NO; - [lastModDate release]; - lastModDate = [[[fm fileAttributesAtPath:fileName traverseLink:NO] fileModificationDate] retain]; + [self setLastModDate:SKFileModificationDateAtPath(theFileName)]; - NSString *basePath = [fileName stringByDeletingLastPathComponent]; + NSString *basePath = [theFileName stringByDeletingLastPathComponent]; NSMutableDictionary *records = [NSMutableDictionary dictionary]; NSMutableArray *files = [NSMutableArray array]; - NSString *pdfsyncString = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL]; + NSString *pdfsyncString = [NSString stringWithContentsOfFile:theFileName encoding:NSUTF8StringEncoding error:NULL]; NSString *file; int recordIndex, line; float x, y; @@ -165,7 +402,7 @@ [scanner scanCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:NULL]; - while ([scanner scanCharacter:&ch]) { + while (shouldKeepRunning && [scanner scanCharacter:&ch]) { if (ch == 'l') { if ([scanner scanInt:&recordIndex] && [scanner scanInt:&line]) { @@ -226,15 +463,15 @@ [pages makeObjectsPerformSelector:@selector(sortUsingDescriptors:) withObject:[NSArray arrayWithObjects:ySortDescriptor, xSortDescriptor, nil]]; - return YES; + return shouldKeepRunning; } -- (BOOL)getLine:(int *)line file:(NSString **)file forLocation:(NSPoint)point inRect:(NSRect)rect atPageIndex:(unsigned int)pageIndex { +- (oneway void)serverFindLineForLocation:(NSPoint)point inRect:(NSRect)rect atPageIndex:(unsigned int)pageIndex { int foundLine = -1; NSString *foundFile = nil; NSDictionary *record = nil; - if ([self parsePdfsyncFileIfNeeded] && pageIndex < [pages count]) { + if (shouldKeepRunning && [self parsePdfsyncFileIfNeeded] && pageIndex < [pages count]) { NSDictionary *beforeRecord = nil; NSDictionary *afterRecord = nil; @@ -293,18 +530,16 @@ } - if (line) *line = foundLine; - if (file) *file = foundFile; - - return record != nil; + if (shouldKeepRunning) + [serverOnMainThread serverFoundLine:foundLine inFile:foundFile]; } -- (BOOL)getPageIndex:(unsigned int *)pageIndex location:(NSPoint *)point forLine:(int)line inFile:(NSString *)file { +- (oneway void)serverFindPageLocationForLine:(int)line inFile:(bycopy NSString *)file { unsigned int foundPageIndex = NSNotFound; NSPoint foundPoint = NSZeroPoint; NSDictionary *record = nil; - if (file && [self parsePdfsyncFileIfNeeded] && [lines objectForKey:file]) { + if (shouldKeepRunning && file && [self parsePdfsyncFileIfNeeded] && [lines objectForKey:file]) { NSDictionary *beforeRecord = nil; NSDictionary *afterRecord = nil; @@ -347,14 +582,13 @@ } } - if (pageIndex) *pageIndex = foundPageIndex; - if (point) *point = foundPoint; - - return record != nil; + if (shouldKeepRunning) + [serverOnMainThread serverFoundLocation:foundPoint atPageIndex:foundPageIndex]; } @end +#pragma mark - @implementation NSMutableDictionary (SKExtensions) Modified: trunk/SKPDFView.m =================================================================== --- trunk/SKPDFView.m 2007-04-28 17:13:26 UTC (rev 1924) +++ trunk/SKPDFView.m 2007-04-28 20:14:20 UTC (rev 1925) @@ -2671,44 +2671,14 @@ if ([document respondsToSelector:@selector(synchronizer)]) { - SKPDFSynchronizer *synchronizer = [document synchronizer]; NSPoint mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; PDFPage *page = [self pageForPoint:mouseLoc nearest:YES]; NSPoint location = [self convertPoint:mouseLoc toPage:page]; unsigned int pageIndex = [[self document] indexForPage:page]; PDFSelection *sel = [page selectionForLineAtPoint:location]; NSRect rect = sel ? [sel boundsForPage:page] : NSMakeRect(location.x - 20.0, location.y - 5.0, 40.0, 10.0); - NSString *file = nil; - int line = -1; - if ([synchronizer getLine:&line file:&file forLocation:location inRect:rect atPageIndex:pageIndex] && - [[NSFileManager defaultManager] fileExistsAtPath:file]) { - - NSString *editorPreset = [[NSUserDefaults standardUserDefaults] objectForKey:SKTeXEditorPresetKey]; - NSString *editorCmd = [[NSUserDefaults standardUserDefaults] objectForKey:SKTeXEditorCommandKey]; - NSMutableString *cmdString = [[[[NSUserDefaults standardUserDefaults] objectForKey:SKTeXEditorArgumentsKey] mutableCopy] autorelease]; - - if ([editorPreset isEqualToString:@""] == NO) { - NSString *appPath = [[NSWorkspace sharedWorkspace] fullPathForApplication:editorPreset]; - NSString *toolPath = appPath ? [NSBundle pathForResource:editorCmd ofType:nil inDirectory:appPath] : nil; - if (toolPath) { - editorCmd = toolPath; - } else { - // Emacs has its tool in Emacs.app/Contents/MacOS/bin/ - toolPath = [[[[NSBundle bundleWithPath:appPath] executablePath] stringByAppendingPathComponent:@"bin"] stringByAppendingPathComponent:cmdString]; - if ([[NSFileManager defaultManager] isExecutableFileAtPath:toolPath]) - editorCmd = toolPath; - } - } - - [cmdString replaceOccurrencesOfString:@"%file" withString:file options:NSLiteralSearch range: NSMakeRange(0, [cmdString length] )]; - [cmdString replaceOccurrencesOfString:@"%line" withString:[NSString stringWithFormat:@"%d", line] options:NSLiteralSearch range:NSMakeRange(0, [cmdString length])]; - [cmdString insertString:@" " atIndex:0]; - [cmdString insertString:editorCmd atIndex:0]; - - [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", cmdString, nil]]; - - } else NSBeep(); + [[document synchronizer] findLineForLocation:location inRect:rect atPageIndex:pageIndex]; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |