If you use iThoughtsX you probably have markdown links to DEVONthink records in your maps. Clicking one opens the record. That’s nice if you want to see the records content or do other stuff with it.
As new iThoughtsX user my first approach to learn how iThoughtsX works was to review a whole database in it (split into parts). But clicking each topics link I wanted to act on soon became annoying as there’s too much overhead:
- click link
- change records meta data or run a script
- close window
- activate iThoughtsX
- [repeat]
After unsatisfying success with UI scripting I asked the developer if there’s another way and he told me that itmz
are just zip
files with XML inside.
I made up this nice script which lets me manipulate DEVONthink records from within iThoughtsX. That means instead of clicking one topic by one to get to the linked record it’s possible to do multiple selection in iThoughtsX, then run the script and it applies code to all records at once. It took at least 4 steps to handle 1 record in iThoughtsX. Using the script with 1 record still takes 2 steps: selecting the topic and running the script. But there’s no need to just select 1 topic, we can select as many as we want.
Don’t get me wrong, this is not about saving some clicks. And it’s not “the script”. It’s just a connector between iThoughtsX topics and DEVONthink records. If you use it you most probably will do something else than I will.
The script only creates the connection from a iThoughtsX topic (which holds a DEVONthink markdown link) to the DEVONthink record - what you do with the record(s) from within iThoughtsX is up to you. Could be simple things like setting a label or sometimes not that simpel things like splitting up a database.
The main advantage of manipulating records from within iThoughtsX is that you first don’t do anything with your records. You’re just using a great mind mapping app which happen to have some links to DEVONthink records. You can do all the normal mind mapping stuff, reorganize topics, group them, create links, take notes (even in topics that hold DEVONthink markdown links). When everything is set up and you want to “write back” the result to DEVONthink then it’s only some line of AppleScript and that’s it. Before running your script it’s a mind map. Afterwards it’s a snapshot of changes you applied to some records, some groups or some databases.
See the screenshot, I created a group listing with markdown links, pasted in iThoughtsX, selected some topics and ran the script with set label of thisRecord to 2
. As you can see the label was set for those DEVONthink groups. The most basic example I could think of, but as you know DEVONthink has extensive AppleScript support and everything you have in mind can be planned and rearranged in iThoughtsX.
Note that in this early test there was no chance to tell which topics the script ran on once the selection was lost. So changing selected topics text and / or form is a good idea. I use Keyboard Maestro for this but it’s possible with UI scripting too (see example in script).
Ok, some more advanced examples
-
The database I want to review holds stuff which is often outdated and in this database I can tell that from a records name. But I don’t like to read long filenames from screen edge to edge. So I’ll do this in iThoughtsX instead where I can decide how text wraps. I’ll write what I need in this situation into the script, e.g. move records (via selected topics) to trash. When I’ve reviewed all records in iThoughtsX I’ll go back to DEVONthink and every outdated record sits in trash, ready to delete (By the way, the
move
command doesn’t work the way I thought it does until yesterday. If you’ve selected a record that has replicantsmove
deletes all replicants and moves the record to the destination, so be aware. There’s an optional parameter “from” (move from
) but I didn’t try this yet). -
Really promising is the combination of @cgrunenberg s “Create Listing” script (to be precise @clane47 s and @korm s modifications which I used to “build” (added two lines…) a “Create Listing with markdown links” version on, see below) and this script as you can try different group structures right in iThoughtsX without changing the current structure of a database.
- Copy a group listing with markdown links in DEVONthink
- Paste in iThoughtsX
- Restructure in iThoughtsX
- As you see fit select the topic whose position in the map you’ve changed
- Run the script with
display group selector
andmove
(ormove from
, see above) - In group selector select the name of the new parent topic and move it to its new location in DEVONthink
-
Link records
- Create links between topics in iThoughtsX
- Select all topics that link to each other
- Run the script with
set custom meta data
and let it add a records Reference URL as type URL to all linked records.
-
Use records across databases in one map
- Copy markdown links in database A
- Paste in iThoughtsX
- Copy markdown links in database B
- …
- Create a new database and
duplicate
to it or usemove
to merge (parts) of existing databases - Or just
set label
to mark selected topics / records and create a global smart group
-
Create or restructure nested Tags
-
create location
…
-
-
I think really anything that can be done with DEVONthinks AppleScript dictionary and that benefits from
- organizing in mind maps
- without touching your records at all until you decide to run your script
By the way: the script can be adapted to every app which owns a URL scheme (if this makes sense depends on the apps (Apple)Script support).
If you don’t use markdown yet here’s a script that copies the DEVONthink selection as markdown links.
Script - "Copy markdown links"
- Copy markdown links
tell application id "DNtp"
try
set windowClass to class of window 1
if {viewer window, search window} contains windowClass then
set currentRecord_s to selection of window 1
else if windowClass = document window then
set currentRecord_s to content record of window 1 as list
end if
if currentRecord_s = {} then
display notification "Nichts ausgewählt!" with title "DEVONthink"
return
end if
if (count of currentRecord_s) = 1 then
set theRecord to item 1 of currentRecord_s
set the clipboard to "[" & (name of theRecord) & "](" & (reference URL of theRecord) & ")"
display notification "Markdown-Link kopiert" with title "DEVONthink"
else
set theMarkdownLinksString to ""
set theCount to 0
repeat with thisRecord in currentRecord_s
set thisMarkdownLink to "[" & (name of thisRecord) & "](" & (reference URL of thisRecord) & ")"
set theCount to theCount + 1
if theCount ≠ (count of currentRecord_s) then
set theMarkdownLinksString to theMarkdownLinksString & thisMarkdownLink & return
else
set theMarkdownLinksString to theMarkdownLinksString & thisMarkdownLink
end if
end repeat
set the clipboard to theMarkdownLinksString
display notification "Markdown-Links kopiert" with title "DEVONthink"
end if
on error error_message number error_number
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
end try
end tell
This is a markdown version of the “Create Listing” script, be aware that it takes the selection of the navigate sidebar.
Script - "Create Listing with markdown links"
-- Create Listing with markdown links
-- Create Listing.
-- Created by Christian Grunenberg on Sun Jul 24 2005.
-- Copyright (c) 2005-2009. All rights reserved.
-- Modified 20130602 to capture only groups
--Modified by @clane47 11_01_2013 to capture only groups to a rich text file
-- Modified by @korm 20131102 to put the listing on the clipboard for pasting elsewhere
-- Additional modification 20131102 to optionally set base group for the listing to the selected group
-- Modified by @pete31 20200309 to use markdown links (e.g. in iThoughtsX)
tell application id "DNtp"
try
if not (exists current database) then error "No database is open."
set theDatabase to the current database
show progress indicator "Creating Listing..."
set listScope to button returned of (display dialog "Scope of Group Listing" buttons {"Whole Database", "Selected Group and Children", "Cancel"} default button 1 cancel button 3 with title "Put a Group Listing on the Clipboard")
if listScope is "Whole Database" then
set the clipboard to my createListing(children of root of theDatabase, "")
else if listScope is "Selected Group and Children" then
set rootGroup to the current group
set the clipboard to my createListing(children of rootGroup, "")
else
return
end if
hide progress indicator
display notification "Listing in clipboard!" with title "Create Listing"
on error error_message number error_number
hide progress indicator
if the error_number is not -128 then display alert "DEVONthink Pro" message error_message as warning
end try
end tell
on createListing(theseRecords, theTabs)
local this_record, this_type, this_listing, this_name
tell application id "DNtp"
set this_listing to ""
repeat with this_record in theseRecords
set this_name to (name of this_record as string)
set this_refURL to (reference URL of this_record as string)
set this_type to type of this_record
if this_type is group then
set this_listing to this_listing & theTabs & "[" & this_name & "](" & this_refURL & ")" & return
step progress indicator this_name
set this_listing to this_listing & my createListing(children of this_record, theTabs & (ASCII character 9))
end if
end repeat
end tell
return this_listing
end createListing
Ok, the “Manipulate DEVONthink records from within iThoughtsX” script.
Some things to consider:
-
If selection changed we must make sure that iThoughtsX saves this change (otherwise we get the wrong DEVONthink records and that’s something that really shouldn’t happen). I’m not sure if it’s enough to
keystroke "s" using command down
without a delay. Testing with small maps worked fine, but running the script withset label
on a 1000 links map it did not process all selected topics I think, couldn’t reproduce. So a delay may be needed for large® maps. Don’t know yet if there’s something else thankeystroke "s" using command down
and / or if we can get the write status ofdisplay_state.plist
via shell - but I hope that it’s possible somehow. Maybe checking the modification date is a way to go? -
Couldn’t find a way to make System Events XML suite accept data that’s not written to a file. Is there a way? Would this help in this script anyway?
-
Don’t know why but I’m quiete sure (at least) the double repeat part that’s looking for the DEVONthink UUIDs is far from optimal.
-
Make sure you run the script only on DEVONthink markdown links as there’s no error handling yet.
-
Make sure that you do something with the DEVONthink records, the script as posted does nothing with them.
-
Except for some testing I did not use the script but it’s fun
-
Use a test database!
-- Manipulate DEVONthink records from within iThoughtsX
-- How to use:
-- Copy markdown links in DEVONthink (selected records or group listing)
-- Paste in iThoughtsX
-- [Do stuff in iThoughtsX]
-- Select topics whose DEVONthink records you want to manipulate
-- Run script (but make sure that your code is in the last DEVONthink tell block)
-- Save iThoughtsX and get document path
activate application "iThoughtsX"
tell application "System Events"
try
tell process "iThoughtsX"
keystroke "s" using command down
-- delay 1.5
set theLocation to value of attribute "AXDocument" of window 1
end tell
set theLocation to characters 8 thru -1 in theLocation as string
set thePath to my decode_Text(theLocation)
on error
display notification "Kein Dokument gefunden!" with title "iThoughtsX"
return
end try
end tell
-- Get selected iThoughtsX UUIDs
try
set selectedTopicsUUIDsString to do shell script "/usr/libexec/PlistBuddy -c 'Print selected' /dev/stdin <<< $(unzip -p " & quoted form of thePath & " 'display_state.plist')" -- How to make PlistBuddy accept stdin: https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/
on error
display notification "Nichts ausgewählt!" with title "iThoughtsX"
return
end try
-- Selected iThoughtsX UUIDs as list
set d to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","
set selectedTopicsUUIDs to text items of selectedTopicsUUIDsString
set AppleScript's text item delimiters to d -- always set them back
-- Get content of iThoughtsX mapdata.xml
set theXMLContent to do shell script "unzip -p " & quoted form of thePath & " 'mapdata.xml'"
-- Content of iThoughtsX mapdata.xml as list
set theParagraphs to paragraphs of theXMLContent
-- Get DEVONthink UUIDs
set theDEVONthinkUUIDs to {}
repeat with thisSelectedTopicsUUID in selectedTopicsUUIDs
repeat with thisParagraph in theParagraphs
if thisParagraph contains thisSelectedTopicsUUID then
set thisParagraph to contents of thisParagraph
set devon_offset to offset of "x-devonthink-item://" in thisParagraph
set thisDEVONthinkUUID to characters (devon_offset + 20) thru (devon_offset + 55) in thisParagraph as string
set end of theDEVONthinkUUIDs to thisDEVONthinkUUID
exit repeat
end if
end repeat
end repeat
-- Get DEVONthink records and [your code]
tell application id "DNtp"
try
repeat with thisDEVONthinkUUID in theDEVONthinkUUIDs
set thisRecord to (get record with uuid thisDEVONthinkUUID)
--- your code
end repeat
on error error_message number error_number
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
end try
end tell
-- -- Do something to make selected topics stand out (I use Keyboard Maestro for this but it's also possible with UI scriting) e.g. bold text
-- activate application "iThoughtsX"
-- tell application "System Events"
-- tell process "iThoughtsX"
-- click menu 1 of menu bar item 5 of menu bar 1 -- open menu "Text"
-- click menu item 1 of menu 1 of menu bar item 5 of menu bar 1 -- click menu item "Bold"
-- end tell
-- end tell
on decode_Text(theText) -- http://applescript.bratis-lover.net (not available anymore)
local str
try
return (do shell script "/bin/echo " & quoted form of theText & ¬
" | perl -MURI::Escape -lne 'print uri_unescape($_)'")
on error eMsg number eNum
error "Can't urlDecode: " & eMsg number eNum
end try
end decode_Text