Indented listing of a folder's entire contents

By default, the “find” utility returns paths in an order whereby the items within each folder (or “directory”) are sorted by name and each folder path is followed immediately by the paths to the folder’s items. So for an indented display of the names alone, all that’s needed is to substitute a tab for the “root folder” part of each path and a tab for each subsequent slash-terminated element:

set qpp to quoted form of POSIX path of (choose folder)

set txt to (do shell script ("find -f " & qpp & " | sed -E  '1 !s:(^.+//|[^/]+/):'$'\\t'':g ;'"))

tell application "TextEdit"
	activate
	make new document with properties {text:txt}
end tell

The “sed” code above exploits (and depends on) the fact that the input to “find” is the ‘POSIX path’ of the root folder as supplied by AppleScript, which ends with a slash. This causes the paths returned by “find” to have two slashes between their root parts and subsequent elements, making the root parts easy to identify:

Instead of using the regex “.+//”, I could simply have concatenated the root path and a slash into the “sed” code, but let’s be sophisticated here.

It would be nice to have each folder name in the output terminated with a slash, but “find” doesn’t provide that option. One way round this is to get the folder and file paths separately, doctor the folder paths, and then sort the two groups of paths together before doing the tab substitutions.

To ensure that the sort phase reproduces “find”'s order for a full set of paths, it’s necessary first to replace all the slashes with characters whose codes are lower than or equal to the lowest likely to occur in the paths. Tabs seem a good choice. The process then becomes:

¢ Get the folder paths, replace every slash in them with a tab, and append a tab to the end of each path except for the first (the root path).
¢ Get the file paths and replace every slash in them with a tab.
¢ Concatenate and sort the two groups of paths.
¢ Restore the slashes in the first (root) path.
¢ In each of the other paths, replace any tab at the end with a slash, then substitute tabs for the root section (which now ends with two tabs) and for each subsequent tab-terminated section.

The code below does all this and also contains inserts which suppress (or not) paths where any element begins with “.” or is “Contents”. The filtering could be done by “find”, but on the AppleScript principle that it’s better not to give file utilities too much to think about, I’ve given the job to “sed”.

set withInvisibles to false -- 'false' suppresses items where any name in the path begins with ".".
set withBundleContents to false -- 'false' suppresses items where any folder name in the path is "Contents".

set invisiblesInsert to item ((withInvisibles as integer) + 1) of {"/'$'\\t''\\./ d ; ", ""}
set bundleInsert to item ((withBundleContents as integer) + 1) of {"/\\.[^'$'\\t'']+'$'\\t''Contents'$'\\t''?/ d ; ", ""}

set qpp to quoted form of POSIX path of (choose folder)

set txt to (do shell script ("dirs=$(find -f " & qpp & " \\( -type d \\) | sed -E 's:/:'$'\\t'':g ;  1 !s:$:'$'\\t'': ' ;) ; files=$(find -f " & qpp & " \\( -type f \\) | sed -E 's:/:'$'\\t'':g' ;) ; echo \"$dirs\\n$files\" | sort -f | sed -E  '1 s:'$'\\t'':/:g ; 1 !{ " & invisiblesInsert & bundleInsert & " s:'$'\\t''$:/: ; s:(^.+'$'\\t\\t''|[^'$'\\t'']+'$'\\t''):'$'\\t'':g ;}'"))

tell application "TextEdit"
	activate
	make new document with properties {text:txt}
end tell

(* -- Or:
tell application "TextWrangler"
	activate
	tell (make new text window with properties {text:txt}) to select insertion point before its text
end tell *)

:cool:

How Nice!

I have put a run handler around and stuffed it into the MenuScripts of BBEdit with a name of Insert¢Folder Listing. so I get the listing inserted into the current document, Iyou can do the same with TextWrangler

I just ended it off with:


tell application "BBEdit"
		set selection of text window 1 to txt
	end tell 

Since I want it into the current document when I want it.

Edit
I also have a different listing made by find, so that I can just stand on a line of the listing hit cmd-L for selecting it, then hit cmd-D for opening it, it is very practical.

The snippet for doing that goes like this:


to fullPthList from aTgt
	local tPth
	set tPth to text 1 through -2 of POSIX path of aTgt
	set txt to (do shell script "find  " & quoted form of tPth & "  -name \\* 2>/dev/null")
	return txt
end fullPthList