Modify script to output an RTF text file

Hi, I found this working script below by member Rich Cohen of macscripter.net from 2012. The script produces a list of all the contents of a folder, including sub folders, as a plain .txt file. I have 2 questions:

  1. Can this script below be modified to output the list as an RTF text file?

This is an example of the output list :

Inventory 			     (main folder)
Warehouse A Inventory    (subfolder)		
Stock List			     (files)
Equipment List
Supplies List
Warehouse B Inventory    (subfolder)
Stock List			      (files)
Equipment List
Supplies List
Warehouse C Inventory   (subfolder)
Stock List			     (files)
Equipment List
Supplies List
  1. Assuming the file is an RTF text file and because the sub folders are hard to pick out, is it possible to search the document with an Applescript and
    select “Warehouse A Inventory” text and change the color to blue, select “Warehouse B Inventory” text and change the color to blue, etc?

Thanks in advance for any help with this project.

property file_id : null

set this_folder to choose folder with prompt "Choose the root folder"
set log_file_path to (path to desktop as string) & "Folder Inventory.txt"
set file_id to open for access file log_file_path with write permission
write ("Start " & (current date) & return) to file_id starting at eof
my do_subfolders(this_folder, "")
write (return & return) to file_id starting at eof
close access file_id
say "finished"
return

on do_subfolders(this_folder, name_prefix)
   tell application "Finder"
       log name_prefix & (name of this_folder) as string
       write (return & name_prefix & (name of this_folder) as string) to file_id starting at eof
       set file_list to every file in this_folder
       repeat with this_file in file_list
           log name_prefix & " " & (name of this_file) as string
           write (return & name_prefix & " " & (name of this_file) as string) to file_id starting at eof
       end repeat
       set folder_list to every folder in this_folder
       repeat with this_subfolder in folder_list
           my do_subfolders(this_subfolder, " " & name_prefix)
       end repeat
   end tell
end do_subfolders

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

This isn’t exactly what you asked for, but could probably be adapted. It requires OS X 1010 or later, and lists the frontmost Finder window.

File names are in blue, folder names in red, with the rest of the path in light gray. The resulting .rtf file is saved in your tmp folder, and opened in your default editor for .rtf files. Change the value of the fullPaths property depending on whether you want to see the full paths or not. It’s best run from a scripts menu, like the built-in one or FastScripts.

use AppleScript version "2.4" -- 10.10
use scripting additions
use framework "Foundation"
use framework "AppKit"
property fullPaths : false -- set to true to list full paths rather than relative paths

tell application "Finder"
	try
		set theTarget to target of Finder window 1 as alias
	on error
		error number -128
	end try
end tell

-- make URL
set targetURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of theTarget)
if not fullPaths then set targetLength to (targetURL's |path|()'s |length|()) + 1 -- use to trim paths
-- set up destination path
set tempPath to POSIX path of (path to temporary items)
set destURL to ((current application's |NSURL|'s fileURLWithPath:tempPath)'s URLByAppendingPathComponent:(targetURL's lastPathComponent()))'s URLByAppendingPathExtension:"rtf"
-- set up paragraph style for line-spacing
set parStyle to current application's NSParagraphStyle's defaultParagraphStyle()'s mutableCopy()
parStyle's setLineHeightMultiple:1.3
-- set up font
set theFont to current application's NSFont's fontWithName:"Menlo-Regular" |size|:14.0
-- set up colors
set fileColor to current application's NSDictionary's dictionaryWithObject:(current application's NSColor's blueColor()) forKey:(current application's NSForegroundColorAttributeName)
set folderColor to current application's NSDictionary's dictionaryWithObject:(current application's NSColor's redColor()) forKey:(current application's NSForegroundColorAttributeName)
set lighterColor to current application's NSDictionary's dictionaryWithObject:(current application's NSColor's lightGrayColor()) forKey:(current application's NSForegroundColorAttributeName)
-- define base style from above
set baseStyle to current application's NSMutableDictionary's dictionaryWithObjects:{theFont, parStyle, -0.1} forKeys:{current application's NSFontAttributeName, current application's NSParagraphStyleAttributeName, (current application's NSExpansionAttributeName)}
baseStyle's addEntriesFromDictionary:lighterColor
set styledLinefeed to current application's NSAttributedString's alloc()'s initWithString:linefeed attributes:baseStyle

-- set up styled string
set theStyledString to current application's NSMutableAttributedString's new()
theStyledString's beginEditing()
set theString to current application's NSString's stringWithFormat_("Listing of %@, %@" & linefeed & linefeed, targetURL's |path|(), ((current date) as text))
set styledPath to (current application's NSAttributedString's alloc()'s initWithString:theString attributes:baseStyle)
theStyledString's appendAttributedString:styledPath
theStyledString's addAttributes:folderColor range:{0, theString's |length|()}
-- get all items in folder
set dirKey to current application's NSURLIsDirectoryKey
set packageKey to current application's NSURLIsPackageKey
set theFileManager to current application's NSFileManager's defaultManager()
set theEnumerator to theFileManager's enumeratorAtURL:targetURL includingPropertiesForKeys:{dirKey, packageKey} options:((current application's NSDirectoryEnumerationSkipsHiddenFiles) + (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer)) errorHandler:(missing value)
repeat with anItem in theEnumerator's allObjects()
	-- flag for file status
	set isFile to true
	-- is it a directory?
	set {theResult, theValue, theError} to (anItem's getResourceValue:(reference) forKey:dirKey |error|:(reference))
	if theValue as boolean then
		-- is it a package?
		set {theResult, theValue, theError} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(reference))
		if not theValue as boolean then
			set isFile to false
		end if
	end if
	-- add styled path 
	if fullPaths then
		set styledPath to (current application's NSAttributedString's alloc()'s initWithString:(anItem's |path|()) attributes:baseStyle)
	else
		set styledPath to (current application's NSAttributedString's alloc()'s initWithString:(anItem's |path|()'s substringFromIndex:targetLength) attributes:baseStyle)
	end if
	(theStyledString's appendAttributedString:styledPath)
	-- style name differently depending on whether it's a folder or file
	set theLength to anItem's lastPathComponent()'s |length|()
	set fullLength to theStyledString's |length|()
	if isFile then
		(theStyledString's addAttributes:fileColor range:{fullLength - theLength, theLength})
	else
		(theStyledString's addAttributes:folderColor range:{fullLength - theLength, theLength})
	end if
	-- add linefeed
	(theStyledString's appendAttributedString:styledLinefeed)
end repeat
-- end editing of styled string
theStyledString's endEditing()

-- get RTF data, write it to file, then open the file
set docAtts to current application's NSDictionary's dictionaryWithObjects:{current application's NSRTFTextDocumentType} forKeys:{current application's NSDocumentTypeDocumentAttribute}
set theData to theStyledString's RTFFromRange:{0, theStyledString's |length|()} documentAttributes:(missing value)
theData's writeToURL:destURL atomically:true
current application's NSWorkspace's sharedWorkspace()'s openURL:destURL

Here are a couple of solutions.

The first’s a quick adaptation of the original script. Instead of being written directly to file, the text is opened in TextEdit, coloured, and saved:

global collector

main()

on main()
	set this_folder to choose folder with prompt "Choose the root folder"
	set log_file_path to (path to desktop as string) & "Folder Inventory.rtf"
	set collector to {}
	do_subfolders(this_folder, "")
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to return
	set log_text to collector as text
	set AppleScript's text item delimiters to astid
	tell application "TextEdit"
		activate
		set frontDoc to (make new document with properties {text:log_text})
	end tell
	set TEDefaults to (do shell script "defaults read -app TextEdit")
	if (TEDefaults contains "RichText = 0;") then
		tell application "System Events"
			set frontmost of application process "TextEdit" to true
			keystroke "t" using {command down, shift down}
		end tell
	end if
	tell application "TextEdit"
		set color of every paragraph of frontDoc where it contains "Warehouse" and it ends with "Inventory" & return to {0, 0, 65535}
		save frontDoc in file log_file_path
		-- close front document -- 'frontDoc' name reference not valid after save.
		-- quit
	end tell
	set collector to {}
	say "Finished"
end main

on do_subfolders(this_folder, name_prefix)
	tell application "Finder"
		set end of collector to name_prefix & (name of this_folder)
		set file_list to every file in this_folder
		repeat with this_file in file_list
			set end of collector to name_prefix & " " & (name of this_file)
		end repeat
		set folder_list to every folder in this_folder
		repeat with this_subfolder in folder_list
			my do_subfolders(this_subfolder, " " & name_prefix)
		end repeat
	end tell
end do_subfolders

And this one, like Shane’s, uses ASObjC. It doesn’t use TextEdit:

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
-- use framework "AppKit"

main()

on main()
	set this_folder to POSIX path of (choose folder with prompt "Choose the root folder")
	set log_file_path to POSIX path of ((path to desktop as text) & "Folder Inventory.rtf")
	
	set |⌘| to current application
	-- Convert the supplied root folder path to an NSURL.
	set rootURL to |⌘|'s class "NSURL"'s fileURLWithPath:(this_folder)
	-- Set up an NSFileManager enumerator to get the folder's "entire contents" (visible files and folders).
	set theFileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set theEnumerator to theFileManager's enumeratorAtURL:(rootURL) includingPropertiesForKeys:(missing value) options:((|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer)) errorHandler:(missing value)
	-- Get the (POSIX) paths to these contents as a mutable array and insert a header line and the root folder name at the beginning.
	set thePaths to (theEnumerator's allObjects()'s valueForKey:("path"))'s mutableCopy()
	tell thePaths to insertObject:(rootURL's lastPathComponent()) atIndex:(0)
	tell thePaths to insertObject:("Start " & (current date) & linefeed) atIndex:(0)
	-- Truncate the paths themselves, replacing the root path and any other container components with spaces to indent the names of the items.
	set truncationRegex to |⌘|'s class "NSString"'s stringWithString:("^" & this_folder & "|[^/]++/")
	repeat with i from 3 to (count thePaths)
		set thisPath to item i of thePaths
		set item i of thePaths to (thisPath's stringByReplacingOccurrencesOfString:(truncationRegex) withString:("  ") options:(|⌘|'s NSRegularExpressionSearch) range:({location:0, |length|:thisPath's |length|()}))
	end repeat
	-- Coerce the array to a single text using a linefeed as a delimiter.
	set thePaths to thePaths's componentsJoinedByString:(linefeed)
	-- Create a mutable attributed string from this text.
	set theStyledText to |⌘|'s class "NSMutableAttributedString"'s alloc()'s initWithString:(thePaths)
	-- Create a "blue" color object.
	set blue to |⌘|'s class "NSColor"'s colorWithCalibratedRed:(0.0) green:(0.0) blue:(1.0) alpha:(0.0)
	-- Find the ranges in the text of all lines consisting of indent-"Warehouse"-space(s)-non space(s)-space(s)-"Inventory".
	set warehouseInventoryRegex to |⌘|'s class "NSRegularExpression"'s regularExpressionWithPattern:("^ *Warehouse ++[^ ]++ ++Inventory$") options:(|⌘|'s NSRegularExpressionAnchorsMatchLines) |error|:(missing value)
	set warehouseInventoryRanges to (warehouseInventoryRegex's matchesInString:(thePaths) options:(0) range:({location:0, |length|:thePaths's |length|()}))'s valueForKey:("range")
	-- Apply the blue color to these ranges in the attributed string.
	repeat with thisRange in warehouseInventoryRanges
		tell theStyledText to addAttribute:(|⌘|'s NSForegroundColorAttributeName) value:(blue) range:(thisRange)
	end repeat
	-- Extract RTF data from the attribute string and save using a URL derived from the given log file path.
	set theRTFData to theStyledText's RTFFromRange:({location:0, |length|:theStyledText's |length|()}) documentAttributes:(missing value)
	set logFileURL to |⌘|'s class "NSURL"'s fileURLWithPath:(log_file_path)
	tell theRTFData to writeToURL:(logFileURL) atomically:(true)
	say "Finished"
end main

Thanks Shane and Thanks Nigel, you two are scripting wizards!!! Those scripts are terrific!!!

Mike.

Hi Shane, this is a great script, is very close to what I wanted. I probably didn’t ask the question correctly.
I have a couple changes to ask you about. The only font that works is “Menlo-Regular”. I replaced “Menlo-Regular” with “Comic Sans MS” in the script and got this:

RTFFromRange:{0, theStyledString’s |length|()} documentAttributes:(missing value) (this line highlighted in script)

error “-[NSNull fontDescriptor]: unrecognized selector sent to instance 0x7fff7a092030” number -10000 (in results)

I changed to other fonts also and got the same error. Did I change it wrong? I didn’t see any other reference to Menlo.

Also, I don’t need the path, only the Folder and Sub Folder Names, and the File Names.

Lastly, I was able to change to colors by changing the filecolor and foldercolor by name without any problem. Is there a list of NSColors Names? Does the script reference /system/library/colors to find the colorname, and/or are the colors limited to the same colors that “Tags”, in the menus use? How can more colors be added?

Thanks for all your help.
Mike.

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

You have to use the correct PostScript names for fonts. You can find out the correct names for your fonts using this:

use framework "Foundation"
use framework "AppKit"

current application's NSFontManager's sharedFontManager()'s availableFonts() as list

If you still want the indenting, change the lighter color to whiteColor.

Here: developer.apple.com/reference/appkit/nscolor?language=objc And if you look in Nigel’s second example, you’ll see how to create your own by specifying RGBA values.

I’ve realised that my AObjC script wasn’t including the header or the root folder name in the output, so I’ve edited it above to correct that. The indentation’s also deepened, the script’s now commented, and the bit lifted from Shane’s script isn’t so obvious. :wink:

@Nigel

As I’m not fond of spaces for indentations, I edited one instruction.

set item i of thePaths to (thisPath's stringByReplacingOccurrencesOfString:(truncationRegex) withString:("	") options:(|⌘|'s NSRegularExpressionSearch) range:({location:0, |length|:thisPath's |length|()}))

In the original version were two spaces between the double quotes
[format]withString:(" ")[/format]

I just replaced them by a tab character.
[format]withString:(" ")[/format]

Yvan KOENIG running El Capitan 10.11.6 in French (VALLAURIS, France) mercredi 14 septembre 2016 19:41:25

Hi Yvan.

Yes, that’s one possibility. The two spaces were just to make the indentation a bit clearer than the original one space without being too different from it. Otherwise the choice is entirely up to personal preference.

For a single tab or space, I’d probably use a ‘tab’ or '‘space’ constant in the code to clarify what was there. I would have prefered to use ‘tab’ instead of the literal tabs in this script, but with four concatenation operators needed as well, the regex became unreadable!

Hi Nigel, thanks for the reply and the script improvements. However, when i used your script the folders are not in blue. Also, I discovered that I described my example incorrectly as having sub folders all named the same. The enclosing folder and the sub folder have different names. I need the names of any folders present to be blue. There could be any number of sub folders. I’m sorry my example was unclear. This is a better representation:

Inventory          (main folder)        to be blue
  Folder X            (subfolder)          to be blue
Stock List               files)
Equipment List
Supplies List
 Folder Y              (subfolder)         to be blue
Stock List               (files)
Equipment List
Supplies List
 Folder Z               (subfolder)        to be blue
Stock List                (files)
Equipment List
Supplies List

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

Hi 1994firehawk.

No problem. I did see the earlier posting of your message and have been looking at the script again this evening:

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

main()

on main()
	-- set this_folder to POSIX path of (choose folder with prompt "Choose the root folder")
	set this_folder to "/volumes/files/inventory"
	set log_file_path to POSIX path of ((path to desktop as text) & "Folder Inventory.rtf")
	
	-- Ensure that the root path has the correct cases and a trailing slash.
	set this_folder to POSIX path of ((POSIX file this_folder) as alias)
	
	set |⌘| to current application
	set rootURL to |⌘|'s class "NSURL"'s fileURLWithPath:(this_folder)
	
	-- Set up an NSFileManager enumerator and get the folder's "entire contents" (visible files and folders as NSURLs).
	set theFileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set dirAndPackageKeys to |⌘|'s class "NSArray"'s arrayWithArray:({|⌘|'s NSURLIsDirectoryKey, |⌘|'s NSURLIsPackageKey})
	set theEnumerator to theFileManager's enumeratorAtURL:(rootURL) includingPropertiesForKeys:(dirAndPackageKeys) options:((|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer)) errorHandler:(missing value)
	set entireContents to theEnumerator's allObjects()
	
	-- Initialise an NSMutableAttributedString with the title line and two linefeeds.
	set styledText to |⌘|'s class "NSMutableAttributedString"'s alloc()'s initWithString:("Start " & (current date) & linefeed & linefeed)
	
	-- Make an attribute dictionary specifying blue as a foreground colour.
	set blue to |⌘|'s class "NSColor"'s colorWithCalibratedRed:(0.0) green:(0.0) blue:(1.0) alpha:(1.0)
	set blueText to |⌘|'s class "NSDictionary"'s dictionaryWithObject:(blue) forKey:(|⌘|'s NSForegroundColorAttributeName)
	
	-- Make an NSAttributedString with the root folder name and the blue foreground colour and append it to the NSMutableAttributedString.
	set thisAddition to |⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(rootURL's lastPathComponent) attributes:(blueText)
	tell styledText to appendAttributedString:(thisAddition)
	
	-- Work through the "entire contents", truncating and colouring the paths as required and appending them to the NSMutableAttributedString.
	set truncationRegex to |⌘|'s class "NSString"'s stringWithString:("^" & this_folder & "|[^/]++/")
	set LF to |⌘|'s class "NSString"'s stringWithString:(linefeed)
	repeat with thisItem in entireContents
		set thisPath to thisItem's |path|()
		-- Replace the root path and any other container components in this path with spaces, leaving just the indented name.
		set indentedName to (thisPath's stringByReplacingOccurrencesOfString:(truncationRegex) withString:("  ") options:(|⌘|'s NSRegularExpressionSearch) range:({location:0, |length|:thisPath's |length|()}))
		-- Put a linefeed on the front, ready for appending to the preceding text.
		set textToAppend to (LF's stringByAppendingString:(indentedName))
		
		-- Get this item's directory and package values. If they're the same, the item's either a file or a package, otherwise it's a folder.
		set dpDictionary to (thisItem's resourceValuesForKeys:(dirAndPackageKeys) |error|:(missing value))
		set treatingAsFile to ((dpDictionary's objectForKey:(|⌘|'s NSURLIsDirectoryKey))'s isEqual:(dpDictionary's objectForKey:(|⌘|'s NSURLIsPackageKey))) as boolean
		
		-- Create an NSAttributedString with the doctored path, coloured or not as appropriate, and append it to the mutable one.
		if (treatingAsFile) then
			set thisAddition to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(textToAppend))
		else
			set thisAddition to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(textToAppend) attributes:(blueText))
		end if
		tell styledText to appendAttributedString:(thisAddition)
	end repeat
	
	-- Set the required font if you don't like the default Helvetica Neue 12.0.
	set theFont to |⌘|'s class "NSFont"'s fontWithName:("Times New Roman") |size|:(12.0)
	if (theFont is not missing value) then
		tell styledText to addAttribute:(|⌘|'s NSFontAttributeName) value:(theFont) range:({location:0, |length|:its |length|()})
	end if
	
	-- Extract RTF data from the attribute string and save using a URL derived from the given log file path.
	set theRTFData to styledText's RTFFromRange:({location:0, |length|:styledText's |length|()}) documentAttributes:(missing value)
	set logFileURL to |⌘|'s class "NSURL"'s fileURLWithPath:(log_file_path)
	tell theRTFData to writeToURL:(logFileURL) atomically:(true)
	say "Finished"
end main

Edits: Cosmetic changes for clarity (!). Font setting added. Root folder POSIX path ensured compatible with script.

Hi again, I’m having a little problem and it’s probably something I’m doing wrong. When I use the script with the “Choose Folder” function the results are just the way I want them :

Inventory
Folder A
Folder Inventory.pdf
Folder B
Create with Selected File.scpt
Select File.scpt
Folder C
iBooks Open.scpt
Paypal.rtf
Untitled 4.scpt
Folder D
Book with Selected Files.workflow
ColorPicker.scpt
Folder Inventory v5.scpt
iPad Remove iCloud lock.rtf
Paypal.rtf
Select File.scpt
Selected File.scpt

I want to use your script as part of another script to automate the making of the RTF file. The path to the folder is: “volumes/files/inventory” .
When I change the this_folder path to : set this_folder to POSIX path of “/volumes/files/inventory” the results are:

inventory
/ Folder A
/ Folder Inventory.pdf
/ Folder B
/ Create with Selected File.scpt
/ Select File.scpt
/ Folder C
/ iBooks Open.scpt
/ Paypal.rtf
/ Untitled 4.scpt
/ Folder D
/ Book with Selected Files.workflow
/ ColorPicker.scpt
/ Folder Inventory v5.scpt
/ iPad Remove iCloud lock.rtf
/ Paypal.rtf
/ Select File.scpt
/ Selected File.scpt

Each line starts with a slash, Inventory is written with a lower case " i " , and the indent doubled. What would the correct script be to select a folder? Thanks a lot for your help. I hope this will be my last question on this.

Thanks, Mike

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

Hi Mike.

“/volumes/files/inventory” is already a POSIX path, so it shouldn’t have 'POSIX path of ’ in front of it.

The effects you were getting were caused by my assuming that the characters in the root path would be in the same cases as in the names of the items on the disk and that the path itself would end with a slash. The root folder name’s taken almost directly from the path and so is shown in the same case as in the path. The non-matching cases and the lack of a trailing slash meant the root path wasn’t being recognised at the beginnings of the found paths.

I’ve now conveniently fixed all this by inserting a line near the beginning to ensure that the root path matches the script’s assumptions. :slight_smile:

Let me know if there are still any problems.

Hi again Nigel, it looks like I’ll need one more little tweak. When I copied the script into a run Applescript window and tried to run it I got a Syntax Error. It worked fine in Script Editor. If I remark out the command it runs.

“Expected end of line but found property” with “value” highlighted.

set theFont to |⌘|'s class "NSFont"'s fontWithName:("Times New Roman") |size|:(12.0)
   if (theFont is not missing value) then
       tell styledText to addAttribute:(|⌘|'s NSFontAttributeName) value:(theFont) range:({location:0, |length|:its |length|()})
   end if

Thanks,
Mike.

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

Possibly you have an OSAX installed which uses the term ‘value’. Try putting bars round the term here.

set theFont to |⌘|'s class "NSFont"'s fontWithName:("Times New Roman") |size|:(12.0)
if (theFont is not missing value) then
	tell styledText to addAttribute:(|⌘|'s NSFontAttributeName) |value|:(theFont) range:({location:0, |length|:its |length|()})
end if

XMLLib.osax uses value.

[format]XMLFind‚v : select a child (or children) satisfying a simple criterion: the name of the XML element and/or the key and value of an attribute. XMLFind is a poor man’s XMLXPath suitable (and fast) for simple queries and is not aware of the namespace specifiers
XMLFind XMLRef : the parent where the search occurs
[name string] : the name of the element
[key string] : the key of the attribute
[value string] : the value of the attribute
[all occurrences boolean] : returns a list of all occurrences. Default : false
→ XMLRef : or a list of XMLRefs with all occurrences[/format]

[format]PlistMatch‚v : return a list of dictionaries containing a given key or a given (key, value) pair.
PlistMatch CFRef : an array containing dictionaries
key string : the key to match. For a more complex request, omit this parameter and provide the “using” parameter
[using string] : a selecting path (see PlistChild)
[value string, real, or boolean] : the requested value of the key
→ list of CFRef[/format]

Yvan KOENIG running El Capitan 10.11.6 in French (VALLAURIS, France) vendredi 16 septembre 2016 21:37:06

Thanks for that tweak, that was the problem. The script is working great!!

I have question using your script above in concert with a script written by Shane Stanley that I have combined below. Shane’s script moves anyfile after X number of days to another location and is working perfectly. What would the extra commands be, to tell Shane’s script, that ONLY if anyfile was moved, then it should continue and run the “Folder Inventory” scripting. If no move was made the script would stop. The file moved will always have a different name. Combining these 2 scripts would produce a new inventory list as soon as a change took place. Also, I have observed that when the script successfully moves a file the result window shows “false”. If it doesn’t move anything the result window is blank.

Thanks for your help,
Mike.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use framework "AppKit"

on moveFilesFrom:posixFolderPath toFolder:destPosixPath numberOfDaysOld:numDays
	-- get date limit
	set dateLimit to current application's NSDate's dateWithTimeIntervalSinceNow:-(numDays * days)
	set dateLimit to current application's NSCalendar's currentCalendar()'s startOfDayForDate:dateLimit
	-- make URLs of POSIX paths
	set destFolderURL to current application's |NSURL|'s fileURLWithPath:destPosixPath
	set sourceFolderURL to current application's |NSURL|'s fileURLWithPath:posixFolderPath
	-- get file manager
	set theNSFileManager to current application's NSFileManager's defaultManager()
	-- get contents of directory, ignoring invisible items
	set theURLs to theNSFileManager's contentsOfDirectoryAtURL:sourceFolderURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- loop through URLs
	repeat with aURL in theURLs
		-- get date added
		set {theResult, theDate} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLAddedToDirectoryDateKey) |error|:(missing value))
		-- test date
		if theResult as boolean and (theDate's compare:dateLimit) as integer < 0 then
			-- get name of file
			set theName to aURL's lastPathComponent()
			-- make new URL
			set destURL to (destFolderURL's URLByAppendingPathComponent:theName)
			-- move file
			(theNSFileManager's moveItemAtURL:aURL toURL:destURL |error|:(missing value))
			-- check destination for already exists,
			if (destURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then
				-- if yes, Delete
				(theNSFileManager's removeItemAtURL:aURL |error|:(missing value))
			end if
		end if
	end repeat
end moveFilesFrom:toFolder:numberOfDaysOld:

#=====

# Define your own paths here
set posixFolderPath to "volumes/files 1.5T/inventory/Folder A"
set destPosixPath to "volumes/files 1.5T/inventory/Folder B"

my moveFilesFrom:posixFolderPath toFolder:destPosixPath numberOfDaysOld:30

set posixFolderPath to "volumes/files 1.5T/inventory/Folder C"
set destPosixPath to "volumes/files 1.5T/inventory/Folder D"

my moveFilesFrom:posixFolderPath toFolder:destPosixPath numberOfDaysOld:30





main()

on main()
	-- set this_folder to POSIX path of (choose folder with prompt "Choose the root folder")
	set this_folder to "/volumes/files 1.5t/inventory"
	set log_file_path to POSIX path of ((path to desktop as text) & "Folder Inventory.rtf")
	
	-- Ensure that the root path has the correct cases and a trailing slash.
	set this_folder to POSIX path of ((POSIX file this_folder) as alias)
	
	set |⌘| to current application
	set rootURL to |⌘|'s class "NSURL"'s fileURLWithPath:(this_folder)
	
	-- Set up an NSFileManager enumerator and get the folder's "entire contents" (visible files and folders as NSURLs).
	set theFileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set dirAndPackageKeys to |⌘|'s class "NSArray"'s arrayWithArray:({|⌘|'s NSURLIsDirectoryKey, |⌘|'s NSURLIsPackageKey})
	set theEnumerator to theFileManager's enumeratorAtURL:(rootURL) includingPropertiesForKeys:(dirAndPackageKeys) options:((|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer)) errorHandler:(missing value)
	set entireContents to theEnumerator's allObjects()
	
	-- Initialise an NSMutableAttributedString with the title line and two linefeeds.
	set styledText to |⌘|'s class "NSMutableAttributedString"'s alloc()'s initWithString:("Start " & (current date) & linefeed & linefeed)
	
	-- Make an attribute dictionary specifying blue as a foreground colour.
	set blue to |⌘|'s class "NSColor"'s colorWithCalibratedRed:(0.0) green:(0.0) blue:(1.0) alpha:(1.0)
	set blueText to |⌘|'s class "NSDictionary"'s dictionaryWithObject:(blue) forKey:(|⌘|'s NSForegroundColorAttributeName)
	
	-- Make an NSAttributedString with the root folder name and the blue foreground colour and append it to the NSMutableAttributedString.
	set thisAddition to |⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(rootURL's lastPathComponent) attributes:(blueText)
	tell styledText to appendAttributedString:(thisAddition)
	
	-- Work through the "entire contents", truncating and colouring the paths as required and appending them to the NSMutableAttributedString.
	set truncationRegex to |⌘|'s class "NSString"'s stringWithString:("^" & this_folder & "|[^/]++/")
	set LF to |⌘|'s class "NSString"'s stringWithString:(linefeed)
	repeat with thisItem in entireContents
		set thisPath to thisItem's |path|()
		-- Replace the root path and any other container components in this path with spaces, leaving just the indented name.
		set indentedName to (thisPath's stringByReplacingOccurrencesOfString:(truncationRegex) withString:("  ") options:(|⌘|'s NSRegularExpressionSearch) range:({location:0, |length|:thisPath's |length|()}))
		-- Put a linefeed on the front, ready for appending to the preceding text.
		set textToAppend to (LF's stringByAppendingString:(indentedName))
		
		-- Get this item's directory and package values. If they're the same, the item's either a file or a package, otherwise it's a folder.
		set dpDictionary to (thisItem's resourceValuesForKeys:(dirAndPackageKeys) |error|:(missing value))
		set treatingAsFile to ((dpDictionary's objectForKey:(|⌘|'s NSURLIsDirectoryKey))'s isEqual:(dpDictionary's objectForKey:(|⌘|'s NSURLIsPackageKey))) as boolean
		
		-- Create an NSAttributedString with the doctored path, coloured or not as appropriate, and append it to the mutable one.
		if (treatingAsFile) then
			set thisAddition to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(textToAppend))
		else
			set thisAddition to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(textToAppend) attributes:(blueText))
		end if
		tell styledText to appendAttributedString:(thisAddition)
	end repeat
	
	-- Set the required font if you don't like the default Helvetica Neue 12.0.
	set theFont to |⌘|'s class "NSFont"'s fontWithName:("Times New Roman") |size|:(12.0)
	if (theFont is not missing value) then
		tell styledText to addAttribute:(|⌘|'s NSFontAttributeName) value:(theFont) range:({location:0, |length|:its |length|()})
	end if
	
	-- Extract RTF data from the attribute string and save using a URL derived from the given log file path.
	set theRTFData to styledText's RTFFromRange:({location:0, |length|:styledText's |length|()}) documentAttributes:(missing value)
	set logFileURL to |⌘|'s class "NSURL"'s fileURLWithPath:(log_file_path)
	tell theRTFData to writeToURL:(logFileURL) atomically:(true)
	say "Finished"
end main

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

If I’ve understood what you want, it would look something like this. I’ve inserted a boolean flag in Shane’s handler which gets set to ‘true’ if any items are moved. This is returned at the end of the handler and if it’s ‘true’, my handler (now renamed makeInventory()) makes an inventory of the folder from which the items were moved. I haven’t been able to test it, but it looks OK.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use framework "AppKit"

main()

on main()
	# Define your own paths here
	set posixFolderPath to "volumes/files 1.5T/NEW"
	set destPosixPath to "volumes/files 1.5T/OLD"
	
	set moveOccurred to (my moveFilesFrom:posixFolderPath toFolder:destPosixPath numberOfDaysOld:4)
	if (moveOccurred) then makeInventory(posixFolderPath)
end main

on moveFilesFrom:posixFolderPath toFolder:destPosixPath numberOfDaysOld:numDays
	-- get date limit
	set dateLimit to current application's NSDate's dateWithTimeIntervalSinceNow:-(numDays * days)
	set dateLimit to current application's NSCalendar's currentCalendar()'s startOfDayForDate:dateLimit
	-- make URLs of POSIX paths
	set destFolderURL to current application's |NSURL|'s fileURLWithPath:destPosixPath
	set sourceFolderURL to current application's |NSURL|'s fileURLWithPath:posixFolderPath
	-- get file manager
	set theNSFileManager to current application's NSFileManager's defaultManager()
	-- get contents of directory, ignoring invisible items
	set theURLs to theNSFileManager's contentsOfDirectoryAtURL:sourceFolderURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- Initialise a flag indicating whether any files have been moved. It'll be changed to 'true' below if any are.
	set moveOccurred to false
	-- loop through URLs
	repeat with aURL in theURLs
		-- get date added
		set {theResult, theDate} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLAddedToDirectoryDateKey) |error|:(missing value))
		-- test date
		if theResult as boolean and (theDate's compare:dateLimit) as integer < 0 then
			-- get name of file
			set theName to aURL's lastPathComponent()
			-- make new URL
			set destURL to (destFolderURL's URLByAppendingPathComponent:theName)
			-- move file
			(theNSFileManager's moveItemAtURL:aURL toURL:destURL |error|:(missing value))
			-- Note the fact.
			set moveOccurred to true
			-- check destination for already exists,
			if (destURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then
				-- if yes, Delete
				(theNSFileManager's removeItemAtURL:aURL |error|:(missing value))
			end if
		end if
	end repeat
	return moveOccurred
end moveFilesFrom:toFolder:numberOfDaysOld:

on makeInventory(this_folder)
	-- set this_folder to POSIX path of (choose folder with prompt "Choose the root folder")
	--set this_folder to "/volumes/files/new"
	set log_file_path to POSIX path of ((path to desktop as text) & "Folder Inventory.rtf")
	
	-- Ensure that the root path has the correct cases and a trailing slash.
	set this_folder to POSIX path of ((POSIX file this_folder) as alias)
	
	set |⌘| to current application
	set rootURL to |⌘|'s class "NSURL"'s fileURLWithPath:(this_folder)
	
	-- Set up an NSFileManager enumerator and get the folder's "entire contents" (visible files and folders as NSURLs).
	set theFileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set dirAndPackageKeys to |⌘|'s class "NSArray"'s arrayWithArray:({|⌘|'s NSURLIsDirectoryKey, |⌘|'s NSURLIsPackageKey})
	set theEnumerator to theFileManager's enumeratorAtURL:(rootURL) includingPropertiesForKeys:(dirAndPackageKeys) options:((|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer)) errorHandler:(missing value)
	set entireContents to theEnumerator's allObjects()
	
	-- Initialise an NSMutableAttributedString with the title line and two linefeeds.
	set styledText to |⌘|'s class "NSMutableAttributedString"'s alloc()'s initWithString:("Start " & (current date) & linefeed & linefeed)
	
	-- Make an attribute dictionary specifying blue as a foreground colour.
	set blue to |⌘|'s class "NSColor"'s colorWithCalibratedRed:(0.0) green:(0.0) blue:(1.0) alpha:(1.0)
	set blueText to |⌘|'s class "NSDictionary"'s dictionaryWithObject:(blue) forKey:(|⌘|'s NSForegroundColorAttributeName)
	
	-- Make an NSAttributedString with the root folder name and the blue foreground colour and append it to the NSMutableAttributedString.
	set thisAddition to |⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(rootURL's lastPathComponent) attributes:(blueText)
	tell styledText to appendAttributedString:(thisAddition)
	
	-- Work through the "entire contents", truncating and colouring the paths as required and appending them to the NSMutableAttributedString.
	set truncationRegex to |⌘|'s class "NSString"'s stringWithString:("^" & this_folder & "|[^/]++/")
	set LF to |⌘|'s class "NSString"'s stringWithString:(linefeed)
	repeat with thisItem in entireContents
		set thisPath to thisItem's |path|()
		-- Replace the root path and any other container components in this path with spaces, leaving just the indented name.
		set indentedName to (thisPath's stringByReplacingOccurrencesOfString:(truncationRegex) withString:("  ") options:(|⌘|'s NSRegularExpressionSearch) range:({location:0, |length|:thisPath's |length|()}))
		-- Put a linefeed on the front, ready for appending to the preceding text.
		set textToAppend to (LF's stringByAppendingString:(indentedName))
		
		-- Get this item's directory and package values. If they're the same, the item's either a file or a package, otherwise it's a folder.
		set dpDictionary to (thisItem's resourceValuesForKeys:(dirAndPackageKeys) |error|:(missing value))
		set treatingAsFile to ((dpDictionary's objectForKey:(|⌘|'s NSURLIsDirectoryKey))'s isEqual:(dpDictionary's objectForKey:(|⌘|'s NSURLIsPackageKey))) as boolean
		
		-- Create an NSAttributedString with the doctored path, coloured or not as appropriate, and append it to the mutable one.
		if (treatingAsFile) then
			set thisAddition to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(textToAppend))
		else
			set thisAddition to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(textToAppend) attributes:(blueText))
		end if
		tell styledText to appendAttributedString:(thisAddition)
	end repeat
	
	-- Set the required font if you don't like the default Helvetica Neue 12.0.
	set theFont to |⌘|'s class "NSFont"'s fontWithName:("Times New Roman") |size|:(12.0)
	if (theFont is not missing value) then
		tell styledText to addAttribute:(|⌘|'s NSFontAttributeName) |value|:(theFont) range:({location:0, |length|:its |length|()})
	end if
	
	-- Extract RTF data from the attribute string and save using a URL derived from the given log file path.
	set theRTFData to styledText's RTFFromRange:({location:0, |length|:styledText's |length|()}) documentAttributes:(missing value)
	set logFileURL to |⌘|'s class "NSURL"'s fileURLWithPath:(log_file_path)
	tell theRTFData to writeToURL:(logFileURL) atomically:(true)
	say "Finished"
end makeInventory

Hi Nigel, I’ve edited my previous post at the end of the first script to move files, under “Define your own paths here”, to more accurately show you what I’m trying to do. I have an Inventory main folder with 4 folders inside. Any files that have been in Folder A more than 30 days will be moved to Folder B. Any files in Folder C more than 30 days will be moved to Folder D. The Folder Inventory RTF should still be generated from the main enclosing folder “Inventory” as shown earlier in this thread.

These 2 scripts are the beginning pieces of a longer script that processes the Inventory RTF further. So, that’s the reason I asked for the script to only generate the Inventory RTF when a file has been moved. Perhaps a better/easier request would be for an instruction line that stops the script if no files were moved. The script as shown does work now, to move the files and generate the RTF. I just don’t want the complete script to run if no files were moved.

Your patience and your help are greatly appreciated,
Mike.

Model: Mac Mini
AppleScript: 2.4
Browser: Safari 600.3.18
Operating System: Mac OS X (10.10)

With regard to the results you see in Script Editor from the version of Shane’s handler you posted, they’re simply the results (if any) from the last thing it does before it finishes. It doesn’t explicity return a result.

I’m actually a bit puzzled by that part of the handler. It moves each qualifying item to the new location, then checks to see if an item with that name already exists there. If there is one ” and there should be by then, one way or another ” the handler tries to delete the item in the source location. The results shown in Script Editor are consistent with that.

Presumably the intended action is to check the destination first and delete any conflicting item there before attempting the move. I’ve adjusted the handler code to do that below. As in my script above, it also now explicitly returns whether or not a move took place. In the light of your clarification, I’ve renamed my own handler logFolderHierarchy() and have made both the root path and the path to the RTF file its parameters. That way, you only need to specify the paths explicity once, near the top of the script, and can use the variables to feed whatever code you add later. Edit: I’ve also made it more efficient by styling the text per block of colour instead of per line.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use framework "AppKit"

main()

on main()
	# Define your own paths here
	set inventoryFolderPath to "Volumes/Files 1.5T/Inventory"
	set logFilePath to POSIX path of ((path to desktop as text) & "Folder Inventory.rtf")
	
	set folderAPath to inventoryFolderPath & "/Folder A"
	set folderBPath to inventoryFolderPath & "/Folder B"
	
	set AtoBMoveOccurred to (my moveFilesFrom:folderAPath toFolder:folderBPath numberOfDaysOld:30)
	
	set folderCPath to inventoryFolderPath & "/Folder C"
	set folderDPath to inventoryFolderPath & "/Folder D"
	
	set CtoDMoveOccurred to (my moveFilesFrom:folderCPath toFolder:folderDPath numberOfDaysOld:30)
	
	-- Finish here if no items were moved.
	if (not ((AtoBMoveOccurred) or (CtoDMoveOccurred))) then return
	
	logFolderHierarchy(inventoryFolderPath, logFilePath)
end main

-- Move items from one folder to another if they've been there more than a certain number of calendar days.
-- Handler by Shane Stanley. 'moveOccurred' flag added and destination check altered by NG.
on moveFilesFrom:posixFolderPath toFolder:destPosixPath numberOfDaysOld:numDays
	-- get date limit
	set dateLimit to current application's NSDate's dateWithTimeIntervalSinceNow:-(numDays * days)
	set dateLimit to current application's NSCalendar's currentCalendar()'s startOfDayForDate:dateLimit
	-- make URLs of POSIX paths
	set destFolderURL to current application's |NSURL|'s fileURLWithPath:destPosixPath
	set sourceFolderURL to current application's |NSURL|'s fileURLWithPath:posixFolderPath
	-- get file manager
	set theNSFileManager to current application's NSFileManager's defaultManager()
	-- get contents of directory, ignoring invisible items
	set theURLs to theNSFileManager's contentsOfDirectoryAtURL:sourceFolderURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	-- Initialise a flag indicating whether any files have been moved. It'll be changed to 'true' below if any are.
	set moveOccurred to false
	-- loop through URLs
	repeat with aURL in theURLs
		-- get date added
		set {theResult, theDate} to (aURL's getResourceValue:(reference) forKey:(current application's NSURLAddedToDirectoryDateKey) |error|:(missing value))
		-- test date
		if theResult as boolean and (theDate's compare:dateLimit) as integer < 0 then
			-- get name of file
			set theName to aURL's lastPathComponent()
			-- make new URL
			set destURL to (destFolderURL's URLByAppendingPathComponent:theName)
			-- check destination for already exists,
			if (destURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then
				-- if yes, Delete
				(theNSFileManager's removeItemAtURL:destURL |error|:(missing value))
			end if
			-- move file
			(theNSFileManager's moveItemAtURL:aURL toURL:destURL |error|:(missing value))
			-- Note that at least one move has occurred.
			set moveOccurred to true
		end if
	end repeat
	
	return moveOccurred
end moveFilesFrom:toFolder:numberOfDaysOld:

-- List a folder's entire visible hierarchy (names only, indented according to depth; folder names in blue) and save as RTF text.
-- Handler by Nigel Garvey.
on logFolderHierarchy(rootPath, logFilePath)
	-- The paths are assumed to be POSIX paths. Ensure that rootPath has the correct cases and a trailing slash.
	set rootPath to POSIX path of ((POSIX file rootPath) as alias)
	
	set |⌘| to current application
	set rootURL to |⌘|'s class "NSURL"'s fileURLWithPath:(rootPath)
	
	-- Set up an NSFileManager enumerator and get the folder's "entire contents" (visible files and folders as NSURLs).
	set theFileManager to |⌘|'s class "NSFileManager"'s defaultManager()
	set dirAndPackageKeys to |⌘|'s class "NSArray"'s arrayWithArray:({|⌘|'s NSURLIsDirectoryKey, |⌘|'s NSURLIsPackageKey})
	set theEnumerator to theFileManager's enumeratorAtURL:(rootURL) includingPropertiesForKeys:(dirAndPackageKeys) options:((|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles) + (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer)) errorHandler:(missing value)
	set entireContents to theEnumerator's allObjects()
	
	-- Initialise an NSMutableAttributedString with the title line and two linefeeds.
	set styledText to |⌘|'s class "NSMutableAttributedString"'s alloc()'s initWithString:("Start " & (current date) & linefeed & linefeed)
	
	-- Make an attribute dictionary specifying blue as a foreground colour.
	set blue to |⌘|'s class "NSColor"'s colorWithCalibratedRed:(0.0) green:(0.0) blue:(1.0) alpha:(1.0)
	set blueText to |⌘|'s class "NSDictionary"'s dictionaryWithObject:(blue) forKey:(|⌘|'s NSForegroundColorAttributeName)
	
	-- Start a "run" of folder names with the name of the root folder.
	set currentRun to rootURL's lastPathComponent()'s mutableCopy()
	set isFileRun to false
	
	-- Work through the "entire contents", replacing container components in the paths with indents. If an item's of the same type (file or folder) as the item before, append its name to the current run of names. If not, style the current run and append it to the styled text, then start a new run with the current name.
	set rootAndContainerRegex to |⌘|'s class "NSString"'s stringWithString:("^" & rootPath & "|[^/]++/")
	set LF to |⌘|'s class "NSString"'s stringWithString:(linefeed)
	repeat with thisItem in entireContents
		set thisPath to thisItem's |path|()
		-- Replace the root path and any other container components in this path with spaces, leaving just an indented name.
		set indentedName to (thisPath's stringByReplacingOccurrencesOfString:(rootAndContainerRegex) withString:("  ") options:(|⌘|'s NSRegularExpressionSearch) range:({location:0, |length|:thisPath's |length|()}))
		-- Append to a linefeed, ready for appending to the preceding text.
		set indentedNameLine to (LF's stringByAppendingString:(indentedName))
		
		-- Get this item's directory and package flags. If they're equal, the item's either a file or a package. Otherwise it's a folder.
		set dpDictionary to (thisItem's resourceValuesForKeys:(dirAndPackageKeys) |error|:(missing value))
		set treatingAsFile to ((dpDictionary's objectForKey:(|⌘|'s NSURLIsDirectoryKey))'s isEqual:(dpDictionary's objectForKey:(|⌘|'s NSURLIsPackageKey))) as boolean
		-- Is the item of the same type as for the current run of names?
		if ((treatingAsFile) = (isFileRun)) then
			-- If so, simply append its indented name to the run text.
			tell currentRun to appendString:(indentedNameLine)
		else
			-- Otherwise, make an NSAttributedString with the current run text, coloured or not as appropriate.
			if (isFileRun) then
				set thisColourBlock to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(currentRun))
			else
				set thisColourBlock to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(currentRun) attributes:(blueText))
			end if
			-- Append this to the main styled text.
			tell styledText to appendAttributedString:(thisColourBlock)
			-- Start a new run text with the current name line and set the run-type flag accordingly.
			set currentRun to indentedNameLine's mutableCopy()
			set isFileRun to treatingAsFile
		end if
	end repeat
	-- Append the final run to the styled text at the end. 
	if (isFileRun) then
		set thisColourBlock to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(currentRun))
	else
		set thisColourBlock to (|⌘|'s class "NSAttributedString"'s alloc()'s initWithString:(currentRun) attributes:(blueText))
	end if
	tell styledText to appendAttributedString:(thisColourBlock)
	
	-- Set the required font if you don't like the default Helvetica Neue 12.0.
	set theFont to |⌘|'s class "NSFont"'s fontWithName:("Geneva") |size|:(12.0)
	if (theFont is not missing value) then
		tell styledText to addAttribute:(|⌘|'s NSFontAttributeName) |value|:(theFont) range:({location:0, |length|:its |length|()})
	end if
	
	-- Extract RTF data from the styled text and save using a URL derived from the given log file path.
	set theRTFData to styledText's RTFFromRange:({location:0, |length|:styledText's |length|()}) documentAttributes:(missing value)
	set logFileURL to |⌘|'s class "NSURL"'s fileURLWithPath:(logFilePath)
	tell theRTFData to writeToURL:(logFileURL) atomically:(true)
	say "Finished"
end logFolderHierarchy