Reply to topic  [ 7 posts ] 
Restricting macros to operate on specific paragraph styles 
Author Message

Joined: 2010-09-29 03:28:07
Posts: 3
Location: Scotland
Is it possible/easy to limit NW macros such that they will operate on specific paragraph (or character) styles?

I have an NW Pro macro that carries out a series of grep Finds and Replaces on documents (styled MS Word documents, typically several hundred pages long). I want this macro to operate on a specific paragraph style (or, perhaps, list of paragraph styles). Is there an easy way to create an array or subset of styles that the macro can can operate on? Alternatively, is it easy to create an exclusion list, i.e. paragraph styles that it should not operate on?

The macro operates perfectly by the way. I just want it restrict it to specific styles.

Using NW Pro 1.4.1 and Mac OS X 10.6.4.


2010-09-29 11:24:46
Profile

Joined: 2008-05-17 04:02:32
Posts: 400
djmacd wrote:
I have an NW Pro macro that carries out a series of grep Finds and Replaces on documents [ . . .]. I want this macro to operate on a specific paragraph style (or, perhaps, list of paragraph styles).
If your macro consists exclusively of Find and Replace commands, you can make them work on selections preserving the selections by adding ‘sS’ to their options. For example, . . .
Code:
Find and Replace '^[\x20\t]+|[\x20\t]+$', '', 'EasS'  # remove leading/trailing space and tab
Find and Replace '\x20{2,}', '\x20', 'EasS'  #shorten two or more spaces to one
Or, if you prefer Replace All in Selection like me:
Code:
Replace All in Selection '^[\x20\t]+|[\x20\t]+$', '', 'ES'
Replace All in Selection '\x20{2,}', '\x20', 'ES'
Then, all you need to do is to select all texts in specific styles before running your macro. For that, try this one.
Code:
### Select by Styles ###

$charStyleMark = Cast to String ' [a̱]'
$paraStyleMark = Cast to String ' [¶]'

$doc = Document.active
if $doc == undefined
   exit  # no open document
end

$charStyles = $paraStyles = Hash.new

foreach $text in $doc.allTexts
   $i = 0
   while $i < $text.length
      $attr = $text.attributesAtIndex $i
      $range = $text.rangeOfAttributesAtIndex $i
      $sel = TextSelection.new $text, $range
      if Defined $attr.characterStyleName
         if $charStyles{$attr.characterStyleName} == undefined
            $charStyles{$attr.characterStyleName} = Array.new
         end
         $charStyles{$attr.characterStyleName}.appendValue $sel
      end
      if Defined $attr.paragraphStyleName
         if $paraStyles{$attr.paragraphStyleName} == undefined
            $paraStyles{$attr.paragraphStyleName} = Array.new
         end
         $paraStyles{$attr.paragraphStyleName}.appendValue $sel
      end
      $i = $range.bound
   end
end

$styleNames = $charStyles.keys
$styleNames.sort 'li'
foreach $i, $name in $styleNames
   $name &= $charStyleMark
   $styleNames.setValueAtIndex $name, $i
end

$paraStyleNames = $paraStyles.keys
$paraStyleNames.sort 'li'
foreach $name in $paraStyleNames
   $name &= $paraStyleMark
   $styleNames.appendValue $name
end

if ! $styleNames.count
   exit 'No applied style fouond, exiting . . .'
end

$styleNames = Prompt Checkboxes 'Select all texts in specific styles . . .', '', '', $styleNames
if ! $styleNames.count
   exit 'Nothing checked, exiting . . .'
end

$sels = Array.new
$charStyleMark = '\Q' & $charStyleMark
$charStyleMark &= '\E$'
$paraStyleMark = '\Q' & $paraStyleMark
$paraStyleMark &= '\E$'

foreach $name in $styleNames
   $check = $name.findAndReplace $charStyleMark, '', 'E-i'
   if Defined $check
      $sels.appendValuesFromArray $charStyles{$name}
   else
      $name.findAndReplace $paraStyleMark, '', 'E-i'
      $sels.appendValuesFromArray $paraStyles{$name}
   end
end

$doc.setSelections $sels
When you need to make negative selections, use Edit > Select > Invert Selection along with the macro above.


2010-09-30 02:01:43
Profile

Joined: 2010-09-29 03:28:07
Posts: 3
Location: Scotland
That is remarkably helpful. I don't know the NW macro language well yet, but I think I follow the code you have provided.

I hope that I will be in a position to return the favour one day.


2010-09-30 08:08:35
Profile

Joined: 2010-09-29 03:28:07
Posts: 3
Location: Scotland
I now understand the code. It's elegant and very useful, and not just for the macro I asked about, but generally useful for selecting styles before running any macro. Thank you again.


2010-10-01 14:43:24
Profile
Official Nisus Person
User avatar

Joined: 2002-07-11 17:14:10
Posts: 4251
Location: San Diego, CA
That is a very useful macro, thanks Kino. I'll have to add it to the macro repository!


2010-10-04 13:39:02
Profile WWW

Joined: 2008-05-17 04:02:32
Posts: 400
The macro posted above was unnecessarily complicated. The cause of my writing such crappy code is that, for some reason I don’t remember, I thought it was necessary to add [a̱] and [¶] at the end of each style name. But why not add them at the top of style names??? Then, you don’t need using different hashes for character styles and paragraph styles respectively. Just a single hash is sufficient because names beginning with [a̱] and [¶] are sorted by kind naturally, without your doing anything special. And, in this way, names look better in the Macro Prompt, at least to my eyes. Also, why not use “[a̱] style name” and “[¶] style name” as hash keys instead of just “style name”??? Then, you can get rid of the last foreach loop and related code.

So here is a revised version, which supports list styles ([#] style name) too. Also, it allows you to select paragraphs having no paragraph style directly. For that, I had to add a routine to exclude special characters between tables and other text objects. Otherwise, the macro will pick up such characters as “[¶] <no style>” on which, however, you cannot apply any paragraph style. You can do nothing against them. That should be confusing and irritating.
Attachment:
SelectByStyle_20110110_nwm.zip [5.29 KiB]
Downloaded 249 times

Code:
### Select by Style (rev. 3) ###

# This macro lists up all Paragraph/Character/List styles
# used in the frontmost document and enables you to select
# all text portions in specific style(s).

$charStyleMark = Cast to String '[a̱] '  # customizable
$paraStyleMark = Cast to String '[¶] '  # customizable
$listStyleMark = Cast to String '[#] '  # customizable
$noStyleName = Cast to String '<no style>'  # customizable

Require Pro Version 1.3
$doc = Document.active
if $doc == undefined
   exit  # no open document
end

$language = Language.systemLanguage
$selectionsByStyle = Hash.new

foreach $text in $doc.allTexts
   $textRanges = Array.new
   if $text.tables.count  # then, exclude special chars enclosing tables
      $tableRanges = Array.new
      foreach $table in $text.tables
         $tableRanges.appendValue $table.enclosingTextRange
      end
      $tableRanges.sort
      $i = 0
      foreach $tableRange in $tableRanges
         $range = Range.newWithLocationAndBound $i, $tableRange.location
         $textRanges.appendValue $range
         $i = $tableRange.bound
      end
      $range = Range.newWithLocationAndBound $i, $text.length
   else
      $range = Range.new 0, $text.length
   end
   $textRanges.appendValue $range
   foreach $textRange in $textRanges
      $i = $textRange.location
      while $i < $textRange.bound
         $attr = $text.attributesAtIndex $i
         $range = $text.rangeOfAttributesAtIndex $i
         $sel = TextSelection.new $text, $range
         if Defined $attr.characterStyleName
            $name = $charStyleMark & $attr.characterStyleName
            if $selectionsByStyle{$name} == undefined
               $selectionsByStyle{$name} = Array.new
            end
            $selectionsByStyle{$name}.appendValue $sel
         end
         if Defined $attr.paragraphStyleName
            $name = $paraStyleMark & $attr.paragraphStyleName
            if $selectionsByStyle{$name} == undefined
               $selectionsByStyle{$name} = Array.new
            end
            $selectionsByStyle{$name}.appendValue $sel
         else
            $name = $paraStyleMark & $noStyleName
            if $selectionsByStyle{$name} == undefined
               $selectionsByStyle{$name} = Array.new
            end
            $selectionsByStyle{$name}.appendValue $sel
         end
         if Defined $attr.listStyle
            $name = $listStyleMark & $attr.listStyle.name
            if $selectionsByStyle{$name} == undefined
               $selectionsByStyle{$name} = Array.new
            end
            $selectionsByStyle{$name}.appendValue $sel
         end
         $i = $range.bound
      end
   end
end

$styleNames = $selectionsByStyle.keys
$styleNames.sort 'li', $language

$styleNames = Prompt Checkboxes 'Select all texts in specific styles . . .', '', '', $styleNames

if ! $styleNames.count
   exit 'Nothing checked, exiting . . .'
end

$sels = Array.new
foreach $name in $styleNames
   $sels.appendValuesFromArray $selectionsByStyle{$name}
end

$doc.setSelections $sels

### end of macro ###


2011-01-13 09:55:02
Profile

Joined: 2008-05-17 04:02:32
Posts: 400
I modified the macro again. Thanks to getProperty command, I could simplify the code in the first “foreach . . . end” loop. This makes it easier to maintain the macro, e.g. fix a potential/real bug. As a side effect, not only for Paragraph Style but also for Character and List Styles, selections not having any style are listed up. Useless, I think, but harmless. And perhaps there may be situations in which “[a̱] <no style>” or “[#] <no style>” are useful.

In spite of that, this version is longer than the previous ones because...

 • It checks for empty document (i.e. not a singe character in it).
 • The Macro Prompt is more informative (addition of $detail).
 • More easily customizable/localizable because of variables.

The last reason mentioned above applies especially to an array$styleCategories” and hashes declared in “$styleSymbols = $properties = $selectionsByStyle = Hash.new”. The macro works without problem even if the definition of $styleCategories has been changed to “$styleCategories = Array.new '○', '▴', '□'”, for example ;-)

IMO, one of the most fantastic features of Nisus Writer Pro Macro language is hash. It is very strong and versatile. You can put in it anything: normal Text object ($styleSymbols and $properties although the latter will be treated as Attributes Object properties by getProperty), array ($selectionsByStyle) and/or anything else.
Code:
 $noStyleName = Cast to String '<no style>'  # customizable
$styleString = 'Style'  # customizable (used in Macro Prompt's $detail)
$promptMessage = 'Select all texts in styles of your choice...'  # customizable
$emptyDocument = 'Empty document, exiting...'  # customizable (error message)
$nothingChecked = 'Nothing checked, exiting...'  # customizable (error message)
$sp = Cast to String "\x20"  # customizable but...

$styleCategories = Array.new 'Character', 'Paragraph', 'List'  # customizable

$styleSymbols = $properties = $selectionsByStyle = Hash.new
$styleSymbols{$styleCategories[0]} = Cast to String '[a̱]'  # customizable (for Character Style)
$styleSymbols{$styleCategories[1]} = Cast to String '[¶]'  # customizable (for Paragraph Style)
$styleSymbols{$styleCategories[2]} = Cast to String '[#]'  # customizable (for List Style)

$properties{$styleCategories[0]} = 'characterStyle'
$properties{$styleCategories[1]} = 'paragraphStyle'
$properties{$styleCategories[2]} = 'listStyle'

Require Pro Version 1.3
$doc = Document.active
if $doc == undefined
   exit  # no open document
end

$language = Language.systemLanguage

foreach $text in $doc.allTexts
   if $text.length
      $textRanges = Array.new
      if $text.tables.count  # then, exclude special chars enclosing tables
         $tableRanges = Array.new
         foreach $table in $text.tables
            $tableRanges.appendValue $table.enclosingTextRange
         end
         $tableRanges.sort
         $i = 0
         foreach $tableRange in $tableRanges
            $range = Range.newWithLocationAndBound $i, $tableRange.location
            $textRanges.appendValue $range
            $i = $tableRange.bound
         end
         $range = Range.newWithLocationAndBound $i, $text.length
      else
         $range = Range.new 0, $text.length
      end
      $textRanges.appendValue $range
      foreach $textRange in $textRanges
         $i = $textRange.location
         while $i < $textRange.bound
            $attr = $text.displayAttributesAtIndex $i
            $range = $text.rangeOfDisplayAttributesAtIndex $i
            $sel = TextSelection.new $text, $range
            foreach $property in $properties.keys
               $styleObject = $attr.getProperty $properties{$property}
               $name = $styleSymbols{$property}
               if Defined $styleObject
                  $name &= $sp & $styleObject.name
               else
                  $name &= $sp & $noStyleName
               end
               if $selectionsByStyle{$name} == undefined
                  $selectionsByStyle{$name} = Array.new
               end
               $selectionsByStyle{$name}.appendValue $sel
            end
            $i = $range.bound
         end
      end
   end
end

if ! $selectionsByStyle.count
   exit $emptyDocument
end

$styleNames = $selectionsByStyle.keys
$styleNames.sort 'li', $language

$detail = Array.new
foreach $key, $value in $styleSymbols
   $temp = ''
   $temp = $temp.textByAppending $value, $sp, $key, $sp, $styleString
   $detail.appendValue $temp
end
$detail.sort 'li', $language
$detail = $detail.join ', '

$styleNames = Prompt Checkboxes $promptMessage, $detail, 'Select!', $styleNames

if ! $styleNames.count
   exit $nothingChecked
end

$sels = Array.new
foreach $name in $styleNames
   $sels.appendValuesFromArray $selectionsByStyle{$name}
end

$doc.setSelections $sels
Attachment:
SelectByStyle_20110116_nwm.zip [5.41 KiB]
Downloaded 240 times


2011-01-15 10:09:16
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 7 posts ] 

Who is online

Users browsing this forum: Bing [Bot] and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software