Reply to topic  [ 6 posts ] 
Can a variable be made to survive a macro? 
Author Message

Joined: 2007-04-12 14:59:36
Posts: 229
Is it possible to create a variable that survives the macro and is kept for a whole Nisus session?
Can document properties by attributed by a macro and later read?


2009-02-28 10:34:42
Profile
Official Nisus Person
User avatar

Joined: 2002-07-11 17:14:10
Posts: 4251
Location: San Diego, CA
js wrote:
Is it possible to create a variable that survives the macro and is kept for a whole Nisus session?

It is possible- you'll want to use the Registry object. Which registry you use depends on how long you want the value to stick around. If you just want something for a "session", which I imagine means the time from launch to quit, then use the "applicationRegistry", eg:
Code:
$valueKey = 'com.nisus.example.favoriteColor'
$registry = Registry.applicationRegistry
$color = $registry.loadValueWithName($valueKey)
If $color == undefined
   $color = Prompt Input "What's your favorite color?"
   $registry.saveValueWithName($color, $valueKey)
   Prompt "Thanks, I'll remember that until you quit NWP."
Else
   Prompt "Probably your favorite color is still $color."
End

See the macro reference for more.

Quote:
Can document properties by attributed by a macro and later read?

That's an interesting idea. There's currently no such feature, but I'll file a request, thanks.


2009-02-28 14:34:15
Profile WWW

Joined: 2007-04-12 14:59:36
Posts: 229
Thanks for your help. Based on your example I created a pair of macros that set a flag into a text and jump to its position respectively. I gave them the shortcuts cd-FL and cd-FLL.

Code:
#set flag
$valueKey = 'com.nisus.example.myLoc'
$registry = Registry.applicationRegistry
$flagLoc = $registry.loadValueWithName($valueKey)
$flagLoc = Selection Location
$registry.saveValueWithName($flagLoc, $valueKey)


Code:
#jump to flag
$valueKey = 'com.nisus.example.myLoc'
$registry = Registry.applicationRegistry
$flagLoc = $registry.loadValueWithName($valueKey)
Set Selection Location $flagLoc
Scroll to selection


I find these very helpful to edit large documents. Of course the macros would be even better if they could also memorize the document-path, instead of only the selection. Could this be done in one go together with the selection, or would one need a separate pair: one for the location and one for the path?


2009-03-02 08:57:22
Profile

Joined: 2008-05-17 04:02:32
Posts: 400
js wrote:
Of course the macros would be even better if they could also memorize the document-path, instead of only the selection. Could this be done in one go together with the selection, or would one need a separate pair: one for the location and one for the path?

A while ago, I wrote such macros which might be of your interest. They use a hash -- $zeroMarker{$doc} -- to memorise a location per document.
Code:
### Zero Marker (3.1.3) ###

#   This macro works as a toggle command and sets or clears the zero marker depending on the situation.

#   - If there is no zero marker, the macro sets the zero marker to the current selection (the last selection if there are multiple selections) on the active document. The selection may be zero-width (caret).

#   - If the active document has already the zero marker, the macro restore the selection stored in the zero marker.

#   - if the selection stored in the zero marker is exactly the same as the current selection (the last selection if there are multiple selections), the macro clears the zero marker. In other words, you can clear the zero marker by running the macro twice without modifying the current selection.

#   The zero marker consists of a Document object and a TextSelection object stored in the Application Registry (global variable). And a TextSelection object consists of a text object and a character range. So you may not be able to get back to the same position/selection if the portion of document preceding the zero marker has been modified after it was set.

Require Application Version '3.1'  # require NW Pro v1.1 (3.1 is an internal version number)
$doc = Document.active  # get the document object of this document and put it in $doc
if $doc == undefined
   Exit 'No document is open, exit...'
end

$selection = $doc.textSelections.lastValue  # get the current selection -- the last selection if there are multiple selections -- and put it in $selection

$identifier = 'com.nisususerkino.zeromarker.selection'  # you can use another identifier as far as it is unigue and the same as that of Zero Marker Select macro
$appRegistry = Registry.applicationRegistry  # use applicationRegistry which persists until NW Pro quits
$zeroMarker = $appRegistry.loadValueWithName $identifier  # load the value for $identifier from the Registry to $zeroMaker

if $zeroMarker == undefined  # which means that the Registry has no value corresponding to $identifier
   $zeroMarker = Hash.new $doc, $selection  # re-initialize $zeroMaker as a new hash with "key = this document" and "value = the current selection"
else
   if $zeroMarker{$doc} == undefined  # which means that $zeroMarker has no value for this document
      $zeroMarker{$doc} = $selection  # define the value of $zeroMarker for this document as the current selection
   else
      $zeroMarkerRange = $zeroMarker{$doc}.range
      if $zeroMarkerRange.bound > $doc.text.length
         if $zeroMarkerRange.location > $doc.text.length
            $zeroMarkerRange.location = $doc.text.length
         end
         $zeroMarkerRange.bound = $doc.text.length
         $zeroMarker{$doc} = TextSelection.new $zeroMarker{$doc}.text, $zeroMarkerRange
      end
      if $zeroMarker{$doc} == $selection  # if the value of $zeroMarker for this document is the same as the current selection
         $zeroMarker.removeKey $doc  # make the value of $zeroMarker for this document undefined
      else
         $doc.setSelection $zeroMarker{$doc}  # restore the selection stored in $zeroMarker
      end
   end
end

$appRegistry.saveValueWithName $zeroMarker, $identifier  # save the updated $zeroMarker to the Registry as the value of $identifier

### end of macro ###

Code:
### Zero Marker Select (3.1.2) ###

#   This macro selects from the active selection (the last selection if there are multiple selections) to the zero marker. The selection may be zero-width (caret).

#   This macro works as a toggle command and sets or clears the zero marker depending on the situation.

#   - If there is no zero marker, the macro sets the zero marker to the current selection (the last selection if there are multiple selections) on the active document. The selection may be zero-width (caret).

#   - If the active document has already the zero marker and if the text object is the same for the zero marker and for the active selection, the macro selects from the active selection to the zero marker.

#   - If the active document has already the zero marker and if the text object is different for the zero marker and for the active selection (for example, the zero marker is in the footnotes area and the active selection in the body), the macro resets the zero marker to the active selection without modifying the latter.

#   - If the selection stored in the zero marker or the new selection which will cover from the zero marker to the current selection is exactly the same as the current selection (the last selection if there are multiple selections), the macro clears the zero marker and put the caret at the end of the current selection. In other words, you can clear the zero marker by running the macro twice without modifying the current selection.

#   The zero marker consists of a Document object and a TextSelection object stored in the Application Registry (global variable). And a TextSelection object consists of a text object and a character range. So you may not be able to get back to the same position/selection if the portion of document preceding the zero marker has been modified after it was set.

Require Application Version '3.1'  # require NW Pro v1.1 (3.1 is an internal version number)
$doc = Document.active  # get the document object of this document and put it in $doc
if $doc == undefined
   Exit 'No document is open, exit...'
end

$selection = $doc.textSelections.lastValue  # get the current and the last selection and put it in $selection

$identifier = 'com.nisususerkino.zeromarker.selection'  # you can use another identifier as far as it is unigue and the same as that of Zero Marker macro
$appRegistry = Registry.applicationRegistry  # use applicationRegistry which persists until NW Pro quits
$zeroMarker = $appRegistry.loadValueWithName $identifier  # load the value for $identifier from the Registry to $zeroMaker

if $zeroMarker == undefined  # it means that the Registry has no value corresponding to $identifier
   $zeroMarker = Hash.new $doc, $selection  # re-initialize $zeroMaker as a new hash with this document as key and the current selection as value
elsif $zeroMarker{$doc} == undefined  # then, the Registry has $zeroMarker which, however, has no value for this document
   $zeroMarker{$doc} = $selection  # define the value of $zeroMarker for this document as the current selection
else  # then, the Registry has $zeroMarker which has a value for this document
   if $zeroMarker{$doc} == $selection  # if the value of $zeroMarker for this document is the same as the current selection
      $zeroMarker.removeKey $doc  # make the value of $zeroMarker for this document undefined
      $range = Range.new $selection.bound, 0  # create a zero-width range corresponding to the selection end
   elsif $zeroMarker{$doc}.text == $selection.text  # if the value of $zeroMarker for this document is differnt from the current selection but belongs to the same text object
      $allSelections = Array.new $zeroMarker{$doc}, $selection  # create an array containing both selections
      $allSelections.sort  # sort $allSelections by location
      $bound = $allSelections[1].bound  # which corresponds to the boundary of the selection closer to the document end
      if $bound > $selection.text.length  # if it is beyond the document end
         $bound = $selection.text.length  # reset $bound to the document end
      end
      $range = Range.newWithLocationAndBound $allSelections[0].location, $bound  # create a range covering both selections
      if $range == $selection.range  # if the range covering both selections is identical to that of the current selection
         $range = Range.new $selection.bound, 0  # re-initialize $range as a zero-width range corresponding to the selection end
         $zeroMarker.removeKey $doc  # make the value of $zeroMarker for this document undefined
      end
      $newSelection = TextSelection.new $selection.text, $range  # create a TextSelection object corresponding to $range
      $doc.setSelection $newSelection  # select $newSelection
   else  # if the value of $zeroMarker for this document is differnt from the current selection and belongs to a different text object
      $zeroMarker{$doc} = $selection  # redefine the value of $zeroMarker for this document as the current selection
   end
end

$appRegistry.saveValueWithName $zeroMarker, $identifier  # save the updated $zeroMarker to the Registry as the value of $identifier

### end of macro ###


2009-03-02 09:19:27
Profile

Joined: 2007-04-12 14:59:36
Posts: 229
Thanks, Kino. Your macros are obviously far more sophisticated, and I find they work very well. Still, in some circumstances we might want a simple macro that finds the spot of it's origin, in whatever document you are.


2009-03-02 14:21:07
Profile

Joined: 2008-05-17 04:02:32
Posts: 400
js wrote:
Still, in some circumstances we might want a simple macro that finds the spot of it's origin, in whatever document you are.

How about this one?
Code:
#   This macro works as a toggle command and defines or remove $markedSelection (document object and text selection object) depending on the situation.
#   if $markedSelection is not defined, use the current selection to define it.
#   if $markedSelection is defined, the macro restores the selection and removes it except that...
#      if the document has become too short to restore the selection, the macro puts the caret at the end of the text object (document end if it is body text).
#      if the document is not open anymore, the macro will not try to open it.

Require Application Version '3.1'
$doc = Document.active
if $doc == undefined
   Exit 'No document is open, exit...'
end
$sel = $doc.textSelection

$message = ''
$identifier = 'com.usermacro.markedSelection'
$appRegistry = Registry.applicationRegistry
$markedSelection = $appRegistry.loadValueWithName $identifier

if $markedSelection == undefined
   $markedSelection = Array.new $doc, $sel
   # create an array with the active document and text selection objects
   $appRegistry.saveValueWithName $markedSelection, $identifier
   # save $markedSelection as $identifier in $appRegistry
   $message = 'This selection has been saved as marked.'
else  # i.e. if $markedSelection is defined
   $markedDoc = $markedSelection.firstValue  # put the document object in $markedDoc
   $markedSel = $markedSelection.lastValue  # put the text selection object in $markedSel
   $docs = Document.openDocuments  # put document objects of all open documents in $doc (array)
   $check = $docs.indexOfValue $markedDoc
   if $check == -1  # i.e. if $markedDoc is not found in $docs
      $message = 'Marked document is not open anymore.'
   else
      Document.setActive $markedDoc
      $len = $markedSel.text.length
      if $markedSel.bound > $len
         $message = 'This document has become too short to restore the original selection.'
         $markedSel = TextSelection.newWithLocationAndLength $markedSel.text, $len, 0
         # redefine $markedSel so as to make a zero-width selection at the document end
      end
      $markedDoc.setSelection $markedSel
   end
   $appRegistry.removeValueWithName $identifier  # clear $markedSelection
end

if $message  # i.e. if $message is not empty...
   exit $message
end

### end of macro ###

If you find annoying some of the messages, just remove the corresponding $message = '...' or the last "if ... end" block.

I think it would be great if Nisus Writer Pro Macro has a way of notification which does not force the user to click OK button, something like what Growl does.


2009-03-02 23:27:52
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 6 posts ] 

Who is online

Users browsing this forum: No registered users and 3 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