Finder Bookmark Utility

EDIT JULY 28, 2021. This thread contains two basic scripts. The first bookmarks folders and opens a bookmarked folder in a Finder window. The most recent version of this script is in post 6. The second script bookmarks files and opens a bookmarked file in the default app. The most recent version is in post 11. The operation of these scripts require no real explanation, and, to test either script, simply open it in a script editor and run. END EDIT

This is a bookmark utility for the Finder. To use the script, first save it as a script or application and then run the script with the Finder open and select “Add a Bookmark”. This creates two text files, which contain the bookmark data, in the ~/Library/Preferences folder. A bookmark name that begins with a dash is treated as a menu divider only; the operation of the utility is otherwise pretty straightforward.

I run the script by way of a keyboard shortcut utilizing the Fastscripts utility. A simpler but perhaps less convenient method is to save the script as an application and then to Command-drag the application to the toolbar, which will create an icon. You may have to set permissions in System Preferences if the script is run as an application.

-- Revised 2020.10.05

main()

on main()
	set preferencePath to POSIX path of (path to preferences)
	set dataFile to preferencePath & "Bookmark Data.txt"
	set settingFile to preferencePath & "Bookmark Setting.txt"
	
	set {bookmarkNames, bookmarkPaths} to readDataFile(dataFile)
	set dialogDefault to readSettingFile(settingFile)
	
	if bookmarkNames = {} then
		set dialogMenu to {"Add a Bookmark", "Edit Bookmark File"}
		set dialogDefault to "Add a Bookmark"
	else
		set dialogMenu to bookmarkNames & {"--", "Add a Bookmark", "Delete a Bookmark", "Edit Bookmark File"}
	end if
	
	choose from list dialogMenu with title "Finder Bookmark" default items dialogDefault
	if result = false then
		error number -128
	else
		set dialogResult to result as text
	end if
	
	if dialogResult = "Add a Bookmark" then
		addBookmark(bookmarkNames, bookmarkPaths, settingFile)
		set {bookmarkNames, bookmarkPaths} to result
		writeDataFile(bookmarkNames, bookmarkPaths, dataFile)
		writeSettingFile(item 1 of bookmarkNames, settingFile)
	else if dialogResult = "Delete a Bookmark" then
		deleteBookmark(bookmarkNames, bookmarkPaths)
		set {bookmarkNames, bookmarkPaths} to result
		writeDataFile(bookmarkNames, bookmarkPaths, dataFile)
		writeSettingFile("Delete a Bookmark", settingFile)
	else if dialogResult = "Edit Bookmark File" then
		editBookmarkFile(dataFile)
		writeSettingFile("Edit Bookmark File", settingFile)
	else if dialogResult begins with "-" then
		error number -128
	else
		changeFolder(bookmarkNames, bookmarkPaths, dialogResult)
		writeSettingFile(dialogResult, settingFile)
	end if
end main

on readDataFile(dataFile)
	set bookmarkNames to {}
	set bookmarkPaths to {}
	try
		set openedFile to paragraphs of (read POSIX file dataFile)
		repeat with i from 1 to (count openedFile) by 2
			if item i of openedFile > "" then
				set end of bookmarkNames to item i of openedFile
				set end of bookmarkPaths to item (i + 1) of openedFile
			else
				exit repeat
			end if
		end repeat
	end try
	return {bookmarkNames, bookmarkPaths}
end readDataFile

on readSettingFile(settingFile)
	try
		set theText to paragraph 1 of (read POSIX file settingFile)
	on error
		set theText to "Add a Bookmark"
	end try
	return theText
end readSettingFile

on addBookmark(bookmarkNames, bookmarkPaths, settingFile)
	try
		tell application "Finder"
			set currentName to name of Finder window 1
			set currentPath to target of Finder window 1 as alias
		end tell
	on error
		errorDialog("Add a Bookmark", "Finder window not found or the target of Finder window cannot be bookmarked")
	end try
	
	set currentPath to POSIX path of currentPath
	
	set text item delimiters to {"/"}
	set pathList to text items of currentPath
	if (count pathList) ≤ 6 then
		set dialogPath to currentPath
	else
		set dialogPath to (items 1 thru 3 of pathList & "..." & items -3 thru -1 of pathList) as text
	end if
	set text item delimiters to {""}
	
	display dialog "Bookmark name for \"" & dialogPath & "\"" default answer currentName buttons {"Cancel", "OK"} default button 2 cancel button 1 with title "Finder Bookmark"
	set currentName to text returned of result
	if currentName = "" then error number -128
	
	if currentName is in bookmarkNames then
		writeSettingFile("Add a bookmark", settingFile)
		errorDialog("Add a Bookmark", "A bookmark named " & quote & currentName & quote & " already exists")
	end if
	
	if currentName begins with "-" then set currentPath to currentName
	
	set beginning of bookmarkNames to currentName
	set beginning of bookmarkPaths to currentPath
	
	return {bookmarkNames, bookmarkPaths}
end addBookmark

on deleteBookmark(bookmarkNames, bookmarkPaths)
	choose from list bookmarkNames with title "Finder Bookmark" with prompt "Select bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed
	if result = false then
		error number -128
	else
		set deleteList to result
	end if
	
	set nameTemp to {}
	set pathTemp to {}
	repeat with i from 1 to (count bookmarkNames)
		if item i of bookmarkNames is not in deleteList then
			set end of nameTemp to item i of bookmarkNames
			set end of pathTemp to item i of bookmarkPaths
		end if
	end repeat
	return {nameTemp, pathTemp}
end deleteBookmark

on editBookmarkFile(bookmarkFile)
	try
		do shell script "open -e " & quoted form of bookmarkFile
		delay 0.3
	on error
		errorDialog("Edit Bookmark File", "The bookmark file could not be found. Please rerun this script and select " & quote & "Add a Bookmark" & quote)
	end try
end editBookmarkFile

on changeFolder(bookmarkNames, bookmarkPaths, dialogResult)
	repeat with i from 1 to (count bookmarkNames)
		if item i of bookmarkNames = dialogResult then
			try
				set thePath to (POSIX file (item i of bookmarkPaths)) as alias
				exit repeat
			on error
				errorDialog("Change Finder Folder", "The folder named " & quote & dialogResult & quote & " is offline or otherwise not available")
			end try
		end if
	end repeat
	
	tell application "Finder"
		try
			set target of Finder window 1 to thePath
		on error
			open thePath
		end try
	end tell
end changeFolder

on writeDataFile(bookmarkNames, bookmarkPaths, dataFile)
	set mergedData to {}
	repeat with i from 1 to (count bookmarkNames)
		set end of mergedData to (item i of bookmarkNames)
		set end of mergedData to (item i of bookmarkPaths)
	end repeat
	set AppleScript's text item delimiters to {linefeed}
	set mergedData to mergedData as text
	set AppleScript's text item delimiters to {""}
	
	try
		set openedFile to open for access (POSIX file dataFile) with write permission
		set eof of openedFile to 0
		write mergedData to openedFile
		close access openedFile
	on error
		try
			close access openedFile
		end try
	end try
end writeDataFile

on writeSettingFile(dialogDefault, settingFile)
	try
		set openedFile to open for access (POSIX file settingFile) with write permission
		set eof of openedFile to 0
		write dialogDefault to openedFile
		close access openedFile
	on error
		try
			close access openedFile
		end try
	end try
end writeSettingFile

on errorDialog(textOne, textTwo)
	display alert textOne message textTwo buttons {"OK"} default button 1 as critical
	error number -128
end errorDialog

1 Like

Welcome to Code Exchange, Peavine.

Note that there’s an Applescript button on the form for submitting code. Using that for selected AppleScript code encloses the code with a wrapper that makes it easy for readers to open the code in their own Script Editor. I’ve inserted the appropriate tags in your script.

Adam Bell

Adam. Thanks for letting my know that and for making the correction. I don’t know how I missed that big Applescript button. :slight_smile:

Peavine

The following is a companion script designed to work with the script in post 1 above. It automatically adds a bookmark for the folder that is the target of the front finder window (the bookmark name is the folder name). It also sets the added bookmark as the default selection in the bookmark menu.

The operation of the script is simple: run the script and it will add the bookmark and make that bookmark the default selection. This script creates two small text files in the user’s preferences folder if they don’t exist. There’s no reason to run this script until the script in post 1 has been tested and found to be useful.

-- Revised 2020.10.04

main()

on main()
	set preferencePath to POSIX path of (path to preferences)
	set dataFile to preferencePath & "Bookmark Data.txt"
	set settingFile to preferencePath & "Bookmark Setting.txt"
	
	try
		tell application "Finder" to set hfsPath to target of Finder window 1 as alias
		set posixPath to POSIX path of hfsPath
	on error
		display alert "Finder Bookmark Helper" message "Finder window not found or target of Finder window cannot be bookmarked." buttons {"OK"} default button 1 as critical
		error number -128
	end try
	
	set AppleScript's text item delimiters to {":"}
	set bookmarkName to text item -2 of (hfsPath as text)
	set AppleScript's text item delimiters to {""}
	
	try
		set bookmarkData to paragraphs of (read POSIX file dataFile)
	on error
		set bookmarkData to {}
	end try
	
	if bookmarkName is in bookmarkData then
		display notification quote & bookmarkName & quote & " bookmark exists" with title "Bookmark Helper"
		writeFile(bookmarkName, settingFile)
		error number -128
	else
		display notification quote & bookmarkName & quote & " bookmark created" with title "Bookmark Helper"
	end if
	
	set AppleScript's text item delimiters to {linefeed}
	set bookmarkData to ({bookmarkName, posixPath} & bookmarkData) as text
	set AppleScript's text item delimiters to {""}
	
	writeFile(bookmarkData, dataFile)
	writeFile(bookmarkName, settingFile)
end main

on writeFile(theText, theFile)
	try
		set openedFile to open for access (POSIX file theFile) with write permission
		set eof of openedFile to 0
		write theText to openedFile
		close access openedFile
	on error
		try
			close access openedFile
		end try
	end try
end writeFile
1 Like

I revised my script to utilize property list files to store bookmark data. The script can be tested by opening and running it in Script Editor. A few comments:

  • The script bookmarks the folder that is the target of the front Finder window.
  • A divider can be inserted in the bookmark list by selecting “Add a Bookmark” and entering a dash followed by any or no additional characters.
  • The script has been tested on Catalina only.
  • The script does not work properly when trying to bookmark a folder in a volume on an external drive created by the asr software-restore utility. There is no simple fix for this.
-- Revised 2021.03.14

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set bookmarkSettingPlist to "com.peavine.FinderBookmarkSetting"
	set dialogDefault to item 1 of readPlist(bookmarkSettingPlist, "Add a Bookmark")
	set bookmarkDataPlist to "com.peavine.FinderBookmarkData"
	set bookmarkData to readPlist(bookmarkDataPlist, {})
	set bookmarkNames to {}
	
	repeat with anItem in bookmarkData
		set end of bookmarkNames to item 1 of anItem
	end repeat
	
	set dialogMenu to bookmarkNames & {"--", "Add a Bookmark", "Delete a Bookmark", "Sort Bookmarks"}
	choose from list dialogMenu with title "Finder Bookmark" default items dialogDefault
	if result = false then
		error number -128
	else
		set dialogResult to result as text
	end if
	
	if dialogResult = "Add a Bookmark" then
		set bookmarkData to addBookmark(bookmarkData, bookmarkNames, bookmarkSettingPlist)
		writePlist(bookmarkDataPlist, bookmarkData)
	else if dialogResult = "Delete a Bookmark" then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist(bookmarkDataPlist, bookmarkData)
	else if dialogResult = "Sort Bookmarks" then
		set bookmarkData to sortList(bookmarkData)
		writePlist(bookmarkDataPlist, bookmarkData)
	else if dialogResult begins with "-" then
		error number -128
	else
		changeFolder(bookmarkData, dialogResult)
	end if
	
	writePlist(bookmarkSettingPlist, {dialogResult})
end main

on addBookmark(bookmarkData, bookmarkNames, bookmarkSettingPlist)
	try
		tell application "Finder"
			set currentName to name of Finder window 1
			set currentPath to target of Finder window 1 as alias
		end tell
	on error
		errorDialog("Add a Bookmark", "Finder window not found or target of Finder window cannot be bookmarked")
	end try
	set currentPath to POSIX path of currentPath
	
	set thePath to (current application's NSString's stringWithString:currentPath)'s pathComponents()
	if (count thePath) < 7 then
		set dialogPath to text 1 thru -2 of currentPath
	else
		set dialogPath to current application's NSString's stringWithFormat_("/%@/%@/.../%@/%@", item 2 of thePath, item 3 of thePath, item -3 of thePath, item -2 of thePath)
	end if
	
	display dialog "Bookmark name for " & quote & dialogPath & quote default answer currentName buttons {"Cancel", "OK"} default button 2 cancel button 1 with title "Finder Bookmark"
	set currentName to text returned of result
	
	if currentName = "" then
		error number -128
	else if currentName is in bookmarkNames then
		writePlist(bookmarkSettingPlist, {"Add a Bookmark"})
		errorDialog("Add a Bookmark", "A bookmark named " & quote & currentName & quote & " already exists")
	else if currentName begins with "-" then
		set currentPath to currentName
	end if
	
	set beginning of bookmarkData to {currentName, currentPath}
	return bookmarkData
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames)
	if bookmarkNames = {} then errorDialog("Delete a Bookmark", "There are no bookmarks to delete")
	
	choose from list bookmarkNames with title "Finder Bookmark" with prompt "Select bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed
	if result = false then
		error number -128
	else
		set deleteList to result
	end if
	
	repeat with anItem in bookmarkData
		if (item 1 of anItem) is in deleteList then set contents of anItem to missing value
	end repeat
	return lists of bookmarkData
end deleteBookmark

on sortList(theList)
	repeat with i from (count theList) to 2 by -1
		repeat with j from 1 to i - 1
			if item 1 of item j of theList > item 1 of item (j + 1) of theList then
				set {item j of theList, item (j + 1) of theList} to {item (j + 1) of theList, item j of theList}
			end if
		end repeat
	end repeat
	return theList
end sortList

on changeFolder(bookmarkData, dialogResult)
	repeat with anItem in bookmarkData
		if item 1 of anItem = dialogResult then
			try
				set thePath to (POSIX file (item 2 of anItem)) as alias
				exit repeat
			on error
				errorDialog("Change Finder Folder", "The folder named " & quote & dialogResult & quote & " is offline or otherwise not available")
			end try
		end if
	end repeat
	
	try
		tell application "Finder" to set target of Finder window 1 to thePath
	on error
		set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
		theWorkSpace's openURL:thePath
	end try
end changeFolder

on readPlist(thePlist, theDefault)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:thePlist
	theDefaults's registerDefaults:{theKey:theDefault}
	return theKey of theDefaults as list
end readPlist

on writePlist(thePlist, theList)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:thePlist
	set theKey of theDefaults to theList
end writePlist

on errorDialog(textOne, textTwo)
	display alert textOne message textTwo buttons {"OK"} default button 1 as critical
	error number -128
end errorDialog

main()
1 Like

This is a revised version of my script. It uses a dictionary rather than an array to save bookmark data but otherwise is pretty much unchanged.

-- Revised 2021.11.08

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set preferenceFolder to (current application's NSHomeDirectory()'s stringByAppendingPathComponent:"Library")'s stringByAppendingPathComponent:"Preferences"
	set settingPlist to preferenceFolder's stringByAppendingPathComponent:"FinderBookmarkFolderSetting.plist"
	set dataPlist to preferenceFolder's stringByAppendingPathComponent:"FinderBookmarkFolderData.plist"
	
	try
		set dialogDefault to settingOne of readPlist(settingPlist) as text
	on error
		set dialogDefault to "Add a Bookmark"
	end try
	
	try
		set bookmarkData to readPlist(dataPlist)
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"caseInsensitiveCompare:") as list
	on error
		set bookmarkData to (current application's NSMutableDictionary's new())
		set bookmarkNames to {}
	end try
	
	set dialogMenu to bookmarkNames & {"--", "Add a Bookmark", "Delete a Bookmark"}
	set dialogResult to (choose from list dialogMenu with title "Finder Folder Bookmark" default items dialogDefault)
	if dialogResult = false then error number -128
	set dialogResult to item 1 of dialogResult
	
	if dialogResult = "Add a Bookmark" then
		set {bookmarkData, currentName} to addBookmark(bookmarkData, bookmarkNames, settingPlist)
		writePlist(dataPlist, bookmarkData)
		set dialogResult to currentName
	else if dialogResult = "Delete a Bookmark" then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist(dataPlist, bookmarkData)
	else if dialogResult begins with "-" then
		error number -128
	else
		changeFolder(bookmarkData, dialogResult)
	end if
	
	set theSetting to current application's NSDictionary's dictionaryWithDictionary:{settingOne:dialogResult}
	writePlist(settingPlist, theSetting)
end main

on addBookmark(bookmarkData, bookmarkNames, settingPlist)
	try
		tell application "Finder"
			set currentName to name of Finder window 1
			set currentPath to target of Finder window 1 as alias
		end tell
	on error
		errorDialog("A Finder window was not found or the target of the front Finder window cannot be bookmarked")
	end try
	set currentPath to POSIX path of currentPath
	
	set thePath to (current application's NSString's stringWithString:currentPath)'s pathComponents()
	if (count thePath) < 7 then
		set dialogPath to text 1 thru -2 of currentPath
	else
		set dialogPath to current application's NSString's stringWithFormat_("/%@/%@/.../%@/%@", item 2 of thePath, item 3 of thePath, item -3 of thePath, item -2 of thePath) as text
	end if
	
	set currentName to text returned of (display dialog "Bookmark name for " & quote & dialogPath & quote default answer currentName buttons {"Cancel", "OK"} default button 2 cancel button 1 with title "Finder Folder Bookmark")
	if currentName = "" then error number -128
	
	if currentName is in bookmarkNames then
		set theSetting to current application's NSDictionary's dictionaryWithDictionary:{settingOne:"Add a Bookmark"}
		writePlist(settingPlist, theSetting)
		errorDialog("A bookmark named " & quote & currentName & quote & " already exists")
	end if
	
	bookmarkData's setObject:currentPath forKey:currentName
	return {bookmarkData, currentName}
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames)
	if bookmarkNames = {} then errorDialog("There are no bookmarks to delete")
	
	set deleteItems to (choose from list bookmarkNames with title "Finder Folder Bookmark" with prompt "Select bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed)
	if deleteItems = false then error number -128
	
	set deleteItems to current application's NSArray's arrayWithArray:deleteItems
	(bookmarkData's removeObjectsForKeys:deleteItems)
	return bookmarkData
end deleteBookmark

on changeFolder(bookmarkData, dialogResult)
	set thePath to (bookmarkData's valueForKey:dialogResult) as text
	
	try
		set theAlias to POSIX file thePath as alias
	on error
		errorDialog("The folder named " & quote & dialogResult & quote & " is offline or otherwise unavailable")
	end try
	
	try
		tell application "Finder" to set target of Finder window 1 to theAlias
	on error
		set theWorkspace to current application's NSWorkspace's sharedWorkspace()
		theWorkspace's selectFile:(missing value) inFileViewerRootedAtPath:thePath
	end try
end changeFolder

on readPlist(thePath)
	return (current application's NSMutableDictionary's dictionaryWithContentsOfFile:thePath)
end readPlist

on writePlist(thePath, theDictionary)
	theDictionary's writeToFile:thePath atomically:true
end writePlist

on errorDialog(theMessage)
	display alert "An error has occurred" message theMessage buttons {"OK"} default button 1 as critical
	error number -128
end errorDialog

main()

1 Like

Hi Peavine

Thank you 4 wonderful script, I quite like the idea of having frequently used folders at hand, with ability to add/ remove from the list

Just wondered if its possible to do a similar list with frequently used documents/ Files. Selecting them in list → opens them in default application

Cheers

One208. I’m happy to hear that you like my bookmark script, and thanks for the suggestion, which would not be difficult to implement but would take a bit of time to write and test. I’ll work on that after I finish another project.

Hi Peavine
Thank you for ur script, I have modified a few lines for it to bookmark Files and open them in default application
Please suggest if following cud be achieved

  • Select Multiple Files & Bookmark them
  • Prevent Folders getting Bookmarked
    Cheers

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set preferencesFolder to POSIX path of (path to preferences as text)
	set settingPlist to preferencesFolder & "FileBookmarkSetting.plist"
	set dataPlist to preferencesFolder & "FileBookmarkData.plist"
	
	try
		set dialogDefault to settingOne of readPlist(settingPlist) as text
	on error
		set dialogDefault to "Add a FileBookmark"
	end try
	
	try
		set bookmarkData to readPlist(dataPlist)
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"caseInsensitiveCompare:") as list
	on error
		set bookmarkData to (current application's NSMutableDictionary's new())
		set bookmarkNames to {}
	end try
	
	set dialogMenu to bookmarkNames & {"--", "Add a FileBookmark", "Delete a FileBookmark"}
	set dialogResult to (choose from list dialogMenu with title "File Bookmark" default items dialogDefault)
	if dialogResult = false then error number -128
	set dialogResult to item 1 of dialogResult
	
	if dialogResult = "Add a FileBookmark" then
		set {bookmarkData, currentName} to addBookmark(bookmarkData, bookmarkNames, settingPlist)
		writePlist(dataPlist, bookmarkData)
		set dialogResult to currentName
	else if dialogResult = "Delete a FileBookmark" then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist(dataPlist, bookmarkData)
	else if dialogResult begins with "-" then
		error number -128
	else
		changeFolder(bookmarkData, dialogResult)
	end if
	
	set theSetting to current application's NSDictionary's dictionaryWithDictionary:{settingOne:dialogResult}
	writePlist(settingPlist, theSetting)
end main

on addBookmark(bookmarkData, bookmarkNames, settingPlist)
	try
		tell application "Finder"
			set currentPath to selection as alias
			set currentName to name of currentPath
			## 			set currentName to name of Finder window 1
			## 			set currentPath to target of Finder window 1 as alias
		end tell
	on error
		errorDialog("Add a Bookmark", "A Selected File was not found or the File cannot be bookmarked")
	end try
	set currentPath to POSIX path of currentPath
	
	set thePath to (current application's NSString's stringWithString:currentPath)'s pathComponents()
	if (count thePath) < 7 then
		set dialogPath to text 1 thru -2 of currentPath
	else
		set dialogPath to current application's NSString's stringWithFormat_("/%@/%@/.../%@/%@", item 2 of thePath, item 3 of thePath, item -3 of thePath, item -2 of thePath) as text
	end if
	
	set currentName to text returned of (display dialog "Bookmark name for " & quote & dialogPath & quote default answer currentName buttons {"Cancel", "OK"} default button 2 cancel button 1 with title "File Bookmark")
	if currentName = "" then error number -128
	
	if currentName is in bookmarkNames then
		set theSetting to current application's NSDictionary's dictionaryWithDictionary:{settingOne:currentName}
		writePlist(settingPlist, theSetting)
		errorDialog("Add a Bookmark", "A bookmark named " & quote & currentName & quote & " already exists")
	end if
	
	bookmarkData's setObject:currentPath forKey:currentName
	return {bookmarkData, currentName}
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames)
	if bookmarkNames = {} then errorDialog("Delete a Bookmark", "There are no bookmarks to delete")
	
	set deleteItems to (choose from list bookmarkNames with title "File Bookmark" with prompt "Select File bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed)
	if deleteItems = false then error number -128
	
	set deleteItems to current application's NSArray's arrayWithArray:deleteItems
	(bookmarkData's removeObjectsForKeys:deleteItems)
	return bookmarkData
end deleteBookmark

on changeFolder(bookmarkData, dialogResult)
	set thePath to (bookmarkData's valueForKey:dialogResult) as text
	
	try
		set theAlias to POSIX file thePath as alias
	on error
		errorDialog("Go To Bookmark", "The File named " & quote & dialogResult & quote & " is offline or otherwise not available")
	end try
	
	try
		-- Uncommnet to switch between New window v/s ReUse Front window CJ Mod
		# tell application "Finder" to set target of Finder window 1 to theAlias -- uses foremost finder window to display Selected folder
		# tell application "Finder" to make new window to theAlias -- Opens New Finder window
		
		tell application "Finder" to open theAlias -- Opens Document (need to be POSIX path as AppleScript cannot coerce to an alias or file object acceptable to the Finder)
	on error
		set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
		theWorkSpace's openURL:theAlias
	end try
end changeFolder

on readPlist(thePath)
	return (current application's NSMutableDictionary's dictionaryWithContentsOfFile:thePath)
end readPlist

on writePlist(thePath, theDictionary)
	theDictionary's writeToFile:thePath atomically:true
end writePlist

on errorDialog(textOne, textTwo)
	display alert textOne message textTwo buttons {"OK"} default button 1 as critical
	error number -128
end errorDialog

main()

1 Like

One208. If you want to bookmark multiple files at one time, my inclination would be to skip the dialog that prompts for a bookmark name and instead to utilize the file name as the bookmark name. Then, the script could fairly quickly loop through each selected file and add the file name and path to the bookmarkData dictionary. Just as a rough demonstration:

tell application "Finder" to set theSelectedFiles to selection as alias list
repeat with aFile in theSelectedFiles
-- the code which adds the file name and path to the dictionary
end repeat

As regards identifying a folder, there are many options, but perhaps the simplest is to use Finder’s kind property. For example

tell application "Finder"
	set theFiles to selection as alias list
	set theKind to kind of item 1 of theFiles --> returns "Folder" for a folder
end tell

I tested your script and it seems to work well.

1 Like

This script allows the user to bookmark files selected in a Finder window and to open the bookmarked files with their default apps. The script’s operation is straightforward, although it should be noted:

  • The script does not allow the user to bookmark folders or package files.

  • When adding a bookmark, an existing bookmark with the same name is overwritten.

-- Revised 2021.07.21

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set preferencesFolder to POSIX path of (path to preferences as text)
	set settingPlist to preferencesFolder & "FinderBookmarkFileSetting.plist"
	set dataPlist to preferencesFolder & "FinderBookmarkFileData.plist"
	
	set dialogDefault to readPlist(settingPlist)
	if dialogDefault = (missing value) then
		set dialogDefault to "Add a Bookmark"
	else
		set dialogDefault to (settingOne of dialogDefault) as list
	end if
	
	set bookmarkData to readPlist(dataPlist)
	if bookmarkData = (missing value) then
		set bookmarkData to (current application's NSMutableDictionary's new())
		set bookmarkNames to {}
	else
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"caseInsensitiveCompare:") as list
	end if
	
	set dialogMenu to bookmarkNames & {"--", "Add a Bookmark", "Delete a Bookmark"}
	set dialogResult to (choose from list dialogMenu with title "Finder File Bookmark" default items dialogDefault with multiple selections allowed)
	if dialogResult = false then error number -128
	if (count dialogResult) > 1 then
		if "Add a Bookmark" is in dialogResult or "Delete a Bookmark" is in dialogResult or "--" is in dialogResult then
			errorDialog("Conflicting dialog items were selected")
		end if
	end if
	
	if dialogResult = {"Add a Bookmark"} then
		set bookmarkData to addBookmark(bookmarkData)
		writePlist(dataPlist, bookmarkData)
	else if dialogResult = {"Delete a Bookmark"} then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist(dataPlist, bookmarkData)
	else if dialogResult = {"--"} then
		error number -128
	else
		openFiles(bookmarkData, dialogResult, dataPlist)
		if result = false then set dialogResult to "Add a Bookmark"
	end if
	
	delay 0.5
	
	set theSetting to current application's NSDictionary's dictionaryWithDictionary:{settingOne:dialogResult}
	writePlist(settingPlist, theSetting)
end main

on addBookmark(bookmarkData)
	try
		tell application "Finder" to set selectedFiles to selection as alias list
	on error
		errorDialog("An item selected in a Finder window or on the desktop cannot be bookmarked")
	end try
	if (count selectedFiles) = 0 then errorDialog("A file must be selected in a Finder window or on the desktop")
	
	repeat with aFile in selectedFiles
		set aFilePath to (current application's NSString's stringWithString:(POSIX path of aFile))
		set aFileName to aFilePath's lastPathComponent() as text
		
		set aFileURL to (current application's |NSURL|'s fileURLWithPath:aFilePath)
		set {theResult, theValue} to (aFileURL's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
		if (theValue as boolean) = true then errorDialog("An item selected in a Finder window or on the desktop appears to be a folder or package file and cannot be bookmarked")
		
		set aFileName to text returned of (display dialog "Enter a bookmark name for:" default answer aFileName with icon note)
		if aFileName = "" then errorDialog("A bookmark name was not entered in the dialog")
		
		(bookmarkData's setObject:aFilePath forKey:aFileName)
	end repeat
	
	return bookmarkData
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames)
	if bookmarkNames = {} then errorDialog("There are no bookmarks to delete")
	
	set deleteItems to (choose from list bookmarkNames with title "Finder File Bookmark" with prompt "Select bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed)
	if deleteItems = false then error number -128
	
	set deleteItems to current application's NSArray's arrayWithArray:deleteItems
	(bookmarkData's removeObjectsForKeys:deleteItems)
	return bookmarkData
end deleteBookmark

on openFiles(bookmarkData, fileNames, dataPlist)
	set theFilesToOpen to {}
	set fileManager to current application's NSFileManager's defaultManager()
	repeat with aFileName in fileNames
		set aFilePath to (bookmarkData's valueForKey:aFileName) as text
		if not (fileManager's fileExistsAtPath:aFilePath) then
			removeOrphanBookmark(bookmarkData, aFileName, dataPlist)
			return false
		end if
		set end of theFilesToOpen to quoted form of aFilePath & space
	end repeat
	
	do shell script "open " & theFilesToOpen
	return true
end openFiles

on removeOrphanBookmark(bookmarkData, theBookmark, dataPlist)
	display alert "An error has occurred" message "The file referenced by the bookmark " & quote & theBookmark & quote & " could not be found" buttons {"Stop", "Remove Bookmark"} default button 1 as critical
	if button returned of result = "Stop" then
		error number -128
	else
		(bookmarkData's removeObjectForKey:theBookmark)
		writePlist(dataPlist, bookmarkData)
	end if
end removeOrphanBookmark

on readPlist(thePath)
	return (current application's NSMutableDictionary's dictionaryWithContentsOfFile:thePath)
end readPlist

on writePlist(thePath, theDictionary)
	theDictionary's writeToFile:thePath atomically:true
end writePlist

on errorDialog(messageText)
	display alert "An error has occurred" message messageText buttons {"Stop"} default button 1 as critical
	error number -128
end errorDialog

main()
1 Like

The previous 2 posts don’t work.

Can’t get settingOne of missing value.
From this line
“set dialogResult to (choose from list dialogMenu with title “Finder File Bookmark” default items dialogDefault with multiple selections allowed)”

However this line is the problem
“try
set dialogDefault to settingOne of readPlist(settingPlist) as list
on error
set dialogDefault to “Add a Bookmark”
end try”

The first time running this, no plist exists but it does not trigger the error.
I guess the “as list” hides the error from AppleScript. not good

Change to “as text” then it will be detected.

Would probably be better to test for “missing value”??

Also: several lines down
if “Add a Bookmark” is in dialogResult or “Delete a Bookark” is in dialogResult or “–” is in dialogResult then"

“Bookark” should be “Bookmark”

Thanks xjonnie for testing my script and reporting the errors. I’ve fixed both errors in the script in post 11 above.

The following is a simplified version of my script that bookmarks files. It should be noted that:

  • The name of the bookmark is the name of the file.
  • Existing bookmark names are overwritten.
  • The script will only open one bookmark at a time.
  • The script creates a plist file (com.peavine.FileBookmark.plist) in the user’s preference folder.
-- revised 2022.12.26

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	try
		set dialogDefault to readPlist("dialogDefaultKey") as text
		set bookmarkData to readPlist("bookmarkDataKey")'s mutableCopy()
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"localizedStandardCompare:") as list
	on error
		set dialogDefault to "Add a Bookmark"
		set bookmarkData to (current application's NSMutableDictionary's new())
		set bookmarkNames to {}
	end try
	
	set dialogMenu to bookmarkNames & {"--", "Add a Bookmark", "Delete a Bookmark"}
	set dialogResult to (choose from list dialogMenu with title "File Bookmark" default items dialogDefault)
	if dialogResult is false then error number -128
	set dialogResult to item 1 of dialogResult
	
	if dialogResult is "Add a Bookmark" then
		set {bookmarkData, dialogResult} to addBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if dialogResult is "Delete a Bookmark" then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if dialogResult is "--" then
		error number -128
	else
		openBookmark(bookmarkData, dialogResult)
	end if
	
	writePlist("dialogDefaultKey", dialogResult)
end main

on addBookmark(bookmarkData, bookmarkNames)
	set theFiles to (choose file with prompt "Select files to bookmark" with multiple selections allowed)
	set theFiles to reverse of theFiles
	repeat with aFile in theFiles
		set theFile to (current application's NSString's stringWithString:(POSIX path of aFile))
		set fileName to (theFile's stringByDeletingPathExtension())'s lastPathComponent()
		(bookmarkData's setObject:theFile forKey:fileName)
	end repeat
	return {bookmarkData, fileName}
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames)
	if bookmarkNames is {} then
		display alert "An error has occurred" message "There are no bookmarks to delete"
		error number -128
	end if
	set deleteItems to (choose from list bookmarkNames with title "File Bookmark" with prompt "Select bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed)
	if deleteItems is false then error number -128
	set deleteItems to current application's NSArray's arrayWithArray:deleteItems
	(bookmarkData's removeObjectsForKeys:deleteItems)
	return bookmarkData
end deleteBookmark

on openBookmark(bookmarkData, fileName)
	set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
	set theFile to bookmarkData's valueForKey:fileName
	set fileOpened to (theWorkSpace's openFile:theFile)
	if fileOpened as boolean is false then deleteOrphanBookmark(bookmarkData, fileName)
	delay 0.5
end openBookmark

on deleteOrphanBookmark(bookmarkData, fileName)
	display alert "An error has occurred" message "The file " & quote & fileName & quote & " could not be opened" buttons {"Cancel", "Delete Bookmark"} cancel button 1 default button 2 as critical
	(bookmarkData's removeObjectForKey:fileName)
	writePlist("bookmarkDataKey", bookmarkData)
	writePlist("dialogDefaultKey", "Add a Bookmark")
	error number -128
end deleteOrphanBookmark

on readPlist(theKey)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileBookmark"
	return theDefaults's objectForKey:theKey
end readPlist

on writePlist(theKey, theValue)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileBookmark"
	theDefaults's setObject:theValue forKey:theKey
end writePlist

main()

The above script opens a bookmarked file with the default app. The openBookmark handler can be modified to open a file that has a particular file extension with a specific app:

on openBookmark(bookmarkData, fileName)
	set theApps to {|app|:"Script Editor", txt:"TextEdit"} -- put extension in vertical bars
	set theApps to current application's NSDictionary's dictionaryWithDictionary:theApps
	set theFile to bookmarkData's objectForKey:fileName
	set fileExtension to theFile's pathExtension()'s lowercaseString()
	set theApp to theApps's objectForKey:fileExtension
	set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
	if theApp is missing value then
		set fileOpened to (theWorkSpace's openFile:theFile)
	else
		set fileOpened to (theWorkSpace's openFile:theFile withApplication:theApp)
	end if
	if fileOpened as boolean is false then deleteOrphanBookmark(bookmarkData, fileName)
	delay 0.5
end openBookmark
1 Like

I find this post a bit “Deceiving” as it does not at all use Apple’s NSURL’s bookmarkData.

https://developer.apple.com/documentation/foundation/nsurl/1417795-bookmarkdatawithoptions?language=objc

It’s obvious that there is nothing “Deceiving” about my post, and it’s difficult to know exactly what technomorph is saying. One possibility is that he believes my script should use bookmarkDataWithOptions rather than POSIX paths to bookmark files. This has the potential advantage of bookmarks often (but not always) remaining linked to bookmarked files that are moved or renamed. I find this to be a bad idea in many instances, but, FWIW, the following script works in this fashion. In limited testing, bookmarks in this script remained linked to files to the same extent that Finder alias files remain linked to files.

-- revised 2022.01.07 to use bookmarkDataWithOptions
-- this is a test version not intended for regular use

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	try
		set dialogDefault to readPlist("dialogDefaultKey") as text
		set bookmarkData to readPlist("bookmarkDataKey")'s mutableCopy()
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"localizedStandardCompare:") as list
	on error
		set dialogDefault to "Add a Bookmark"
		set bookmarkData to (current application's NSMutableDictionary's new())
		set bookmarkNames to {}
	end try
	
	set dialogMenu to bookmarkNames & {"--", "Add a Bookmark", "Delete a Bookmark"}
	set dialogResult to (choose from list dialogMenu with title "File Bookmark" default items dialogDefault)
	if dialogResult is false then error number -128
	set dialogResult to item 1 of dialogResult
	
	if dialogResult is "Add a Bookmark" then
		set {bookmarkData, dialogResult} to addBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if dialogResult is "Delete a Bookmark" then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if dialogResult is "--" then
		error number -128
	else
		openBookmark(bookmarkData, dialogResult)
	end if
	
	writePlist("dialogDefaultKey", dialogResult)
end main

on addBookmark(bookmarkData, bookmarkNames)
	set theFiles to (choose file with prompt "Select files to bookmark" with multiple selections allowed)
	set theFiles to reverse of theFiles
	repeat with aFile in theFiles
		set theFile to (current application's |NSURL|'s fileURLWithPath:(POSIX path of aFile))
		set fileName to (theFile's URLByDeletingPathExtension())'s lastPathComponent()
		set theBookmarkData to (theFile's bookmarkDataWithOptions:0 includingResourceValuesForKeys:{} relativeToURL:(missing value) |error|:(missing value))
		(bookmarkData's setObject:theBookmarkData forKey:fileName)
	end repeat
	return {bookmarkData, fileName}
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames)
	if bookmarkNames is {} then
		display alert "An error has occurred" message "There are no bookmarks to delete"
		error number -128
	end if
	set deleteItems to (choose from list bookmarkNames with title "File Bookmark" with prompt "Select bookmarks to delete:" default items {item 1 of bookmarkNames} with multiple selections allowed)
	if deleteItems is false then error number -128
	set deleteItems to current application's NSArray's arrayWithArray:deleteItems
	(bookmarkData's removeObjectsForKeys:deleteItems)
	return bookmarkData
end deleteBookmark

on openBookmark(bookmarkData, fileName)
	set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
	set theFile to bookmarkData's valueForKey:fileName
	set theFile to current application's |NSURL|'s URLByResolvingBookmarkData:theFile options:0 relativeToURL:(missing value) bookmarkDataIsStale:(missing value) |error|:(missing value)
	set fileOpened to (theWorkSpace's openURL:theFile)
	if fileOpened as boolean is false then deleteOrphanBookmark(bookmarkData, fileName)
	delay 0.5
end openBookmark

on deleteOrphanBookmark(bookmarkData, fileName)
	display alert "An error has occurred" message "The file " & quote & fileName & quote & " could not be opened" buttons {"Cancel", "Delete Bookmark"} cancel button 1 default button 2 as critical
	(bookmarkData's removeObjectForKey:fileName)
	writePlist("bookmarkDataKey", bookmarkData)
	writePlist("dialogDefaultKey", "Add a Bookmark")
	error number -128
end deleteOrphanBookmark

on readPlist(theKey)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileBookmark1"
	return theDefaults's objectForKey:theKey
end readPlist

on writePlist(theKey, theValue)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileBookmark1"
	theDefaults's setObject:theValue forKey:theKey
end writePlist

main()

The above script was tested on Monterey only.

2 Likes

The script works just fine on macOS 10.14.6 Mojave.

Thanks Chris for testing my script.

1 Like

The script included below allows the user to bookmark folders selected in a Finder window. It is similar to the script in post 6 above but uses Shane’s Myriad Tables script library. In recent versions of macOS, the script can only be run by Script Debugger (for testing) and FastScripts (for actual use). The script creates a small plist file in the user’s preferences folder.

use framework "AppKit"
use framework "Foundation"
use scripting additions
use script "Myriad Tables Lib" version "1.0.13"

on main()
	try
		set dialogDefault to readPlist("dialogDefaultKey") as text
		set bookmarkData to readPlist("bookmarkDataKey")'s mutableCopy()
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"caseInsensitiveCompare:")
	on error
		set dialogDefault to "Add a Bookmark"
		set bookmarkData to (current application's NSMutableDictionary's new())'s mutableCopy()
		set bookmarkNames to current application's NSArray's arrayWithArray:{}
	end try
	
	set {theSelection, theButton} to showDialog(dialogDefault, bookmarkNames)
	
	if theButton is 2 then -- delete button selected
		set bookmarkData to deleteBookmark(bookmarkData, theSelection)
		writePlist("bookmarkDataKey", bookmarkData)
		set theSelection to "Add a Bookmark"
	else if theSelection is "Add a Bookmark" then
		set {bookmarkData, theSelection} to addBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if theSelection is "--" then
		error number -128
	else
		changeFolder(bookmarkData, theSelection)
	end if
	
	writePlist("dialogDefaultKey", theSelection)
end main

on showDialog(dialogDefault, bookmarkNames)
	set dialogList to bookmarkNames's arrayByAddingObjectsFromArray:{"--", "Add a Bookmark"}
	set rowNumber to (dialogList's indexOfObject:dialogDefault) + 1
	set theTable to make new table with data (dialogList as list) with prompt "Make a selection:" with title "Folder Bookmarks" initially selected rows {rowNumber}
	modify table theTable OK button name "Select" extra button name "Delete" with alternate backgrounds
	set theValues to display table theTable
	return {item 1 of values selected of theValues, button number of theValues}
end showDialog

on addBookmark(bookmarkData, bookmarkNames)
	try
		tell application "Finder"
			set theFolder to selection
			if theFolder is {} then set theFolder to {target of front Finder window}
			if class of item 1 of theFolder is not folder then error
			set theFolder to item 1 of theFolder as alias
			set folderName to name of theFolder
		end tell
	on error
		writePlist("dialogDefaultKey", "Add a Bookmark")
		errorAlert("A folder in a Finder window must be selected")
	end try
	set theFolder to POSIX path of theFolder
	set dialogList to theFolder
	set p to (current application's NSString's stringWithString:theFolder)'s componentsSeparatedByString:"/"
	set theCount to p's |count|()
	if theCount is greater than 6 then set dialogList to current application's NSString's stringWithFormat_("/%@/%@/.../%@/%@/", p's objectAtIndex:1, p's objectAtIndex:2, p's objectAtIndex:(theCount - 3), p's objectAtIndex:(theCount - 2))
	set folderName to text returned of (display dialog "Enter name for " & quote & (dialogList as text) & quote default answer folderName buttons {"Cancel", "OK"} default button 2 cancel button 1 with title "Folder Bookmarks")
	if folderName is "" then error number -128
	if (bookmarkNames's containsObject:folderName) is true then
		writePlist("dialogDefaultKey", "Add a Bookmark")
		errorAlert("A bookmark named " & quote & folderName & quote & " already exists")
	end if
	bookmarkData's setObject:theFolder forKey:folderName
	return {bookmarkData, folderName}
end addBookmark

on deleteBookmark(bookmarkData, deleteItem)
	if bookmarkData's |count|() is 0 then errorAlert("There are no bookmarks to delete")
	bookmarkData's removeObjectForKey:deleteItem
	return bookmarkData
end deleteBookmark

on changeFolder(bookmarkData, theKey)
	set thePath to (bookmarkData's objectForKey:theKey) as text
	try
		set theAlias to POSIX file thePath as alias
	on error
		errorAlert("The folder named " & quote & theKey & quote & " is offline or otherwise unavailable")
	end try
	try
		tell application "Finder" to set target of Finder window 1 to theAlias
	on error
		set theWorkspace to current application's NSWorkspace's sharedWorkspace()
		theWorkspace's selectFile:(missing value) inFileViewerRootedAtPath:thePath
	end try
end changeFolder

on readPlist(theKey)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FolderBookmarks"
	return theDefaults's objectForKey:theKey
end readPlist

on writePlist(theKey, theValue)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FolderBookmarks"
	theDefaults's setObject:theValue forKey:theKey
end writePlist

on errorAlert(dialogMessage)
	display alert "An error has occurred" message dialogMessage as critical
	error number -128
end errorAlert

main()
1 Like

The script included below bookmarks files and opens bookmarked files with their default apps. It is a minor rewrite of the script included in post 14 above.

It may be useful to specify the apps that will be used to open files that have a specified extension. To implement this feature, replace the openBookmark handler with the following and change the first line of the handler to the desired file extensions and apps. Some file extensions (e.g. |app|) may need to be surrounded by vertical bars:

on openBookmark(bookmarkData, fileName)
	set theApps to {scpt:"Script Editor", txt:"TextEdit"} -- this must contain a record
	set theApps to current application's NSDictionary's dictionaryWithDictionary:theApps
	set theFile to bookmarkData's objectForKey:fileName
	set fileExtension to theFile's pathExtension()'s lowercaseString()
	set theApp to theApps's objectForKey:fileExtension
	set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
	if theApp is missing value then
		set fileOpened to (theWorkSpace's openFile:theFile)
	else
		set fileOpened to (theWorkSpace's openFile:theFile withApplication:theApp)
	end if
	if fileOpened as boolean is false then deleteOrphanBookmark(bookmarkData, fileName)
	delay 0.5
end openBookmark

The script has a flaw of sorts in that the bookmark names are the file names but without an extension. This means that you cannot bookmark both FileOne.txt and FileOne.pdf. To include the file extensions in the bookmark names, replace existing line 1 below with new line 2:

set fileName to (theFile's stringByDeletingPathExtension())'s lastPathComponent()
set fileName to theFile's lastPathComponent()

Please note that the script creates a small plist file in the user’s preference folder.

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	try
		set dialogDefault to readPlist("dialogDefaultKey") as text
		set bookmarkData to readPlist("bookmarkDataKey")'s mutableCopy()
		set bookmarkNames to (bookmarkData's allKeys()'s sortedArrayUsingSelector:"localizedStandardCompare:")
	on error
		set dialogDefault to "Add a Bookmark"
		set bookmarkData to (current application's NSMutableDictionary's new())
		set bookmarkNames to current application's NSArray's arrayWithArray:{}
	end try
	
	set dialogMenu to bookmarkNames's arrayByAddingObjectsFromArray:{"--", "Add a Bookmark", "Delete a Bookmark"}
	set dialogResult to (choose from list (dialogMenu as list) with title "File Bookmark" default items dialogDefault)
	if dialogResult is false then error number -128
	set dialogResult to item 1 of dialogResult
	
	if dialogResult is "Add a Bookmark" then
		set {bookmarkData, dialogResult} to addBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if dialogResult is "Delete a Bookmark" then
		set bookmarkData to deleteBookmark(bookmarkData, bookmarkNames)
		writePlist("bookmarkDataKey", bookmarkData)
	else if dialogResult is "--" then
		error number -128
	else
		openBookmark(bookmarkData, dialogResult)
	end if
	
	writePlist("dialogDefaultKey", dialogResult)
end main

on addBookmark(bookmarkData, bookmarkNames)
	set theFiles to (choose file with prompt "Select files to bookmark" with multiple selections allowed)
	set theFiles to reverse of theFiles
	repeat with aFile in theFiles
		set theFile to (current application's NSString's stringWithString:(POSIX path of aFile))
		set fileName to (theFile's stringByDeletingPathExtension())'s lastPathComponent()
		if (bookmarkNames's containsObject:fileName) then
			display alert "A bookmark with the name " & quote & (fileName as text) & quote & " already exists and will be skipped"
		else
			(bookmarkData's setObject:theFile forKey:fileName)
		end if
	end repeat
	return {bookmarkData, fileName}
end addBookmark

on deleteBookmark(bookmarkData, bookmarkNames as list)
	if bookmarkNames is {} then
		display alert "An error has occurred" message "There are no bookmarks to delete"
		error number -128
	end if
	set deleteItems to (choose from list bookmarkNames with title "File Bookmark" with prompt "Select bookmarks to delete" default items {item 1 of bookmarkNames} with multiple selections allowed)
	if deleteItems is false then error number -128
	set deleteItems to current application's NSArray's arrayWithArray:deleteItems
	(bookmarkData's removeObjectsForKeys:deleteItems)
	return bookmarkData
end deleteBookmark

on openBookmark(bookmarkData, fileName)
	set theFile to bookmarkData's objectForKey:fileName
	set fileOpened to (current application's NSWorkspace's sharedWorkspace())'s openFile:theFile
	if fileOpened is false then deleteOrphanBookmark(bookmarkData, fileName)
	delay 0.5
end openBookmark

on deleteOrphanBookmark(bookmarkData, fileName)
	display alert "An error has occurred" message "The bookmark " & quote & fileName & quote & " could not be opened. Either the file or its designated app could not be found." buttons {"Cancel", "Delete Bookmark"} cancel button 1 default button 2 as critical
	(bookmarkData's removeObjectForKey:fileName)
	writePlist("bookmarkDataKey", bookmarkData)
	writePlist("dialogDefaultKey", "Add a Bookmark")
	error number -128
end deleteOrphanBookmark

on readPlist(theKey)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileBookmark"
	return theDefaults's objectForKey:theKey
end readPlist

on writePlist(theKey, theValue)
	set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileBookmark"
	theDefaults's setObject:theValue forKey:theKey
end writePlist

main()
1 Like