Hi there, this script wraps every freeform search term in asterisks but leaves search operators (e.g. OR
) and DEVONthink 3 search prefixes (e.g. kind:text
) alone. It can be used to start a search e.g. via Alfred or it can be used to toggle an existing query, meaning it will add or remove asterisks. I use one version (internalUsage=false) in Alfred and one (internalUsage=true) in the toolbar (but it should work from the script menu as well).
Background:
Before DEVONthink 3 I had a nice workflow to start simple searches (no search operators) in a new search window. I used Alfred at the start of the workflow to input the query (mainly because it’s possible to use modifiers to alter it) and I used Keyboard Maestro to open a new search window and insert the query (as this turned out to be more reliable then AppleScript in Alfred). With Alfreds modifiers (which were used with very simple regex) I had the choice between
- wrap every search term in asterisks (used as default)
- wrap whole query in quotes
- prefix tilde
- input = output
Now with DEVONthink 3 I want to make use of search prefixes and I think this means the old workflow is gone. I tried to write regex that lets me use Alfreds modifiers as I used to but failed… If someone knows how to split the “freeform” search terms from potentially existing search prefixes and search operators with regex (or another approach) please let me know. This could make altering a query much simpler and some things seem not to be possible in AppleScript at all, at least not for me.
However after failing on a regex solution (which was no surprise) I started to try at least the asterisks thing in AppleScript as this was my default way to search, So here’s the result
-- Wrap search terms in asterisks or remove them [Toggle] (but leave search operators and DEVONthink 3 search prefixes alone)
-- Can be used to start a search via Alfred, Keyboard Maestro etc. or to toggle an existing search query (e.g. from the toolbar or the scripts menu)
-- Needs a query like this but all parts are optional: [freeform search terms (and search operators] [search prefixes] [scope]
-- If used from DEVONthinks toolbar it grabs the current content of the search field; it will only work if you already searched something
-- If changes you've made in the script doesn't apply immediately when used from toolbar restart DEVONthink 3
-- Use two versions to take full effect, one to start a search, one to toggle an existing query
-- RemoveFromString handler: http://applescript.bratis-lover.net
property prefixOperators : {":", "!", "=", "<", ">", "~", "#"}
property searchOperators : {"-", "!", "?", "[", "]", "*", "&", "^", "|", "~", "AFTER", "AND", "BUT", "EOR", "NEAR", "NEXT", "NOT", "OPT", "OR", "XOR"}
property noSearchTerm : false
property internalUsage : false -- set this to true and uncomment the first code block for usage in DEVONthink 3 toolbar
#if internalUsage = true then
# activate application "DEVONthink 3"
# tell application "System Events"
# tell process "DEVONthink 3"
# set theQuery to value of text field 1 of group 3 of toolbar 1 of window 1
# end tell
# end tell
# if theQuery = "" then return
#end if
if theQuery = "" then return
if theQuery does not contain "*" then
set theFreeformList to getFreeformList(theQuery, prefixOperators)
set modifiedFreeformList to {}
repeat with thisItem in theFreeformList
set isOperator to false
repeat with thisOperator in searchOperators
considering case
if thisItem contains thisOperator then
set isOperator to true
exit repeat
end if
end considering
end repeat
if isOperator = false then
if thisItem starts with "(" then
set end of modifiedFreeformList to "(*" & characters 2 thru -1 in thisItem & "*"
else if thisItem ends with ")" then
set end of modifiedFreeformList to "*" & characters 1 thru -2 in thisItem & "*)"
else
set end of modifiedFreeformList to "*" & thisItem & "*"
end if
else
set end of modifiedFreeformList to thisItem
end if
end repeat
set modifiedFreeformString to makeStringFromList(modifiedFreeformList, space)
try
set lastFreeformItem to item -1 in theFreeformList
set splitAt to (offset of lastFreeformItem in theQuery) + (count of (characters of lastFreeformItem)) + 1
set theModifiedQuery to modifiedFreeformString & space & (characters splitAt thru -1 in theQuery)
on error
set theModifiedQuery to modifiedFreeformString
end try
else
set theModifiedQuery to RemoveFromString(theQuery, "*")
end if
if noSearchTerm = true then set theModifiedQuery to characters 4 thru -1 in theModifiedQuery as string
tell application id "com.devon-technologies.think3"
tell viewer window 1
set search query to theModifiedQuery
end tell
end tell
on getFreeformList(theQuery, prefixOperators)
set d to AppleScript's text item delimiters
set AppleScript's text item delimiters to " "
set TextItems to text items of theQuery
set AppleScript's text item delimiters to d
set theFreeformList to {}
repeat with thisTextItem in TextItems
if thisTextItem as string ≠ "" then
repeat with thisOperator in prefixOperators
if thisTextItem contains thisOperator then
set noPrefix to false
exit repeat
else
set noPrefix to true
end if
end repeat
if noPrefix = true then
set end of theFreeformList to thisTextItem as string
else
exit repeat
end if
end if
end repeat
if theFreeformList = {} then
set theFreeformList to {""}
set noSearchTerm to true
end if
return theFreeformList
end getFreeformList
on makeStringFromList(theList, theDelimiter)
set theString to ""
set theCount to 0
repeat with thisItem in theList
set thisItem to thisItem as string
set theCount to theCount + 1
if theCount ≠ (count of theList) then
set theString to theString & thisItem & theDelimiter
else
set theString to theString & thisItem
end if
end repeat
return theString
end makeStringFromList
-- http://applescript.bratis-lover.net
--c-- RemoveFromString(theText, CharOrString)
--d-- Case-sensitive remove substring from string.
--a-- theText : string -- the string to search
--a-- CharOrString : string -- the string to remove
--r-- string
--x-- RemoveFromString("Hello hello", "hello") --> "Hello "
--u-- ljr (http://applescript.bratis-lover.net/library/string/)
on RemoveFromString(theText, CharOrString)
local ASTID, theText, CharOrString, lst
set ASTID to AppleScript's text item delimiters
try
considering case
if theText does not contain CharOrString then ¬
return theText
set AppleScript's text item delimiters to CharOrString
set lst to theText's text items
end considering
set AppleScript's text item delimiters to ASTID
return lst as text
on error eMsg number eNum
set AppleScript's text item delimiters to ASTID
error "Can't RemoveFromString: " & eMsg number eNum
end try
end RemoveFromString