Selecting stuff with AppleScript

There was a tweet about Numbers the other day:

#applescript can be such a pain sometimes to use. Simple things, like getting the selection of the current cell in #numbers is not easy info to come by.

I totally understand the author's feeling and my first take was based on a misunderstanding: in the tweet where my reply is (that you can see below his) I took his request as looking for the value of the selected cell, but now that I think of it, he meant "the selected thing within the current cell". So let's take a minute to see how hard it is to find that information in Number's dictionary (hint: it's not there, as far as I can tell):

We have 2 items to base our investigation on: "selection" and "cell".

Looking for "selection" does not bring anything interesting, we only get "selection range" which is a property of table and returns the "cells currently selected in the table." So let's check "cell". We end up with 1 class and 2 elements (one of table and one of range). So let's check the class:

celln [inh. range] : A cell in a table

We get a number of properties for cell, including value that return various objects (number, date, text, boolean, or missing value) but further investigation does not help us finding something that returns the textual selection.

In fact, checking the dictionaries of the main applications delivered by Apple, only 2 seem to have a way to get a textual selection: Script Editor and Xcode. Page, Keynotes, Numbers, Notes, Preview, TextEdit, Contacts, Calendar, Reminders, Safari, etc. don't have anything. Finder, Mail, Terminal have a "selection" mechanism but only to select objects specific to their models and not to select a textual range.

Now, that doesn't mean it is not possible to get the textual selection in the above applications, just that a reasonable investigation into the various dictionaries did not provide us with that information.

So, now that we're stuck, the only path I'd think of to access that textual selection is to use GUI scripting to copy the selection, put it in the clipboard and access it from there.

tell application "Numbers"
delay 0.1
tell application "System Events"
keystroke "c" using {command down}
end tell
end tell

set mySelection to the clipboard

Ok, it's ugly. But we got it.

Last but not least, I'd like to go back to that "selection" thing.

In Script Editor it's very easy to use:

tell application "Script Editor"
tell document "Untitled 3"
selection's properties
end tell
end tell

--> {class:selection-object, character range:{35, 60}, contents:"tell document \"Untitled 3\""}

We get textual information but only the actual text contents, nothing like what the clipboard tells us (with clipboard info for ex).

In Xcode we seem to be able to get the "selected character range" only of source files. RTF files return errors.

tell application "Xcode"
selected character range of document 4
end tell
--> {1, 5}

and it's easy to get mixed up since for each independent document opened, Xcode will create a "workspace document" that includes it. So if we just create a single source file outside of any project, we still need to refer to it as document 2 because document 1 will be the enclosing workspace...

Some applications I use frequently have good selection support: BBEdit works a bit like Script Editor where a simple "selection" in the application tell block will return the user visible selection. Word needs "selection's content" to return the textual value of the selection but selection itself offers plenty of properties including style, etc.

Finding one's way in an application's AppleScript dictionary...

The other day I wanted to find a way to accelerate the process of zooming a Word window so that it fits the width of the document. It's something I've done manually thousands of times over the years. Just go to Display, then Zoom, select the option and hit Enter.

I know that Word is scriptable but everything looked so complex that I never really tried. When I script in uncharted territory I usually go the top-bottom way: I get a document, check it's properties and go deeper and deeper until I find what I need. The issue with this approach is that there are so many different classes and sub-classes and properties all over that you easily get lost and frustrated.

I just tried the bottom-up approach with this Word feature and it worked pretty well: start from what you thing is the end property and go up the ladder to the highest level object.

In the case at hand, I suppose the element I'm looking for has "fit" in its description. That's my only assumption.

So, here we go. Open Script Editor, open the Microsoft Word dictionary and search for "fit".

In the "Microsoft Word Suite" we find 2 properties and 1 command:

fit text width is a property of "selection object"

fit text width (real) : Returns or sets the width in the current measurement units in which Microsoft Word fits the text in the current selection.

page fit is a property of "zoom"

page fit (page fit none/page fit full page/page fit best fit) : Returns or sets the view magnification of a window so that either the entire page is visible or the entire width of the page is visible.

fit to pagesv : Decreases the font size of text just enough so that the document will fit on one fewer pages. An error occurs if Word is unable to reduce the page count by one.

A cursory reading tells us that we'd like to try "page fit" first. We know it is a property of "zoom", which is defined as:

zoomn [inh. base object] : Contains magnification options, for example, the zoom percentage for a window or pane.

Now we're getting closer to bridging our "bottom" (fit) to some "up" (which would be a document, or a window). Since we do have a reference to a window zoom percentage in the definition let's check "window" and see what we come up with.

The first thing we get is "active window", and the first item is:

active window (window, r/o) : Returns the currently active window object.

which is a property of application. active window returns a window object, so let's check what window objects are made of.

A glance at the list of properties of a window does not give us any hints at how to link a window to a zoom... There are no zoom properties so we have to go back to zoom and find hints there.

There is a second item for zoom, it is a property of a view:

zoom (zoom, r/o) : Returns the zoom object associated with this view object.

We're one step higher now, and since the definition of view is:

viewn [inh. base object] : Contains the view attributes, show all, field shading, table gridlines, and so on, for a window or pane.

we have a connection to the window that we found earlier.

If we check window again, we see that it indeeds has a view property:

view (view, r/o) : Returns a view object that represents the view for the window.

So let's put this together:

active window is a window and has a view property that has a zoom property that has a page fit property which can hold one of the following 3 values: page fit none/page fit full page/page fit best fit

To make sure that we're not missing anything let's check the code item by item, I assume that you have a Word document open, otherwise the result will be "missing value".

tell application "Microsoft Word"
get active window
end tell
--> active window

so far, so good.

tell application "Microsoft Word"
get view of active window
end tell
--> view of active window

no issue with that

tell application "Microsoft Word"
get zoom of view of active window
end tell
--> zoom of view of active window

we're progressing

tell application "Microsoft Word"
get page fit of zoom of view of active window
end tell
--> page fit full page

Boom ! We made it. Our document is in full page view.

So, let's set it to "page fit best fit":

tell application "Microsoft Word"
set page fit of zoom of view of active window to page fit best fit
end tell

Et voilĂ ! The window is now in page width fit.

I'm not sure which is the fastest: checking the web for a "zoom my document to page width in AppleScript" answer or finding your way into the dictionary to find the answer yourself, but I know which will help you be proficient with AppleScript faster...