[Top][All Lists]

[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)

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

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


reply via email to

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