Making RTF links out of the selected Devonthink items

Thought it might be useful to the community as it is to me )


Script takes selected items from Devonthink, makes the RTF links (thanks to ASObjC part by Shane Stanley from LateNight Software) with addresses like x-devonthink-item://uuid?reveal=1 using the filename as the name of the link. If there are more than one item is selected it makes a linebreak list. Then it copies the result to the system clipboard for you to paste it in any RTF accepting context.

You may want to tweak some settings:

  1. List now uses a linebreak, you may change it to anything you want, like " ," or any HTML code
  2. Link is assembled using ?reveal=1 command to reveal the item instead of opening it. Delete it if you don’t want it.
  3. Add more custom HTML goodies you like :slight_smile:
-- Script to make the list of RTF links out of selected DT records and place them in the clipboard
-- Created by Silverstone on 03.12.2021
-- Based on the AppleScript ObjC code by Shane Stanley

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

property NSUnicodeStringEncoding : a reference to 10
property NSString : a reference to current application's NSString
property NSAttributedString : a reference to current application's NSAttributedString

tell application id "DNtp"
	set theRecords to (get selection)
	set theHTMLlist to {}
	if (count of theRecords) > 0 then
		repeat with theRecord in theRecords
			set theTitle to the filename of theRecord as string
			-- Set up the link here
			set theURL to "x-devonthink-item://" & (uuid of theRecord) & "?reveal=1"
			set the end of theHTMLlist to "<a href=" & theURL & ">" & theTitle & "</a>"
		end repeat
		-- Set up a links divider (instead of <br>)
		set {saveTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "<br>"}
		set theHTML to theHTMLlist as string
		set AppleScript's text item delimiters to saveTID
		set htmlString to NSString's stringWithString:theHTML
		set htmlData to htmlString's dataUsingEncoding:NSUnicodeStringEncoding
		set attString to NSAttributedString's alloc()'s initWithHTML:htmlData documentAttributes:(missing value)
		set pb to current application's NSPasteboard's generalPasteboard()
		pb's clearContents()
		pb's writeObjects:{attString}
	end if
end tell

Hello - can you clarify how an RTF link differs from a standard Devonthink item link and thus what typical uses might be for this script?

The problem with setting the clipboard to an NSAttributedString is that it won’t adopt the receiving app’s current font and font size. Which means you’ll have to do it manually for each pasted link.

Script: Copy RTF and Markdown link does both automatically.


The difference is:

  1. This link is in a ready RTF format, thus you can paste to in any RTF context like: MS Word, Pages, OmniOutliner - to any RTF document, notwithstanding their really numerous file types.
  2. This link will be named after a filename, not just abstract no-name UUID
  3. If you paste it in Typora (known markdown editor), it’ll recognize the RTF link, and it will be pasted automatically using markdown template, like [fileneme](link)
  4. If you paste in a plain text file - you’ll get a list of filenames. If you need just a list of filenames - clean format to plain text and paste this list of filenames anywhere.
  5. Those RTF apps, which work correctly with the system pasteboard, will adopt the link to the context (font face, font size and etc.) accordingly. These are: Pages, OmniOutliner e.g.

Use cases

  • Say, you have a bunch of files in different groups, or even in different databases in DT. Then you need to structure them in some logic, but groups, replicants and tags are not enough. I use Omni Outliner for this, with its flexible structuring (like any OPML app). So you can paste links in any structure as topics, or inside topics (or comments) in a free text flow and so on.
  • Pasting links to annotations to some files, making a network connections
  • More meaningful mentions of DT items (filename shows you the name of file and its filetype) right inline the RTF text.
1 Like

Interesting script.
Tried it with MS Word, it pastes a markdown link there…

BTW, NSAttributedString is enough with Pages and OmniOutliner for context match, but apps like e.g. Write and MS Word take wrong font face and size.

So, is there a universal way to setup the pasteboard to adopt the receiving app’s current font and font size? Or we need to list all types we use, an do smth for each one?

Didn’t test that. It also pastes plain text in OmniOutliner, but that’s the same when we copy via DEVONthink’s menu. OmniOutliner works with a single RTF link but it seems it can’t create multiple RTF links.

Did you actually test that with a non-default font? Over here (still on Mojave) it doesn’t match the font in any app and I doubt that it can do that at all. An attributed string can’t have “no attribute” or a placeholder or something like that. It will always paste with the attributes that were used to create it.

Don’t think there’s an universal way.

1 Like

Yes, I tested it with Pages and OmniOutliner. They both adopt the inserted text.

  • Edit: Pages adopts the format only for the inline link. The links which comes after as new paragraphs retain initial format…

This was the initial intent for creating this script: I choose multiple items in DT, run this script, then paste in OO. The result is:

  • if the whole topic is selected then CMD+V inserts topics lower - each new topic is one link
  • if you are in edit topic mode then CMD+V makes one topic with linefeed after each link

All are RTF links with the adopted format.

1 Like

So, the only way is to choose the most used font face and size and embed it in HTML beforehand?
Like set the end of theHTMLlist to "<font face=\"Helvetica Neue\"><a href=" & theURL & ">" & theTitle & "</a></font>"

Probably. As I seldom use OmniOutliner I’ll stick with my script which works fine with the apps I use. Already tried to make a mix out of both scripts, but unfortunately adding RTF breaks the automatic adoption of font and font size over here.

Very interesting - works well

Thanks for the insight

Having not done my research ahead of time, I created my own version of a script that does something similar. Nonetheless I’ll post it here, even though your version is more elegant.

This one uses display group selector because sometimes while I’m writing in another application, I want to quickly insert a link to something in my DEVONthink database without leaving the page I’m writing in. But this script is limited to groups only, not items, because afaik there’s no command like display item selector available.

tell application id "DNtp"
	set theGroup to display group selector
	set theUuid to (the uuid of theGroup) as string
	set theItemLink to quote & "x-devonthink-item://" & theUuid & quote
	set theName to the name of theGroup
	set the theHTML to "<a href=" & theItemLink & ">" & theName & "</a>"
	set theRTF to (do shell script "echo " & quoted form of theHTML & " | textutil -stdin -stdout -inputencoding utf-8 -format html -convert rtf | pbcopy")
	set theRTF to the clipboard
	set theRTF to «class RTF » of theRTF
end tell
# using code found here to convert to RTF:

RTF link from selected text using original formatting

This procedure takes the text from the pasteboard and makes it a link using the value of thisLink variable. I use Keyboard maestro with this script to copy selected text and replace it with the RTF link under this text, keeping the formatting of the context.

@pete31, this script keeps formatting of the context, and maybe this trick can be used to get formatting of the context and make multiple links as in previous script, - like copy some symbols from the left and/or right from the cursor and use this formatting for the inserted text…

on copy_RTF_link_from_pasteboard for thisLink
	-- get the clipboard
	set pb to current application's NSPasteboard's generalPasteboard()
	-- get any attributed strings off clipboard
	set allATS to (pb's readObjectsForClasses:{current application's NSAttributedString} options:(missing value))
	if allATS's |count|() = 0 then error "No rich text found on the clipboard"
	-- make an editable copy of the first item of the array so we can modify it
	set richText to allATS's firstObject()'s mutableCopy()
	-- build the link URL
	--set linkString to richText's |string|()'s stringByTrimmingCharactersInSet:(current application's NSCharacterSet's whitespaceAndNewlineCharacterSet())
	set linkURL to current application's nsurl's URLWithString:thisLink
	-- make dictionary of attributes: the NSURL, blue text, single underline
	set attsDict to current application's NSDictionary's dictionaryWithObjects:{linkURL, current application's NSNumber's numberWithUnsignedInteger:(current application's NSSingleUnderlineStyle), (current application's NSColor's blueColor())} forKeys:{current application's NSLinkAttributeName, current application's NSUnderlineStyleAttributeName, current application's NSForegroundColorAttributeName}
	-- add link and replace clipboard
	richText's addAttributes:attsDict range:{0, richText's |length|()}
	pb's clearContents()
	pb's writeObjects:{richText}
end copy_RTF_link_from_pasteboard