
This 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 function.  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).

===========================================================================
Buffer-local Hooks
===========================================================================

Buffer-local hooks are hooks that are defined on a buffer-by-buffer
basis.  These hooks are associated with the current buffer via the
function `set_buffer_hook'.  The syntax for this function is

    set_buffer_hook (name_of_hook, &hook_function);
    
Here name_of_hook is a string that indicates the name of the hook that
is being set.  The second argument, `hook_function' specifies the
S-Lang function to be associated with the hook.  The calling syntax of
the hook function varies with the hook.

The following buffer-local hooks are supported:

 "par_sep"

    This hook is used to determine whether or no the current line
    constitutes the beginning or the end of a paragraph. The function
    attached to this hook must be defined to take no arguments and
    return 1 if the current line is the beginning or end of a
    paragraph, or 0 otherwise.  If this hook has not been defined, the
    global hook is_paragraph_separator will be called.

 "indent_hook"

    If this hook exists, it will be used by the indent_line function
    to indent the line.  It takes no arguments and returns no values.

 "wrap_hook"

    This hook is called whenever a character insertion has caused a
    line to be wrapped.  It takes no arguments and returns nothing.

    Here is a simple example of the use of this hook: Often when
    writing text, I use numbered paragraphs or lists, e.g., in jed's
    changes.txt file.  After wrapping, I want paragraphs to be
    indented beyond the number.  This is accomplished via a wrap_hook
    such as:

       static define text_mode_wrap_hook ()
       {
	  variable p;
	  push_spot ();
	  go_up(1); bol (); skip_white ();
	  p = what_column ();
	  skip_chars ("0-9"); 
	  if ((p != what_column ()) and looking_at (". "))
	    {
	       go_down(1); bol (); skip_white ();
	       p = what_column ();
	       bol (); trim ();
	       whitespace (p + 3);
	    }
	  pop_spot ();
       }

    and then declared as the wrap-hook in text mode:
    
       define text_mode_hook ()
       {
          set_buffer_hook ("wrap_hook", &text_mode_wrap_hook);
       }

 "newline_indent_hook"

     If this hook exists, it will be called by the newline_and_indent
     function.  It takes no arguments and returns nothing.

 "bob_eob_error_hook"

     This hook is called whenever one of the internal cursor
     movement functions would have generated an end-of-buffer or
     beginning-of-buffer error.  It is passed an integer that
     indicates which function would have generated the error.
     Specifically:

                       -1  previous_line_cmd
                       -2  previous_char_cmd
                       -3  page_up
                        1  next_line_cmd
                        2  next_char_cmd
                        3  page_down
     
     The hook returns nothing.

 "mouse_down", "mouse_up", "mouse_drag", "mouse_2click", "mouse_3click"

     These hooks are used to override default hooks defined by the
     mouse_set_default_hook function.

 "update_hook"

     This hook is called prior to updating the display.  It takes no
     arguments and returns nothing.

===========================================================================
S-Lang Hooks
===========================================================================

This type of hook is called from another S-Lang function. 
The most common hook of this class is a mode-hook, e.g., c_mode_hook.

*_mode_hook
-----------

Nearly all mode-setting functions call a hook via the `run_mode_hooks'
function that the user may use for customization.  Examples, include
text_mode_hook, c_mode_hook, etc.

These are hooks that get called when the editor enters a particular
mode.  Usually, one just wants to setup some key bindings for the mode.
For this purpose, the `local_setkey' function should be used.  For
instance, c_mode sets the RETURN key to the function
`newline_and_indent'.  Some users may not like this binding and prefer
the simpler `newline' function.  Defining a c_mode_hook easily permits
this customization:

     define c_mode_hook ()
     {  
         local_setkey ("newline", "\r");
     }

global_mode_hook
----------------

This hook is called by the run_mode_hooks function prior to calling
the actual mode-hook.  It takes a single argument whose value is the
name of the mode-hook.  For instance, many users prefer to have the
TAB key always insert a TAB instead of running the indent_line
function.  The easiest way to enforce this for every mode is through a
global_mode_hook such as:

    define global_mode_hook (hook_name)
    {
        if (hook_name != "c_mode_hook")
	  local_setkey ("self_insert_cmd", "\t");
    }

This example illustrates how to cause the TAB key to insert a TAB in
all modes _except_ C-mode.

keybindings_hook
----------------

This hook is called after a set of keybindings have been loaded.  The
function takes a single argument that indicates the name of the
keybindings, e.g., "emacs", "ide", etc:

    define keybindings_hook (name)
    {
       if (name == "emacs")
         {
	    unsetkey ("^A");
	    setkey ("dabbrev", "^A");
	 }
    }


===========================================================================
			    Internal Hooks
===========================================================================
Internal hooks are hooks that are called by the C functions of the
editor.

mode_hook
---------

One of the most important hooks that the user may want to define or
customize if `mode_hook'.  This hook may be used to associate a mode
with a file or buffer.

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 reference
`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 simply 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 another example of the `mode_hook', 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;

format_paragraph_hook
---------------------

This hook is called after a paragraph is formatted but only if a
prefix argument was given prior to the execution of the internal
function `format_paragraph'.  More explicitly, 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 is in
tmisc.sl, and causes the paragraph to be left and right justified.

is_paragraph_separator
----------------------

This hook is called by the editor to locate paragraph delimiters.  If
defined, it applies globally to all buffers except those which have a
local definition (see the description of the buffer-local `par_sep'
hook). The default value is coded internally 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 return a non-zero value
if the current line is a paragraph delimiter or zero if it is not.


command_line_hook
-----------------

This hook is called from within the editor to parse the command line
arguments, and it also loads the user's personal initialization file.
It is defined in the file `site.sl' and should not be customized by
the user.

===========================================================================
Internal Hook Lists
===========================================================================

Some internal hooks may be chained together.  All hooks in a chain may
be executed, or executed until some value is returned.  A hook may be
inserted at the beginning of a specified chain via the add_to_hook
function, or appended to the chain via append_to_hook.

_jed_startup_hooks
------------------

  This set of hooks are called just prior to entering the main editor
  loop of the editor.  All the hooks in the chain are called.  Each
  hook takes no arguments and should return no values.
  An example of the hook is provided in site.sl.  

_jed_exit_hooks
---------------

  The hooks in this chain are called from the internal function
  `exit_jed'.  Each hook in the chain is called until one of them
  returns a value less than or equal to zero.  If one of these hooks
  returns such a value, then the attempted exit will be aborted.  If
  one of the hooks recursively calls `exit_jed', then exit will take
  place without calling other exit-hooks.

  For instance, suppose that one wants to be prompted before exiting.
  The following accomplishes this:

        static define my_exit_hook ()
	{
	   variable ch;
	   
	   if (BATCH) return 1;
	   
	   ch = get_mini_response ("Really Exit?");
	   if ((ch == 'y') or (ch == 'Y'))
	     return 1;
	   return 0;
	}
       add_to_hook ("_jed_exit_hooks", &my_exit_hook);

_jed_quit_hooks
----------------

   The hooks in this list are called by the `quit_jed' function.
   Each hook in this list takes no arguments and returns no value.
   All hooks in the list are executed.
   
   For systems such as MSDOS or VMS that do not have a separate
   working directory for each process, it might be desirable to ensure
   that the editor exit in the same directory in which it started.
   The following quit-hook may be used to implement this:
       
          define my_quit_hook ()
	  {
	     variable dir;
	     if (bufferp("*scratch*"))
	       {
		  (,dir,,) = getbuf_info ("*scratch*");
		  () = chdir (dir);
	       }
	  }

_jed_suspend_hooks
------------------

   The hooks in this list are called by the `sys_spawn_cmd' function
   which causes the editor to be suspended on Unix, or spawn a
   subprocess on other systems.  They are called prior to the
   suspension action and if any hook returns less than or equal to
   zero, suspension will not take place.   

_jed_resume_hooks
-----------------

   All the hooks in the _jed_resume_hooks list are called after
   returning from a suspension state.  Hooks in this list take no
   arguments and return no values.  A silly example of this hook is:
   
       static define my_resume_hook ()
       {
          message ("Welcome back to JED");
       }
       add_to_hook ("_jed_resume_hooks", &my_resume_hook);

  
_jed_init_display_hooks, _jed_reset_display_hooks
--------------------------------------------------

  The corresponding hooks in these lists are called after
  initializing, or prior to resetting the display.  The hook functions
  take no parameters and return no values.  See lib/mousex.sl for an
  example of these hooks.

_jed_save_buffer_before_hooks, _jed_save_buffer_after_hooks
------------------------------------------------------------

  The hooks in these lists are called before and after the current
  buffer has been saved, respectively.  Each hook is passed a single
  argument: the name of the file to which the buffer is to be written.
  The hooks return no values.

_jed_find_file_before_hooks
----------------------------

  Each of the hooks in this list will be passed the name of the file
  to be found.  The hooks in this list are called until one returns a
  value of 1, which indicates that the file has been found and read
  into a buffer. Otherwise, the hook must return 0 to allow the rest
  of the hooks in the chain to run.  If a hook indicates that the file
  has been found, then the related hooks _jed_find_file_after_hooks
  will _not_ be run.

_jed_find_file_after_hooks
---------------------------

  After a file has been read into a buffer and had its mode set, all
  the hooks in this list are called.  These hooks take no arguments
  and return no values.

_jed_insert_file_hooks
-----------------------

  The hooks in this list are called upon to insert the specified file,
  passed as an argument to the hook into the current buffer.  If the
  specified file has been inserted, the hook should return 1;
  otherwise it must return 0 to indicate that the file was not
  inserted.

_jed_read_file_hooks
---------------------

  The hooks in this list are called upon to read the specified file
  passed as an argument to the hook, into an empty buffer.  If the
  specified file has been read into the buffer, the hook should return 1;
  otherwise it must return 0 to indicate that the file was not read.

  Note that the difference between these hooks and
  _jed_insert_file_hooks is somewhat subtle.  The main difference
  between the two sets of hooks is that the scope of
  _jed_insert_file_hooks is more limited.  See lib/compress.sl for an
  example of these hooks.

_jed_write_region_hooks, _jed_append_region_hooks
-------------------------------------------------

  These hooks are called upon whenever a region is written out, or
  appended to a file.  Each of the hooks in these lists will be passed
  the name of the file.  The hooks execute until one returns 1 to
  indicate that the region was written (or appended) to the specified
  file; otherwise the hooks should return 0.

_jed_set_mode_hooks
--------------------
   
  These hooks are called before `mode_hook' is called to set the
  buffer's mode.  Like `mode_hook', the filename extension is passed
  to the hooks in this list.  If one of the hooks returns 1, the the
  mode is considered to be set.  If none of the hooks return 1, then
  mode_hook will be called to set the mode.


_jed_switch_active_buffer_hooks
-------------------------------

  These hooks are called from the main editing loop if the active
  buffer has changed to a different one.  The active buffer is defined
  to be the buffer that one is interactively editing. One should note
  that this does not mean that these hooks will be called whenever one
  switches to a different buffer because such a switch may not be
  visible from within the main editing loop.  Also note that these
  hooks may not be called during the execution of keyboard macros
  since they are executed outside of the main editing loop.  Nor will
  these hooks be called when the mini-buffer is the current buffer
  since the mini-buffer is not considered to be an active buffer.

  Functions in this list take a single argument: the name of the
  previously active buffer.  No value should be returned.
  
  The following example shows how this hook may be used to set the
  name of the Xjed window to that of the currently active buffer.

     static define my_switch_buffer_hook (old_buffer)
     {
         x_set_window_name (whatbuf ());
     }
     add_to_hook ("_jed_switch_active_buffer_hooks", &my_switch_buffer_hook);
