                                ZapJRF
                                ======

Introduction
------------
This module began life as 'ZapDecimal' because of a minor bug in version 1.20
of Zap. The bug was fixed in 1.30, but the name sort of stuck. However, any
copies of that module should be deleted and this version used instead.

In this module are a few useful commands, and some not so useful ones :
   JRF_RUNFILE     Save file to disc and Filer_Run it
   JRF_PATCHTAB    Insert my custom tabs for JFPatch
   JRF_NOTIFY      Place a message in the minibuffer
   JRF_ALTERSEL    Alter the selection
   JRF_CLEARSEL    Clear the selection
   JRF_BRACKET     Bracket the current word with a string
   JRF_BRACKETSEL  Bracket the selection with a string
   JRF_EACHLINE    Perform some set of commands on every line of the selection
   JRF_IF          Conditional execution based on the text at the cursor
   JRF_DROPMARK    Drop a marker at the cursor
   INSERTFILE      Insert a file at the cursor
   RUNSCRIPT       Execute a 'script' file
   JRF_SCRIPTADDR  Execute a 'script' from memory (selected use)

Also, ZapJRF adds an OSCLI command *ZapCommand which allows you to run
commands from Obey files.


*ZapCommand
-----------
Syntax:  *ZapCommand <any valid zap command>
Purpose: Executing ZapCommands from 'elsewhere'
Description:
  From outside Zap you can execute a single command string on the window with
  the current focus. This might be useful if you wanted to load a text file
  and move to the bottom, or something. The main reason I wrote it was to
  select Decimal display mode, but this is no-longer required.


JRF_RUNFILE
-----------
Syntax:  JRF_RUNFILE
Purpose: Save file to disc and Filer_Run it
Description:
  This tends to be useful for files that don't have their own modes, but can
  work quite happily in one of the other modes. Good examples of this might be
  Perl, Clips or Prolog being displayed in C mode (although there is now a
  dedicated Perl mode).


JRF_PATCHTAB
------------
Syntax:  JRF_PATCHTAB
Purpose: Inserting my custom tabs for JFPatch
Description:
  Inserts tabs at column 3, 11 or 41, whichever is the next one along.
  At column 41 a semi-colon and space will automatically inserted. I find
  that this is useful for editing JFPatch files, but SAsm users may like it.


JRF_NOTIFY
----------
Syntax:  JRF_NOTIFY "<message>"
Purpose: Placing a message in the minibuffer
Description:
  If you ever need to notify the user of some operation then this might be
  one way of doing it. Originally I wrote this to allow my BaseMap changes
  to notify me.


JRF_ALTERSEL
------------
Syntax:  JRF_ALTERSEL
Purpose: Alter the selection whilst in Auto-Clr selection mode
Description:
  I wanted to write a 'shift-cursor' selection thing for HTML, but because
  I use the auto-clear selection mode this didn't work. This version of
  ALTERSEL remembers the previous selection and modifies that so that Zap
  can't delete it. It doesn't work amazingly well.


JRF_CLEARSEL
------------
Syntax:  JRF_CLEARSEL
Purpose: Clear the selection
Description:
  As JRF_ALTERSEL remembers the last selection location I had to write a
  'clearer' so that I can actually get rid of a selection every so often.


JRF_BRACKET
-----------
Syntax:  JRF_BRACKET "<break><left string><break><right string>"
Purpose: Bracket the current word with a string
Description:
  If you do any work in HTML or StrongHelp you'll know that certain things
  are delimited by characters or sequences, eg HREF's. JRF_BRACKET can be
  useful to surround a word with one of these groups.


JRF_BRACKETSEL
--------------
Syntax:  JRF_BRACKET "<break><left string><break><right string>"
Purpose: Bracket the selection with a string
Description:
  This is identical to JRF_BRACKET but applies to a selection.


JRF_EACHLINE
------------
Syntax:  JRF_EACHLINE "<break><top com><break><line com><break><end com>"
Purpose: Perform some set of commands on every line of the selection
Description:
  Originally this was designed to create instant HTML lists. The first
  argument will be executed at the top of the selection, the last at the
  end of the selection, and the middle one on the start of every line
  of the selection.


JRF_IF
------
Syntax:  JRF_IF <break><compare><break><then clause>
    or:  JRF_IF <break><compare><break><break><else clause>
    or:  JRF_IF <break><compare><break><then clause><break><else clause>
Purpose: Conditional execution based on the text at the cursor
Description:
  Whilst working in the HTML modes I found it useful to be able to do things
  depending on what was already at the cursor. JRF_IF allows you to check the
  text at the cursor and execute one of two different sets of instructions
  depending on whether the text and your string are the same.
  Comparison is case insensitive and control characters can be checked by
  using |<character> in the same way as the *Echo command.
  A large stack is installed when you execute this command because depths
  of around 6 JRF_IF's mean that there is no longer any stack space to run
  commands.
  Remember that such a depth results in 64 consecutive " symbols appearing
  consecutively. Whilst this is allowable, and I have safely executed
  commands with over 1024 consecutive "'s in them, this is NOT recommended.
  Special checks are present in this code to extend the stack as at this level
  of complexity the standard stack is not large enough.
  If you wish to write such complex commands, do it as an extension module,
  or use RUNSCRIPT.


JRF_DROPMARK
------------
Syntax:  JRF_DROPMARK
Purpose: Drops a marker at the cursor
Description:
  This should explicitly drop a mark at the current cursor location, rather
  than toggling if there is a mark as TOGGLEMARK does.
  

INSERTFILE
----------
Syntax:  INSERTFILE "[*][|]<filename>"
Purpose: Inserts a file at the cursor
Description:
  I got fed up writing those long command lines in the Keys file. Not only do
  they take up lots of memory, but they are clumbersome and getting the
  number of "'s correct just drives me mad !
  INSERTFILE will do just that - insert a file at the cursor. You may
  prefix the filename with | to indent it as if it were typed in the mode, or
  * to parse the lines with GSTrans before insertion.
  Please keep the lines (and their expansions) less than 256 bytes - if you
  try to do more things will not go right.


RUNSCRIPT & JRF_SCRIPTADDR
---------   --------------
Syntax:  RUNSCRIPT "<filename>"
         JRF_SCRIPTADDR <address>
Purpose: Execute a 'script' file (or from memory)
Description:
  These are arguably the most powerful Zap command I've written. At least I
  argue it. The file (or memory) you specify will be read in, a line at a
  time, and each command executed. There are also special functions available
  in script files :
    #IfText "<text>"
      Like JRF_IF, this will perform a comparisson on the text at the cursor
      and, if they are the same, execute the next block of code. In addition
      to the escaped characters in JRF_IF, you can also use |" to escape a "
      symbol.
    #IfMode <mode>[{,<mode>}]
      Like MJE_IFMODE, this will perform a check on the current mode before
      executing the next block of code.
    #IfModeN <mode name>[{,<mode>}]
      This is identical to #IfMode, except that it requires mode names.
    #Else
      Inverts the execution state (if we are executing this block).
    #EndIf
      Ends the current If statement.
    |<anything>
      Is ignored.
    #Stop
      Stops execution at the current point (obeying 'if's)
    #ScriptEnd
      Marks the end of a script (only really useful in JRF_SCRIPTADDR where
      it MUST be used).

  If statements can be nested up to 256 levels - this is still poorly managed
  but should be adequate for most uses. Lines in scripts MUST NOT exceed 255
  characters currently.


Scripting directive additions
-----------------------------
You can write modules which provide their own scripting directives to
supplement the built in ones. To do this you should recognise the following
service calls :

Service_ZapJRFScripts &90480 (not officially allocated and picked at random)
  => r0 = reason
          (0 = starting, 1 = dying)
     r1 = &90480
  
  This service is issued as ZapJRF starts and shuts down. You should call
  ZapJRF_RegisterScriptDirectives or ZapJRF_DeRegisterScriptDirectives 
  respectively.
  You should not claim this service. 
  
ZapJRF_RegisterScriptDirectives
  => r0-> table of directives, of the form :
          <zero-terminated capitalised string>
          <offset>
          repeated, and terminated with a null string (ie 0 byte)
     r1-> base of offsets (ie, where the offsets are from)
     r2 = private word
  
  You should call this to register your script directives table. This should
  be done on initialisation and when receiving Service_ZapJRFScripts with
  reason = 0.

ZapJRF_DeRegisterScriptDirectives
  => r0-> table of directives, of the form :
          <zero-terminated capitalised string>
          <offset to routine>
          repeated, and terminated with a null string (ie 0 byte)
     r1-> base of offsets (ie, where the offsets are from)
     r2 = private word
  
  You should call this to deregister your script directives table. This
  should be done on finalisation and when receiving Service_ZapJRFScripts
  with reason = 1. The registers passed should all be the same as when
  originally passed.

Routines will be called with the following parameters :
  => r0-> first valid character (if any)
     r2 = character we stopped on (32 for params, 0 if none)
     r3 = private word
     r4-> 'if structure'
     r5 = 'if structure' offset (depth)
     r6-> start of line buffer (add 256 for a temporary buffer)
     r7 reserved for future update
     r8-> window block (as for Zap)
     r9-> file block (as for Zap)
     r10-> cursor block (as for Zap)
     r11 = 1 if command should be done ('if' state)
     r12-> zap workspace
     r13-> full descending stack (of unspecified length)
     r14-> return address

  <= r7,r12 preserved
     r8,r9,r10 preserved or updated
     r5 preserved or incremented/decremented by 1
     r11 preserved, or toggled for 'if's, or set to 2 to stop
     r0-r4,r6 corrupt
     Do NOT restore flags on return

  You will be able to call any Zap routine with the standard FNcall()
  code. Try not to write code which dies :-)


External file
-------------
You'll need to add the following to your external file
<Zap$3rdParty>.Fletcher.!ZapJRF.ZapJRF Obey <Zap$3rdParty>.Fletcher.!ZapJRF.!Run *
	-
	JRF_PATCHTAB			&0
	JRF_RUNFILE			&0
	JRF_NOTIFY			&118
	JRF_ALTERSEL			&0
	JRF_CLEARSEL			&0
	JRF_BRACKET			&18
	JRF_BRACKETSEL			&18
	JRF_EACHLINE			&18
	JRF_IF				&18
	JRF_DROPMARK			&0
	INSERTFILE			&18
	RUNSCRIPT			&18
	JRF_SCRIPTADDR			&2010
	-

History (Note, Justin: You must assemble this with BasicVExt installed)
-------
Older versions : Sometime long ago
                 Who cares what happened to them... they're dead and buried.
Version 1.13 : 05 Dec 1996
               Renamed to ZapJRF and other changes.
Version 1.15 : 12 Mar 1997
               Insertion of lumps of text with JRF_INSERTFILE implemented
               JRF_UPDATEWINDOW killed - use TMT_UPDATEWINDOW in preference.
               (As of 23 May 1997, use UPDATEWINDOW in preference)
Version 1.17 : 19 Mar 1997
               Scripting added using JRF_DOFILE.
Version 1.18 : 02 Apr 1997
               Renamed JRF_INSERTFILE to INSERTFILE and JRF_DOFILE to
               RUNSCRIPT. JRF_SCRIPTADDR written.
               Scripts should now use | as comments. #ScriptEnd and #Stop
               added.
Version 1.19 : 03 Apr 1997
               Multiple script directive tables now supported.
Version 1.20 : 07 May 1997
               Bug in JRF_SCRIPTADDR fixed (ValidateAddress)
