[comp.emacs] hooks in Gnumacs

ciaran@hrc63.co.uk (Ciaran Byrne) (09/15/87)

Here is something to help you go on living when you discover that
the author of your favorite function arrogantly thought that his
code did everything anyone could possible want, 
so didn't provide a user hook for you to prove him/her wrong.

The first command, add-hook, sticks any s-exp onto the end
of the target function definition,
the second, make-hook-var, uses add-hook to
invoke run-hooks on a variable of your choice.

I personally prefer using just the former for simple extras, since you
don't need to mess round with function or lambda definitions to 
provide arguments.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; module: 	hook.el	
;;;; version: 	1.3
;;;; author: 	Ciaran A Byrne
;;;; date:	20:Aug:87
;;;;
;;;;;;;;;;;;;;;;;;;; hook insertion fns;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;;	macros:
;;;;		some c[ad]+r fns
;;;;
;;;;	commands:
;;;;		add-hook		- appends s-exp to function
;;;;		make-hook-var		- adds hook variable to a function
;;;;

(defmacro caar (x) (list 'car (list 'car x)))
(defmacro cadr (x) (list 'car (list 'cdr x)))
(defmacro caadr (x) (list 'car (list 'car (list 'cdr x))))
(defmacro caddr (x) (list 'car (list 'cdr (list 'cdr x))))
(defmacro cadar (x) (list 'car (list 'cdr (list 'car x))))

(defmacro cdar (x) (list 'cdr (list 'car x)))
(defmacro cddr (l) "" (list 'cdr (list 'cdr l)))
(defmacro cdadr (x) (list 'cdr (list 'car (list 'cdr x))))


(defun add-hook (target-function extrafn) 
"Redefines FUNCTION so that SEXP is evaluated (apparently!) after the 
function has completed.

e.g. (add-hook 'next-line '(what-line))

The original return value is preserved.
Does not work with subr's.
"

;Even if it did attempt to put a wrapper around a subr,
;it would be only partially effective, 
;since subrs get called from other 'C'-coded fns.

    (interactive "aTarget function: 
xs-exp: ")

;	OLD FORM	    ==>		NEW FORM
;
;  (defun foo (args) "bar"	(defun foo (args) "bar"
;	(interactive "s")	     (interactive "s")
;	(s1)			     (prog1
;	(s2))				(progn 
;					    (s1)
;					    (s2))  ; old result
;					extrafn)   ; new action
;
  (if (subrp (symbol-function target-function))
      	 (message "No can do; %s is a subr" target-function)

    (let* (  (fval (symbol-function target-function))
	      (args (cadr fval))
	      (body (cddr fval))
	      (doc  (car body))
	      (newfn (list 'lambda args)) )
	
	(if (or (numberp doc) (stringp doc))	; move body past doc 
	    (setq newfn (append newfn (list doc))
		  body (cdr body)))

	(if (eq 'interactive (caar body)) ; move body past (interactive ..)
	    (setq newfn (append newfn (list (car body)))
		  body (cdr body)))

	(fset target-function
	    (append newfn
		(list 
		    (list 'prog1
			(append '(progn) body)
			extrafn))
	    )
	)
    ) ; let
  )
)

(defun make-hook-var (hook-name target-function) "Causes the functions (if any)
in  VARIABLE to be run at the completion of FUNCTION.
e.g.

(make-hook-var compilation-sentinel-hook-var compilation-sentinel)
; adds hook var to compilation-sentinel
; eg:
(setq compilation-sentinel-hook-var '(next-error))

use this instead of add-hook (qv) when you need to be able to change
the hook functions without reloading.
"
    (interactive "SNew hook var name : 
aFunction : ")
    (add-hook target-function
	(list 'run-hooks
	    (list 'quote hook-name))))

(provide 'hook)
;
;
; comments/suggestions to ...!seismo!mcvax!ukc!gec-rl-hrc!ciaran
;
; When you said ``HEAVILY FORESTED'' it reminded me of an overdue
; CLEANING BILL..  Don't you SEE?  O'Grogan SWALLOWED a VALUABLE
; COIN COLLECTION and HAD to murder the ONLY MAN who KNEW!!

quiroz@cs.rochester.edu (Cesar Quiroz) (09/19/87)

Expires:

Sender:

Followup-To:


In a recent article, <280@hrc63.co.uk>, Ciaran Byrne contributes
some functions to add hooks to code that originally didn't have
them. 

That posting contained some definitions of the classic c[ad]+r
functions, only as macros.  I want to make a plea so other Emacs
contributors consider for a moment that those macros make it hard
to implement the standardly accepted meanings of those functions.
(Byrne's code is by no means unique in this respect, by the way,
just the most recent one to provide c[ad]+r as macros.)

As to why it could be good to approximate standardly accepted Lisp
behavior, you could see the notes that accompany cl.el in recent
releases of GNU Emacs (I understand it was in 18.47, cannot confirm
right now).  As to why redefining them as macros causes trouble,
imagine an implementation of defstruct that uses list structure to
represent a struct and apply-ies c[ad]+r to instances in order to
retrieve the slot values.  (The one in cl.el uses vectors, so it
doesn't have this problem, but others might easily occur.)

It can be argued that the language should have included these
functions as primitives.  However, it is so easy to define them
"correctly", that it should be done the right way.  (Notice that in
18.47 and later, if cl.el is available, just (require 'cl) should be
enough.) 

By the way, if someone wants to discuss language extensions for
Emacs Lisp or implementation/design questions, that could be a nice
thing to do in this group.  Ideas anyone?
-- 
Cesar Augusto  Quiroz Gonzalez
Department of Computer Science     {allegra|seismo}!rochester!quiroz
University of Rochester            or
Rochester,  NY 14627               quiroz@cs.rochester.edu

quiroz@CS.ROCHESTER.EDU (09/19/87)

In a recent article, <280@hrc63.co.uk>, Ciaran Byrne contributes
some functions to add hooks to code that originally didn't have
them. 

That posting contained some definitions of the classic c[ad]+r
functions, only as macros.  I want to make a plea so other Emacs
contributors consider for a moment that those macros make it hard
to implement the standardly accepted meanings of those functions.
(Byrne's code is by no means unique in this respect, by the way,
just the most recent one to provide c[ad]+r as macros.)

As to why it could be good to approximate standardly accepted Lisp
behavior, you could see the notes that accompany cl.el in recent
releases of GNU Emacs (I understand it was in 18.47, cannot confirm
right now).  As to why redefining them as macros causes trouble,
imagine an implementation of defstruct that uses list structure to
represent a struct and apply-ies c[ad]+r to instances in order to
retrieve the slot values.  (The one in cl.el uses vectors, so it
doesn't have this problem, but others might easily occur.)

It can be argued that the language should have included these
functions as primitives.  However, it is so easy to define them
"correctly", that it should be done the right way.  (Notice that in
18.47 and later, if cl.el is available, just (require 'cl) should be
enough.) 

By the way, if someone wants to discuss language extensions for
Emacs Lisp or implementation/design questions, that could be a nice
thing to do in this group.  Ideas anyone?

aglew@ccvaxa.UUCP (09/20/87)

I haven't used the hooks package for GNU EMACS yet,
but may I comment that this is probably the way most
hooks should be done? Ie. instead of every package
using a slightly different name for its pre and post
hooks, have no hooks at all, but let the user be able
to add them dynamically, in a standard way.

quiroz@cs.rochester.edu (Cesar Quiroz) (09/21/87)

Expires:

Sender:

Followup-To:


From article <28500017@ccvaxa> (aglew@ccvaxa.UUCP):
: ... instead of every package using a slightly different name for
:its pre and post hooks, have no hooks at all, but let the user be
:able to add them dynamically, in a standard way.
Looks like a useful idea.  Other Lisps (Interlisp, for one) have
well evolved `advising' facilities, that permit not only pre- and
post- customized activity, but also around- activity.  The user
retains ultimate control and can do useful things not thought of by
the original writer.

For instance, take the old newline-and-reindent (or whatever it was
called).  It could have been just an around-advice of indent-line,
that called the internal function twice.  (Details might be a little
out of synch with reality, please just get the big picture.)
Byrne's code could be used as a starting point.  (Getting the advice
to the right place is a simple macro, controlling how different
pieces of advice interact takes a bit more effort, storing and
retrieving the advice might be harder...  Hmm, going beyond the
simple seems to require something like flavor composition.)


-- 
Cesar Augusto  Quiroz Gonzalez
Department of Computer Science     {allegra|seismo}!rochester!quiroz
University of Rochester            or
Rochester,  NY 14627               quiroz@cs.rochester.edu