I’ve posted before about creating a Hit List task from an email message. But since I’ve switched to using LaunchBar, I’ve wanted to create tasks directly from there. So I delved a little deeper into the dark world of AppleScript. A language I still have very little understanding of. One of the life savers I found while trying to put this script together was a Python to AppleScript conversion chart.

To make LaunchBar able to create Hit List tasks, you’ll have to create an save an AppleScript file. You can find the file (in text form) here. Once you have the file, open it in Script Editor and save it to ~/Library/Application Support/LaunchBar/Actions as whatever name you like, e.g., New Hit List Task.

To use it, activate LaunchBar and type something from the name of the script, when it’s selected, hit the space bar and type the text of the new task. If, like me, you organize your tasks into multiple lists, you can append a ‘%’ and the list name to have the task created directly in that list. If you don’t provide a list name or mistype it, the task will be created in the Inbox. Here’s a few examples:

  • Take out the trash %home
  • Put this task in the inbox
  • I’ll do this task when I retire %on hold

The list name is case insensitive. If you have multiple lists with the same name then the task will go into the first one found.

# Called by LaunchBar with the text entered in the LaunchBar text field
on handle_string(theTask)
    tell application "The Hit List"
        # Get the list of all groups from The Hit List
        # and parse the task text looking for a group name

        set theFoundGroups to my accumulate_folders()
        set theParsedTask to my parse_task(theTask)

        # The result of parsing the task text is:
        # item 1 is the task text w/o the group
        # item 2 is the group name or null if a group wasn't specified

        if (item 2 of theParsedTask is equal to null) then
            my create_task(inbox, theTask)
            set shortTaskText to item 1 of theParsedTask

            # Look for the group name specified in the task
            # The search ignores case.  If there are multiple groups with the
            # same name, only the first one will be used

            set theGroup to my find_group(theFoundGroups, item 2 of theParsedTask)

            # If we didn't find the group (it's null), use the inbox

            if theGroup is equal to null then
                my create_task(inbox, shortTaskText)
                my create_task(theGroup, shortTaskText)
            end if
        end if
    end tell
end handle_string

# Create a task in a group (folder)
# Set the start date to today
on create_task(theGroup, theTaskText)
    tell application "The Hit List"
        tell theGroup to make new task with properties {title:theTaskText, start date:current date}
    end tell
end create_task

# Get the list of all groups
# returns the list
on accumulate_folders()
    tell application "The Hit List"
        set theFolders to folders group
        set theFoundGroups to {}
        repeat with theFolder in theFolders
            my accumulate_groups(groups of theFolder, theFoundGroups)
        end repeat
    end tell

    return theFoundGroups
end accumulate_folders

# Recursively searches groups, adding new groups to
# theFoundGroups
on accumulate_groups(theGroups, theFoundGroups)
    tell application "The Hit List"
        repeat with theGroup in theGroups
            # We only want lists, not groups or folders
            set objClass to class of theGroup as rich text
            if objClass = "list" then
                set end of theFoundGroups to theGroup
            end if
                my accumulate_groups(groups of theGroup, theFoundGroups)
            end try
        end repeat
    end tell
end accumulate_groups

# Try to find a named group in a list of groups
# Groups are matched on leading characters, e.g., "des" will match "design"
# If the text matches multiple groups then no match is assumed
# Exact matches are always preferred
# returns the group item if found or null if not found
on find_group(theGroups, theName)
    set theFoundGroups to {}
    repeat with theGroup in theGroups
        if name of theGroup is equal to theName then
            return theGroup
        end if
        if name of theGroup starts with theName then
            set the end of theFoundGroups to theGroup
        end if
    end repeat
    if (count of theFoundGroups) is 1 then
        return first item of theFoundGroups
        return null
    end if
end find_group

# Parse the task text looking for a group name
# returns a two-part list, item 1 is the task text w/ the group name
# item 2 is the group name or null if no group was specified
on parse_task(theTask)
    set theParsedTask to {}
    set tid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "%"

    set tokens to text items of theTask
    if (count of tokens) is equal to 1 then
        set theParsedTask to {theTask, null}
        set theShortTask to items 1 thru -2 of tokens as text
        set theParsedTask to {theShortTask, last item of tokens}
    end if

    set AppleScript's text item delimiters to tid

    return theParsedTask
end parse_task

Update 4/4/09: Made lists match by leading characters and excluded non-lists.