Previous  |  Main  |  Next
AppleScript Logo

Multi-File Search with Grep

Script for: BBEdit
Copyright: Matthias Steffens, use at your own risk!
Description: Searches for the entered text within all files of the chosen folder.
The search folder and the search string will be remembered.
Search results are displayed in a BBEdit-SearchResults window or,
alternatively, a search hit log file can be built which contains path,
line no. and context of the respective search hits.
Necessary: None
Download: MultiFileSearch_v1.2.hqx (for BBEdit 6.x)
MultiFileSearch_v1.1.hqx (for BBEdit 5.x)
History: v1.2  -  works now with BBEdit 6.x (but not with BBEdit 5.x anymore -- use v1.1 together with BBEdit 5.x)
v1.1  -  features the following code improvements:
  • the search routine was rewritten so that one routine would fit all situations
  • when building a log file, canceling the process will now return those items
    that have been processed already
  • the layout of the log file was refined
v1.0  -  original script posted at this site
The Script:
property TheFolderToSearch : 0
property SearchPattern : "Enter a search string !"
property CaseSensitive : {SearchCaseSensitive:false, DisplayString:"case insensitive", ButtonText:"case sensitive"}
property SelectedButton : "SearchResults Window"

global screenSize, ArrangeSearchResultsWindow

-- change the following variable to false if you do not wish to get the Search Results Window to get zoomed & soft wrapped:
set ArrangeSearchResultsWindow to true

tell application "Finder"
	try
		copy the bounds of desktop's window to screenSize
		if not (exists (file TheFolderToSearch)) then
			my GetSearchFolder()
		else
			my SearchDialog()
		end if
	on error ErrText number errNo
		if errNo is not -128 then -- if user didn't press 'cancel':
			if errNo is 32768029 then -- "file not found"
				my GetSearchFolder()
			else -- present an error message
				display dialog "The following error has occurred:" & return & return & ErrText & return & ¬
					"(Error Code: " & errNo & ")" with icon caution buttons {"OK"} default button 1
			end if
		end if
	end try
end tell


on SearchDialog()
	set DialogResult to display dialog ¬
		"The current search folder is: " & return & "\"" & TheFolderToSearch & "\"" & return & return & ¬
		"Search for the following string with grep (" & (DisplayString of CaseSensitive) & "):" default answer SearchPattern with icon note ¬
		buttons {(ButtonText of CaseSensitive), "Change Folder|Cancel", "OK"} default button 3
	
	set SearchPattern to text returned of DialogResult
	
	if button returned of DialogResult is "Change Folder|Cancel" then
		my GetSearchFolder()
	end if
	
	if button returned of DialogResult is (ButtonText of CaseSensitive) then
		if (ButtonText of CaseSensitive) is "case insensitive" then
			set CaseSensitive to {SearchCaseSensitive:false, DisplayString:"case insensitive", ButtonText:"case sensitive"}
		else -- (ButtonText of CaseSensitive) is "case sensitive"
			set CaseSensitive to {SearchCaseSensitive:true, DisplayString:"case sensitive", ButtonText:"case insensitive"}
		end if
		my SearchDialog()
	end if
	
	if button returned of DialogResult is "OK" then
		set dialogResult2 to display dialog "Display search hits in a BBEdit SearchResults Window or " & ¬
			"write all hits to a Log Window ?" with icon note buttons {"Cancel", "Make Log Window", "SearchResults Window"} default button SelectedButton
		if button returned of dialogResult2 is not "Cancel" then
			set SelectedButton to button returned of dialogResult2 -- save chosen button as default button for the next run
			if SelectedButton is "Make Log Window" then
				my DoSearch(false, true)
			else if SelectedButton is "SearchResults Window" then
				my DoSearch(true, false)
			end if
		end if
	end if
end SearchDialog


on DoSearch(DisplayResultsWindow, ReturnResults)
	tell application "BBEdit 6.0"
		activate
		set TheHitList to find SearchPattern searching in TheFolderToSearch options {search mode:grep, case sensitive:(SearchCaseSensitive of CaseSensitive), match words:false, showing results:DisplayResultsWindow, returning results:ReturnResults}
		
		if not found of TheHitList then -- nothing found
			beep 2
		else -- something was found
			if DisplayResultsWindow then
				if ArrangeSearchResultsWindow then -- (if not disabled) set properties of Search Results Window:
					tell window 1
						set bounds to {0, 41, item 3 of screenSize, item 4 of screenSize}
						set soft wrap text to true
					end tell
				end if
			end if
			if ReturnResults then
				my MakeLog(found matches of TheHitList)
			end if
		end if
	end tell
end DoSearch


on MakeLog(FoundMatches)
	tell application "BBEdit 6.0"
		set ct to count of FoundMatches
		
		if (count of SearchPattern) > 14 then -- truncate the search pattern before writing it to the window title
			set SnippedSearchPattern to ((text 1 thru 13 of SearchPattern) & "…")
		else
			set SnippedSearchPattern to SearchPattern
		end if
		
		make new window with properties {bounds:{0, 41, (item 3 of screenSize), (item 4 of screenSize)}, name:"SearchLog for \"" & SnippedSearchPattern & "\""}
		
		if ct > 1 then
			set thePlural to "es"
		else
			set thePlural to ""
		end if
		
		set contents of window 1 to ((ct & " match" & thePlural & " found for \"" & SearchPattern & ¬
			"\" (" & (DisplayString of CaseSensitive) & "):") as string) & return & return & ¬
			"Note: Selecting the path and pressing \"cmd-D\" (\"cmd-opt-D\") will open (reveal) the file." & ¬
			return & return & return & "please wait…" & return & "(press cmd-. to cancel)"
		
		set ResultsForDisplayList to {}
		set WarningUponCancel to ""
		repeat with i from 1 to ct
			try
				set theItem to item i of FoundMatches
				copy (("Line|Path:" & tab & result_line of theItem & " | " & ((result_file of theItem) as text) & return & ¬
					"Context:" & tab & "\"" & message of theItem & "\"") & return as text) to end of ResultsForDisplayList
			on error
				set WarningUponCancel to "• PROCESSING OF HIT LIST WAS CANCELED! THEREFORE ONLY SOME HITS COULD BE DISPLAYED! •" & return & return & return
				exit repeat
			end try
		end repeat
		
		set old_delims to AppleScript's text item delimiters
		set AppleScript's text item delimiters to return
		copy ResultsForDisplayList as text to ResultsForDisplayList
		set AppleScript's text item delimiters to old_delims
		
		tell window 1
			set (characters -36 thru -1) to ""
			set contents to contents & WarningUponCancel & ResultsForDisplayList
			select insertion point before character 1
		end tell
	end tell
end MakeLog


on GetSearchFolder()
	set TheFolderToSearch to (choose folder with prompt "Choose a search folder:")
	my SearchDialog()
end GetSearchFolder

 


Contact: Matthias Steffens  |  Previous  |  Main  |  Next  |  Last Updated: 24-Sep-00