How to select all Headings with the same attributes?

Get help using and writing Nisus Writer Pro macros.
Post Reply
Þorvarður
Posts: 236
Joined: 2012-12-19 05:02:52

How to select all Headings with the same attributes?

Post by Þorvarður » 2015-01-11 09:47:38

Let's say I have a document with headings like this one (see screenshot 1).
1.png
1.png (27.88 KiB) Viewed 1991 times
In order to select all headings with the same attributes I know I can place the cursor in a heading and select "Select All" from the small pop-up menu in the lower right corner.
2.png
2.png (11.75 KiB) Viewed 1991 times
[1] Is it possible to assign a keyboard shortcut to this "Select All" command?

[2] Is it possible to write a macro that does the same thing? If that's possible, then I could assign a keyboard shortcut to that macro.


I found the following in the Nisus Macro Reference. Looks like it could perhaps be used to return text attributes of the text where the cursor is, but I have no idea how to do it. I did not find any examples in the Reference.
.typingAttributes
.displayTypingAttributes
And while I'm at it, what is the part in front of the dot called?

And what is the part after the dot called? Is is called "property"?
3.png
3.png (32.01 KiB) Viewed 1991 times

User avatar
phspaelti
Posts: 889
Joined: 2007-02-07 00:58:12
Location: Japan

Re: How to select all Headings with the same attributes?

Post by phspaelti » 2015-01-11 19:17:54

Hello Þorvarður,

I thought that there was some way to call that command in a macro, but I can't remember it right now, which is too bad, because even though it is possible to recreate that feature in a macro it is surprisingly difficult/complicated. I'm pretty sure there is a macro by Kino somewhere that can do this.

One "obvious", but kludgy, way to do this would be to copy the attributes, then paste them onto a string '.+' and then do an attribute sensitive Find for that.

The way which you seem to have happened on would be to use the object model of the macro language. This is preferable, but unfortunately in this case not so easy.
So what's the 'object model'?

Internally Nisus organises itself using objects. These are actually very straightforward things. Document, Text, Notes, Tables, Comments, Selections, etc. everything is an object. Each comes with sensible properties, and commands that allow you to find out things about them, and do things to them. The list of properties and commands for each is very long, which is why the Macro Language Reference is such a big document.

So in the case you were interested in '.typingAttributes' is indeed a property. It is a property of the Selection object. So in order to get it you need such an object. How to get one?
The current selection can be got with the following code:

Code: Select all

$sel = TextSelection.active
In this code $sel is a variable name. It can be pretty much any word you want as long as it begins with a dollar sign $, but $sel is a fairly conventional name to use for this case. TextSelection.active is a TextSelection command which returns the active selection, and with $sel = we 'catch' that object.
Now that we have the object we can ask for its properties:

Code: Select all

$attr = $sel.typingAttributes
This code 'catches' the typing attributes of the object. What are the 'typing attributes'? Well, they are again a kind of object, in this case an Attributes object. An Attributes object is just a collection of attributes, i.e., a kind of list with specifications like 'font:Times, size:12pt,…' etc. This list is what's known as a Hash, and each of the values for any given attribute can be again accessed as a property of the Attributes object (e.g., $attr.font, $attr.size,…)

Now if the Attributes object were all it could be, there might be some convenient command that would just let you select all bits in the document that had those attributes, but unfortunately there isn't. The problem is that dealing with attributes is a bit complicated. Attributes aren't simple objects that exist in the document, they are spread out all across the text of the whole document. They can come alone or in groups. So what we want to do now is go through the entire document - actually the text of the document - and check the attributes at each place in the document, and see if they are the same as the ones we just retrieved from the current selection. So before we can proceed, we need yet another object, the Text object of the current document.

Code: Select all

$doc = Document.active
$text = $doc.text
And when you have that you have to 'walk through' the document, checking the attributes. The best way to do this is using what I like to think of as a 'Kino loop':

Code: Select all

$index = 0
while $index < $text.length
    $range = $text.rangeOfAttributesAtIndex $index
    …
    $index = $range.bound
end
The '…' is where you can put the code to check the attributes of the text at the index and then do whatever you need to do; in this case store the location of stretches where the attributes are the same as the ones you are looking for. Even that turns out to be not that straightforward. I am attaching a macro that does this.
Attachments

[The extension nwm has been deactivated and can no longer be displayed.]

philip

Þorvarður
Posts: 236
Joined: 2012-12-19 05:02:52

Re: How to select all Headings with the same attributes?

Post by Þorvarður » 2015-01-14 00:29:08

Philip, thank you so much for your excellent explanation. The macro does exactly what I wanted. Nisus should have hired you to write the Macro Reference. :)

Post Reply