Monday, March 1, 2021

#1 2021-02-20 10:16:30 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 790

A specialized file-find utility

There are a great many file-find solutions for the Mac, but I was looking for something that would allow me to quickly find and then open files in one particular folder (and its subfolders). The goal was simplicity, and the solution had to support basic (asterisk only) wildcard searches. So, I wrote the script contained below.

A few comments:

* The user will need to edit the searchOne and searchTwo lists at the top of the script. The first item in each list is the name of the search for use with the dialogs and the second item is the search path.

* The script finds files only and skips folders, hidden files, and the contents of packages.

* If a wildcard is detected in user input, the script adds asterisks at the beginning and end of the user input and does a wildcard search. Thus, if the user input is visa*2020, then the actual wildcard search becomes *visa*2020*.

* The user input is retained from session to session and is saved in a plist with the name "com.peavine.FileFind".

* The use of a choose-from-list dialog is not optimal and I hope to implement one of Shane's custom dialogs in the future.

Applescript:

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

on main()
   set fileDivider to " <> " -- additional spacing may be helpful
   set searchOne to {"Home", "/Users/Robert/"}
   set searchTwo to {"Records", "/Volumes/Backup 1/"}
   
   set defaultAnswer to readOrWritePlist("read", "")
   
   display dialog "Enter a search string:" default answer defaultAnswer buttons {"Cancel", (item 1 of searchOne), (item 1 of searchTwo)} cancel button 1 default button 3 with title "File Find" with icon note
   set {searchString, searchFolder} to {text returned, button returned} of result
   
   if searchString = "" then
       error number -128
   else if searchString contains "*" then
       set wildcardSearch to true
   else
       set wildcardSearch to false
   end if
   
   if searchFolder = (item 1 of searchOne) then
       set searchPath to (item 2 of searchOne)
   else
       set searchPath to (item 2 of searchTwo)
   end if
   
   readOrWritePlist("write", searchString)
   
   set theFiles to getFile(searchPath, searchString, wildcardSearch)
   
   if theFiles = {} then
       display dialog "No matching files were found" buttons {"Cancel", "New Search"} cancel button 1 default button 2 with title "File Find" with icon caution
       main()
   else if (count theFiles) > 45 then
       display dialog ((count theFiles) as text) & " files found" buttons {"Cancel", "Continue", "New Search"} cancel button 1 default button 3 with title "File Find" with icon caution
       if button returned of result = "New Search" then main()
   end if
   
   set AppleScript's text item delimiters to {"/"}
   
   repeat with aFile in theFiles
       set aPosixFile to POSIX path of aFile
       if aPosixFile ends with "/" then set aPosixFile to text 1 thru -2 of aPosixFile
       set contents of aFile to (text item -1 of aPosixFile & fileDivider & text items 1 thru -2 of aPosixFile)
   end repeat
   
   set AppleScript's text item delimiters to fileDivider
   
   set selectedFiles to choose from list ({"New Search"} & theFiles) default items "New Search" with title searchFolder with multiple selections allowed
   if selectedFiles = false then
       set AppleScript's text item delimiters to {""}
       error number -128
   else if selectedFiles contains "New Search" then
       set AppleScript's text item delimiters to {""}
       main()
   else
       repeat with aFile in selectedFiles
           set contents of aFile to (text item 2 of aFile & "/" & text item 1 of aFile)
       end repeat
   end if
   
   set AppleScript's text item delimiters to {""}
   
   set theWorkSpace to current application's NSWorkspace's sharedWorkspace()
   repeat with aFile in selectedFiles
       set aFile to (current application's |NSURL|'s fileURLWithPath:aFile)
       (theWorkSpace's openURL:aFile)
   end repeat
   
   delay 0.5
   error number -128
end main

on getFile(theFolder, theString, wildcardSearch)
   set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
   set fileManager to current application's NSFileManager's defaultManager()
   set packageOption to current application's NSDirectoryEnumerationSkipsPackageDescendants
   set hiddenOption to current application's NSDirectoryEnumerationSkipsHiddenFiles as integer
   set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:(packageOption + hiddenOption) errorHandler:(missing value))'s allObjects()
   if wildcardSearch then
       set searchStringPredicate to current application's NSPredicate's predicateWithFormat_("lastPathComponent LIKE[c] %@ and pathExtension != ''", "*" & theString & "*")
   else
       set searchStringPredicate to current application's NSPredicate's predicateWithFormat_("lastPathComponent CONTAINS[c] %@ and pathExtension != ''", theString)
   end if
   set theFiles to folderContents's filteredArrayUsingPredicate:searchStringPredicate
   set sortDescriptors to current application's NSArray's arrayWithObject:(current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"caseInsensitiveCompare:")
   return (theFiles's sortedArrayUsingDescriptors:sortDescriptors) as list
end getFile

on readOrWritePlist(readOrWrite, theString)
   set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.peavine.FileFind"
   if readOrWrite = "read" then
       theDefaults's registerDefaults:{theKey:"man"}
       return (theKey of theDefaults) as text
   else
       set theKey of theDefaults to theString
   end if
end readOrWritePlist

main()

Last edited by peavine (2021-02-24 09:39:16 am)


2018 Mac mini - macOS Catalina

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)