;;; an emacs-like hook package

(provide 'hooks)
(setq *package* 'hooks)

;;AUTOLOAD: add-hook
;;AUTODOC: add-hook "add a function to the specified hook list"
"(add-hook HOOK FUNCTION)

 - Function: add-hook HOOK FUNCTION &optional APPEND
     This function is the handy way to add function FUNCTION to hook
     variable HOOK.  The argument FUNCTION may be any valid Lisp
     function with the proper number of arguments.  For example,

          (add-hook 'text-mode-hook 'my-text-hook-function)

     adds `my-text-hook-function' to the hook called `text-mode-hook'.

     You can use `add-hook' for abnormal hooks as well as for normal
     hooks.

     It is best to design your hook functions so that the order in
     which they are executed does not matter.  Any dependence on the
     order is \"asking for trouble.\"  However, the order is predictable:
     normally, FUNCTION goes at the front of the hook list, so it will
     be executed first (barring another `add-hook' call).

     If the optional argument APPEND is non-`nil', the new hook
     function goes at the end of the hook list and will be executed
     last.
"

(defun add-hook (hook func &optional append? &aux
    hook-list
  )
  (if (not (typep hook Atom))
    (error "hook names must be atoms, not: %0 of type %t0" hook)
  )

  (if (not (and (boundp hook) hook)) (set hook (list))) ;init undefined variables

  (setq hook-list (eval hook))
  (if (seek hook-list func)
    ()					;already here, do nothing
    (if append? (lappend hook-list func) (insert hook-list 0 func))
  )
  hook-list
)

;;AUTOLOAD: run-hooks
;;AUTODOC: run-hooks "execute a specified hook list"
"(runs-hooks HOOK)

 - Function: run-hooks &rest HOOKVAR
     This function takes one or more hook variable names as arguments,
     and runs each hook in turn.  Each HOOKVAR argument should be a
     symbol that is a hook variable.  These arguments are processed in
     the order specified.

     If a hook variable has a non-`nil' value, that value may be a
     function or a list of functions.  If the value is a function
     (either a lambda expression or a symbol with a function
     definition), it is called.  If it is a list, the elements are
     called, in order.  The hook functions are called with no arguments.

     For example, here's how `emacs-lisp-hooks' runs its mode hook:

          (run-hooks 'emacs-lisp-mode-hook)
"

(defun run-hooks (&rest hooks)
  (dolist (hook hooks)
    (run-hook hook)
))

;;AUTOLOAD: remove-hook
;;AUTODOC: remove-hook "remove a function to the specified hook list"
"(remove-hook HOOK FUNCTION)

 - Function: remove-hook HOOK FUNCTION
     This function removes FUNCTION from the hook variable HOOK.
"

(defun remove-hook (hook func &aux
    (hook-list (if (boundp hook) (eval hook) ()))
  )
  (delete-item hook-list func)
)

;;AUTOLOAD: run-hook
;;AUTODOC: run-hook "execute a specified hook list"
"(runs-hook HOOK args...)

Execute the hook list named HOOK. The hook funcs will be called in the order
they've been added, with optional arguments as specied on the command line.

It is recommended to give arguments as keywords for maximum flexibility and upgradability.

To add a hook to a particular hook list, see add-hook."

(defun run-hook (hook &rest args &aux
    (hook-list (if (boundp hook) (eval hook) ()))
  )
  (dolist (func hook-list)
    (apply func args)
  )
)
    
