Dinamic numbering

Get help using and writing Nisus Writer Pro macros.
Post Reply
riccardino
Posts: 4
Joined: 2007-08-02 07:16:14

Dinamic numbering

Post by riccardino »

I was wondering if there's a way to make a number present in the page (not in a footnote or in the summary) dependant on other numbers.
For instance, I'm including a series of examples in a chapter and they're all preceded by the sentence:
Example 1: how to do this

What I'm trying to achieve is to make the number "1" dynamic: this way, if I put an example before it, the current example nr. 1 will become nr. 2 and the new one will receive the nr. 1.

This would be a huge timesaver, since I won't have to review every chapter to see if someone made some changes.

Any suggestion?
-----
ciao, ric
User avatar
martin
Official Nisus Person
Posts: 5227
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Post by martin »

I suppose you could create a macro that would do what you wish, but you'd have to run it in post each time after your document was complete to fix up the counters.

Code: Select all

# This macro searches your document for special bits of text that indicate where an ever
# increasing numeric counter should be placed.
$marker = '[Counter]'
$count = 0

Set Selection 1, 0
While Find $marker
	Begin Perl
		$count++;
	End
	Insert Text $count
End
So now whenever you want to have one of these counters in your document you insert the text "[Counter]" into your document. Later you can run the macro to generate the numbers.

One other possibly solution is via List Styles. The only issue is that NWP insists on adding a tab character after the automated list item. If you can find a way to live with that, then here's what to do:

1. Create a new List Style via the menu Format > Lists > New List Style.
2. Call the new style Equations (or whatever you like) and make sure the Continue throughout document option is checked. This ensures that all list items/bullets/markers are consecutively numbered even if their content is separated.
3. The list style should be applied automatically, so now use the Lists palette to configure it. You'll want to set the "before text" to "Example " and the "after text" to ":".

Really NWP needs an arbitrary automatic variable feature (which is definitely already on our todo list).
riccardino
Posts: 4
Joined: 2007-08-02 07:16:14

Post by riccardino »

martin wrote:":".

Really NWP needs an arbitrary automatic variable feature (which is definitely already on our todo list).
In the meanwhile, both option are perfectly acceptable, to me.

Thanks a lot, Martin :-)
-----
ciao, ric
Tony
Posts: 12
Joined: 2007-09-22 11:07:40

Post by Tony »

Hello Martin
Probably a bit late on this as I've only just joined, but I have a use for your counter macro coded above. Unfortunately I keep getting an error message on the $count line. Any help would be appreciated.
Thanks
User avatar
martin
Official Nisus Person
Posts: 5227
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Post by martin »

Hi Tony- the problem is that the code copies from Safari with non-breaking spaces, which Perl does not care for. Try replacing all non-breaking spaces with regular spaces and then running the macro.
User avatar
martin
Official Nisus Person
Posts: 5227
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Post by martin »

If you've upgraded to Pro 1.0.1 you could also use this (faster) macro instead:

Code: Select all

# This macro searches your document for special bits of text that indicate where an ever 
# increasing numeric counter should be placed. 
$marker = '[Counter]' 
$count = 0 

Set Selection 1, 0 
While Find $marker 
   $count += 1
   Insert Text $count 
End
Tony
Posts: 12
Joined: 2007-09-22 11:07:40

Post by Tony »

Many thanks Martin - worked like a charm
js
Posts: 259
Joined: 2007-04-12 14:59:36

Post by js »

Code: Select all

# This macro searches your document for special bits of text that indicate where an ever 
# increasing numeric counter should be placed. 
$marker = '[Counter]' 
$count = 0 

Set Selection 1, 0 
While Find $marker 
   $count += 1 
   Insert Text $count 
End
Thanks for this useful macro, Martin. Still I think it would be even more useful if, instead of replacing the marker by a serial number, you would leave the marker and append the serial number to it. This would make it possible then to upgrade the process from time to time while still continuing your work on the document. But I found that finding the $marker together with the appended serial number leads to an infinite regress. Can the find-replace process be stopped somehow at the end of the document?


[/quote][/code]
User avatar
martin
Official Nisus Person
Posts: 5227
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Post by martin »

js wrote:I found that finding the $marker together with the appended serial number leads to an infinite regress. Can the find-replace process be stopped somehow at the end of the document?
It can- you'll want to make two changes. The first is to specify that the Find command should not wrap around to the start of the document. The "wrap around" option is turned on with the "W" character, which you disable by prefixing the "W" with a minus:

Code: Select all

While Find $marker, '-W'
The second change you'll need to make is to deselect the text after the replacement has been made, otherwise that exact same instance will be found again. You have two ways to do this, either add a selection command after the replacement, eg:

Code: Select all

Insert Text "$marker$count"
Select End
Or change "insert text" to "type text", which automatically places the caret after the inserted text:

Code: Select all

Type Text "$marker$count"
js
Posts: 259
Joined: 2007-04-12 14:59:36

Post by js »

Thank you. So I did this:

Code: Select all

$marker = '[Counter]' 
$count = 0 

Set Selection 1, 0
While Find $marker, '-W' 
	$count += 1 
	Type Text "$marker$count"
End
This works quite well. But if you repeat the process, numbers are added instead of replaced. To do replace them it would be necessary of doing a Find of the $marker together with any number following it. Of course you could achieve the desired result in a separate go, deleting any numbers following the [Counter] and then using your above macro. But I was wondering whether this could be done directly.
User avatar
martin
Official Nisus Person
Posts: 5227
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Post by martin »

It can be done directly, but will require the use of PowerFind Pro. Basically we want to change the find expression to match the marker plus any number of digits that follow it.

Code: Select all

$markerName = 'Counter' 
$count = 0 

Set Selection 1, 0 
While Find "\\[$markerName\\]\\d*", 'E-W'
   $count += 1 
   Type Text "[$markerName]$count" 
End
Things get a little tricky with those string literals because of the various meta-characters involved. In a PowerFind Pro expression the square brackets have a special meaning, so we must precede them with a backslash to indicate that we want to match actual bracket characters. But you'll see that I actually use two backslashes because in a double-quoted string literal the backslash also has a special meaning.

Following the translations the string takes will help. First the literal as typed into the macro file:

\\[$markerName\\]\\d*

..is parsed/interpolated by the macro interpreter to be:

\[Counter\]\d*

You'll see that each double-backslash has been collapsed to a single backslash and the value of the variable $markerName has been inserted. This string is then fed to PowerFind Pro. To the find engine "\[" and "\]" mean to match literal brackets, while "\d*" means match zero or more digits.

If all this makes no sense, then don't worry and just use the macro :)
js
Posts: 259
Joined: 2007-04-12 14:59:36

Post by js »

Great. This works just fine. A user might have to keep in mind that the counter in his text has to be put into brackets.
Thanks.
Kino
Posts: 400
Joined: 2008-05-17 04:02:32

Re: Dinamic numbering

Post by Kino »

riccardino wrote:For instance, I'm including a series of examples in a chapter and they're all preceded by the sentence:
Example 1: how to do this

What I'm trying to achieve is to make the number "1" dynamic: this way, if I put an example before it, the current example nr. 1 will become nr. 2 and the new one will receive the nr. 1.
Automatic numbers of that type is not available yet but, in recent versions of NWP, you can use a macro like this to update numbers. Let’s assume you have a document like this:

… blah blah Example 1: blah … blah Example 2: blah … blah Example 3: blah … blah Example 4: blah …

If you want to add an example before Example 2, just add it with an arbitary number, e.g. 0.

… blah blah Example 1: blah … blah Example 0: blah … blah Example 2: blah … blah Example 3: blah … blah Example 4: blah …

After runing the macro, the text will be

… blah blah Example 1: blah … blah Example 2: blah … blah Example 3: blah … blah Example 4: blah … blah Example 5: blah …

Repeat the procedure above when you add new examples.

Code: Select all

### Update Numbers ###

# Update numbers having a prefix and/or a suffix defined in $prefix and $suffix.

# This macro works on selection(s). If there is no selection, the whole document will be processed.

# Cross-references are ignored.

$prefix = 'Example '
$suffix = ':'
$where = '-am'  # in main body only (as to where argument, see "COMMANDS - Find and Replace" in Nisus Macro Reference)

Require Pro Version 1.3
$doc = Document.active
if $doc == undefined  # if there is no open document...
	exit  # then, the macro was run accidentally
end

$findExpression = '(?<=\Q' & $prefix
$findExpression &= '\E)\d+(?=\Q' & $suffix
$findExpression &= '\E)'
	# $findExpression: (?<=\Q$prefix\E)\d+(?=\Q$suffix\E)
	# (?<=***): preceded by ***
	# (?=***): followed by ***
	# characters between \Q and \E are treated literally (i.e. not as metacharacters)

$options = 'E-i'  # E: PowerFind Pro; -i: case-sensitive
if $doc.textSelection.length  # if some text is selected...
	$options &= 's'  # s: in selections
end

$n = Find All $findExpression, $options, $where
if !$n  # $n: number of founds
	exit 'Nothing found, exiting...'
end

$sels = $doc.textSelections
Select Start  # deslect selections to avoid performance hit

foreach $i, $sel in reversed $sels
	$s = Cast to String $sel.subtext  # $s: "[Referenced content is missing.]" if it is a cross-reference
	if $s != $sel.substring  # if it is a cross-reference...
		$sels.removeValueAtIndex $i
	end
end

foreach $i, $sel in reversed $sels
		$sel.text.replaceInRange $sel.range, $i + 1
end

### end of macro ###
When the numbers do not have a prefix or a suffix distinguishing them from other numbers used in the document, I think a handy way would be to create a character style, e.g. Figure Number, and apply it on them. Then, you can update them by [1] selecting one of them, [2] selecting all of them using Select All in the Character Stlye tag on the statusbar and running the following macro.

Code: Select all

 $doc = Document.active
$sels = $doc.textSelections
$n = $sels.count
foreach $sel in reversed $sels
	$sel.text.replaceInRange $sel.range, $n
	$n -= 1
end
Edit: added some explanation and modified the first macro so that cross-references are ignored.
Edit2: fixed a stupid bug introduced by the modification of the macro.
Edit3: modified the explanation a bit.
Post Reply