Serious First Steps In UserTalk Scripting
by Matt Neuburg
Author of the book Frontier: The Definitive Guide
In the previous chapter we created versions of workspace.fileLister that gathered the names of files in a folder into a string; we then wrote that string first into a wptext window, then into a file on disk. Now let's modify workspace.fileLister yet again, so that it lists the names of the files into an outline.An outline, like a wptext, is edited by first ascertaining that it is "the target" and then using editing commands which do not themselves specify what window is to be operated on.
Begin by creating a new outline to write into; create it in the workspace table, and call it fileOutline. Having done that, modify workspace.fileLister to look like this:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return whatFolder = string.replaceAll (whatFolder, "\\\\", "\\") local (theFile, s = "") fileloop (theFile in whatFolder, 1) s = s + theFile + cr edit (@workspace.fileOutline) op.wipe() op.setLineText (s) fileLister ()(The verb op.wipe erases the whole contents of the "target" outline, just in case it has anything in it already.)
Run this. Hmm, it didn't work very well, did it? Our pathnames have come out as a single line, and if we have a lot of pathnames the information has been truncated to just the first 255 characters.
Clearly we need to pull "s" apart into individual pathnames and write each of them as an individual line of the outline. One way to do this is to use UserTalk's string verbs involving fields. A field is that part of a string delimited by any character we care to declare as a delimiter; in this case, the return-character delimits the fields of "s" that we want.
In a loop, we can run through "s", pulling out the contents of each field and writing it to a new line in the outline, like this:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return whatFolder = string.replaceAll (whatFolder, "\\\\", "\\") local (theFile, s = "") fileloop (theFile in whatFolder, 1) s = s + theFile + cr edit (@workspace.fileOutline) op.wipe() local (x) for x = 1 to string.countFields(s, cr) op.insert(string.NthField(s, cr, x), down) fileLister ()Run this; it works much better.
Do you see how it works? We learn the number of fields of "s" delimited by return-characters, using string.countFields(), and prepare a "for" loop using this information; in the loop, we obtain each field, which will be a pathname, using string.NthField(), and write it into a new line of the outline using op.insert().
There is, however, a certain inefficiency in this method, because it contains two loops; first, in the "fileloop", we gather all the names of the files into one string; then, in the "for" loop, we pull that string apart again.
Let's combine the two loops so that there is no "s" at all: as we gather a pathname, we write it straight to the outline, like this:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return whatFolder = string.replaceAll (whatFolder, "\\\\", "\\") edit (@workspace.fileOutline) op.wipe() local (theFile) fileloop (theFile in whatFolder, 1) op.insert(theFile, down) fileLister ()If we run this, it works fine. We are, however, still being somewhat slowed down by the fact that we are creating the outline visibly, before the eyes of the user. It is often desirable to do this; for one thing, it gives the user something to watch while a long action is taking place, and for another, it's sort of fun.
But we can achieve a speed increase by working upon workspace.fileOutline invisibly.
The way to do this is to declare workspace.fileOutline to be "the target" without opening it visibly for editing. Subsequent window-editing commands will work upon it, but since the window will be invisible, the overhead of having to display our actions on the screen will be absent.Such invisible target-manipulation is done with the target verbs. Instead of calling edit(), we call target.set(), so that we are editing the window invisibly. In this case, we will then call edit() only at the very end, to show the result after the outline has been completely built.
Here is our new version:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return whatFolder = string.replaceAll (whatFolder, "\\\\", "\\") close (@workspace.fileOutline) target.set (@workspace.fileOutline) op.wipe() local (theFile) fileloop (theFile in whatFolder, 1) op.insert(theFile, down) edit (@workspace.fileOutline) fileLister ()Here, we actually close the workspace.fileOutline window beforehand, in case it is still open, because if it is open and we declare it to be "the target" we will get exactly the same sort of live updating of the window we were getting before, and this is just what we are trying to avoid.
Now let's really start getting powerful. Go into the workspace table, select the fileOutline entry, and delete it.With both the outline workspace.fileOutline in this chapter and the wptext workspace.testWindow in the previous chapter, we created the database entries manually beforehand, and then used them in scripts to display information.
This seems primitive and clumsy; let's have fileLister() itself create the outline workspace.fileOutline before writing to it. Creation of any table entry can be performed with the "new" verb; this will overwrite an existing entry of the same name, so it is common to use it in combination with the "defined" verb which checks to see whether the entry already exists, like this:
if not defined (workspace.fileOutline) new (outlineType, @workspace.fileOutline)In this case, however, we actually want to overwrite any previously existing workspace.fileOutline, so we won't bother with this extra test.
Observe that the first parameter of "new" requires us to declare the datatype of the entry we are creating; the various datatypes are listed in the Kind popup menu at the bottom of any database table window, and a list of constants representing their names can be found at system.compiler.language.constants.
So now workspace.fileLister looks like this:
on fileLister () local (whatFolder) if not file.getFolderDialog("Pick a folder to list:", @whatFolder) return whatFolder = string.replaceAll (whatFolder, "\\\\", "\\") new (outlineType, @workspace.fileOutline) target.set (@workspace.fileOutline) local (theFile) fileloop (theFile in whatFolder, 1) op.insert(theFile, down) edit (@workspace.fileOutline) fileLister ()We could, at this point, add various refinements. A particularly interesting exercise is to add depth to our file search, so that we end up with an outline that lists both files and folders, and the files inside those folders, and mirrors in its hierarchical structure the structure of the files and folders on your hard disk. The best way is to use a looping technique called recursion; to explain it, though, would be beyond the scope of this tutorial.
All text is by Matt Neuburg, phd, matt@tidbits.com.
For information about the book Frontier: The Definitive Guide, see my home page:
http://www.tidbits.com/matt
All text copyright Matt Neuburg, 1997 and 1998. ALL RIGHTS RESERVED.
No one else has any right to copy or reproduce in
any form, including electronic. You may download this material but you may not post it for others to
see or distribute it to others without explicit permission from the author.
Downloadable versions at http://www.ojai.net/matt/downloads/scriptingTutorial.hqx and http://www.ojai.net/matt/downloads/scriptingTutorial.zip.
Please do not confuse this tutorial with a certain other Frontier 5 tutorial based upon my earlier work.
This page created with
Frontier, 2/11/2000; 6:59:02 PM.