emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: table.el


From: Tak Ota
Subject: Re: table.el
Date: Sat, 01 Dec 2001 01:13:17 -0800 (PST)

Thu, 29 Nov 2001 16:03:59 -0700 (MST): Richard Stallman <address@hidden> wrote:

>     > This code does not have to be special-purpose and limited to table
>     > mode.  For instance, you could make hook variables for those functions
>     > to call.  Then table.el could set the hook variables to suitable
>     > functions.  This might be useful for some other features as well as
>     > table.el.
> 
>     Let me have some time to come up with a proposal for the generic
>     extension to those functions.
> 
> Ok.  Please note that it doesn't have to be designed as *one* generic
> extension.  It could just be a hook or an option in each function.
> There is no need to struggle desperately to make this unified, since
> it is only meant for wizards to use.

I tried to take an easy route as you suggested.  But more I thought I
realized it was not easy to implement the needed operations by options
and hooks.  What table.el does to those functions with advice are; (1)
set up a special environment (2) call the original function (3) do the
cleanup work.

My thoughts eventually reached a concept of `wrappers' which is a
different form of function extension than `hooks'.  While the `hooks'
are prepared for interpolating the original function by inserting some
operations at the strategically chosen hook points, the `wrappers' are
prepared for exterpolating the original function by surrounding the
original function with extra operations.

To realize this mechanism I only needed to define one macro to run the
wrapper.  Let's call it `run-wrappers' since it matches the
counterpart `run-hooks'.  An example implementation would be like this.

(defmacro run-wrappers (wrappers &rest body)
  "Run wrapper functions in WRAPPERS.
WRAPPERS is a symbol whose value is a list of functions"
  (let ((wrapper-value (make-symbol "wrapper-value"))
        (wrapper (make-symbol "wrapper"))
        (wrappers-symbol (cadr wrappers)))
    `(let* ((,wrapper-value (eval ,wrappers))
            (,wrapper (car ,wrapper-value))
            (,wrappers-symbol (cdr ,wrapper-value)))
       (if ,wrapper-value
           (funcall ,wrapper)
         ,@body))))

I believe the people on this list will help me refine this one.

For example, it can be used like this.

(defvar kill-region-wrappers nil)

(defun kill-region (beg end)
  "Document ... "
  (run-wrappers 'kill-region-wrappers
    ...the original kill-region body...
    ...))

Let's define an example wrapper.

(defun kill-region-offset-by-5-wrapper ()
  (kill-region (+ beg 5) (+ end 5)))

To install this wrapper

(add-hook 'kill-region-wrappers (function kill-region-offset-by-5-wrapper))

Now any subsequent calls to `kill-region' are offseted by 5.

It works like this - when `kill-region' is called it will call
`kill-region-offset-by-5-wrapper' which then calls `kill-region' with
modified arguments.  This time `kill-region' does the original body
and return to the wrapper.  The wrapper returns to the first
`kill-region' which skips the body and returns to the top level
caller.

When there are more than one wrappers added, for example when
`kill-region-wrappers' has a value of (wrapper-A wrapper-B wrapper-C),
the call to kill-region goes like the diagram below.  Each wrapper can
perform pre-process before calling `kill-region' and post-process
after calling `kill-region'.


call kill-region
      |
      +----->call wrapper-A
                |
          call kill-region
                |
                +----->call wrapper-B
                          |
                    call kill-region
                          |
                          +----->call wrapper-C
                                    |
                              call kill-region
                                    |
                              kill-region executes
                                    |
                              kill-region returns
                                    |
                          <-----wrapper-C returns
                          |
                    kill-region returns
                          |
                <-----wrapper-B returns
                |
          kill-region returns
                |
      <-----wrapper-A returns
      |
kill-region returns

-Tak



reply via email to

[Prev in Thread] Current Thread [Next in Thread]