In this post I talk on how to write a Service for MacOS X 10.6. If you don’t know what is a Service, Apple describes it here http://www.apple.com/macosx/refinements/:

  • Easily preview Mermaid diagrams
  • Live update when editing in your preferred editor
  • Capture screenshots with customizable margins
  • Create PNG from the Terminal
  • Free download on the Mac App Store
MarkChart

The Services menu in Mac OS X lets you use features of one application while working in another. In Snow Leopard, services are more simplified, streamlined, and helpful. The Services menu is contextual, so it shows just the services appropriate for the application you’re using or content you’re viewing rather than all available services. You can access services with a right click of your mouse or Control-click of your trackpad. You can configure the menu to show only the services you want, and you can even create your own services using Automator.

The technical documentation from Apple on how to write your own Service is available here: Services Implementation Guide. Writing a Service for MacOS X 10.6 is not complicated in itself. Some useful documentation (on how to correctly write the Info.plist of the service) is available but it is hard to find a working sample. So the aim at this post is to provide a sample Service with the source code. The Service is really simple and can do 2 tasks:

  • implement a functionality similar to the ‘Paste and Match Style’ feature available in most applications under the Edit menu.
  • implement a functionality to copy the selection from the front application as plain text in the Clipboard.

Download: You can download here the compiled Service. To install it, unzip it, then move the ‘Citrouille.service’ in your ~/Library/Services folder and log out. If you are interested by the source code, the full sources are available here.

‘Paste and Match Style’: A simple implementation of the ‘Paste and Match Style’ functionality. When you copy text (with whatever fonts, sizes and colours it had), you can select ‘Paste and Match Style’ from the Services menu in any application to paste the text with the current style. This feature doesn’t have advantages over the built-in ‘Paste and Match Style’ from many MacOSX applications.

Figure 1: ‘Paste and Match Style’ in the Services menu

‘Paste and Match Style’ in the Services menu

The implementation for ‘Paste and Match Style’ is really simple:

- (void)doPasteAsPlainText:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error
{
    NSString *outString = @"";
    BOOL hasError = NO;
     
    if(!hasError)
    {
        // Test for strings on the pasteboard.
        NSArray *classes = [NSArray arrayWithObject:[NSString class]];
        NSDictionary *options = [NSDictionary dictionary];
         
        if (![[NSPasteboard generalPasteboard] canReadObjectForClasses:classes options:options])
        {
            outString = @"";
            hasError = YES;
            *error = NSLocalizedString(@"Error: There is no string in the pasteboard.", @"outputing nothing");
        }
    }
     
    if(!hasError)
    {
        outString = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString];
        if(outString == nil)
        {
            outString = @"";
            hasError = YES;
            *error = NSLocalizedString(@"Error: There is no valid string in the pasteboard.", @"outputing nothing");
        }
    }
     
     
    // Write the string onto the pasteboard.
    [pboard clearContents];
    [pboard writeObjects:[NSArray arrayWithObject:outString]];
}

‘Copy as Plain Text’: you can select a text in any application and select ‘Copy as Plain Text’ from the Services menu in any application. This will copy the selected text as plain text (no style) in the clipboard.

Figure 2: ‘Copy as Plain Text’ in the Services menu

‘Copy as Plain Text’ in the Services menu

- (void)doCopyAsPlainText:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error
{
    // Test for strings on the pasteboard.
    NSArray *classes = [NSArray arrayWithObject:[NSString class]];
    NSDictionary *options = [NSDictionary dictionary];
     
    if (![pboard canReadObjectForClasses:classes options:options])
    {
        *error = NSLocalizedString(@"Error: couldn't get text.", @"pboard couldn't give string.");
        return;
    }
     
    NSString *pboardString = [pboard stringForType:NSPasteboardTypeString];
    [[NSPasteboard generalPasteboard] clearContents];
    [[NSPasteboard generalPasteboard]  writeObjects:[NSArray arrayWithObject:pboardString]];
}