Remove Specific Tag with AppleScript

I cobbled together an AppleScript to lock a selected item in the Finder, and once that’s done, to add a ”Finder-locked” tag to DEVONthink.

The script actually toggles the Finder-locking, but as you can probably see, the AppleScript code for the removal of just the one specific ”Finder-locked” tag (for when the file is to be unlocked in the Finder) is missing, as I’m not sure how to do it.

I could remove all tags, but there might be other tags that I would still want to keep.

How could I modify the AppleScript to remove just that ”Finder-locked” tag when the file in the Finder is unlocked by the script?

tell application id "DNtp"
	try
		set windowClass to class of think window 1
		if windowClass = main window then
			set theRecords to selection of window 1
		else if windowClass = document window then
			set theRecords to content record of window 1 as list
		end if
		repeat with thisRecord in theRecords
			set thisPath to path of thisRecord
			if locking of thisRecord = false then
				set locking of thisRecord to true
				tell application "Finder" to set locked of file (POSIX file thisPath as alias) to true
				tell thisRecord to set tags to ("Finder-locked")
			else
				set locking of thisRecord to false
				tell application "Finder" to set locked of file (POSIX file thisPath as alias) to false
-- "unsetting" the "Finder-locked" tag would go here...
			end if
		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

Well I’m beginning to have some respect for Google’s AI:

tell application id "DNtp"
	try
		set windowClass to class of think window 1
		if windowClass = main window then
			set theRecords to selection of window 1
		else if windowClass = document window then
			set theRecords to content record of window 1 as list
		end if
		
		repeat with thisRecord in theRecords
			set thisPath to path of thisRecord
			set currentTags to tags of thisRecord
			
			if locking of thisRecord = false then
				-- Enable Locks
				set locking of thisRecord to true
				tell application "Finder" to set locked of (POSIX file thisPath as alias) to true
				
				-- Append tag if it doesn't exist
				if currentTags does not contain "Finder-locked" then
					set tags of thisRecord to currentTags & "Finder-locked"
				end if
			else
				-- Disable Locks
				set locking of thisRecord to false
				tell application "Finder" to set locked of (POSIX file thisPath as alias) to false
				
				-- Remove only the specific tag
				set newTags to {}
				repeat with aTag in currentTags
					if (aTag as string) is not "Finder-locked" then set end of newTags to aTag
				end repeat
				set tags of thisRecord to newTags
			end if
		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

Another case of AI-generated code that is not fit for publication except as example for bad coding.

  • comparing a Boolean to a literal Boolean
  • getting the POSIX part of something that already is one
  • useless checking for the existence of the tag before adding it

Not saying that the code does not work. It is just full of no-gos.

Instead, I’d negate the current state into a new variable, set the Finder‘s an the record‘s locking state to it and then conditionally add/remove the tag. Cleaner, shorter, easier to understand.

You mean something like:

tell application id "DNtp"
	try
		set theRecords to (selection of think window 1)
		set tagName to "Finder-locked"
		repeat with thisRecord in theRecords
			set newLockStatus to not (locking of thisRecord)
			set thisPath to path of thisRecord
			set locking of thisRecord to newLockStatus
			tell application "Finder" to set locked of (POSIX file thisPath as alias) to newLockStatus
			set currentTags to tags of thisRecord
			if newLockStatus is true then
				if currentTags does not contain tagName then set tags of thisRecord to currentTags & tagName
			else
				set newTags to {}
				repeat with aTag in currentTags
					if (aTag as string) is not tagName then set end of newTags to aTag
				end repeat
				set tags of thisRecord to newTags
			end if
		end repeat
	on error error_message number error_number
		if error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell


More ‘Zen’ I suppose, though it makes no difference to what it actually does.

Clearer. Don’t know about Zen. And why bout just use selected records instead of selection of think window?
I still don’t see why one would want to cast a tag to a string (isn’t it one already?) or the path to a POSIX file. But then I’m not an AppleScript person.

I heard you like JavaScript? :wink:

(() => {
	const DT = Application("DEVONthink"),
		  Sys = Application("System Events"),
		  Finder = Application("Finder");
	for (app of [DT, Sys, Finder]) app.includeStandardAdditions = true;
	
	const sel = DT.selectedRecords(),
		    r = DT.contentRecord(),
	  records = sel.length > 0 ? sel : (r ? [r] : null);
	
	if (!records) {
	 DT.displayAlert("No records selected/open"); return
	}
	
	records.forEach(r => {
		
		const lockTag = "Finder-locked",
			  lockState = !r.locking(),
			  tags = r.tags(),
			  file = Finder.items[ Sys.diskItems[r.path()].path() ];
		
		r.locking   = lockState;
		file.locked = lockState;
		r.tags = lockState ? tags.concat(lockTag)
						   : tags.filter(t => t !== lockTag);
	
	})
})()
2 Likes

That‘s a nice one! Thanks

How do you run that from the script menu ?

As every other script

What chrillek says. Save it as a script file, put it in DT’s script menu folder. Just set the language in Script Editor to JavaScript before you compile.