unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* dynamic-completion-table
@ 2003-06-19 14:31 Roland Winkler
  2003-06-20 14:11 ` dynamic-completion-table Richard Stallman
  0 siblings, 1 reply; 5+ messages in thread
From: Roland Winkler @ 2003-06-19 14:31 UTC (permalink / raw



In order to avoid duplicating code in bibtex.el Stefan Monnier
suggested to me to use a macro dynamic-completion-table.


(defmacro dynamic-completion-table (fun)
  "Turn a function FUN returning a completion table, into a completion table.
FUN is called with no argument and should return a completion table.
If completion is performed in the minibuffer, FUN will be called in the
buffer from which the minibuffer was entered."
  ;; (declare (debug t))
  `(lambda (string predicate mode)
     (with-current-buffer (let ((win (minibuffer-selected-window)))
                            (if (window-live-p win) (window-buffer win)
                                (current-buffer)))
       (cond
        ((eq mode t) (all-completions string (,fun) predicate))
        ((not mode) (try-completion string (,fun) predicate))
        (t (test-completion string (,fun) predicate))))))


I'd like to suggest that it could be made available in, e.g.,
simple.el. I think it comes quite handy if a completion table must
be calculated dynamically by means of an appropriate function. For
example, the function sh-add-completer in sh-script.el could use
dynamic-completion-table.

If completion is performed in the minibuffer, FUN will be called in
the buffer from which the minibuffer was entered. I believe that
such a "well-defined environment" for evaluating FUN is in general
more useful than a macro without it. An alternative to using
minibuffer-selected-window might be that the buffer name for
evaluating FUN is passed to dynamic-completion-table as an
(optional) argument or via a variable like sh-add-buffer in
sh-script.el. However, for my application it is an important part of
dynamic-completion-table that the buffer name is determined
automatically:

I use dynamic-completion-table to define the global initial values
of buffer-local variables that contain completion lists. The idea is
that if the user hits tab, FUN calculates the completion list and
stores it in the buffer-local variables. In that way, the
buffer-local values of the completion lists are calculated only once
- provided the completion lists are required at all. (Maybe, this
scheme for initializing completion lists is of interest elsewhere,
too?)

Maybe, the macro dynamic-completion-table requires some adjustment
in order to make it even more useful for other purposes, too.
Suggestions welcome!

Roland

PS: I have not subscribed to emacs-devel@gnu.org

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: dynamic-completion-table
  2003-06-19 14:31 dynamic-completion-table Roland Winkler
@ 2003-06-20 14:11 ` Richard Stallman
  2003-06-24 14:11   ` dynamic-completion-table Roland Winkler
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Stallman @ 2003-06-20 14:11 UTC (permalink / raw
  Cc: emacs-devel

      "Turn a function FUN returning a completion table, into a completion table.

That sentence is very confusing--you need to say it a different way.

    I use dynamic-completion-table to define the global initial values
    of buffer-local variables that contain completion lists. The idea is
    that if the user hits tab, FUN calculates the completion list and
    stores it in the buffer-local variables.

Should this macro produce the code to do that?
It might be more useful that way.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: dynamic-completion-table
  2003-06-20 14:11 ` dynamic-completion-table Richard Stallman
@ 2003-06-24 14:11   ` Roland Winkler
  2003-06-25 19:53     ` dynamic-completion-table Richard Stallman
  0 siblings, 1 reply; 5+ messages in thread
From: Roland Winkler @ 2003-06-24 14:11 UTC (permalink / raw
  Cc: emacs-devel

On Fri Jun 20 2003 Richard Stallman wrote:
>       "Turn a function FUN returning a completion table, into a completion table.
> 
> That sentence is very confusing--you need to say it a different
> way.

I suggest the following. I hope that the new docstring is less
confusing.

Note also that I modified the code: FUN is called with one argument,
the string for which completion is required. Furthermore, in order
to avoid name conflicts make-symbol is used to create local
variables.

(defmacro dynamic-completion-table (fun)
  "Use function FUN as a dynamic completion table.
FUN is called with one argument, the string for which completion is required,
and it should return an alist containing all the intended possible
completions. If completion is performed in the minibuffer, FUN will be called
in the buffer from which the minibuffer was entered.
`dynamic-completion-table' then computes the completion, see Info
node `(elisp)Programmed Completion'."
  ;; (declare (debug t))
  (let ((win (make-symbol "window"))
        (string (make-symbol "string"))
        (predicate (make-symbol "predicate"))
        (mode (make-symbol "mode")))
    `(lambda (,string ,predicate ,mode)
       (with-current-buffer (let ((,win (minibuffer-selected-window)))
                              (if (window-live-p ,win) (window-buffer ,win)
                                (current-buffer)))
         (cond
          ((eq ,mode t) (all-completions ,string (,fun ,string) ,predicate))
          ((not ,mode) (try-completion ,string (,fun ,string) ,predicate))
          (t (test-completion ,string (,fun ,string) ,predicate)))))))

>     I use dynamic-completion-table to define the global initial values
>     of buffer-local variables that contain completion lists. The idea is
>     that if the user hits tab, FUN calculates the completion list and
>     stores it in the buffer-local variables.
> 
> Should this macro produce the code to do that?
> It might be more useful that way.

I think it is conceptually cleaner to create lazy completion tables
by means of a second macro that uses dynamic-completion-table. My
suggestion is the following:

(defmacro lazy-completion-table (var fun &rest args)
  "Initialize variable VAR as a lazy completion table.
If the completion table VAR is used for the first time (e.g., by passing VAR
as an argument to `try-completion'), the function FUN is called with arguments
ARGS. FUN must return the completion table that will be stored in VAR. If
completion is requested in the minibuffer, FUN will be called in the buffer
from which the minibuffer was entered. The return value of
`lazy-completion-table' must be used to initialize the value of VAR."
  (let ((str (make-symbol "string")))
    `(dynamic-completion-table
      (lambda (,str)
        (unless (listp ,var)
          (setq ,var (funcall ',fun ,@args)))
        ,var))))

Then a typical application of lazy-completion-table is the following:

(defvar bibtex-reference-keys
  (lazy-completion-table bibtex-reference-keys bibtex-parse-keys nil nil t)
  "Completion table for BibTeX reference keys.")
(make-variable-buffer-local 'bibtex-reference-keys)


Is this code useful for other packages, too so that the above macros
should be made available, e.g., in simple.el?

Suggestions welcome!

Roland

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: dynamic-completion-table
  2003-06-24 14:11   ` dynamic-completion-table Roland Winkler
@ 2003-06-25 19:53     ` Richard Stallman
  2003-06-26 13:17       ` dynamic-completion-table Roland Winkler
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Stallman @ 2003-06-25 19:53 UTC (permalink / raw
  Cc: emacs-devel

      "Use function FUN as a dynamic completion table.
    FUN is called with one argument, the string for which completion is required,
    and it should return an alist containing all the intended possible
    completions.

Is FUN required to return only the possible completions of that
string, or can it ignore the string and always return the full list of
possibilities?  Looking at the code, I think it can ignore the string.
The doc string should say so.

Both macros seem useful--you can install them.  Don't forget to
mention them in etc/NEWS.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: dynamic-completion-table
  2003-06-25 19:53     ` dynamic-completion-table Richard Stallman
@ 2003-06-26 13:17       ` Roland Winkler
  0 siblings, 0 replies; 5+ messages in thread
From: Roland Winkler @ 2003-06-26 13:17 UTC (permalink / raw
  Cc: emacs-devel

On Wed Jun 25 2003 Richard Stallman wrote:
>       "Use function FUN as a dynamic completion table.
>     FUN is called with one argument, the string for which
>     completion is required, and it should return an alist
>     containing all the intended possible completions.
> 
> Is FUN required to return only the possible completions of that
> string, or can it ignore the string and always return the full list of
> possibilities?  Looking at the code, I think it can ignore the string.
> The doc string should say so.
> 
> Both macros seem useful--you can install them.

Stefan,

Could you please do that for me? Thank you very much!
I hope that the docstring of dynamic-completion-table is now OK.

(defmacro dynamic-completion-table (fun)
  "Use function FUN as a dynamic completion table.
FUN is called with one argument, the string for which completion is required,
and it should return an alist containing all the intended possible
completions. This alist may be a full list of possible completions so that FUN
can ignore the value of its argument. If completion is performed in the
minibuffer, FUN will be called in the buffer from which the minibuffer was
entered. `dynamic-completion-table' then computes the completion, see Info
node `(elisp)Programmed Completion'."
  (let ((win (make-symbol "window"))
        (string (make-symbol "string"))
        (predicate (make-symbol "predicate"))
        (mode (make-symbol "mode")))
    `(lambda (,string ,predicate ,mode)
       (with-current-buffer (let ((,win (minibuffer-selected-window)))
                              (if (window-live-p ,win) (window-buffer ,win)
                                (current-buffer)))
         (cond
          ((eq ,mode t) (all-completions ,string (,fun ,string) ,predicate))
          ((not ,mode) (try-completion ,string (,fun ,string) ,predicate))
          (t (test-completion ,string (,fun ,string) ,predicate)))))))

(defmacro lazy-completion-table (var fun &rest args)
  "Initialize variable VAR as a lazy completion table.
If the completion table VAR is used for the first time (e.g., by passing VAR
as an argument to `try-completion'), the function FUN is called with arguments
ARGS. FUN must return the completion table that will be stored in VAR. If
completion is requested in the minibuffer, FUN will be called in the buffer
from which the minibuffer was entered. The return value of
`lazy-completion-table' must be used to initialize the value of VAR."
  (let ((str (make-symbol "string")))
    `(dynamic-completion-table
      (lambda (,str)
        (unless (listp ,var)
          (setq ,var (funcall ',fun ,@args)))
        ,var))))


> Don't forget to mention them in etc/NEWS.

The following should be put into etc/NEWS:

*** The new macro dynamic-completion-table supports using functions
as a dynamic completion table.

  (dynamic-completion-table FUN)

FUN is called with one argument, the string for which completion is required,
and it should return an alist containing all the intended possible
completions. This alist may be a full list of possible completions so that FUN
can ignore the value of its argument. If completion is performed in the
minibuffer, FUN will be called in the buffer from which the minibuffer was
entered. dynamic-completion-table then computes the completion.

*** The new macro lazy-completion-table initializes a variable
as a lazy completion table.

  (lazy-completion-table VAR FUN &rest ARGS)

If the completion table VAR is used for the first time (e.g., by passing VAR
as an argument to `try-completion'), the function FUN is called with arguments
ARGS. FUN must return the completion table that will be stored in VAR. If
completion is requested in the minibuffer, FUN will be called in the buffer
from which the minibuffer was entered. The return value of
`lazy-completion-table' must be used to initialize the value of VAR.




Roland

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-06-26 13:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-06-19 14:31 dynamic-completion-table Roland Winkler
2003-06-20 14:11 ` dynamic-completion-table Richard Stallman
2003-06-24 14:11   ` dynamic-completion-table Roland Winkler
2003-06-25 19:53     ` dynamic-completion-table Richard Stallman
2003-06-26 13:17       ` dynamic-completion-table Roland Winkler

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).