Thu Jan 22 13:08:54 1998This file documents the various hooks for extending JED.

A `hook' is simply a user defined S-Lang function that may be used to extend
the editor or to modify how it behaves under certain circumstances.  There
are two kinds of hooks that vary according to whether the hook is called
``internally'' from the editor by the underlying C code or whether the hook
is called from another S-Lang routine.  The hooks may be subdivided further
according to their scope.  They may apply to all buffers (globally), only
buffers sharing the same mode (modal), or to a single buffer (local).

Global Hooks.

   The global hooks affect all buffers.  They are:

     1. `command_line_hook': This hook is called from within the editor to
	parse the command line arguments.  It is defined in the file
	`site.sl' and cannot be customized by the user.  However, the it may
	be customized by the system manager.  In addition to parsing the
	command line arguments the default value of this hook also loads the
	user's personal initialization file.
     
     2. `jed_startup_hook':  Although this function is defined in `site.sl',
	it can be changed by a user because it is called after the user
	initialization file is loaded.  This hook is called just prior to
	the main editing loop of the editor.  It also calls the hook
	`startup_hook' which may be defined by the user as a convenient way
	to customize `jed_startup_hook'.  See `exit_hook' for an example of
	how this may be exploited.
	
     3. `exit_hook':  This hook is called when the intrinsic function
	`exit_jed' is called.  Although it has no default definition does
	not mean that it is not useful.  For example, one could use:
	
	define exit_hook()
	{
	   variable ch;
	   if (BATCH) exit_jed();
	   
	   flush("Really Exit? ");
	   ch = getkey();
	   if ((ch == 'Y') || (ch == 'y')) exit_jed ();
	   error ("Aborted!");
        }

       to confirm the exit.  Note also that although `exit_jed' calls this
       function, `exit_hook' will not be called again if it int turn calls
       `exit_jed'.
       
       Also, for MSDOS it might be desirable for the editor to exit in the
       same directory that it started.  This will work:
       
          define exit_hook()
	  {
	     variable dir;
	     if (bufferp("*scratch*"))
	       {
	          sw2buf("*scratch*");
		  (,dir,,) = getbuf_info();
		  change_default_dir(dir); pop();
	       }
	     call( "exit_jed" );
	  }

       Like many hooks, if an error is generated by the hook, the function
       that called it will fail and the operation will be aborted.
       
       Finally, `exit_hook' and `startup_hook' may be used together to
       implement a way of saving the state of the editor.  A minimal
       implementation might be:
       
           variable Jed_State_File = dircat (getenv ("HOME"), ".jedstate");

           define exit_hook ()
	   {
	     variable file = buffer_filename ();
	     variable cmd;
	     
	     if (strlen (file))
	       {
	          % This is mainly for MSDOS to fix the backslash character
		  % used for path names.
	          file = str_quote_string (file, "\\", '\\');
		  
		  cmd = Sprintf ("() = find_file (\"%s\");", file, 1);
		  cmd = Sprintf ("%s\ngoto_line (%d); goto_column (%d);",
		                  cmd, whatline (), what_column (), 3);

		  () = write_string_to_file (cmd, Jed_State_File); 
	       }
	     exit_jed ();
	   }
	   
	   define startup_hook ()
	   {
	      if (1 == file_status (Jed_State_File))
	        {
		  () = evalfile (Jed_State_File);
		  () = delete_file (Jed_State_File);
	        }
	   }
	   
	   
        
    4. `suspend_hook': This hook has no default value and is called just
       before suspending the editor.  One might use it as a simple way of
       prohibiting suspension, e.g.,
       
           define suspend_hook ()
	   {
	      error ("Suspending not allowed.");
	   }

    5. `resume_hook': It is called immediately after JED resumes after being
       suspended.  This hook is predefined only on VMS systems.  This does
       not mean that it cannot be used on other systems as well.  For
       example, here is a silly use

           define resume_hook ()
	   {
	      message ("Welcome back!");
	   }
	   
       but I am sure that you will think of something more clever.
       
    6. `mode_hook':  Immediately after JED loads a file into a buffer, it
       calls `mode_hook' to set the mode of the buffer.  The default value
       is defined in `site.sl'.  This hook is called with with the file name
       extension of the file as its only parameter.  This function sets the
       mode of the buffer based on the value of the file name extension.
       
       There are several ways to customize this hook.  The easiest is to
       simply call the function `add_mode_for_extension' with the mode that
       is to be associated with a particular extension.  For example,
       suppose that you edit files with names like `main.c++'.  To have
       `c_mode' associated with files of this type, simply call:
       
          add_mode_for_extension ("c", "c++");
	  
       The important point to realize is that the first parameter is the
       name of the mode but it should not include the `_mode' part of the
       mode name.
       
       The other way to customize mode_hook is through the function pointer
       `mode_hook_pointer' which the user can define to set the mode.  If
       the function pointed to by `mode_hook_pointer' returns non-zero,
       `mode_hook' will return to the calling routine.  Specifically, the
       default value of `mode_hook' looks like:

           define mode_hook (ext)
	   {
	      if (mode_hook_pointer (ext)) return;
	      .
	      .
	   }
       
       One could simple point `mode_hook_pointer' to something like:
       
           define set_no_mode (ext)
	   {
	      return 1;
	   }
	   mode_hook_pointer = &set_no_mode;
	   
       Typically, one would do something useful like:
       
          define my_mode_hook (ext)
	  {
	     if (strcmp ("pas", ext)) return 0;
	     my_pascal_mode ();
	     return 1;
	  }
	  mode_hook_pointer = &my_mode_hook;
	  
       Here `my_pascal_mode' is a hypothetical pascal mode.
       
       As a final example, consider the case where one would like to set the
       mode based on the filename and NOT the extension.  For example, the
       Elm mailer user files of the form `snd.XXX' and one would like to use
       text mode on such files.  Again, the solution is to use the
       `mode_hook_pointer':
       
          define my_mode_hook (ext)
	  {
	     variable file;
	     (file,,,) = getbuf_info ();
	     if (0 != strncmp (file, "snd.", 4)) return 0;
	     text_mode ();
	     return 1;
	  }
	  mode_hook_pointer = &my_mode_hook;
	  
       Finally, the global variable `Default_Mode' may be pointed to a
       function to set the mode if a suitable mode was not obtained from the
       extension.  By default, it has the value:
       
           Default_Mode = &text_mode;
	   

      
    7. `find_file_hook':  This hook is called after a file is read into the
       editor via the internal function `find_file'.  It is passed the full
       filename of the file read into the buffer.  The supplied default for
       this function simply looks for an autosave file and warns the user 
       if it should be used instead.  It might also be used to preprocess
       the buffer before the user starts to edit it.
       
          *** Note: This hook will most likely be changed such that it is
	            called before the file is read in.

    8. `format_paragraph_hook': This hook is called after a paragraph is
       formatted but only if the a prefix argument was given prior to the
       execution of the internal function `format_paragraph'.  That is, the
       default binding of `format_paragraph' is `ESC q'.  Pressing `ESC 1'
       immediately before pressing `ESC q' will format the paragraph and
       then call `format_paragraph_hook'.  The default definition for this
       hook left and right justifies the paragraph.

    9. `is_paragraph_separator': This hook is called by the editor to locate
       paragraph delimeters.  If defined, it applies globally to all buffers
       except those which have a local definition (see the `par_sep' hook).
       The default value is coded in C and basically reduces to:
       
       define is_paragraph_separator ()
       {
         bol();
	 if (looking_at("\\") or looking_at("%")) return (1);
         skip_white();
	 return (eolp());
       }

       which is useful for TeX mode.  The hook must simply return a non-zero
       value if the current line is a paragraph delimeter or zero if it is
       not.

   10. `save_buffer_hook': This hook is called just prior to saving
       the current buffer to a file.  If defined, it should accept two
       arguments: the name of the file and the mode of the buffer, e.g.,
       
           define save_buffer_hook (file, mode)
	   {
	      if (mode != "C")
	        return;
	        
	      push_spot ();
	      bob ();
	      vinsert ("/* %s */\n", time ());
	      pop_spot ();
	   }

       will cause the current line to be inserted at the top of the
       buffer if the buffer's mode is C.
      
Mode Hooks:

  These are hooks that get called when the editor enters a particular
  mode.  Usually, one just wants to defined keys.  For this purpose, use the
  `local_setkey' function.
  
  1. `tex_mode_hook':  This hook is called when JED starts its TeX mode.
      Use it to bind certain functions that either have no binding or have
      one that you do not like, e.g.,
      
         define tex_mode_hook ()
	 {
	    local_unsetkey ("^C");
	    local_setkey ("latex_do_environment", "^C^E");
	    local_setkey (" \\alpha", "^Ca");
	    local_setkey (" \\Alpha", "^CA");
	    local_setkey (" \\Beta",  "^CB");
	    local_setkey (" \\beta",  "^Cb");
	    % etc...
	 }
      
      Notice that in this hook, I have simply set keys `Ctrl-C a', etc... to
      insert `\alpha', etc...
      
  2. c_mode_hook
  3. fortran_hook
  4. text_mode_hook
  5. mail_hook
  
       A useful hook here is to defined Ctrl-C Ctrl-C to send the message al
       la emacs:
       
           define mail_hook ()
	   {
	      local_unsetkey ("^C");
	      local_setkey ("send", "^C^C");
	   }

  6. slang_mode_hook
  7. dired_mode_hook
  8. fortran_hook
  
Local hooks:
  
   These hooks apply to individual buffers.  They must be ``declared'' to
   the buffer using the intrinsic function `set_buffer_hook'.
   
      1. `par_sep': function used to determine where paragraph boundaries
         are.  See the hook `is_paragraph_separator' for more information.
	 
      2. `indent_hook': function called after a line is indented by the
         function `indent_line'.
	 
      3. `wrap_hook': function called after a line is wrapped.  For example,
         in writing this document, I want the lines following the numbers to
	 be offset some.  So I wrote:
	 
	       define text_mode_wrap_hook ()
	       {
	          variable p;
	          push_spot ();
		  go_up(1); bol (); skip_white ();
		  p = POINT;
		  skip_chars ("0-9"); 
		  if ((p != POINT) and looking_at (". "))
		    {
		       go_down(1); bol (); skip_white ();
		       p = what_column ();
		       bol (); trim ();
		       whitespace (p + 3);
		    }
		  pop_spot ();
	       }
	       
	 In fact, I always use this in text_mode so I put in in my
	 `text_mode_hook':
	 
	      define text_mode_hook ()
	      {
	         set_buffer_hook ("wrap_hook", "text_mode_wrap_hook");
	      }

