Listing folder contents

One of the things I regularly want to do is see the contents of a folder, fully expanded, but with full paths. I’ve written scripts to do it before, but sometimes the full paths are distracting. I finally got around to writing one that shows the paths, but with all but the name in a lighter color. The listing gets saved to the desktop as an rtf file, and opened in the default rtf editor. It’s not perhaps the most obvious of code, but some might find it useful.

It requires the BridgePlus script library (download here: www.macosxautomation.com/applescript/apps/BridgePlus.html), although it could easily be modified to do without it. (Edit: This requirement for BridgePlus has now been removed.) Because it’s potentially doing a lot of styling, don’t point it at very large folders and expect to see anything in a hurry.

It works on the target of the frontmost Finder window, and if you hold the control key while launching it, it includes the contents of packages.

It requires at least OS X 10.9 (you’ll need to put it in a script library under Mavericks).

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

set skipPackages to not (my checkModifier:"control") -- if control key is down, include contents of packages

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

-- set up destination path
set theTarget to current application's NSURL's fileURLWithPath:(POSIX path of theTarget)
set destURL to current application's NSURL's fileURLWithPath:(POSIX path of (path to temporary items))
set destURL to (destURL's URLByAppendingPathComponent:(theTarget'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 -- change to suit
-- set up font
set theFont to current application's NSFont's fontWithName:"Menlo-Regular" |size|:14.0 -- change to suit
-- set up colors
set highlightColor to current application's NSDictionary's dictionaryWithObject:(current application's NSColor's blueColor()) forKey:(current application's NSForegroundColorAttributeName) -- change to suit
set lighterColor to current application's NSDictionary's dictionaryWithObject:(current application's NSColor's lightGrayColor()) forKey:(current application's NSForegroundColorAttributeName) -- change to suit
-- 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

-- get all items in folder
set theOptions to current application's NSDirectoryEnumerationSkipsHiddenFiles
if skipPackages then
	set theOptions to theOptions + (get current application's NSDirectoryEnumerationSkipsPackageDescendants)
end if
set fileManager to current application's NSFileManager's defaultManager()
set theURLs to (fileManager's enumeratorAtURL:theTarget includingPropertiesForKeys:(missing value) options:theOptions errorHandler:(missing value))'s allObjects()
set allPaths to theURLs's valueForKey:"path"
-- match Finder sorting
set allPaths to allPaths's sortedArrayUsingSelector:"localizedStandardCompare:"
-- make string of paths
set theString to allPaths's componentsJoinedByString:linefeed
set theString to theString's stringByAppendingString:linefeed
-- get range of last component of paths
set theRegex to current application's NSRegularExpression's regularExpressionWithPattern:"[^\\/]+\\n" options:0 |error|:(missing value)
set theMatches to (theRegex's matchesInString:theString options:0 range:{0, theString's |length|()})'s valueForKey:"range"
-- make styled string
set styledString to current application's NSMutableAttributedString's alloc()'s initWithString:theString attributes:baseStyle
-- add highlightColor to the names
repeat with aRange in theMatches
	(styledString's addAttributes:highlightColor range:aRange)
end repeat
-- get RTF data, write it to file, then open the file
set theData to styledString's RTFFromRange:{0, styledString's |length|()} documentAttributes:(missing value)
theData's writeToURL:destURL atomically:true
current application's NSWorkspace's sharedWorkspace()'s openURL:destURL

on checkModifier:keyName
	if keyName = "option" then
		set theMask to current application's NSAlternateKeyMask as integer
	else if keyName = "control" then
		set theMask to current application's NSControlKeyMask as integer
	else if keyName = "command" then
		set theMask to current application's NSCommandKeyMask as integer
	else if keyName = "shift" then
		set theMask to current application's NSShiftKeyMask as integer
	else
		return false
	end if
	set theFlag to current application's NSEvent's modifierFlags() as integer
	if ((theFlag div theMask) mod 2) = 0 then
		return false
	else
		return true
	end if
end checkModifier:

Edited to include Finder-style sorting

Thanks for the script.

I tried it.
As I see, it shows folder contents in TextEdit window, but sometimes it can’t open as frontmost window. And, the TextEdit window remains on background…
I can’t fixed this problem and need help. Maybe, it is something simple.

UPDATE: it was simple: adding tell application “TextEdit” to activate at the end of on run handler solves this “problem”.

Other is this: in the Script Debugger code runs fine, but in the Script Editor I got following error:
error “The bundle “BridgePlus” couldn’t be loaded.” number -4960 from framework “BridgePlus”

Below I give a script version, 1) not using third-party software, 2) with the activation of TextEdit at the end, to show the results, 3) with predefined options, in the properties:


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

property |⌘| : a reference to current application
property fontName : "Menlo-Regular" -- change to suit
property fontSize : 14.0 -- change to suit
property outputFileName : "_WindowContents.rtf" -- change to suit
property theOptions : 6 -- skip package subitems and hidden files. Change to suit

-- GET TARGET OF FINDER WINDOW 1
tell application "Finder"
	try
		set aTarget to target of Finder window 1 as alias
	on error
		display dialog "SCRIPT WILL TERMINATED, SINCE NO FOLDER SELECTED." & return & ¬
			return & "SELECT FOLDER IN FINDER, THEN RUN SCRIPT AGAIN."
		return
	end try
end tell
set aTargetURL to |⌘|'s |NSURL|'s fileURLWithPath:(POSIX path of aTarget)

-- SET UP DESTINATION PATH
set desktopPath to POSIX path of (path to desktop)
set desktopURL to |⌘|'s |NSURL|'s fileURLWithPath:desktopPath
set destinationURL to desktopURL's URLByAppendingPathComponent:outputFileName

-- SET UP PARAGRAPH STYLE FOR LINE-SPACING
set parStyle to |⌘|'s NSParagraphStyle's defaultParagraphStyle()'s mutableCopy()
parStyle's setLineHeightMultiple:1.3 -- change to suit

-- SET UP FONT, SET UP COLORS
set theFont to |⌘|'s NSFont's fontWithName:fontName |size|:fontSize
set highlightColor to |⌘|'s NSDictionary's dictionaryWithObject:(|⌘|'s NSColor's blueColor()) ¬
	forKey:(|⌘|'s NSForegroundColorAttributeName) -- change to suit
set lighterColor to |⌘|'s NSDictionary's dictionaryWithObject:(|⌘|'s NSColor's lightGrayColor()) ¬
	forKey:(|⌘|'s NSForegroundColorAttributeName) -- change to suit

-- DEFINE BASE STYLE FROM ABOVE SETTINGS
set baseStyle to |⌘|'s NSMutableDictionary's dictionaryWithObjects:{theFont, parStyle} ¬
	forKeys:{|⌘|'s NSFontAttributeName, |⌘|'s NSParagraphStyleAttributeName}
baseStyle's addEntriesFromDictionary:lighterColor

-- GET ALL ITEMS IN FINDER
set fileManager to |⌘|'s NSFileManager's |defaultManager|()
set theURLs to (fileManager's enumeratorAtURL:(aTargetURL) includingPropertiesForKeys:({missing value}) ¬
	options:(theOptions) errorHandler:(missing value))'s allObjects()

-- MATCH FINDER SORTING
set sortDescriptor to |⌘|'s NSSortDescriptor's sortDescriptorWithKey:("path") ascending:(true) ¬
	selector:("localizedStandardCompare:")
theURLs's sortUsingDescriptors:({sortDescriptor})

-- MAKE STRING OF PATHS
set thePaths to ""
repeat with aURL in theURLs
	set thePaths to thePaths & (aURL's |path|) & linefeed
end repeat

-- GET RANGE OF LAST COMPONENT OF PATHS
set theRegex to |⌘|'s NSRegularExpression's ¬
	regularExpressionWithPattern:"[^\\/]+\\n" options:0 |error|:(missing value)
set theMatches to (theRegex's matchesInString:thePaths ¬
	options:0 range:{0, thePaths's length})'s valueForKey:"range"

-- MAKE STYLED STRING
set styledString to |⌘|'s NSMutableAttributedString's alloc()'s initWithString:thePaths attributes:baseStyle

-- ADD HIGHLIGHTCOLOR TO THE NAMES
repeat with aRange in theMatches
	(styledString's addAttributes:highlightColor range:aRange)
end repeat

-- GET RTF DATA, WRITE TO FILE, THEN OPEN THE FILE
set aData to styledString's RTFFromRange:{0, styledString's |length|()} documentAttributes:(missing value)
aData's writeToURL:destinationURL atomically:true
|⌘|'s NSWorkspace's sharedWorkspace()'s openURL:destinationURL
tell application "TextEdit" to activate

I think the doPackages variable in Shane’s script should be called dontDoPackages. :wink:

NB. BridgePlus’s load framework command doesn’t work in Script Editor in Mojave or later (error “The bundle “BridgePlus” couldn’t be loaded.” number -4960 from framework “BridgePlus”). But it does in Script Debugger. There’s a note explaining this at the top of the ReadMe with BridgePlus 1.3.3.

It took you four years to notice? :wink:

In practice, removing the dependence on BridgePlus shouldn’t make too much difference, so I’ll fix that too.

Hi Shane.

This should of course be:

set theOptions to current application's NSDirectoryEnumerationSkipsHiddenFiles
if skipPackages then
	set theOptions to theOptions + (get current application's NSDirectoryEnumerationSkipsPackageDescendants)
end if

And a very minor observation:

I’m finding that this goes the merest whisker faster if theMatches is coerced to list first and if the highlight colour is set as a style in itself — ie. a copy of baseStyle with its color set to the highlight color and using setAttributes: with this instead of addAttributes: with the color alone.

Interesting, thanks. I’ve fixed the enumeration error above.

A further refinement, for those who’d like to experiment with it, would be to replace this:

-- get RTF data, write it to file, then open the file
set theData to styledString's RTFFromRange:{0, styledString's |length|()} documentAttributes:(missing value)

… with a suitably customised version of this, which sets the size of the document’s viewing window:

-- get RTF data, write it to file, then open the file
--set paperSize to current application's NSSize's NSMakeSize(1000.0, 1200.0) -- Desired viewing size in points. (Set or calculate as required.)
--set paperSizeValue to current application's NSValue's valueWithSize:(paperSize)
-- Or simply:
set paperSizeValue to current application's NSValue's valueWithSize:{1000.0, 1200.0}
--set docAttributes to current application's NSDictionary's dictionaryWithObjects:{current application's NSRTFTextDocumentType, paperSizeValue, paperSizeValue} forKeys:{current application's NSDocumentTypeDocumentAttribute, current application's NSPaperSizeDocumentAttribute, current application's NSViewSizeDocumentAttribute}
-- Or:
set docAttributes to current application's NSDictionary's dictionaryWithObjects:{"NSRTF", paperSizeValue, paperSizeValue} forKeys:{"DocumentType", "PaperSize", "ViewSize"}
set theData to styledString's RTFFromRange:{0, styledString's |length|()} documentAttributes:docAttributes

Edit: Document type settings added as per Shane’s comment immediately below.

Nice. Although my original sets documentAttributes to missing value, the documentation says it should at least contain a value for NSRTFTextDocumentType (in this case, NSRTFTextDocumentType).

Yes it does. Thanks. I’ve modified my code accordingly. I’d have thought though that the requirement for an RTF document type would be implied by the RTFFromRange:documentAttributes: method itself. :confused:

There are several other options, including NSWordMLTextDocumentType and NSOfficeOpenXMLTextDocumentType. All use the same method.