Script: Temporarily exclude group from search

These scripts temporarily exclude a group from search and include it afterwards. Think of them as kind of reverse of DEVONthink allowing multiple selection in the navigation sidebar: instead of choosing where exactly you want to search choose where you don’t want to. Multiple selection and exclusion can be used together which makes really nice fine tuning possible.

I made a simple version the other day, it relied on the group selector remembering the last chosen group. That’s fine as long as you want to exclude one group for a search but easily gets confusing when multiple groups were excluded. Solution to this is to write excluded groups to a record so we don’t have to keep track of them. This log record is created in a group in the global inbox so it’s always available. It gets deleted when its empty, there’s an option to also delete the created group, but if you leave this set to false you can directly see that the group is empty which means there are no groups excluded anymore (I’ve found I can faster find the group than figuring out where it would be if it wasn’t deleted).

There are two versions of the script(s): One uses separate scripts for exluding and including, the other version does both. The difference that makes usage of excluding and including in the latter reasonably practicable is that it opens the log record when a group is excluded so it’s easy to see what’s going on. The version that uses separate scripts got an option to open the log record but it can be easily used without it as there’s no chance of confusion; this version is handy if you want to exclude groups during the day without the log record getting in the way. Let’s say you’ve excluded a lot of groups, how to include all of them again? Doing it one by one is of course possible but there’s a faster way: choose the log record’s group in the group selector and all exclusions are reverted.

Three more options which are pretty self-explanatory: One that updates the search results after an exclusion or inclusion, one that restores the selection and one that tells the log record’s window where you want it to appear.

That’s it.

-- Exclude group from search  / Include group in search

property updateSearchResults : true
property restoreSelection : true
property theLogGroup_Location : "/_Excluded"
property theLogRecord_Name : "Excluded from search"
property theLogRecord_WindowBounds : {} -- e.g. {2560, 280, 3160, 1092}
property deleteEmptyLogGroup : false

tell application id "DNtp"
	try
		set theGroup to display group selector "Exclude from / Include in search:"
		set theRefURL to reference URL of theGroup
		
		set theLogGroup to get record at theLogGroup_Location in inbox
		if theLogGroup = missing value then set theLogGroup to create location theLogGroup_Location in inbox
		set theLogRecord to get record at theLogGroup_Location & "/" & theLogRecord_Name & ".md"
		if theLogRecord = missing value then set theLogRecord to create record with {name:theLogRecord_Name, type:markdown, plain text:""} in theLogGroup
		
		set theText to plain text of theLogRecord
		if theText = "" then
			set theLine to name of database of theGroup & space & "[" & name of theGroup & "](" & theRefURL & ")" & space & space
			set plain text of theLogRecord to theLine
			set newWindow to open window for record theLogRecord
			if theLogRecord_WindowBounds ≠ {} then set bounds of newWindow to theLogRecord_WindowBounds
			tell application "System Events" to tell process "DEVONthink 3" to perform action "AXRaise" of window 2
			set exclude from search of theGroup to true
			display notification (name of theGroup as string) with title "Excluded from search"
			
		else
			set theSource to source of theLogRecord
			if theLogGroup = theGroup then
				repeat with thisRefURL in get links of theSource
					set thisGroup to get record with uuid ((characters 21 thru -1 in thisRefURL) as string)
					set exclude from search of thisGroup to false
				end repeat
				delete record theLogRecord
				if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
				display notification "All" with title "Included in search"
				
			else if theText contains theRefURL then
				set newText_list to {}
				repeat with thisLine in paragraphs of theText
					if thisLine as string does not contain theRefURL then set end of newText_list to thisLine as string
				end repeat
				set newText to my tid(newText_list, linefeed)
				if newText ≠ "" then
					set plain text of theLogRecord to newText
				else
					delete record theLogRecord
					if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
				end if
				set exclude from search of theGroup to false
				display notification (name of theGroup as string) with title "Included in search"
				
			else
				set theLine to name of database of theGroup & space & "[" & name of theGroup & "](" & theRefURL & ")" & space & space
				set plain text of theLogRecord to theText & linefeed & theLine
				if uuid of theLogRecord is not in (uuid of content record of think windows) then
					set newWindow to open window for record theLogRecord
					if theLogRecord_WindowBounds ≠ {} then set bounds of newWindow to theLogRecord_WindowBounds
					tell application "System Events" to tell process "DEVONthink 3" to perform action "AXRaise" of window 2
				end if
				set exclude from search of theGroup to true
				display notification (name of theGroup as string) with title "Excluded from search"
			end if
		end if
		
		if updateSearchResults = true then
			if (exists viewer window 1) then
				set theQuery to (search query of viewer window 1) as string
				if theQuery ≠ "" then
					if restoreSelection = true then set theSelection to selection of viewer window 1
					set search query of viewer window 1 to "_"
					set search query of viewer window 1 to theQuery
					if restoreSelection = true then set (selection of viewer window 1) to theSelection
				end if
			end if
		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

on tid(theList, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set theList_string to theList as text
	set AppleScript's text item delimiters to d
	return theList_string
end tid

Exclude

-- Exclude group from search

property updateSearchResults : true
property restoreSelection : true
property theLogGroup_Location : "/_Excluded"
property theLogRecord_Name : "Excluded from search"
property openLogRecord : true
property theLogRecord_WindowBounds : {} -- e.g. {2560, 280, 3160, 1092}

tell application id "DNtp"
	try
		set theGroup to display group selector "Exclude from search:"
		set exclude from search of theGroup to true
		display notification (name of theGroup as string) with title "Excluded from search"
		
		set theRefURL to reference URL of theGroup
		set theLogRecord to get record at theLogGroup_Location & "/" & theLogRecord_Name & ".md"
		if theLogRecord = missing value then
			set theLogGroup to create location theLogGroup_Location in inbox
			set theLogRecord to create record with {name:theLogRecord_Name, type:markdown, plain text:""} in theLogGroup
		end if
		set theText to plain text of theLogRecord
		if theText does not contain theRefURL then
			set theLine to name of database of theGroup & space & "[" & name of theGroup & "](" & theRefURL & ")" & space & space
			set plain text of theLogRecord to theText & linefeed & theLine
		end if
		if openLogRecord = true then
			if uuid of theLogRecord is not in (uuid of content record of think windows) then
				set newWindow to open window for record theLogRecord
				if theLogRecord_WindowBounds ≠ {} then set bounds of newWindow to theLogRecord_WindowBounds
				tell application "System Events" to tell process "DEVONthink 3" to perform action "AXRaise" of window 2
			end if
		end if
		
		if updateSearchResults = true then
			if (exists viewer window 1) then
				set theQuery to (search query of viewer window 1) as string
				if theQuery ≠ "" then
					if restoreSelection = true then set theSelection to selection of viewer window 1
					set search query of viewer window 1 to "_"
					set search query of viewer window 1 to theQuery
					if restoreSelection = true then set (selection of viewer window 1) to theSelection
				end if
			end if
		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

Include

-- Include group in search

property updateSearchResults : true
property restoreSelection : true
property theLogGroup_Location : "/_Excluded"
property theLogRecord_Name : "Excluded from search"
property deleteEmptyLogGroup : false

tell application id "DNtp"
	try
		set theGroup to display group selector "Include:"
		
		set theLogGroup to get record at theLogGroup_Location in inbox
		if theLogGroup = missing value then set theLogGroup to create location theLogGroup_Location in inbox
		set theLogRecord to get record at theLogGroup_Location & "/" & theLogRecord_Name & ".md"
		if theLogRecord = missing value then set theLogRecord to create record with {name:theLogRecord_Name, type:markdown, plain text:""} in theLogGroup
		
		if theLogGroup = theGroup then
			set theSource to source of theLogRecord
			repeat with thisRefURL in get links of theSource
				set thisGroup to get record with uuid ((characters 21 thru -1 in thisRefURL) as string)
				set exclude from search of thisGroup to false
			end repeat
			delete record theLogRecord
			if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
			display notification "All" with title "Included in search"
		else
			set theRefURL to reference URL of theGroup
			set theText to plain text of theLogRecord
			set newText_list to {}
			repeat with thisLine in paragraphs of theText
				if thisLine as string does not contain theRefURL then set end of newText_list to thisLine as string
			end repeat
			set newText to my tid(newText_list, linefeed)
			if newText ≠ "" then
				set plain text of theLogRecord to newText
			else
				delete record theLogRecord
				if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
			end if
			set exclude from search of theGroup to false
			display notification (name of theGroup as string) with title "Included in search"
		end if
		
		if updateSearchResults = true then
			if (exists viewer window 1) then
				set theQuery to (search query of viewer window 1) as string
				if theQuery ≠ "" then
					if restoreSelection = true then set theSelection to selection of viewer window 1
					set search query of viewer window 1 to "_"
					set search query of viewer window 1 to theQuery
					if restoreSelection = true then set (selection of viewer window 1) to theSelection
				end if
			end if
		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

on tid(theList, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set theList_string to theList as text
	set AppleScript's text item delimiters to d
	return theList_string
end tid
1 Like

Updated scripts (DEVONthink doesn’t automatically close a document window whose content record was deleted via AppleScript anymore).

-- Exclude group from search  / Include group in search

property updateSearchResults : true
property restoreSelection : true
property theLogGroup_Location : "/_Excluded"
property theLogRecord_Name : "Excluded from search"
property theLogRecord_WindowBounds : {} -- e.g. {2560, 280, 3160, 1092}
property deleteEmptyLogGroup : false

tell application id "DNtp"
	try
		set theGroup to display group selector "Exclude from / Include in search:"
		set theRefURL to reference URL of theGroup
		
		set theLogGroup to get record at theLogGroup_Location in inbox
		if theLogGroup = missing value then set theLogGroup to create location theLogGroup_Location in inbox
		set theLogRecord to get record at theLogGroup_Location & "/" & theLogRecord_Name & ".md"
		if theLogRecord = missing value then set theLogRecord to create record with {name:theLogRecord_Name, type:markdown, plain text:""} in theLogGroup
		
		set theText to plain text of theLogRecord
		if theText = "" then
			set theLine to name of database of theGroup & space & "[" & name of theGroup & "](" & theRefURL & ")" & space & space
			set plain text of theLogRecord to theLine
			set newWindow to open window for record theLogRecord
			if theLogRecord_WindowBounds ≠ {} then set bounds of newWindow to theLogRecord_WindowBounds
			tell application "System Events" to tell process "DEVONthink 3" to perform action "AXRaise" of window 2
			set exclude from search of theGroup to true
			display notification (name of theGroup as string) with title "Excluded from search"
			
		else
			set theSource to source of theLogRecord
			if theLogGroup = theGroup then
				repeat with thisRefURL in get links of theSource
					set thisGroup to get record with uuid ((characters 21 thru -1 in thisRefURL) as string)
					set exclude from search of thisGroup to false
				end repeat
				try
					close (first document window whose content record is theLogRecord)
				end try
				delete record theLogRecord
				if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
				display notification "All" with title "Included in search"
				
			else if theText contains theRefURL then
				set newText_list to {}
				repeat with thisLine in paragraphs of theText
					if thisLine as string does not contain theRefURL then set end of newText_list to thisLine as string
				end repeat
				set newText to my tid(newText_list, linefeed)
				if newText ≠ "" then
					set plain text of theLogRecord to newText
				else
					try
						close (first document window whose content record is theLogRecord)
					end try
					delete record theLogRecord
					if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
				end if
				set exclude from search of theGroup to false
				display notification (name of theGroup as string) with title "Included in search"
				
			else
				set theLine to name of database of theGroup & space & "[" & name of theGroup & "](" & theRefURL & ")" & space & space
				set plain text of theLogRecord to theText & linefeed & theLine
				if uuid of theLogRecord is not in (uuid of content record of think windows) then
					set newWindow to open window for record theLogRecord
					if theLogRecord_WindowBounds ≠ {} then set bounds of newWindow to theLogRecord_WindowBounds
					tell application "System Events" to tell process "DEVONthink 3" to perform action "AXRaise" of window 2
				end if
				set exclude from search of theGroup to true
				display notification (name of theGroup as string) with title "Excluded from search"
			end if
		end if
		
		if updateSearchResults = true then
			if (exists viewer window 1) then
				set theQuery to (search query of viewer window 1) as string
				if theQuery ≠ "" then
					if restoreSelection = true then set theSelection to selection of viewer window 1
					set search query of viewer window 1 to "_"
					set search query of viewer window 1 to theQuery
					if restoreSelection = true then set (selection of viewer window 1) to theSelection
				end if
			end if
		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

on tid(theList, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set theList_string to theList as text
	set AppleScript's text item delimiters to d
	return theList_string
end tid

Include

-- Include group in search

property updateSearchResults : true
property restoreSelection : true
property theLogGroup_Location : "/_Excluded"
property theLogRecord_Name : "Excluded from search"
property deleteEmptyLogGroup : false

tell application id "DNtp"
	try
		set theGroup to display group selector "Include:"
		
		set theLogGroup to get record at theLogGroup_Location in inbox
		if theLogGroup = missing value then set theLogGroup to create location theLogGroup_Location in inbox
		set theLogRecord to get record at theLogGroup_Location & "/" & theLogRecord_Name & ".md"
		if theLogRecord = missing value then set theLogRecord to create record with {name:theLogRecord_Name, type:markdown, plain text:""} in theLogGroup
		
		if theLogGroup = theGroup then
			set theSource to source of theLogRecord
			repeat with thisRefURL in get links of theSource
				set thisGroup to get record with uuid ((characters 21 thru -1 in thisRefURL) as string)
				set exclude from search of thisGroup to false
			end repeat
			try
				close (first document window whose content record is theLogRecord)
			end try
			delete record theLogRecord
			if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
			display notification "All" with title "Included in search"
		else
			set theRefURL to reference URL of theGroup
			set theText to plain text of theLogRecord
			set newText_list to {}
			repeat with thisLine in paragraphs of theText
				if thisLine as string does not contain theRefURL then set end of newText_list to thisLine as string
			end repeat
			set newText to my tid(newText_list, linefeed)
			if newText ≠ "" then
				set plain text of theLogRecord to newText
			else
				try
					close (first document window whose content record is theLogRecord)
				end try
				delete record theLogRecord
				if deleteEmptyLogGroup = true then if (count (children of theLogGroup)) = 0 then delete record theLogGroup
			end if
			set exclude from search of theGroup to false
			display notification (name of theGroup as string) with title "Included in search"
		end if
		
		if updateSearchResults = true then
			if (exists viewer window 1) then
				set theQuery to (search query of viewer window 1) as string
				if theQuery ≠ "" then
					if restoreSelection = true then set theSelection to selection of viewer window 1
					set search query of viewer window 1 to "_"
					set search query of viewer window 1 to theQuery
					if restoreSelection = true then set (selection of viewer window 1) to theSelection
				end if
			end if
		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

on tid(theList, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set theList_string to theList as text
	set AppleScript's text item delimiters to d
	return theList_string
end tid