Ticket #10555: trac_10555-extcode.2.patch

File trac_10555-extcode.2.patch, 17.9 KB (added by iandrus, 8 years ago)
  • sage/ext/mac-app/AppController.h

    # HG changeset patch
    # User Ivan Andrus <darthandrus@gmail.com>
    # Date 1294152572 -3600
    # Node ID 3b9f4a1282bbc3a725da3cb1768af1750c953a5a
    # Parent  ed4a0f2e03bf9a9c92dbd1e4e200f1e1cdea4720
    [mq]: trac_10555-extcode.patch
    
    diff --git a/sage/ext/mac-app/AppController.h b/sage/ext/mac-app/AppController.h
    a b  
    6161-(IBAction)showPreferences:(id)sender;
    6262
    6363-(void)setupPaths;
     64-(NSString*)sageBinary;
    6465
    6566// Quit
    6667-(IBAction)stopServerAndQuit:(id)sender;
  • sage/ext/mac-app/AppController.m

    diff --git a/sage/ext/mac-app/AppController.m b/sage/ext/mac-app/AppController.m
    a b  
    294294    }
    295295}
    296296
     297-(NSString*)sageBinary{
     298    return sageBinary;
     299}
     300
    297301-(IBAction)revealInFinder:(id)sender{
    298302    if ( [[sender title] isEqualToString:@"Reveal in Shell"] ) {
    299303        [self terminalRun:[NSString stringWithFormat:@"cd '%@' && $SHELL",
  • sage/ext/mac-app/AppDelegate.h

    diff --git a/sage/ext/mac-app/AppDelegate.h b/sage/ext/mac-app/AppDelegate.h
    a b  
    2929- (BOOL)application:(NSApplication * )theApplication openFile: (NSString * )filename;
    3030- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
    3131
     32// Services
     33- (NSString*)writeData:(NSData*)data toTempFileWithSuffix:(NSString*)format;
     34- (NSString *)urlEncodeValue:(NSString *)str;
     35
     36- (void)serviceUnspkg:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error;
     37- (void)serviceExecute:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error;
     38- (void)serviceTerminalRun:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error;
     39- (void)serviceWorksheet:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error;
     40
    3241@end
  • sage/ext/mac-app/AppDelegate.m

    diff --git a/sage/ext/mac-app/AppDelegate.m b/sage/ext/mac-app/AppDelegate.m
    a b  
    1010#import <WebKit/WebFrame.h>
    1111#import <WebKit/WebView.h>
    1212#import <Carbon/Carbon.h>
     13#import <AppKit/NSPasteboard.h>
    1314
    1415@implementation AppDelegate
    1516
     
    6263        [[NSApp mainMenu] removeItemAtIndex:6]; // Window menu
    6364        [[NSApp mainMenu] removeItemAtIndex:2]; // Edit menu
    6465    }
     66
     67    [NSApp setServicesProvider:self];
    6568}
    6669
    6770- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     
    7780    return NO;
    7881}
    7982
     83# pragma mark NSApplicationDelegate
     84
     85- (NSString *)urlEncodeValue:(NSString *)str {
     86    NSString *result = (NSString *)
     87    CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
     88                                            (CFStringRef)str,
     89                                            NULL,
     90                                            CFSTR(":/?#[]@!$&’()*+,;="),
     91                                            kCFStringEncodingUTF8);
     92    return [result autorelease];
     93}
     94
    8095// From here down are methods from NSApplicationDelegate, which probably do belong in another file.
    8196// If/when this is done, I think you have to change the "File's Owner"'s delegate in IB
    8297- (BOOL)application: (NSApplication * )theApplication openFile: (NSString * )filename{
     
    89104        // Run sage and python files in your terminal
    90105        [appController sageTerminalRun:nil withArguments:[NSArray arrayWithObject:filename]];
    91106
    92     } else if ( [extension isEqual:@"sws"] ) {
     107    } else if ( [extension isEqual:@"sws"] || [extension isEqual:@"txt"] ) {
    93108
    94109        // Browse to a url which will upload the file.
    95110        // Perhaps we should have an option to delete the file when done...
    96111        NSString* theURL = [NSString stringWithFormat:@"upload_worksheet?url=%@",
    97                            [[NSURL fileURLWithPath: filename] relativeString]];
     112                            [self urlEncodeValue:[[NSURL fileURLWithPath: filename] relativeString]]];
    98113        [appController browseLocalSageURL:theURL];
    99114
    100115    } else if ( [extension isEqual:@"spkg"] ) {
     
    142157        // We can install spkg's from URLs
    143158        [appController sageTerminalRun:@"i" withArguments:[NSArray arrayWithObject:urlStr]];
    144159
    145     } else if ( [[urlStr pathExtension] isEqual:@"sws"] ) {
     160    } else if ( [[urlStr pathExtension] isEqual:@"sws"] || [[urlStr pathExtension] isEqual:@"txt"] ) {
    146161
    147162        // Browse to a url which will upload the file.
    148163        // Perhaps we should have an option to delete the file when done...
     
    191206    }
    192207}
    193208
     209
     210#pragma mark Services
     211
     212- (NSArray*)extractFileURLs:(NSPasteboard *)pboard error:(NSString **)error {
     213
     214    NSArray *classes = [NSArray arrayWithObject:[NSURL class]];
     215
     216    // Only on 10.6
     217    if ( [pboard respondsToSelector:@selector(readObjectsForClasses:options:)] ) {
     218
     219        NSArray* fileURLs = [pboard readObjectsForClasses:classes
     220                                                  options:nil];
     221
     222
     223        NSMutableArray* tmpArray = [NSMutableArray arrayWithCapacity:[fileURLs count]];
     224        NSEnumerator *enumerator = [fileURLs objectEnumerator];
     225        id key;
     226        while( (key = [enumerator nextObject]) ) {
     227            if ([key isFileURL]) {
     228                [tmpArray addObject:[key path]];
     229            }
     230        }
     231        NSArray *filePaths = [NSArray arrayWithArray:tmpArray];
     232        return filePaths;
     233
     234    } else if ([[pboard types] containsObject:NSURLPboardType] ) {
     235        // On 10.5 I think you can only get one item no the paste board at a time, so this should be okay.
     236        // Ensure a URL on the pasteboard.
     237        NSURL *url = [NSURL URLFromPasteboard:pboard];
     238        if ([url isFileURL]) {
     239            return [NSArray arrayWithObject:[url path]];
     240        }
     241    }
     242    *error = NSLocalizedString(@"Error: couldn't execute file.",
     243                               @"pboard couldn't give URL.");
     244    return nil;
     245}
     246
     247
     248- (void)serviceTerminalRun:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
     249
     250    NSArray* files = [self extractFileURLs:pboard error:error];
     251    if (files) {
     252        [appController sageTerminalRun:userData withArguments:files];
     253    }
     254}
     255
     256- (void)serviceExecute:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
     257    NSLog(@"userData: %@",userData);
     258    NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
     259    NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
     260    if ( bestType ) {
     261        NSString *str = [pboard stringForType:bestType];
     262        [appController sageTerminalRun: ([userData length] > 0 ? userData : nil)
     263                         withArguments:[NSArray
     264                                        arrayWithObjects:
     265                                        @"\n",
     266                                        str,
     267                                        nil]];
     268    }
     269}
     270
     271- (void)serviceUnspkg:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
     272    NSArray* files = [self extractFileURLs:pboard error:error];
     273    if (files) {
     274
     275        NSWorkspace* ws = [NSWorkspace sharedWorkspace];
     276        NSEnumerator *enumerator = [files objectEnumerator];
     277        id file;
     278        while( (file = [enumerator nextObject]) ) {
     279
     280            [ws openFile:file withApplication: @"/System/Library/CoreServices/Archive Utility.app"] ||
     281            [ws openFile:file withApplication: @"/System/Library/CoreServices/BOMArchiveHelper.app"];
     282
     283        }
     284    }
     285}
     286
     287
     288- (NSString*)writeData:(NSData*)data toTempFileWithSuffix:(NSString*)suffix{
     289
     290    NSString *tempFileTemplate = [NSTemporaryDirectory()
     291                                  stringByAppendingPathComponent:
     292                                  [NSString stringWithFormat:@"sage.XXXX%@", suffix]];
     293    const char *tempFileTemplateCString = [tempFileTemplate fileSystemRepresentation];
     294    char *tempFileNameCString = (char *)malloc(strlen(tempFileTemplateCString) + 1);
     295    strcpy(tempFileNameCString, tempFileTemplateCString);
     296    int fileDescriptor = mkstemps(tempFileNameCString, [suffix length]);
     297    if (fileDescriptor == -1) {
     298        return nil;
     299    }
     300
     301    NSString* tempFileName = [[NSFileManager defaultManager]
     302                              stringWithFileSystemRepresentation:tempFileNameCString
     303                              length:strlen(tempFileNameCString)];
     304
     305    free(tempFileNameCString);
     306
     307    NSFileHandle* tempFileHandle = [[NSFileHandle alloc]
     308                                    initWithFileDescriptor:fileDescriptor
     309                                    closeOnDealloc:YES];
     310
     311    // write to file
     312    [tempFileHandle writeData:data];
     313    [tempFileHandle release];
     314
     315    // Return path to the file
     316    return [NSString stringWithString:tempFileName];
     317}
     318
     319
     320- (void)serviceWorksheet:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
     321
     322    NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
     323    NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
     324    if ( bestType ) {
     325        // Extract data from pasteboard
     326        NSString *str = [pboard stringForType:bestType];
     327
     328        // Give it a title and surround with {{{ }}} if needed
     329        // If it contains {{{ we assume they know what they are doing and pass it straight through
     330        NSData* data;
     331        NSRange match = [str rangeOfString:@"{{{" options:NSLiteralSearch];
     332        if ( match.length == 0 ) {
     333            NSString* tmpStr = [NSString stringWithFormat:@"Untitled\n{{{\n%@\n}}}", str];
     334            data = [tmpStr dataUsingEncoding:NSUTF8StringEncoding];
     335        } else {
     336            data = [str dataUsingEncoding:NSUTF8StringEncoding];
     337        }
     338
     339        // Write data to file
     340        NSString* tmpPath = [self writeData:data toTempFileWithSuffix:@".txt" ];
     341
     342        // upload temp file
     343        if (tmpPath) {
     344            [self application:nil openFile:tmpPath];
     345        }
     346        // tmp file will get cleaned up in 3 days by the system...
     347    }
     348}
     349
     350
     351- (void)servicePreparse:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
     352    NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
     353    NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
     354    if ( bestType ) {
     355        // Extract data from pasteboard
     356        NSString *str = [pboard stringForType:bestType];
     357
     358        // Write data to a temporary file
     359        NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
     360        NSString* tmpPath = [self writeData:data toTempFileWithSuffix:@".sage" ];
     361
     362        // preparse temp file
     363        if (tmpPath) {
     364            NSTask* preparser = [NSTask launchedTaskWithLaunchPath:[appController sageBinary]
     365                                                         arguments:[NSArray arrayWithObjects:@"--preparse",
     366                                                                    tmpPath,
     367                                                                    nil]];
     368            [preparser waitUntilExit];
     369            if ( [preparser terminationStatus] == 0 ) {
     370                NSString* preparsedFile = [[tmpPath stringByDeletingPathExtension]
     371                                           stringByAppendingPathExtension:@"py"];
     372                NSError* err;
     373                NSString* contents = [NSString stringWithContentsOfFile:preparsedFile
     374                                                               encoding:NSUTF8StringEncoding
     375                                                                  error:&err];
     376                if (contents) {
     377                    // The first line contains an autogenerated message that we don't want
     378                    NSRange firstLine = [contents rangeOfString:@"\n"];
     379                    NSRange autoGenerated = [contents rangeOfString:@"This file was *autogenerated* from the file"];
     380                    [pboard declareTypes:supportedTypes owner:nil];
     381
     382                    if ( autoGenerated.length > 0 && firstLine.length > 0 && autoGenerated.location < firstLine.location ) {
     383                        [pboard setString:[contents substringFromIndex:firstLine.location+firstLine.length] forType:NSStringPboardType];
     384                    } else {
     385                        [pboard setString:contents forType:NSStringPboardType];
     386                    }
     387                } else if (error) {
     388                    *error = [err localizedDescription];
     389                }
     390            } else if (error) {
     391                *error = @"Could not preparse file";
     392            }
     393        } else if (error) {
     394            *error = @"Could not create temp file";
     395        }
     396        // tmp file will get cleaned up in 3 days by the system...
     397    }
     398}
     399
     400
     401- (void)serviceEval:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
     402
     403    NSArray *supportedTypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
     404    NSString *bestType = [pboard availableTypeFromArray:supportedTypes];
     405    if ( bestType ) {
     406        NSString *str = [pboard stringForType:bestType];
     407
     408        NSPipe* sageOut = [NSPipe pipe];
     409        NSTask* task = [[NSTask alloc] init];
     410        [task setLaunchPath:[appController sageBinary]];
     411        [task setArguments:[NSArray arrayWithObjects:@"-c", str, nil]];
     412        [task setStandardOutput:sageOut];
     413
     414        [task launch];
     415
     416        // It it writes more than 8k we may be in trouble...
     417        [task waitUntilExit];
     418
     419        if ([task terminationStatus] == 0 ) {
     420
     421            NSData *data = [[sageOut fileHandleForReading] readDataToEndOfFile];
     422            [pboard declareTypes:supportedTypes owner:nil];
     423            [pboard setData:data forType:NSStringPboardType];
     424
     425        } else if (error) {
     426            *error = @"Could not evaluate code.";
     427        }
     428
     429        [task release];
     430    }
     431}
     432
     433
    194434@end
  • sage/ext/mac-app/Sage-Info.plist

    diff --git a/sage/ext/mac-app/Sage-Info.plist b/sage/ext/mac-app/Sage-Info.plist
    a b  
    141141        <string>MainMenu</string>
    142142        <key>NSPrincipalClass</key>
    143143        <string>NSApplication</string>
     144        <key>NSServices</key>
     145        <array>
     146                <dict>
     147                        <key>NSMenuItem</key>
     148                        <dict>
     149                                <key>default</key>
     150                                <string>Sage/Preparse File with Sage</string>
     151                        </dict>
     152                        <key>NSMessage</key>
     153                        <string>serviceTerminalRun</string>
     154                        <key>NSPortName</key>
     155                        <string>Sage</string>
     156                        <key>NSSendFileTypes</key>
     157                        <array>
     158                                <string>org.sagemath.sage-source</string>
     159                        </array>
     160                        <key>NSUserData</key>
     161                        <string>preparse</string>
     162                </dict>
     163                <dict>
     164                        <key>NSMenuItem</key>
     165                        <dict>
     166                                <key>default</key>
     167                                <string>Sage/Test file with Sage</string>
     168                        </dict>
     169                        <key>NSMessage</key>
     170                        <string>serviceTerminalRun</string>
     171                        <key>NSPortName</key>
     172                        <string>Sage</string>
     173                        <key>NSSendFileTypes</key>
     174                        <array>
     175                                <string>org.sagemath.sage-source</string>
     176                                <string>public.folder</string>
     177                        </array>
     178                        <key>NSUserData</key>
     179                        <string>t</string>
     180                </dict>
     181                <dict>
     182                        <key>NSMenuItem</key>
     183                        <dict>
     184                                <key>default</key>
     185                                <string>Sage/Create Sage Package</string>
     186                        </dict>
     187                        <key>NSMessage</key>
     188                        <string>serviceTerminalRun</string>
     189                        <key>NSPortName</key>
     190                        <string>Sage</string>
     191                        <key>NSSendFileTypes</key>
     192                        <array>
     193                                <string>public.folder</string>
     194                        </array>
     195                        <key>NSUserData</key>
     196                        <string>pkg</string>
     197                </dict>
     198                <dict>
     199                        <key>NSMenuItem</key>
     200                        <dict>
     201                                <key>default</key>
     202                                <string>Sage/Create Uncompressed Sage Package</string>
     203                        </dict>
     204                        <key>NSMessage</key>
     205                        <string>serviceTerminalRun</string>
     206                        <key>NSPortName</key>
     207                        <string>Sage</string>
     208                        <key>NSSendFileTypes</key>
     209                        <array>
     210                                <string>public.folder</string>
     211                        </array>
     212                        <key>NSUserData</key>
     213                        <string>pkg_nc</string>
     214                </dict>
     215                <dict>
     216                        <key>NSMenuItem</key>
     217                        <dict>
     218                                <key>default</key>
     219                                <string>Sage/Unpack Sage Package</string>
     220                        </dict>
     221                        <key>NSMessage</key>
     222                        <string>serviceUnspkg</string>
     223                        <key>NSPortName</key>
     224                        <string>Sage</string>
     225                        <key>NSSendFileTypes</key>
     226                        <array>
     227                                <string>org.sagemath.sage-package</string>
     228                        </array>
     229                </dict>
     230                <dict>
     231                        <key>NSMenuItem</key>
     232                        <dict>
     233                                <key>default</key>
     234                                <string>Sage/New Sage Worksheet with Selection</string>
     235                        </dict>
     236                        <key>NSMessage</key>
     237                        <string>serviceWorksheet</string>
     238                        <key>NSPortName</key>
     239                        <string>Sage</string>
     240                        <key>NSSendTypes</key>
     241                        <array>
     242                                <string>public.plain-text</string>
     243                                <string>NSStringPboardType</string>
     244                        </array>
     245                </dict>
     246                <dict>
     247                        <key>NSMenuItem</key>
     248                        <dict>
     249                                <key>default</key>
     250                                <string>Sage/Preparse Code in Sage (and replace)</string>
     251                        </dict>
     252                        <key>NSMessage</key>
     253                        <string>servicePreparse</string>
     254                        <key>NSPortName</key>
     255                        <string>Sage</string>
     256                        <key>NSReturnTypes</key>
     257                        <array>
     258                                <string>public.plain-text</string>
     259                                <string>NSStringPboardType</string>
     260                        </array>
     261                        <key>NSSendTypes</key>
     262                        <array>
     263                                <string>public.plain-text</string>
     264                                <string>NSStringPboardType</string>
     265                        </array>
     266                </dict>
     267                <dict>
     268                        <key>NSMenuItem</key>
     269                        <dict>
     270                                <key>default</key>
     271                                <string>Sage/Evaluate Code in Sage (and replace)</string>
     272                        </dict>
     273                        <key>NSMessage</key>
     274                        <string>serviceEval</string>
     275                        <key>NSPortName</key>
     276                        <string>Sage</string>
     277                        <key>NSReturnTypes</key>
     278                        <array>
     279                                <string>public.plain-text</string>
     280                                <string>NSStringPboardType</string>
     281                        </array>
     282                        <key>NSSendTypes</key>
     283                        <array>
     284                                <string>public.plain-text</string>
     285                                <string>NSStringPboardType</string>
     286                        </array>
     287                </dict>
     288                <dict>
     289                        <key>NSMenuItem</key>
     290                        <dict>
     291                                <key>default</key>
     292                                <string>Sage/New Sage Terminal Session with Selection</string>
     293                        </dict>
     294                        <key>NSMessage</key>
     295                        <string>serviceExecute</string>
     296                        <key>NSPortName</key>
     297                        <string>Sage</string>
     298                        <key>NSSendTypes</key>
     299                        <array>
     300                                <string>public.plain-text</string>
     301                                <string>NSStringPboardType</string>
     302                        </array>
     303                </dict>
     304        </array>
    144305        <key>UTExportedTypeDeclarations</key>
    145306        <array>
    146307                <dict>