Search code examples
objective-cxcode4quicklook

Creating a QuickLook plug-in for text files in Xcode 4.1


Background

I'm learning Objective-C and Cocoa, and I thought creating simple programs to answer my needs would be a nice thing. I already have a solid .NET C# background, some Python knowledge, and a little of C.

One of my "simple first app" I tried to do is a simple QuickLook plug-in for Arduino's sketch files. I thought it would be a simple task to accomplish since these files are plain text C-like scripts, the only "different" thing is they have a .pde extension.

I uploaded the project on GitHub at ArduinoQuickLook as a reference (the first commit contains a vanilla Xcode 4.1 QuickLook plugin-project).

What I found

Looking around the net I found these resources:

What are my problems

  1. Both of them use GeneratePreviewForURL.m and GenerateThumbnailForURL.m files, but when I created the project in Xcode 4.1 it created GeneratePreviewForURL.c and GenerateThumbnailForURL.c (note .c instead of .m).

  2. Both QLStephen and QLColorCode use #import <Foundation/Foundation.h> in their GeneratePreviewForURL.m and GenerateThumbnailForURL.m files, but if I try to #import it it yields to many errors. (Maybe because my files are .c instead of .m?)

  3. It's not clear to me how I declare which files my plug-in will handle, I understood I need to change ArduinoQuickLook/ArduinoQuickLook-Info.plist (row 14) but what I have to write there? Something like cc.arduino.pde?


Solution

  • This tutorial on creating a Quicklook plugin explains things nicely, but to summarise:

    Point 1 and 2 are related - for some strange reason the Quicklook plugin template only contains .c files - as such, importing the Obj-C Foundation.h header causes errors.

    You should just be able to rename the files from .c to .m and it will work as expected.

    It's not clear to me how I declare which files my plug-in will handle

    You need to do two things - one is say which UTI (Uniform Type Identifier) your plugin handles (e.g cc.arduino.pde), by changing the line you mention:

    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>QLGenerator</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>cc.arduino.pde</string>
            </array>
        </dict>
    </array>
    

    ...but you also have to describe that UTI (mostly so it can map the file-extension to that UTI)

    There are two slightly different ways to declare UTI's, [as "Declaring New Uniform Type Identifiers"] describes:

    Your UTI declarations must be either imported or exported:

    • An exported UTI declaration means that the type is available for use by all other parties. For example, an application that uses a proprietary document format should declare it as an exported UTI.
    • An imported UTI declaration is used to declare a type that the bundle does not own, but would like to see available on the system. For example, say a video-editing program creates files using a proprietary format whose UTI is declared in its application bundle. If you are writing an application or plugin that can read such files, you must make sure that the system knows about the proprietary UTI, even if the actual video-editing application is not available. To do so, your application should redeclare the UTI in its own bundle but mark it as an imported declaration.

    For a Quicklook plugin, you probably want an "imported" UTI declaration, in which you would add something like this to your Info.plist:

    <key>UTImportedTypeDeclarations</key>
    <array>
        <dict>
            <key>UTTypeIdentifier</key>
            <string>cc.arduino.pde</string>
            <key>UTTypeReferenceURL</key>
            <string>http://www.example.com</string>
            <key>UTTypeDescription</key>
            <string>Arduino PDE file</string>
            <key>UTTypeConformsTo</key>
            <array>
                <string>public.c-source</string>
                <string>public.text</string>
            </array>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>pde</string>
                </array>
            </dict>
        </dict>
    </array>