Your prescription for increased productivity and profitability
In this post we will look at some of the issues surrounding working with lists. Knowing the ins and outs of lists is paramont when writing scripts to automate Adobe InDesign. For instance the following will return a list of the rectangles found on a page:
tell application "Adobe InDesign CC 2019" tell page 1 of document 1 set aList to every rectangle end tell end tell aList
In running the above, if no rectangles are found, the value of aList will be an empty list.
Should you want to get the geometric bounds of every rectangle, the following will throw an error when no items are found.
tell application "Adobe InDesign CC 2019" tell page 1 of document 1 set aList to geometric bounds of every rectangle end tell end tell
To prevent this error, two approaches can be used: (1) put the statement inside a try statement block:
tell application "Adobe InDesign CC 2019" tell page 1 of document 1 try set aList to geometric bounds of every rectangle end try end tell end tell aList --the value returned will be an empty list
(2) Get the count of items before using the every statement
set aList to {} tell application "Adobe InDesign CC 2019" tell page 1 of document 1 if (count of rectangles) > 0 then set aList to geometric bounds of every rectangle end if end tell end tell aList
Notice in this second example getting the value for aList at the end of the script would produce an error if the variable has not been initialized.
The result of a selection is a list.
tell application "Adobe InDesign CC 2019" set aList to selection end tell
As with the above, a script needs to verify there is a selection before trying to get an item from the list or any item properties:
tell application "Adobe InDesign CC 2019" if selection is not {} then set selItem to item 1 of selection end if end tell
Similarly, trying to get properties from a selection will produce an error if the list is empty
tell application "Adobe InDesign CC 2019" if selection is not {} then set aList to geometric bounds of every item of selection end if end tell
In running the code above, if there is more than one rectangle on the page as expected, a list of lists is returned similar to the following:
{{423.36, 161.28, 578.88, 482.4}, {207.0, 161.28, 381.6, 482.4}, {36.0, 146.88, 167.04, 491.04}}
Notice that the geometric bounds for the rectangles are each list items separated by commas within the parent list.
However if there is only one recrangle on the page, the value of the list is not a list of lists but a single list of the item’s geometric bounds:
{423.36, 161.28, 578.88, 482.4}
To keep the script from falling into this error, your script might want to test for one item as well as no items:
set aList to {} tell application "Adobe InDesign CC 2019" tell page 1 of document 1 if (count of rectangles) = 1 then set end of aList to geometric bounds of rectangle 1 else if ((count of rectangles) > 0) then set aList to geometric bounds of every rectangle end if end tell end tell aList
Of course, you could always use a repeat loop to do the same:
set aList to {} tell application "Adobe InDesign CC 2019" tell page 1 of document 1 repeat with i from 1 to (count of rectangles) set end of aList to geometric bounds of rectangle i end repeat end tell end tell aList
The advantage of using every is that every item can serve as the object of a tell statement:
tell application "Adobe InDesign CC 2019" tell page 1 of document 1 tell every rectangle set fill color to "Black" set fill tint to 50 end tell end tell end tell
One place that working with lists can cause some consternation is in using set and copy. For the most part, there is little difference.
set aList to {1, 2, 3} set end of aList to 4 aList --Result is {1, 2, 3, 4}
Change the second line of the above to use copy instead of set:
copy 4 to end of aList
The result is the same.
But should you have the need to duplicate a list, the difference between using set instead of copy can make all a script fail. For instance, suppose you want a second list of numbers to be the same as the first but incremented by a value of 100. You might write:
set myList to {102, 202, 303} set dupList to myList repeat with i from 1 to length of dupList set item i of dupList to (item i of dupList) + 100 end repeat {myList, dupList}
The Result is that both lists end up being the same: {{202, 302, 403}, {202, 302, 403}}
Instead, using copy, the result will be as anticipated:
set myList to {102, 202, 303} copy myList to dupList repeat with i from 1 to length of dupList set item i of dupList to (item i of dupList) + 100 end repeat {myList, dupList}
The result will be two unique lists as anticipated: {{102, 202, 303}, {202, 302, 403}}
The problem is that set does not create a new list but assigns a reference of the first list to a second variable. When a value in the first list changes, the second does the same.
A script can coerce any single item into a list using as list.
set myList to "Now is the time" as list Result is {"Now is the time"}
Using AppleScript’s text item delimiters, a script can get a variety of results depending on the need.
By default, AppleScript’s text item delimiters is set to an empty string. With this, all of the characters in a string can be coerced into a list.
set myText to "Now is the time" set myList to text items of myText myList --Result is {"N", "o", "w", " ", "i", "s", " ", "t", "h", "e", " ", "t", "i", "m", "e"}
Change the value for AppleScript’s text item delimiters to a space and the result is entirely different:
set AppleScript's text item delimiters to " " set myText to "Now is the time" set myList to text items of myText set AppleScript's text item delimiters to "" myList --Result is {"Now", "is", "the", "time"}
Important: Remember to return the value of AppleScript’s text item delimiters back to its previous setting after using.
Using text item delimiters comes in handy for getting items from a string. For instance, when you use the choose command to get a path to a file, the items in the path are separated with colons:
set thePath to choose file as string
The result will be similar to: “Macintosh HD:Users:userName:Desktop:Filename.docx”
An easy way to get the name of the file is to use text items with the delimiter set to the colon:
set thePath to (choose file) as string set AppleScript's text item delimiters to ":" set fileName to item -1 of (text items of thePath) set AppleScript's text item delimiters to "" fileName
To remove a word from a string you can use text item delimiters. But be aware, every word matching the delimiter will be removed.
set origText to "All good people must be there" set AppleScript's text item delimiters to "good " set myList to text items of origText set AppleScript's text item delimiters to "" myList as text
Notice that the delimiter “good ” in the above includes a word space. Without that, the occurrence of good inside of a word would also be removed. Try the above with the delimiter set to “good” (without the space) and the value for origText to “Goodness knows, most good people will be there”.
You might want to experiment using text item delimiters for creating lists and parsing tab-delimited strings.
Disclaimer:
Scripts provided are for demonstration and educational purposes. No representation is made as to their accuracy or completeness. Readers are advised to use the code at their own risk.