Help scripting with TextWrangler

Hi. I’m trying to write a simple script that opens a text file from a specific folder in TextWrangler, runs a replace changing all “|” into tabs, saves and closes the file and then moves on to the next file in the folder.

When I run my script I get the following error message:

The problem seems to be centered around the replace function. (If I run the same script, telling it only to open the files in TextWrangler and nothing more, it works just fine.)

Here is my code. If anyone out there can find my error and point me in the right direction, I’d be very grateful.

Thanks,
Shannon

set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
	set aFiles to files in aFolder
end tell
repeat with CurrentFile in aFiles
	tell application "TextWrangler"
		open CurrentFile
		replace "|" using "	" searching in text 1 of text document CurrentFile options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		save CurrentFile
		close CurrentFile
	end tell
end repeat

When usung a repeat with a in b
a is pointer to item 1 of b
so converting to a string fixes the problem

set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
	set aFiles to files in aFolder
end tell
repeat with CurrentFile in aFiles
	set CurrentFile to CurrentFile as string
	tell application "TextWrangler"
		open CurrentFile
		tell document 1
			replace "|" using "	" searching in text 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
			save
			close
		end tell
	end tell
end repeat

have fun

Bevan www.applescript.co.nz

It’s also the case that the list returned by the Finder contains Finder references, which TextWrangler doesn’t understand. It’s actually that that’s cured by coercing each reference to string (or preferably to Unicode text or alias). Getting the Finder to return aFiles as an alias list would achieve the same thing.

To make Mr. G’s last point clearer with an example, this construction is quite common:

set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
	try
		set aFiles to files in aFolder as alias list -- this form errors if there is only one file in the chosen folder
	on error
		set aFiles to files in aFolder as alias as list -- this form works with one file
	end try
end tell
--> a list of aliases to the files at the top level of the chosen folder

If the chosen folder might contain folders and you want the files in them too:

set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
	try
		set aFiles to files in entire contents of aFolder as alias list
	on error
		set aFiles to files in entire contents of aFolder as alias as list
	end try
end tell
--> a list of aliases to every file at any depth within the chosen folder.

Hi,

I don’t like and don’t use the alias list construction, unless it’s sure, that the list contains more than one item.
If not, I perfer the “on-the-fly” coercion


...
repeat with CurrentFile in aFiles
	tell application "TextWrangler"
		open (CurrentFile as alias)
		tell document 1
			replace "|" using "	" searching in text 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
			save
			close
		end tell
	end tell
end repeat
...

Thank you so much for all your help everybody. Stefan, that last bit of code you gave me did the trick.

-Shannon

I prefer the “alias list construction” above when I don’t know what might be in a chosen folder and then I know for every time I use an item from that list that it’s an alias. Your construction avoids having to know what’s in the folder chosen because it coerces the file or files found individually. I would guess that would take longer to do than constructing an alias list does (requiring as it does only one Apple Event call instead of one per repeat), but in this case (or for small numbers of files) that doesn’t matter. A matter of philosophy, I guess - if I can do things outside of subsequent repeat loops, I always do.

An alternative, if the application opening the files understands Unicode text paths (as TextWrangler does), is to mass coerce the references to Unicode text, which compares very favourably for speed:

set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return as Unicode text
tell application "Finder" to set aFiles to paragraphs of (files of aFolder as Unicode text)
set AppleScript's text item delimiters to astid

Besides having the Finder coerce the references en masse, more speed can be obtained by having TextWrangler open, resave, and close the documents en masse, so that the repeat loop only has to cycle through documents already in memory.

In TextWrangler 2.1.2, documents have a ‘contents’ property, not multiple ‘text’ elements “ although you wouldn’t know so from the dictionary. The dictionary also doesn’t say that windows contain documents. :confused: (Maybe it depends on the window settings in TextWrangler’s “Documents” preferences.) Anyway, this works very quickly for me:

set aFolder to choose folder with prompt "Choose a folder:"

set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return as Unicode text
tell application "Finder" to set aFiles to paragraphs of (files of aFolder as Unicode text)
set AppleScript's text item delimiters to astid


tell application "TextWrangler"
	activate
	open aFiles opening in new_window
	tell front window
		repeat with i from 1 to (count documents)
			replace "|" using "    " searching in contents of document i options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
		end repeat
		save documents
		close documents
	end tell
end tell

Rather slick, Mr. G. I guess that if TextWrangler can do it, so can BBEdit - I’ll try. :slight_smile:

My 2 cents. Your list doesn’t allow for no files. I do it this way

set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
	set ThenCount to (count of files in entire contents of aFolder)
	if ThenCount = 0 then
		set TheFileList to {}
	else if ThenCount = 1 then
		set TheFileList to files in entire contents of aFolder as alias as list
	else
		set TheFileList to files in entire contents of aFolder as alias list
	end if
end tell

Not relying on error handler

Bevan www.applescript.co.nz

Interesting! There’s a bug or an inconsistency here. If the ‘entire contents’ doesn’t contain the required elements, it errors instead of returning an empty list.

set aFolder to choose folder with prompt "Choose a folder with no files:"

tell application "Finder" to get files of aFolder -- as alias list
--> {}

tell application "Finder" to get files of entire contents of aFolder -- as alias list
--> Error.

So something like this is required to get around two bugs - ugh :frowning: (It’s coercing a null result to alias that fails)


set aFolder to choose folder with prompt "Choose a folder:"
tell application "Finder"
	try
		-- try for more than one
		set aFiles to files in entire contents of aFolder as alias list
	on error
		-- oops, try for one or fewer
		try
			set aFiles to files in entire contents of aFolder as alias as list
		on error
			-- oops, there aren't any
			set aFiles to {}
		end try
	end try
end tell