Customizing Hook integration with DEVONthink

  1. Home
  2. Docs
  3. Help & Support
  4. Integration
  5. Customizing Hook integration with DEVONthink

Note: Custom integration with DEVONthink requires DEVONthink Pro or DEVONthink Pro Office, basic DEVONthink does not have the required Applescript support.

DEVONthink stores documents as ordinary files organized in folders. Hook is out-of-the-box compatible with DEVONthink, but it treats links to DEVONthink documents as links to regular files. That means if you link to a document in DEVONthink, Hook will open it with the default program for the document type (e.g. Preview for pdfs or TextEdit for rtfs) instead of opening it in DEVONthink.

It would make sense for links to DEVONthink to open in DEVONthink. We can modify how Hook handles DEVONthink to do this, by writing custom integration scripts.

DEVONthink doesn’t have any scripts, so they have to be written from scratch, not just modified. In Preferences>Scripts, click the + button at the bottom of the list of apps, and add DEVONthink to begin writing custom scripts for it.

Get Name

tell application id "DNtp"
    if exists (content record of current tab of window 1) then
        -- current open item
        get name of (content record of current tab of window 1)
    else if class of window 1 is in {viewer window, search window} then
        set selected_items to selection of window 1
        if (count of selected_items) = 1 then
            -- current selected item
            get name of item 1 in selected_items
        end if
    end if
end tell

Hook is always invoked on the frontmost window, which is window 1. There are two cases which we have to handle:

  • The most common case is that we are linking to a document which is open. It will be in the current tab, and we can get the name from that.
  • The other case is that an item is selected but not open (e.g. in list view or if if a folder is selected). We can get the name from the selection.

Get Address

tell application id "DNtp"
    if exists (content record of current tab of window 1) then
        -- current open item
        get reference URL of (content record of current tab of window 1)
    else if class of window 1 is in {viewer window, search window} then
        set selected_items to selection of window 1
        if (count of selected_items) = 1 then
            -- current selected item
            get reference URL of item 1 in selected_items
        end if
    end if
end tell

This is almost exactly alike the script for Get Name except it returns the reference URL instead of the name.

  • If more than one document is selected, or if no documents are, Get Address (and Get Name) won’t return anything, which means that no valid resource is detected

And that’s all you need to do to customize Hook’s integration with DEVONthink! Now your links to DEVONthink documents will open in DEVONthink.

But what about the other script fields? Why didn’t we write an Open Item script?

Open Item

Hook uses URLs to link items together. If DEVONthink didn’t already support URLs to open documents Hook could use an Open Item script to parse URLs and open linked content in DEVONthink. But DEVONthink has its own URL scheme, x-devonthink-item, and Hook can use it to link DEVONthink documents.

So an Open Item script is not necessary for integrating Hook with DEVONthink. But writing one anyway does allow us to further customize how Hook and DEVONthink behave.

DEVONthink’s default behaviour is to open linked documents in a new window. We can write an Open Item script to open links in a tab of the front window instead of a new window.

set itemURL to "$0"
set itemID to text ((length of "x-devonthink-item://") + 1) thru -1 of itemURL
tell application id "DNtp"
    activate
    set itemRec to get record with uuid itemID
    if window 1 exists then
        set itemTab to open tab for record itemRec in window 1
        set current tab of window 1 to itemTab
    else
        open window for record itemRec
    end if
end tell

"$0" is replaced by the URL returned by Get Address.

The script parses document-identifier from x-devonthink-item://document-identifier and uses it to get the record and open it in the front window, only opening a new window if there are no pre-existing windows.

We need the call to activate because otherwise DEVONthink will open the link but remain in the background.

Scheme

If we have a custom Open Item script we need to specify the scheme for it. Set the scheme to x-devonthink-item in the field under Open Item

Setting the scheme does two things:

  1. The URL returned by Get Address is transformed from x-devonthink-item://document-identifier into hook://x-devonthink-item/document-identifier. The new URL starts with hook:// so macOS passes it to Hook to handle instead of to the owner of the original scheme (e.g. x-devonthink-item).
  2. Hook uses the scheme to look up the appropriate Open Item script to use to handle each URL. When a URL like hook://x-devonthink-url/document-identifier opens Hook tries to find an Open Item script paired with the scheme x-devonthink-url

And that’s all you need to do to make your links to DEVONthink open neatly in tabs.

But x-devonthink-url is an ugly scheme, and it will make ugly URLs and what’s the point of living if we don’t take the time to make things a bit nicer?

Making things nicer

If we’re handling URLs with the custom Open Item script we wrote for Hook anyway, it doesn’t matter if we use the scheme defined by DEVONthink. Let’s modify our scripts to use devonthink for the scheme instead of x-devonthink-item.

First, go back and change the Get Address script to return URLs formatted devonthink://document-identifier instead of x-devonthink-item://document-identifier

tell application id "DNtp"
    if exists (content record of current tab of window 1) then
        -- current open item
        set refURL to reference URL of (content record of current tab of window 1)
    else if class of window 1 is in {viewer window, search window} then
        set selected_items to selection of window 1
        if (count of selected_items) = 1 then
            -- current selected item
            set refURL to reference URL of item 1 in selected_items
        end if
    end if
end tell

set refURL to "devonthink" & text ((length of "x-devonthink-item") + 1) thru -1 of refURL
return refURL

Next, change the Open Item script to use the new scheme.

set itemURL to "$0"
set itemID to text ((length of "devonthink://") + 1) thru -1 of itemURL
tell application id "DNtp"
    activate
    set itemRec to get record with uuid itemID
    if window 1 exists then
        set itemTab to open tab for record itemRec in window 1
        set current tab of window 1 to itemTab
    else
        open window for record itemRec
    end if
end tell

And finally, set the scheme to devonthink

And that’s all you need to do to make some URLs look a little bit nicer.

But what about that last script? Link to New?

Link to New

Link to New creates a new document and links it to the current item. There are two things to know about writing the Link to New script.

  1. The variable “$title” will be replaced in the script with the name of the source document. It is typically used for naming the new document.
  2. The script must finish by returning the address of the new document so that Hook can link it with the source document.

There is a lot of room to customize the Link to New script according to personal taste.

tell application id "DNtp"
    set newItem to create record with {name:"$title", type:text}
    get reference URL of newItem
end tell

This is the simplest possible script. It just creates a new empty text document in the DEVONthink Global Inbox.

property folderID : "3D175C4C-4F99-4824-A927-FC8B955B0165"
tell application id "DNtp"
    set newDocGroup to get record with uuid folderID
    set newItem to create record with {name:"$title", content:"# $title\n\n", type:markdown} in newDocGroup
    get reference URL of newItem
    set itemPath to path of newItem
end tell

tell application "BBEdit"
    open itemPath
    activate
    tell application "System Events"
        key code 125 using {command down}
    end tell
end tell

This is a more elaborate script. It does a few things.

  • creates a new markdown document
  • gives it a title header (with two new lines)
  • puts it in a predetermined folder (you can get a folder’s ID by selecting a folder and using Hook to copy a link to it)
  • opens the document in BBEdit (since DEVONthink doesn’t edit markdown files)
  • moves the cursor to the bottom of the document (ready to begin writing)

And that really is all you need to do to get started writing your own scripts to customize how Hook works for you.

If you do try your hand at writing custom Hook scripts, check out the forum! There are people who are interested in seeing what you’ve created and are happy to help if you get stuck.

Was this article helpful to you? Yes No

How can we help?