Replacing list numbers with their values

Everything related to our flagship word processor.
dagell
Posts: 6
Joined: 2012-06-29 05:58:23

Replacing list numbers with their values

Post by dagell »

I have a document with numbered paragraphs. The numbers are automatically assigned using a list style. I want to freeze the paragraph numbers so that I can add paragraphs, with out of sequence numbers, between existing numbers without changing the existing numbers. There are about 30 paragraphs numbered in this manner. My simple-minded and manual solution is to find the paragraph with the highest number, add the paragraph number manually, and remove the list style from the paragraph. Find all cross references that are lost, manually add the paragraph number. Repeat for the next highest paragraph number.

Is there an automated way to replace the automatic numbers with their current value?
David
User avatar
phspaelti
Posts: 1314
Joined: 2007-02-07 00:58:12
Location: Japan

Re: Replacing list numbers with their values

Post by phspaelti »

A macro like the following seemed to work for me some of the time. It seemed to depend on being run with the cursor not in a numbered paragraph. Perhaps Martin can suggest something better, or at least explain the behavior.

Code: Select all

$doc = Document.active
Lists:Select All Style
Find All '^[^\t]+', 'Esa'
$autoNums = $doc.textSelections

foreach $sel in reversed $autoNums
	$num = $sel.substring
	$doc.text.replaceInRange $sel.range, $num
end
Anyhow, you definitely want to try this on a copy of your file :!: If it messes up the cross-references, Undo might not restore them easily.
philip
dagell
Posts: 6
Joined: 2012-06-29 05:58:23

Re: Replacing list numbers with their values

Post by dagell »

Thank you. It seems to work. I'm trying to understand the macro language. Up until now, I've used the supplied macros, but haven't tried to understand them.

I find that the macro changes the list items to the number, if I invoke it with the insertion point in a paragraph with the list style applied. If I don't , many lines of text have their styles changed. When it works, however the cross references are lost. I suppose I could enter them by hand, but as a learning exercise, I'm going to try to figure out how to apply a bookmark to each entry, then I can replace the cross references to the list item with a cross reference to a bookmark. If I figure it out, I'll post the result.
David
User avatar
Hamid
Posts: 777
Joined: 2007-01-17 03:25:42

Re: Replacing list numbers with their values

Post by Hamid »

Hello dagell,
As for automatic numbers in cross references, you can change them to their fixed values by selecting the entire text and applying the Tools:Automatic Content:Convert to Fixed Content menu. This will not affect other automatic numbers used in the selection. You can test this on a copy of your file.
dagell
Posts: 6
Joined: 2012-06-29 05:58:23

Re: Replacing list numbers with their values

Post by dagell »

I promised an update, which creates a bookmark for each requirement number changed from the list style automatic number to a fixed number. Here it is. There are still a number of things I don't understand. First and foremost is syntax of Lists:Select All Style. By experiment, I found it selects all paragraphs that contain the list styles applied to the paragraph containing the insertion point. This macro doesn't function as intended if the insert point is in a paragraph that doesn't contain the list style I'm interested in.

I found the help on the macro language somewhat sparse. I couldn't find a reference to the Lists:Select command. Also, nowhere did it state the # character introduces comments. I figured it out when I found an example part way through the file (in the section titled Termination) that had an inline comment.

I have solved my problem, thanks phspaelti.

Code: Select all

# macro to replace automatic numbers with their value
# from phspaeilti via NISUS Bulletin Board
#
# Modified to bookmark text changed from auto list number 
# to fixed number
#
$doc = Document.active

# seems to select all text with the same list styles
# as are applied to the text at the insertion point
Lists:Select All Style 

# in selected text find characters from
# start of selection through tab
Find All '^[^\t]+', 'Esa'

#save the selected text in the variable $autoNums
$autoNums = $doc.textSelections

foreach $sel in reversed $autoNums
   $num = $sel.substring
   $doc.text.replaceInRange $sel.range, $num
  
   # bookmark string, excluding trailing colon and tab
   # requirement numbers are R##, length of 3
   #
   $thisReq = TextSelection.newWithLocationAndLength ($sel.text, $sel.location, 3)
   TextSelection.setActiveRange($thisReq.range)
   Add Bookmark 
end
exit "Processing complete”
David
User avatar
phspaelti
Posts: 1314
Joined: 2007-02-07 00:58:12
Location: Japan

Re: Replacing list numbers with their values

Post by phspaelti »

Hello David,
thanks for commenting my macro :) I really should have done that myself! You seem to have figured things out.

Here are a few comments and tips.

As you mention the macro documentation does not explain "Lists:Select All Style". That is because it isn't part of the macro language. That command is a menu command. (It's under the "Format" menu.) You can generally use any menu command in a NW macro.

Also you point out that the macro only works correctly if you start it with the cursor located on the correct style. That's basically correct. (Actually in my tests things were much more complicated, and I couldn't figure it out. That's why I didn't finish the macro :) )
Generally I would want the macro to select the style itself. Unfortunately there is no easy way to do this, at least with List Styles. Assuming the list style you were looking for was "Number List" the following code would work:

Code: Select all

$doc = Document.active
$text = $doc.text
$listStyles = Hash.new
$pos = 0
while $pos < $text.length
	$attr = $text.attributesAtIndex $pos
	if $attr.listStyle
		$listStyles{$attr.listStyleName} = $pos
	end
	$attrRange = $text.rangeOfAttributesAtIndex $pos
	$pos = $attrRange.bound
end
Set Selection Location $listStyles{“Number List”}

Lists:Select All Style
Not exactly simple :roll:

Finally about your own code. If you're trying to make a range, you don't need to use TextSelection:

Code: Select all

$thisReq = Range.new $sel.location, 3
would work. But you could get what you want even easier if you change the find expression to:

Code: Select all

Find All '^[^:\t]+', 'Esa'
then "$sel.Range" will already be the range you are looking for, since the expression will avoid selecting the colon.

Hope some of this is useful.
philip
User avatar
martin
Official Nisus Person
Posts: 5228
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Re: Replacing list numbers with their values

Post by martin »

phspaelti wrote:A macro like the following seemed to work for me some of the time. It seemed to depend on being run with the cursor not in a numbered paragraph. Perhaps Martin can suggest something better, or at least explain the behavior.
I think I can explain the behavior. Basically there are two situations:

1. If the selection/caret rests in a paragraph with a list style applied, the macro/menu command "Lists:Select All Style" will select all paragraphs using the same list style, in the entire document. That's as intended.
2. If the selection/caret rests in a paragraph without any list style, the the macro/menu command "Lists:Select All Style" will select all text in your document, regardless of list styles, ie: the command is equivalent to a normal "Select All". This is basically a misbehavior. If there's no relevant list style the command should be disabled, or better yet, it should only select paragraphs with no list style applied.
User avatar
martin
Official Nisus Person
Posts: 5228
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Re: Replacing list numbers with their values

Post by martin »

phspaelti wrote:Generally I would want the macro to select the style itself. Unfortunately there is no easy way to do this, at least with List Styles. Assuming the list style you were looking for was "Number List" the following code would work:
...
I'm not sure I understand. Can't you rely upon the user already having placed the selection/caret in the relevant list style? Or did you have something else in mind, like prompting the user with all list styles actually used in the document? That is indeed unfortunately rather involved (you could see Kino's super useful Macro > Find > Select By Style macro).
User avatar
martin
Official Nisus Person
Posts: 5228
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Re: Replacing list numbers with their values

Post by martin »

Hamid wrote:As for automatic numbers in cross references, you can change them to their fixed values by selecting the entire text and applying the Tools:Automatic Content:Convert to Fixed Content menu. This will not affect other automatic numbers used in the selection. You can test this on a copy of your file.
Thanks for sharing that tip Hamid, it's a good one. Ideally we should have the "Convert to Fixed Content" menu give the user a list of content kinds, where they can choose which should be converted (including list items/numbers among the choices). It's filed as an enhancement request.
User avatar
phspaelti
Posts: 1314
Joined: 2007-02-07 00:58:12
Location: Japan

Re: Replacing list numbers with their values

Post by phspaelti »

martin wrote:
phspaelti wrote:A macro like the following seemed to work for me some of the time. It seemed to depend on being run with the cursor not in a numbered paragraph. Perhaps Martin can suggest something better, or at least explain the behavior.
I think I can explain the behavior. Basically there are two situations:

1. If the selection/caret rests in a paragraph with a list style applied, the macro/menu command "Lists:Select All Style" will select all paragraphs using the same list style, in the entire document. That's as intended.
2. If the selection/caret rests in a paragraph without any list style, the the macro/menu command "Lists:Select All Style" will select all text in your document, regardless of list styles, ie: the command is equivalent to a normal "Select All". This is basically a misbehavior. If there's no relevant list style the command should be disabled, or better yet, it should only select paragraphs with no list style applied.
Okay that helps a bit.
But there was another issue. In my test, if I ran the macro on a file with cross-references pointing to the list style, I got the following behavior:
If I tried your [1] the list numbers were changed to text, and all the cross-refs ended up with a [missing reference]. This was what I expected (but not what I desired :) ).
If I tried your [2] the list numbers were changed to text and the cross-references too!. So that was what I wanted, but I couldn't figure out why I was getting it. However it seems this is not the result that David gets.

More to the point, I was wondering; there currently is no macro way to find and/or modify cross-references?
philip
User avatar
phspaelti
Posts: 1314
Joined: 2007-02-07 00:58:12
Location: Japan

Re: Replacing list numbers with their values

Post by phspaelti »

martin wrote:
phspaelti wrote:Generally I would want the macro to select the style itself. Unfortunately there is no easy way to do this, at least with List Styles. Assuming the list style you were looking for was "Number List" the following code would work:
...
I'm not sure I understand. Can't you rely upon the user already having placed the selection/caret in the relevant list style? Or did you have something else in mind, like prompting the user with all list styles actually used in the document? That is indeed unfortunately rather involved (you could see Kino's super useful Macro > Find > Select By Style macro).
Well I was thinking of the kind of macro that David seemed to have in mind, i.e., one that was specific to his list style (for "requirement numbers"). In that case having to place the cursor somewhere specific is a redundant bother. But unfortunately there is no easy way to say "Jump to requirement numbers list style." For non-list styles I usually use the trick of applying the style to the current location, then "Select all (style)" will immediately get all the desired bits. But applying a list style to some random location would unfortunately add an unwanted list number, and perhaps even change the already entered numbers. So a Kino-style macro becomes necessary.
philip
dagell
Posts: 6
Joined: 2012-06-29 05:58:23

Re: Replacing list numbers with their values

Post by dagell »

Philip, you wrote
As you mention the macro documentation does not explain "Lists:Select All Style". That is because it isn't part of the macro language. That command is a menu command. (It's under the "Format" menu.) You can generally use any menu command in a NW macro.
I was looking for this menu command, but didn't find it because I was looking in edit, since I thought it was some kind of search. From the documentation, I would have thought the menu command should have been written "Format:Lists:Select", which also works. What I didn't realize, is that the only the part of the menu path which is unique is needed in the macro, thus both "Format:Lists:Select" and "Lists:Select" work.

This is the first time I've tried to actually work with a macro, other than just running an existing one. I've been using NWP for about 5 years. I guess I've a bit to learn, thank you all for your help.
David
User avatar
martin
Official Nisus Person
Posts: 5228
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Re: Replacing list numbers with their values

Post by martin »

phspaelti wrote:If I tried your [1] the list numbers were changed to text, and all the cross-refs ended up with a [missing reference]. This was what I expected (but not what I desired :) ).
Unfortunately you're right: it's expected that replacing the list items will remove/delete any bookmarks on them (thus breaking any cross-reference targeting those bookmarks).
If I tried your [2] the list numbers were changed to text and the cross-references too!. So that was what I wanted, but I couldn't figure out why I was getting it.
The reason for this might become clear if you stop your macro before it does the replacement. In other words, run just the macro:

Code: Select all

Lists:Select All Style 
Find All '^[^\t]+', 'Esa'
You'll see that your find expression actually selects all the text in any paragraphs without tab characters. Thus, the code that converts the selection to plain text also converts cross-references (and other special content). You would improve the search by using the expression '^[^\t]+\t', but of course there's still paragraphs where that might get you into trouble, depending on your document content. To be really safe, you'd want your macro to use the "Select Next List Item" or "Selection Previous List Item" commands.
More to the point, I was wondering; there currently is no macro way to find and/or modify cross-references?
Unfortunately no, currently macros have no access to cross-references and limited ways of interacting with bookmarks, sorry. I'll make sure we have this enhancement filed, but I think it's already there.
User avatar
martin
Official Nisus Person
Posts: 5228
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Re: Replacing list numbers with their values

Post by martin »

phspaelti wrote:I was thinking of the kind of macro that David seemed to have in mind, i.e., one that was specific to his list style (for "requirement numbers"). In that case having to place the cursor somewhere specific is a redundant bother. But unfortunately there is no easy way to say "Jump to requirement numbers list style."
It turns out this kind of macro isn't too difficult to write using the "Select" commands. Something like this will do the trick:

Code: Select all

$doc = Document.active
$convertListStyleName = 'Number List'

# process in reverse so list numbering doesn't change as we convert
Select Document End
While Select Previous List Item
	$convert = Menu State ":Format:Lists:$convertListStyleName"
	If $convert
		$sel = $doc.textSelection
		$num = $sel.substring
		$doc.text.replaceInRange($sel.range, $num)
	End
End
Just change the name of the list style in the code.
dagell
Posts: 6
Joined: 2012-06-29 05:58:23

Re: Replacing list numbers with their values

Post by dagell »

Well, I thought I'd post the final version of the macro (or at least a version that does more or less what I want).

Code: Select all

 
# macro to replace automatic numbers with their value
#
# Modified to bookmark text changed from auto list number 
# to fixed number
#
$doc = Document.active

# ask user for list style to replace
#
$styles      = $doc.listStyles
$targetStyle = Prompt Options ‘Choose a list style to replace by contents’, ‘detail’, ‘Select’, $styles

$styleName = $targetStyle.name

# Start at end of document
Select Document End

# find each list item with target list style
#
$count = 0

While Select Previous List Item
	# check if this list item is one to be changed
	#
	$convert = Menu State “:Format:Lists:$styleName”
	if $convert
		# convert it
		#
		$sel = $doc.textSelection
		$num = $sel.substring
		$doc.text.replaceInRange($sel.range, $num)

		# now bookmark the new text
		# make the new text the active selection
		# then add a bookmark

		#-1- this works, but includes the :/t in the bookmark name
		#TextSelection.setActiveRange($sel.range)
		
		# now adjust selection to include only alphanumeric
		# characters and bookmark
		
		#-2- this works, but is not general
		#
		# $sel.length = 3  ## specific for req number format R##
		# TextSelection.setActiveRange($sel.range)

		#-3- Find the word text to which the list style was applied
		#    Get the length, and adjust the selection to the length
		#    bookmark the selection
		#
		$newRange = $num.find(“[A-Za-z0-9]+”, “E”)
		$sel.length = $newRange.length
		TextSelection.setActiveRange($sel.range)

		Add Bookmark As $sel.substring
		$count += 1
	end
end
exit “Converted $count automatic numbers to their value”

#notes:
# 1) Menu State “:Format:Lists:$targetStyle.name” did not work
#    assigning $targetStyle.name to variable and using in Menu State did
#
# 2) rangeOfString argument findText is text only, not regexp
#    so it could not be used in block 3
#
# 3) Add named bookmarks, could be automatic named.
There are a couple of commented out sections that show alternatives that I tried. The macro positions the insertion point at the end of the file then finds list items in reverse order - going from the back to the font. It determines if the list style is the target style by checking the state of the format lists menu. Here is the first place I ran into a little trouble. I thought I could use the statement

Code: Select all

 $convert = Menu State “:Format:Lists:$targetStyle.name”
However, when written that way, $convert was never true. So I saved the name in a variable and used the variable in the statement.

Once I changed the text, I needed bookmarks for the so I could cross reference the numbered paragraphs. I tried a couple of different ideas. I wanted the bookmark names to consist of the number text, without trailing punctuation or whitespace. The List style had the form R##:<tab>. The code at -1- just made the active range into the range where the list number was, and bookmarked it. This left the colon and tab in the bookmark name, which is unsightly when the cross reference is listed. The code at -2- made use of apriori knowledge of the form of the list item - not good for the general case. The code at -3- is what I finally arrived at. I tried using $num.rangeOfString which apparently does not do regular expression searches.

Thanks to Martin and Philip for their help and hints. I've spent more time on this than I planned, but I learned a bit about the power of the macro language.
David
Post Reply