Another method to search your scripts by contents

The easiest way I know to build small DBs in AppleScript is to use the ScriptDB.osax by Custom Flow Solutions (Yotam Rosenthal). Costs $12; There is a nice Manual. Recommended.

After working with Database Events I have learned a few things. By following a few simple lessons I have found Database Events to be stable and extremely easy to work with. The initial “instability” that I experienced was because I didn’t know these lessons and therefore did not follow them. I would say that the fault lies not in Database Events itself but the lack of documentation available for it.

Database Events Lessons Learned

  1. Always “launch” Database Events before you try to open an existing database, i.e. Tell application “Database Events” to launch
    reason: Normally if an application isn’t running, and you tell application “X” to open a document, the application will first launch and then open the document. This doesn’t happen with Database Events so you will get an error if Database Events isn’t already running.

  2. Always refer to a database by its name and not by a database number
    reason: the number of open databases varies by the method in which they are opened therefore you can never be sure the number of opened databases. To explain: if you create a new database then the number of open databases is 1. If you open an existing database then the number of open databases is 2… it varies so you can never be sure of a database’s number. So never refer to database 1, always use its name.

  3. Always save your database (if you want the changes saved!) before you quit Database Events
    reason: it may be obvious, but Database Events doesn’t automatically save your changes. Other databases do auto-save, such as SQLite3.

  4. In the beginning of your script always set the “quit delay” to 0 which effectively disables Database Events from automatically quitting itself. Make sure to quit Database Events at the end of your script also.
    reason: Database Events will automatically quit itself after 5 minutes of inactivity, so if it quits itself and you haven’t saved your changes then they will be lost and your databases will be closed.

This is my latest version of the script. It takes into account all of the “lessons learned” that I posted in the above post. Plus it combines the 2 scripts into one so it’s much cleaner now.

(* This script is used to help you search the contents of your applescripts. You can either update or search the database *)

(*  It basically allows you to search your scripts by their contents much like Spotlight allows you to search your files by their contents. It works by creating a database of the code from your scripts found in your user "Scripts" folder. Initially each script is opened in Script Editor and the code is copied from the script into the database. Once the database is created then you can perform searches for code snippets and the scripts containing those snippets are presented to you in the Finder. You will need to update your database as changes occur to your script code, or as scripts are added/deleted from your Scripts folder. *)

(* Searching the database: A dialog box is presented where you input your search terms. There are 2 types of searches you can perform using the search terms: 1) "As One Word" will search for scripts that contain all of the search terms next to each other, and 2) "Individual Words" finds scripts that contain all of the search terms, but the terms do not have to be next to each other. Just separate your search terms with spaces, no special characters or punctuation is needed. The results of the database search are presented in a Finder window. The window is populated with alias files to the original scripts found via the search. *)

(* Updating the database: This updates/creates the script database using "database events". The database is saved in your user's "application support" folder in a folder called "Script Search". This takes time so be patient. You will be notified when the process is complete. Do not use the "Script Editor" application during this time. *)

property ScriptEditorApp : "Script Editor"
property dbName : "scriptDB"
property dbFolderName : "Script Search"
property appSupportFolder : path to application support folder from user domain as Unicode text
property dbFolderPath : appSupportFolder & dbFolderName
property dbPath : appSupportFolder & dbFolderName & ":" & dbName & ".dbev"
property scriptsFolder : path to scripts folder from user domain as Unicode text
property resultWindowName : "Found Scripts"
property resultWindowPath : appSupportFolder & dbFolderName & ":" & resultWindowName
property searchTermsBox : ""
property field1Name : "fileName"
property field2Name : "modDate"
property field3Name : "scriptText"


-- database events require at least MacOSX 10.4
tell (system attribute "sysv") to set vSys to (("1" & it mod 4096 div 256) as string) & "." & it mod 256 div 16 & "." & it mod 16
if vSys < "10.4" then
	display dialog "This script requires the installation of Mac OS X 10.4 or higher." buttons {"OK"} default button 1 with icon 2
	return
end if


-- decide whether to search or update the db
set frontApp to displayed name of (info for (path to frontmost application))
tell application frontApp to display dialog "Search or Update the Database?" & return & return & "Note: the update process takes time so please be patient. You will be alerted when the update is finished. Do not use the \"Script Editor\" application during the update process." buttons {"Cancel", "Update", "Search"} default button 3 with icon note
set button_returned to button returned of the result

if button_returned is "Search" then --> (* SEARCH THE DATABASE *)
	-- check for required files and folders
	tell application "Finder"
		if not (exists file dbPath) then
			set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display dialog "The Script Database does not exist! Please create the database before performing a search." buttons {"OK"} default button 1 with icon stop
			return
		end if
		if not (exists folder resultWindowPath) then make new folder at folder dbFolderPath with properties {name:resultWindowName}
	end tell
	
	repeat
		-- get the search terms
		repeat
			set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display dialog "Enter your search terms:" default answer searchTermsBox with icon note buttons {"Cancel", "As One Word", "Individual Words"} default button 3 with title "Script Search"
			set {text_entered, button_pressed} to {text returned, button returned} of the result
			if text_entered is not "" then
				set searchTermsBox to text_entered
				exit repeat
			end if
		end repeat
		
		-- make them into a list according to button pressed
		if button_pressed is "As One Word" then
			set searchTerms to {text_entered}
		else
			set searchTerms to words of text_entered
		end if
		
		-- conduct the search
		set foundScripts to {}
		tell application "Database Events"
			launch
			open database (POSIX path of dbPath)
			tell database dbName
				repeat with i from 1 to (count of records)
					set theCheck to false
					tell record i
						set scriptPath to value of field "name"
						set scriptName to value of field field1Name
						set scriptText to value of field field3Name
						repeat with sw in searchTerms
							if scriptText contains sw or scriptName contains sw then
								set theCheck to true
							else
								set theCheck to false
								exit repeat
							end if
						end repeat
						if theCheck then set end of foundScripts to scriptPath
					end tell
				end repeat
			end tell
		end tell
		
		-- clean up database events
		tell application "Database Events" to quit
		
		-- create alias's to the results in the result window
		if foundScripts is not {} then
			-- delete previous search results
			tell application "Finder" to set aliasList to every file of folder resultWindowPath
			repeat with anAlias in aliasList
				do shell script ("rm -rf " & quoted form of (POSIX path of (anAlias as Unicode text)))
			end repeat
			
			-- make the alias's
			repeat with aScript in foundScripts
				try
					tell application "Finder" to make new alias file at folder resultWindowPath to file aScript
				on error
					set frontApp to displayed name of (info for (path to frontmost application))
					tell application frontApp to display dialog "The following script could not be found and will not be included in your search results." & return & return & aScript & return & return & "Do you need to update your database?" buttons {"OK"} default button 1 with icon note
				end try
			end repeat
			
			-- open the Finder window
			tell application "Finder"
				activate
				open folder resultWindowPath
			end tell
			exit repeat
		else
			set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display alert "No results were found!" message "Please try different search terms." as warning
		end if
	end repeat
else --> (* UPDATE THE DATABASE *)
	-- opening parameters
	set newRecs to 0
	set updatedRecs to 0
	set deletedRecs to 0
	set inTime to current date
	tell application ScriptEditorApp to launch
	
	-- get a list of all the files in the scripts folder
	set allFiles to my allFiles_ofFolder(scriptsFolder)
	
	--  disable auto-quitting for database events and close all open databases
	tell application "Database Events"
		launch
		set quit delay to 0
	end tell
	
	-- create the necessary folders and open the database
	set updateDB to true
	tell application "Finder"
		if not (exists folder dbFolderPath) then make new folder at folder appSupportFolder with properties {name:dbFolderName}
		if (exists file dbPath) then -- check for the database and create/open it
			tell application "Database Events"
				open database (POSIX path of dbPath)
				set origRecordCount to count of records of database dbName
			end tell
		else
			tell application "Database Events"
				make new database with properties {name:dbName, location:dbFolderPath}
				set updateDB to false
			end tell
			set origRecordCount to 0
		end if
	end tell
	
	-- create or update the database
	if updateDB then -- update the database so checking for existing records takes place
		repeat with aFile in allFiles
			set fileInfo to (info for file aFile)
			if kind of fileInfo is "script" or file creator of fileInfo is "aplt" then -- check for a "script editor" file
				set {fileName, fileModDate} to {name of fileInfo, modification date of fileInfo}
				tell application "Database Events" to tell database dbName
					if (exists record aFile) then
						tell (first record whose name = aFile)
							set recordsModDate to value of field "modDate"
							if fileModDate > recordsModDate then -- use modification date to see if a record needs updating
								set scriptText to my get_scriptText(aFile)
								if scriptText is not "" then
									set updatedRecs to updatedRecs + 1
									set value of field field1Name to fileName
									set value of field field2Name to fileModDate
									set value of field field3Name to scriptText
								end if
							end if
						end tell
					else -- a record doesn't exist for this script so create a new record for it
						set scriptText to my get_scriptText(aFile)
						if scriptText is not "" then
							set newRecs to newRecs + 1
							set thisRecord to make new record with properties {name:aFile}
							tell thisRecord
								make new field with properties {name:field1Name, value:fileName}
								make new field with properties {name:field2Name, value:fileModDate}
								make new field with properties {name:field3Name, value:scriptText}
							end tell
						end if
					end if
				end tell
			end if
		end repeat
		
		-- get a list of the non-existent records, i.e. scripts in the database that are no longer found in the Finder
		tell application "Database Events" to tell database dbName
			save
			set deleteList to {}
			set recordCount to count of records
			repeat with i from 1 to recordCount
				set thisPath to value of field "name" of record i
				tell application "Finder" to if not (exists file thisPath) then set end of deleteList to thisPath
			end repeat
			
			-- remove non-existent records from the database
			if deleteList is not {} then
				repeat with i from 1 to number of items in deleteList
					set this_item to item i of deleteList
					delete record this_item
					set deletedRecs to deletedRecs + 1
				end repeat
			end if
		end tell
		
	else -- we're creating a new database so no checking of the records is necessary
		repeat with aFile in allFiles
			set fileInfo to (info for file aFile)
			if kind of fileInfo is "script" or file creator of fileInfo is "aplt" then -- check for a "script editor" file
				set scriptText to my get_scriptText(aFile)
				if scriptText is not "" then
					set {fileName, fileModDate} to {name of fileInfo, modification date of fileInfo}
					tell application "Database Events" to tell database dbName
						set newRecs to newRecs + 1
						set thisRecord to make new record with properties {name:aFile}
						tell thisRecord
							make new field with properties {name:field1Name, value:fileName}
							make new field with properties {name:field2Name, value:fileModDate}
							make new field with properties {name:field3Name, value:scriptText}
						end tell
					end tell
				end if
			end if
		end repeat
	end if
	
	-- clean up database events
	tell application "Database Events"
		tell database dbName
			save
			set recordCount to count of records
		end tell
		quit
	end tell
	
	-- notify user it's done updating the db and specifics of the process
	set outTime to current date
	set totaltime to (outTime - inTime)
	set theTime to my secs_to_hms(totaltime)
	set frontApp to displayed name of (info for (path to frontmost application))
	tell application frontApp to display dialog "The database has been updated." & return & "Update time: " & theTime & return & return & "Old Number of Records in DB: " & origRecordCount & return & "New Number of Records in DB: " & recordCount & return & "Records Deleted: " & deletedRecs & return & "Records Updated: " & updatedRecs & return & "Records New: " & newRecs buttons {"OK"} default button 1 with icon 1
end if


(*=================== SUBROUTINES =====================*)
on get_scriptText(theScript)
	tell application ScriptEditorApp
		try
			open theScript
			set scriptText to text of document 1
		on error
			set scriptText to ""
		end try
		try
			close document 1
		end try
	end tell
	return scriptText
end get_scriptText

on secs_to_hms(the_secs)
	if the_secs is less than 360000 then
		set hr to text 2 thru 3 of ((100 + the_secs div hours) as string)
		set min to text 2 thru 3 of ((100 + the_secs mod hours div minutes) as string)
		set sec to text 2 thru 3 of ((100 + the_secs mod minutes div 1) as string)
		set fraction to text 2 thru 3 of ((100 + the_secs mod 1 * 100) as string)
		return hr & ":" & min & ":" & sec & "." & fraction
	else
		return false
	end if
end secs_to_hms

on allFiles_ofFolder(aFolder)
	set searchFolder to aFolder as string
	set everyFile to {}
	tell application "Finder"
		try -- there's an error if nothing is in the folder when you get entire contents
			set tempVar to files of entire contents of folder searchFolder
			if (count of tempVar) is 0 then -- answer is 0 when there's only 1 item???
				set end of everyFile to tempVar as string
			else
				repeat with i from 1 to (count of tempVar)
					set end of everyFile to (item i of tempVar) as string
				end repeat
			end if
		end try
	end tell
	return everyFile
end allFiles_ofFolder

Your rules for the use of DataBaseEvents clarify a ton of problems. Thanks for that insight – very very useful. :cool:

Hi , I’m Back.:smiley:
God life without my Mac was hard on me…

Thanks for the concern, but I was actually on Holiday in the north and south of france.
Had a fab time,the sights and landscape are awsome…

I will look at you update and work from that…

Cheers

Mark

Here is the first draft of the ideas above,
The show skipped button should only show if the are skipped.

There may be some redundant bits, not much , but it seems to work.
And I am sure it can be streamlined.
Let me know what you think

Cheers

(* This script is used to help you search the contents of your applescripts. You can either update or search the database *)

(*  It basically allows you to search your scripts by their contents much like Spotlight allows you to search your files by their contents. It works by creating a database of the code from your scripts found in your user "Scripts" folder. Initially each script is opened in Script Editor and the code is copied from the script into the database. Once the database is created then you can perform searches for code snippets and the scripts containing those snippets are presented to you in the Finder. You will need to update your database as changes occur to your script code, or as scripts are added/deleted from your Scripts folder. *)

(* Searching the database: A dialog box is presented where you input your search terms. There are 2 types of searches you can perform using the search terms: 1) "As One Word" will search for scripts that contain all of the search terms next to each other, and 2) "Individual Words" finds scripts that contain all of the search terms, but the terms do not have to be next to each other. Just separate your search terms with spaces, no special characters or punctuation is needed. The results of the database search are presented in a Finder window. The window is populated with alias files to the original scripts found via the search. *)

(* Updating the database: This updates/creates the script database using "database events". The database is saved in your user's "application support" folder in a folder called "Script Search". This takes time so be patient. You will be notified when the process is complete. Do not use the "Script Editor" application during this time. *)

property ScriptEditorApp : "Script Editor"
property dbName : "scriptDB"
property dbFolderName : "Script Search"
property appSupportFolder : path to application support folder from user domain as Unicode text
property dbFolderPath : appSupportFolder & dbFolderName
property dbPath : appSupportFolder & dbFolderName & ":" & dbName & ".dbev"
property scriptsFolder : path to scripts folder from user domain as Unicode text
property resultWindowName : "Found Scripts"
property resultWindowPath : appSupportFolder & dbFolderName & ":" & resultWindowName
property searchTermsBox : ""
property field1Name : "fileName"
property field2Name : "modDate"
property field3Name : "scriptText"
property field4Name : "skip"
property SkippedscriptText : "Skipped"
property notSkippedscriptText : "notSkipped"
property bugcheck : false

-- database events require at least MacOSX 10.4
tell (system attribute "sysv") to set vSys to (("1" & it mod 4096 div 256) as string) & "." & it mod 256 div 16 & "." & it mod 16
if vSys < "10.4" then
	display dialog "This script requires the installation of Mac OS X 10.4 or higher." buttons {"OK"} default button 1 with icon 2
	return
end if


-- decide whether to search or update the db
set frontApp to displayed name of (info for (path to frontmost application))
tell application frontApp to display dialog "Search or Update the Database?" & return & return & "Note: the update process takes time so please be patient. You will be alerted when the update is finished. Do not use the \"Script Editor\" application during the update process." buttons {"Cancel", "Update", "Search"} default button 3 with icon note
set button_returned to button returned of the result

if button_returned is "Search" then --> (* SEARCH THE DATABASE *)
	-- check for required files and folders
	tell application "Finder"
		if not (exists file dbPath) then
			set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display dialog "The Script Database does not exist! Please create the database before performing a search." buttons {"OK"} default button 1 with icon stop
			return
		end if
		if not (exists folder resultWindowPath) then make new folder at folder dbFolderPath with properties {name:resultWindowName}
	end tell
	
	repeat
		-- get the search terms
		repeat
			set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display dialog "Enter your search terms:" default answer searchTermsBox with icon note buttons {"Cancel", "As One Word", "Individual Words"} default button 3 with title "Script Search"
			set {text_entered, button_pressed} to {text returned, button returned} of the result
			if text_entered is not "" then
				set searchTermsBox to text_entered
				exit repeat
			end if
		end repeat
		
		-- make them into a list according to button pressed
		if button_pressed is "As One Word" then
			set searchTerms to {text_entered}
		else
			set searchTerms to words of text_entered
		end if
		
		-- conduct the search
		set foundScripts to {}
		--set Skipped to {}
		tell application "Database Events"
			launch
			open database (POSIX path of dbPath)
			tell database dbName
				repeat with i from 1 to (count of records)
					set theCheck to false
					tell record i
						set scriptPath to value of field "name"
						set scriptName to value of field field1Name
						set scriptText to value of field field3Name
						--set Skippedscript to value of field field4Name
						repeat with sw in searchTerms
							if scriptText contains sw or scriptName contains sw then
								set theCheck to true
							else
								set theCheck to false
								exit repeat
							end if
						end repeat
						if theCheck then
							--if Skippedscript is SkippedscriptText then
							--	set end of Skipped to scriptPath
							--end if
							
							set end of foundScripts to scriptPath
						end if
					end tell
				end repeat
			end tell
		end tell
		
		-- clean up database events
		--tell application "Database Events" to quit
		
		-- create alias's to the results in the result window
		if foundScripts is not {} then
			-- delete previous search results
			tell application "Finder" to set aliasList to every file of folder resultWindowPath
			repeat with anAlias in aliasList
				do shell script ("rm -rf " & quoted form of (POSIX path of (anAlias as Unicode text)))
			end repeat
			
			--** make the alias's
			repeat with aScript in foundScripts
				try
					tell application "Finder" to make new alias file at folder resultWindowPath to file aScript
				on error
					tell application "Database Events" to tell database dbName
						tell (first record whose name = aScript)
							set value of field field4Name to SkippedscriptText
							
						end tell
					end tell
					
					set frontApp to displayed name of (info for (path to frontmost application))
					tell application frontApp to display dialog "The following script could not be found and will not be included in your search results. And Marked as Skipped" & return & return & aScript & return & return & "Do you need to update your database?" buttons {"OK"} default button 1 with icon note
				end try
			end repeat
			
			-- open the Finder window
			tell application "Finder"
				activate
				open folder resultWindowPath
			end tell
			exit repeat
		else
			set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display alert "No results were found!" message "Please try different search terms." as warning
		end if
	end repeat
else --> (* UPDATE THE DATABASE *)
	-- opening parameters
	set newRecs to 0
	set updatedRecs to 0
	set deletedRecs to 0
	set inTime to current date
	tell application ScriptEditorApp to launch
	
	-- get a list of all the files in the scripts folder
	set allFiles to my allFiles_ofFolder(scriptsFolder)
	
	--  disable auto-quitting for database events and close all open databases
	tell application "Database Events"
		launch
		set quit delay to 0
	end tell
	
	-- create the necessary folders and open the database
	set updateDB to true
	tell application "Finder"
		if not (exists folder dbFolderPath) then make new folder at folder appSupportFolder with properties {name:dbFolderName}
		if (exists file dbPath) then -- check for the database and create/open it
			tell application "Database Events"
				open database (POSIX path of dbPath)
				set origRecordCount to count of records of database dbName
			end tell
		else
			tell application "Database Events"
				make new database with properties {name:dbName, location:dbFolderPath}
				set updateDB to false
			end tell
			set origRecordCount to 0
		end if
	end tell
	
	-- create or update the database
	if updateDB then -- update the database so checking for existing records takes place
		repeat with aFile in allFiles
			set fileInfo to (info for file aFile)
			if kind of fileInfo is "script" or file creator of fileInfo is "aplt" then -- check for a "script editor" file
				set {fileName, fileModDate} to {name of fileInfo, modification date of fileInfo}
				tell application "Database Events" to tell database dbName
					if (exists record aFile) then
						tell (first record whose name = aFile)
							set recordsModDate to value of field "modDate"
							if fileModDate > recordsModDate then -- use modification date to see if a record needs updating
								set scriptText to my get_scriptText(aFile)
								if scriptText is not "" then
									set updatedRecs to updatedRecs + 1
									set value of field field1Name to fileName
									set value of field field2Name to fileModDate
									set value of field field3Name to scriptText
									set value of field field4Name to notSkippedscriptText
									--set value of field field4Name to notSkippedscriptText -- new record now so not skipped
								end if
							end if
						end tell
					else -- a record doesn't exist for this script so create a new record for it
						set scriptText to my get_scriptText(aFile)
						if scriptText is not "" then
							set newRecs to newRecs + 1
							set thisRecord to make new record with properties {name:aFile}
							tell thisRecord
								make new field with properties {name:field1Name, value:fileName}
								make new field with properties {name:field2Name, value:fileModDate}
								make new field with properties {name:field3Name, value:scriptText}
								make new field with properties {name:field4Name, value:notSkippedscriptText} -- new record  not skipped
							end tell
						end if
					end if
				end tell
			end if
		end repeat
		
		-- get a list of the non-existent records, i.e. scripts in the database that are no longer found in the Finder
		set skipped_count to 0
		tell application "Database Events" to tell database dbName
			
			
			save
			set SkipList to {}
			set recordCount to count of records
			
			repeat with i from 1 to recordCount
				set thisPath to value of field "name" of record i
				set thisSkipcheck to value of field "skip" of record i
				tell application "Finder"
					if not (exists file thisPath) then
						set end of SkipList to thisPath
					end if
				end tell
				
			end repeat
			if SkipList is not {} then
				repeat with i from 1 to count of SkipList
					set this_rec to item i of SkipList
					tell (first record whose name = this_rec)
						
						set value of field field4Name to SkippedscriptText
						set skipped_count to skipped_count + 1
					end tell
				end repeat
			end if
			---
			(* 	
			set recordCount to count of records
			repeat with i from 1 to recordCount
				set thisSkipcheck to value of field "skip" of record i
				log thisSkipcheck
				if thisSkipcheck is SkippedscriptText then set skipped_count to skipped_count + 0
			end repeat
			set skipped_count to skipped_count as string
			--
			
			
			-- remove non-existent records from the database
			if SkipList is not {} then
				repeat with i from 1 to number of items in SkipList
					set this_item to item i of sList
					delete record this_item
					set deletedRecs to deletedRecs + 1
				end repeat
			end if
			*)
		end tell
		
		
	else -- we're creating a new database so no checking of the records is necessary
		if bugcheck then say 1
		repeat with aFile in allFiles
			set fileInfo to (info for file aFile)
			if kind of fileInfo is "script" or file creator of fileInfo is "aplt" then -- check for a "script editor" file
				set scriptText to my get_scriptText(aFile)
				if scriptText is not "" then
					set {fileName, fileModDate} to {name of fileInfo, modification date of fileInfo}
					tell application "Database Events" to tell database dbName
						if bugcheck then say 2
						set newRecs to newRecs + 1
						set thisRecord to make new record with properties {name:aFile}
						tell thisRecord
							if bugcheck then say 3
							make new field with properties {name:field1Name, value:fileName}
							make new field with properties {name:field2Name, value:fileModDate}
							make new field with properties {name:field3Name, value:scriptText}
							make new field with properties {name:field4Name, value:notSkippedscriptText}
							if bugcheck then say 4
						end tell
					end tell
				end if
			end if
		end repeat
	end if
	
	-- clean up database events
	tell application "Database Events"
		tell database dbName
			if bugcheck then say 6
			save
			set recordCount to count of records
			if bugcheck then say 7
		end tell
	end tell
	
	-- notify user it's done updating the db and specifics of the process
	--set skipped_count to "?"
	set outTime to current date
	set totaltime to (outTime - inTime)
	set theTime to my secs_to_hms(totaltime)
	set frontApp to displayed name of (info for (path to frontmost application))
	set skipbutton to {"Finished"}
	if SkipList is not {} then
		set skipbutton to {"Show Skipped", "Finished"}
	end if
	
	tell application frontApp to display dialog "The database has been updated." & return & "Update time: " & theTime & return & return & "Old Number of Records in DB: " & origRecordCount & return & "new Number of Records in DB: " & recordCount & return & "Records  with files : " & (recordCount - skipped_count) & return & "Skipped Records : " & skipped_count & return & "Records Updated: " & updatedRecs & return & "Records New: " & newRecs buttons skipbutton default button 1 with icon 1
	
	
	set the button_pressed to the button returned of the result
	my showSkipped(button_pressed, SkipList, dbName, deletedRecs, frontApp)
	
	
end if

-- clean up database events
tell application "Database Events"
	tell database dbName
		if bugcheck then say 9
		save
		set recordCount to count of records
		if bugcheck then say 10
	end tell
	if bugcheck then say 11
	quit
end tell
(*=================== SUBROUTINES =====================*)
on showSkipped(button_pressed, SkipList, dbName, deletedRecs, frontApp)
	repeat until button_pressed is "Exit"
		if the button_pressed is "Show Skipped" then
			
			tell application frontApp to set theChosen to choose from list SkipList with prompt "Choose Record/s to Recompile or Delete" default items {item 1 of SkipList} OK button name "Actions" cancel button name "Exit" with multiple selections allowed
			if result is false then exit repeat
			log theChosen
			set still_To_Action to {}
			repeat with i from 1 to number of items in SkipList
				set this_skipitem to item i of SkipList
				if this_skipitem is not in theChosen then
					copy this_skipitem to end of still_To_Action
				end if
			end repeat
			set SkipList to still_To_Action
			tell application frontApp to display dialog "Choose Action for the selected Records." buttons {"Exit", "Delete", "Recompile"} default button 2 with icon 1
			set the button_pressed to the button returned of the result
			repeat with i from 1 to number of items in theChosen
				set this_rec to item i of theChosen
				tell application "Database Events" to tell database dbName
					if the button_pressed is "Delete" then
						
						
						delete record this_rec
						set deletedRecs to deletedRecs + 1
						
						
						
					else if the button_pressed is "Recompile" then
						log this_rec
						tell record this_rec to set thisText to value of field "scriptText"
						tell record this_rec to set thisName to value of field "name"
						
						
						set thisName to do shell script "basename " & quoted form of (POSIX path of thisName)
						tell application "Script Editor"
							make document with properties {name:thisName, text:thisText}
						end tell
					else
						exit repeat
					end if
				end tell
			end repeat
		else
			exit repeat
		end if
	end repeat
end showSkipped
on get_scriptText(theScript)
	tell application ScriptEditorApp
		try
			open theScript
			set scriptText to text of document 1
		on error
			set scriptText to ""
		end try
		try
			close document 1
		end try
	end tell
	return scriptText
end get_scriptText

on secs_to_hms(the_secs)
	if the_secs is less than 360000 then
		set hr to text 2 thru 3 of ((100 + the_secs div hours) as string)
		set min to text 2 thru 3 of ((100 + the_secs mod hours div minutes) as string)
		set sec to text 2 thru 3 of ((100 + the_secs mod minutes div 1) as string)
		set fraction to text 2 thru 3 of ((100 + the_secs mod 1 * 100) as string)
		return hr & ":" & min & ":" & sec & "." & fraction
	else
		return false
	end if
end secs_to_hms

on allFiles_ofFolder(aFolder)
	set searchFolder to aFolder as string
	set everyFile to {}
	tell application "Finder"
		try -- there's an error if nothing is in the folder when you get entire contents
			set tempVar to files of entire contents of folder searchFolder
			if (count of tempVar) is 0 then -- answer is 0 when there's only 1 item???
				set end of everyFile to tempVar as string
			else
				repeat with i from 1 to (count of tempVar)
					set end of everyFile to (item i of tempVar) as string
				end repeat
			end if
		end try
	end tell
	return everyFile
end allFiles_ofFolder

Hi Mark, good to see you back. :slight_smile:

I checked out the script and it works pretty well except for a few comments I listed below. I’m still not convinced of the need for keeping deleted scripts in the database. I’m still deciding in my own mind if that’s a capability I want. It’s an interesting idea but I’m not sure I’ll use it yet. But I’ll certainly work with you to perfect it and in the end we’ll have a choice of the capabilities we want… which is a good thing.

Here’s my comments after using your changes.

When creating a new database:
I got errors. The ending dialog box which shows the results of the update process was missing 2 variables. The fix was to add the following under the “opening parameters” section under the “update the database” part of the code.
Set skiplist to {}
Set skipped_count to 0

When searching:
If my search terms are found in a skipped script then I need an option to recompile the script. Now it only tells me that the script is missing but that’s when I would want to recompile it. Now the only time I can recompile a script is when I’m updating the database.

A thought about a possible error:
Suppose I add a new script to my scripts folder, and it has the same name as a script I have skipped in my database, what happens? Right now what happens is that the “skipped” record gets overwritten with the new scripts text but there is not alert message telling me I’m about to overwrite one of my skipped records. I could be accidentally losing valuable data that I wanted to keep.

Hi regulus6633,

Boy that’s a lot to chew over, my head is hurting… :o :slight_smile:

Try this

One thing I notice is.
How would you handle file that are older than a record or a skipped record, but have been moved into the files folder.

if fileModDate < recordsModDate then

Cheers

(* This script is used to help you search the contents of your applescripts. You can either update or search the database *)

(*  It basically allows you to search your scripts by their contents much like Spotlight allows you to search your files by their contents. It works by creating a database of the code from your scripts found in your user "Scripts" folder. Initially each script is opened in Script Editor and the code is copied from the script into the database. Once the database is created then you can perform searches for code snippets and the scripts containing those snippets are presented to you in the Finder. You will need to update your database as changes occur to your script code, or as scripts are added/deleted from your Scripts folder. *)

(* Searching the database: A dialog box is presented where you input your search terms. There are 2 types of searches you can perform using the search terms: 1) "As One Word" will search for scripts that contain all of the search terms next to each other, and 2) "Individual Words" finds scripts that contain all of the search terms, but the terms do not have to be next to each other. Just separate your search terms with spaces, no special characters or punctuation is needed. The results of the database search are presented in a Finder window. The window is populated with alias files to the original scripts found via the search. *)

(* Updating the database: This updates/creates the script database using "database events". The database is saved in your user's "application support" folder in a folder called "Script Search". This takes time so be patient. You will be notified when the process is complete. Do not use the "Script Editor" application during this time. *)

property ScriptEditorApp : "Script Editor"
property dbName : "scriptDB"
property dbFolderName : "Script Search"
property appSupportFolder : path to application support folder from user domain as Unicode text
property dbFolderPath : appSupportFolder & dbFolderName
property dbPath : appSupportFolder & dbFolderName & ":" & dbName & ".dbev"
property scriptsFolder : path to scripts folder from user domain as Unicode text
property resultWindowName : "Found Scripts"
property resultWindowPath : appSupportFolder & dbFolderName & ":" & resultWindowName
property searchTermsBox : ""
property field1Name : "fileName"
property field2Name : "modDate"
property field3Name : "scriptText"
property field4Name : "skip"
property SkippedscriptText : "Skipped"
property notSkippedscriptText : "notSkipped"
property bugcheck : false

tell application "System Events"
	set frontApp to name of the first process whose frontmost is true and background only is false
end tell
global SkipList, frontApp, button_pressed, overwrite
set deletedRecs to {}
-- database events require at least MacOSX 10.4
tell (system attribute "sysv") to set vSys to (("1" & it mod 4096 div 256) as string) & "." & it mod 256 div 16 & "." & it mod 16
if vSys < "10.4" then
	display dialog "This script requires the installation of Mac OS X 10.4 or higher." buttons {"OK"} default button 1 with icon 2
	return
end if


-- decide whether to search or update the db
--set frontApp to displayed name of (info for (path to frontmost application))

tell application frontApp to display dialog "Search or Update the Database?" & return & return & "Note: the update process takes time so please be patient. You will be alerted when the update is finished. Do not use the \"Script Editor\" application during the update process." buttons {"Cancel", "Update", "Search"} default button 3 with icon note
set button_returned to button returned of the result

if button_returned is "Search" then --> (* SEARCH THE DATABASE *)
	-- check for required files and folders
	tell application "Finder"
		if not (exists file dbPath) then
			--set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display dialog "The Script Database does not exist! Please create the database before performing a search." buttons {"OK"} default button 1 with icon stop
			return
		end if
		if not (exists folder resultWindowPath) then make new folder at folder dbFolderPath with properties {name:resultWindowName}
	end tell
	
	repeat
		-- get the search terms
		repeat
			--set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display dialog "Enter your search terms:" default answer searchTermsBox with icon note buttons {"Cancel", "As One Word", "Individual Words"} default button 3 with title "Script Search"
			set {text_entered, button_pressed} to {text returned, button returned} of the result
			if text_entered is not "" then
				set searchTermsBox to text_entered
				exit repeat
			end if
		end repeat
		
		-- make them into a list according to button pressed
		if button_pressed is "As One Word" then
			set searchTerms to {text_entered}
		else
			set searchTerms to words of text_entered
		end if
		
		-- conduct the search
		set foundScripts to {}
		set Skipped to {}
		tell application "Database Events"
			launch
			open database (POSIX path of dbPath)
			tell database dbName
				repeat with i from 1 to (count of records)
					set theCheck to false
					tell record i
						set scriptPath to value of field "name"
						set scriptName to value of field field1Name
						set scriptText to value of field field3Name
						set Skippedscript to value of field field4Name
						repeat with sw in searchTerms
							if scriptText contains sw or scriptName contains sw then
								set theCheck to true
							else
								set theCheck to false
								exit repeat
							end if
						end repeat
						if theCheck then
							if Skippedscript is SkippedscriptText then
								set end of Skipped to scriptPath
							end if
							
							set end of foundScripts to scriptPath
						end if
					end tell
				end repeat
			end tell
		end tell
		
		-- clean up database events
		--tell application "Database Events" to quit
		
		-- create alias's to the results in the result window
		if foundScripts is not {} then
			-- delete previous search results
			tell application "Finder" to set aliasList to every file of folder resultWindowPath
			repeat with anAlias in aliasList
				do shell script ("rm -rf " & quoted form of (POSIX path of (anAlias as Unicode text)))
			end repeat
			
			--** make the alias's
			repeat with aScript in foundScripts
				try
					tell application "Finder" to make new alias file at folder resultWindowPath to file aScript
				on error
					tell application "Database Events" to tell database dbName
						tell (first record whose name = aScript)
							set value of field field4Name to SkippedscriptText
							if aScript is not in Skipped then copy aScript to end of Skipped
						end tell
					end tell
					--**__		
					
				end try
			end repeat
			if Skipped is not {} then
				set SkipList to Skipped
				--set frontApp to displayed name of (info for (path to frontmost application))
				tell application frontApp to display dialog "Some scripts or script could not be found and will not be included in your search results, and Marked as Skipped" & return & return & SkipList & return & return & "Do you want to view them with the Option to Recompile them now?" buttons {"Recompile script", "Continue"} default button 1 with icon note
				set the button_pressed to the button returned of the result
				my showSkipped(button_pressed, SkipList, dbName, deletedRecs, frontApp)
				
			end if
			
			
			
			-- open the Finder window
			tell application "Finder"
				activate
				open folder resultWindowPath
			end tell
			exit repeat
		else
			--set frontApp to displayed name of (info for (path to frontmost application))
			tell application frontApp to display alert "No results were found!" message "Please try different search terms." as warning
		end if
	end repeat
else --> (* UPDATE THE DATABASE *)
	-- opening parameters
	set newRecs to 0
	set updatedRecs to 0
	set deletedRecs to 0
	set SkipList to {}
	set skipped_count to 0
	set inTime to current date
	tell application ScriptEditorApp to launch
	
	-- get a list of all the files in the scripts folder
	set allFiles to my allFiles_ofFolder(scriptsFolder)
	
	--  disable auto-quitting for database events and close all open databases
	tell application "Database Events"
		launch
		set quit delay to 0
	end tell
	
	-- create the necessary folders and open the database
	set updateDB to true
	tell application "Finder"
		if not (exists folder dbFolderPath) then make new folder at folder appSupportFolder with properties {name:dbFolderName}
		if (exists file dbPath) then -- check for the database and create/open it
			tell application "Database Events"
				open database (POSIX path of dbPath)
				set origRecordCount to count of records of database dbName
			end tell
		else
			tell application "Database Events"
				make new database with properties {name:dbName, location:dbFolderPath}
				set updateDB to false
			end tell
			set origRecordCount to 0
		end if
	end tell
	
	-- create or update the database
	if updateDB then -- update the database so checking for existing records takes place
		repeat with aFile in allFiles
			set fileInfo to (info for file aFile)
			if kind of fileInfo is "script" or file creator of fileInfo is "aplt" or type identifier of fileInfo is "com.apple.applescript.text" then -- check for a "script editor" file
				set {fileName, fileModDate} to {name of fileInfo, modification date of fileInfo}
				tell application "Database Events" to tell database dbName
					if (exists record aFile) then
						tell (first record whose name = aFile)
							
							set thisSkipcheck to value of field "skip"
							set recordsModDate to value of field "modDate"
							if fileModDate > recordsModDate then 
								set overwrite to true
								log overwrite
								if thisSkipcheck is SkippedscriptText then -- checking so as not to overwrite a skipped script by mistake
									--set frontApp to displayed name of (info for (path to frontmost application))
									my skippdialog(frontApp, aFile)
									--my showSkipped(button_pressed, SkipList, dbName, deletedRecs, frontApp)
								end if
								-- use modification date to see if a record needs updating
								set scriptText to my get_scriptText(aFile)
								if scriptText is not "" and overwrite is true then
									log overwrite
									set updatedRecs to updatedRecs + 1
									set value of field field1Name to fileName
									set value of field field2Name to fileModDate
									set value of field field3Name to scriptText
									set value of field field4Name to notSkippedscriptText
									--set value of field field4Name to notSkippedscriptText -- new record now so not skipped
								end if
							end if
						end tell
					else -- a record doesn't exist for this script so create a new record for it
						set scriptText to my get_scriptText(aFile)
						if scriptText is not "" then
							set newRecs to newRecs + 1
							set thisRecord to make new record with properties {name:aFile}
							tell thisRecord
								make new field with properties {name:field1Name, value:fileName}
								make new field with properties {name:field2Name, value:fileModDate}
								make new field with properties {name:field3Name, value:scriptText}
								make new field with properties {name:field4Name, value:notSkippedscriptText} -- new record  not skipped
							end tell
						end if
					end if
				end tell
			end if
		end repeat
		
		-- get a list of the non-existent records, i.e. scripts in the database that are no longer found in the Finder
		set skipped_count to 0
		tell application "Database Events" to tell database dbName
			
			
			save
			set SkipList to {}
			set recordCount to count of records
			
			repeat with i from 1 to recordCount
				set thisPath to value of field "name" of record i
				set thisSkipcheck to value of field "skip" of record i
				tell application "Finder"
					if not (exists file thisPath) then
						set end of SkipList to thisPath
					end if
				end tell
				
			end repeat
			if SkipList is not {} then
				repeat with i from 1 to count of SkipList
					set this_rec to item i of SkipList
					tell (first record whose name = this_rec)
						
						set value of field field4Name to SkippedscriptText
						set skipped_count to skipped_count + 1
					end tell
				end repeat
			end if
			---
			(* 	
			set recordCount to count of records
			repeat with i from 1 to recordCount
				set thisSkipcheck to value of field "skip" of record i
				log thisSkipcheck
				if thisSkipcheck is SkippedscriptText then set skipped_count to skipped_count + 0
			end repeat
			set skipped_count to skipped_count as string
			--
			
			
			-- remove non-existent records from the database
			if SkipList is not {} then
				repeat with i from 1 to number of items in SkipList
					set this_item to item i of sList
					delete record this_item
					set deletedRecs to deletedRecs + 1
				end repeat
			end if
			*)
		end tell
		
		
	else -- we're creating a new database so no checking of the records is necessary
		if bugcheck then say 1
		repeat with aFile in allFiles
			set fileInfo to (info for file aFile)
			if kind of fileInfo is "script" or file creator of fileInfo is "aplt" or type identifier of fileInfo is "com.apple.applescript.text" then -- check for a "script editor" file
				set scriptText to my get_scriptText(aFile)
				if scriptText is not "" then
					set {fileName, fileModDate} to {name of fileInfo, modification date of fileInfo}
					tell application "Database Events" to tell database dbName
						if bugcheck then say 2
						set newRecs to newRecs + 1
						set thisRecord to make new record with properties {name:aFile}
						tell thisRecord
							if bugcheck then say 3
							make new field with properties {name:field1Name, value:fileName}
							make new field with properties {name:field2Name, value:fileModDate}
							make new field with properties {name:field3Name, value:scriptText}
							make new field with properties {name:field4Name, value:notSkippedscriptText}
							if bugcheck then say 4
						end tell
					end tell
				end if
			end if
		end repeat
	end if
	
	-- clean up database events
	tell application "Database Events"
		tell database dbName
			if bugcheck then say 6
			save
			set recordCount to count of records
			if bugcheck then say 7
		end tell
	end tell
	
	-- notify user it's done updating the db and specifics of the process
	--set skipped_count to "?"
	set outTime to current date
	set totaltime to (outTime - inTime)
	set theTime to my secs_to_hms(totaltime)
	--set frontApp to displayed name of (info for (path to frontmost application))
	set skipbutton to {"Finished"}
	if SkipList is not {} then
		set skipbutton to {"Show Skipped", "Finished"}
	end if
	
	tell application frontApp to display dialog "The database has been updated." & return & "Update time: " & theTime & return & return & "Old Number of Records in DB: " & origRecordCount & return & "new Number of Records in DB: " & recordCount & return & "Records  with files : " & (recordCount - skipped_count) & return & "Skipped Records : " & skipped_count & return & "Records Updated: " & updatedRecs & return & "Records New: " & newRecs buttons skipbutton default button 1 with icon 1
	
	
	set the button_pressed to the button returned of the result
	my showSkipped(button_pressed, SkipList, dbName, deletedRecs, frontApp)
	
	
end if

-- clean up database events
tell application "Database Events"
	tell database dbName
		if bugcheck then say 9
		save
		set recordCount to count of records
		if bugcheck then say 10
	end tell
	if bugcheck then say 11
	quit
end tell
(*=================== SUBROUTINES =====================*)
on skippdialog(frontApp, aFile)
	tell application frontApp to display dialog "The script " & return & ¬
		" is marked as skipped, A newer file with the same name exist," & return & return & aFile & return & return & "Do you want to view the  record as a recompiled script first" buttons {"View Script", "Continue"} default button 1 with icon note
	set the button_pressed to the button returned of the result
	
	if the button_pressed is "View script" then
		set this_rec to aFile
		my recompile(this_rec)
		set overwrite to false
		log overwrite
	else
		-- action for 2nd button goes here
	end if
end skippdialog
on showSkipped(button_pressed, SkipList, dbName, deletedRecs, frontApp)
	repeat until button_pressed is "Exit"
		if the button_pressed is "Show Skipped" or the button_pressed is "Recompile script" then
			
			tell application frontApp to set theChosen to choose from list SkipList with prompt "Choose Record/s to Recompile or Delete" default items {item 1 of SkipList} OK button name "Actions" cancel button name "Exit" with multiple selections allowed
			if result is false then exit repeat
			log theChosen
			set still_To_Action to {}
			repeat with i from 1 to number of items in SkipList
				set this_skipitem to item i of SkipList
				if this_skipitem is not in theChosen then
					copy this_skipitem to end of still_To_Action
				end if
			end repeat
			set SkipList to still_To_Action
			tell application frontApp to display dialog "Choose Action for the selected Records." buttons {"Exit", "Delete", "Recompile"} default button 2 with icon 1
			set the button_pressed to the button returned of the result
			repeat with i from 1 to number of items in theChosen
				set this_rec to item i of theChosen
				tell application "Database Events" to tell database dbName
					if the button_pressed is "Delete" then
						
						
						delete record this_rec
						set deletedRecs to deletedRecs + 1
						
						
						
					else if the button_pressed is "Recompile" then
						log this_rec
						my recompile(this_rec)
						
					else
						exit repeat
					end if
				end tell
			end repeat
		else
			exit repeat
		end if
	end repeat
end showSkipped
on recompile(this_rec)
	
	tell application "Database Events" to tell database dbName
		tell record this_rec to set thisText to value of field "scriptText"
		tell record this_rec to set thisName to value of field "name"
		
		
		set thisName to do shell script "basename " & quoted form of (POSIX path of thisName)
		tell application "Script Editor"
			make document with properties {name:thisName, text:thisText}
		end tell
	end tell
end recompile

on get_scriptText(theScript)
	tell application ScriptEditorApp
		try
			open theScript
			set scriptText to text of document 1
		on error
			set scriptText to ""
		end try
		try
			close document 1
		end try
	end tell
	return scriptText
end get_scriptText

on secs_to_hms(the_secs)
	if the_secs is less than 360000 then
		set hr to text 2 thru 3 of ((100 + the_secs div hours) as string)
		set min to text 2 thru 3 of ((100 + the_secs mod hours div minutes) as string)
		set sec to text 2 thru 3 of ((100 + the_secs mod minutes div 1) as string)
		set fraction to text 2 thru 3 of ((100 + the_secs mod 1 * 100) as string)
		return hr & ":" & min & ":" & sec & "." & fraction
	else
		return false
	end if
end secs_to_hms

on allFiles_ofFolder(aFolder)
	set searchFolder to aFolder as string
	set everyFile to {}
	tell application "Finder"
		try -- there's an error if nothing is in the folder when you get entire contents
			set tempVar to files of entire contents of folder searchFolder
			if (count of tempVar) is 0 then -- answer is 0 when there's only 1 item???
				set end of everyFile to tempVar as string
			else
				repeat with i from 1 to (count of tempVar)
					set end of everyFile to (item i of tempVar) as string
				end repeat
			end if
		end try
	end tell
	return everyFile
end allFiles_ofFolder