bug-gnu-emacs
[Top][All Lists]
Advanced

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

bug#1085: 23.0.60; all-completions, try-completion inconsistent: Info-re


From: Drew Adams
Subject: bug#1085: 23.0.60; all-completions, try-completion inconsistent: Info-read-node-name-1
Date: Sun, 5 Oct 2008 21:29:28 -0700

> From: Stefan Monnier Sent: Sunday, October 05, 2008 4:36 PM
> > Lisp code needs to be able to depend on the fact that the valid
> > completions returned by `all-completions' have the common prefix
> > that is returned by `try-completion' (which must in turn have the
> > input as its prefix).
> 
> This fact has simply never been true in general.
> It's true as long as the completion table is not a function, but
> otherwise all bets are off.

It has been true in general. It has just been false for a few exceptions. I
think it should be true always. It should be possible to bring those exceptions
into the fold. And if in some case there must truly be an exception, so be it.
But that is not so for all of the cases today where the invariants are not
respected. `Info-read-node-name-1' is a case in point - see below for code.

There is something to be gained by eliminating such exceptions, beyond just
consistency. As I said,

 One should be able to use `all-completions' to construct a cons
 completion table that is equivalent to the original TABLE argument,
 regardless of how TABLE is defined (e.g. function, obarray).

That should be possible at least for all deterministic TABLE functions that have
a finite range, that is, for most functional TABLE args used in practice.

> In practice the main case where this "invariant" does not hold is when
> the completion table is the one for file names, where all-completions
> returns names that do not "full" (i.e. do not include the directory
> name).

Why shouldn't it be true in that case also? It isn't now, but it could be, could
it not? File name completion could be made to keep the same user behavior it has
now and still respect the invariants I mentioned.

> But other cases exist.

I don't think it's right to allow it. It's especially not right not to
discourage it. It just makes it impossible for Lisp code to reason about or act
generally regarding completions. I don't see why it's necessary to allow it at
all.

> For code that needs to live with this problem (e.g. minibuffer.el),
> Emacs-23 introduces a new way to call the completion table 
> function with a `boundary' argument.

Why should `Info-read-node-name-1' in particular "need to live with this
problem"? Why shouldn't it return, for a CODE of t, a valid list of completions
satisfying the invariants I mentioned? Why not do it right?

Ideally (this part is for the wish list), we would provide completion not only
for input such as `(ema', giving all-completions `("(emacs)" "(emacs-mime)")',
but also for input such as `(emacs)Mac', giving all-completions `("(emacs)Mac
Directories" "(emacs)Mac Environment"...)'.

This is analogous to file-name completion, with directories as analogs of Info
file names such as "(emacs)". Today there is no completion even for `(emacs)Mac
OS', though you can hit RET with that input to go to node `Mac OS'. That would
be like saying that you can complete "/ema" to "/emacs" and you can hit RET to
visit "/emacs/COPYING", but you cannot complete "/emacs/COP".

Until that wish-list item is implemented we should at least make the Info
file-name completion DTRT for `all-completions' (i.e. fix this bug).

FWIW, here is the code I'm using now to do that for Emacs 23:

(defun Info-read-node-name-1 (string predicate code)
  (cond ((string-match "\\`(\\([^)]*\\))\\'" string) ; e.g. (emacs)
         (cond ((eq code nil) string)
               ((eq code t) (list string))
               (t t)))
        ((string-match "\\`(\\([^)]*\\)\\'" string) ; e.g. (emacs
         (let ((ctwc (completion-table-with-context
                      "("
                      (apply-partially
                       'completion-table-with-terminator ")"
                       (apply-partially 'Info-read-node-name-2
                                        Info-directory-list
                                        (mapcar 'car Info-suffix-list)))
                      (match-string 1 string)
                      predicate
                      code)))
           (cond ((eq code nil) ctwc)
                 ((eq code t)
                  (mapcar (lambda (file) (concat "(" file ")")) ctwc))
                 (t t))))
        ((string-match "\\`(" string) ; e.g. (emacs)Mac OS - just punt.
         (cond ((eq code nil) string)
               ((eq code t) nil)
               (t t)))
        ;; Otherwise use Info-read-node-completion-table - e.g. Mac OS
        (t (complete-with-action code Info-read-node-completion-table
                                 string predicate))))

And FWIW, here is the code I'm using now for Emacs 22:

(defun Info-read-node-name-1 (string predicate code)
  (cond ((string-match "\\`(\\([^)]*\\))\\'" string) ; e.g. (emacs) or
(emacs-mime)
         (cond ((eq code nil) string)
               ((eq code t) (list string))
               (t t)))
        ((string-match "\\`(\\([^)]*\\)\\'" string) ; e.g. (emacs
         (let ((file (match-string 1 string)))
           (cond ((eq code nil)
                  (let ((comp (try-completion
                                file 'Info-read-node-name-2
                                (cons Info-directory-list
                                      (mapcar #'car Info-suffix-list)))))
                    (cond ((eq comp t) (concat string ")"))
                          (comp (concat "(" comp)))))
                 ((eq code t)
                  (mapcar (lambda (file) (concat "(" file ")"))
                          (all-completions file 'Info-read-node-name-2
                                           (cons Info-directory-list
                                                 (mapcar #'car
Info-suffix-list)))))
                 (t nil))))
        ((string-match "\\`(" string) ; e.g. (emacs)Mac OS or (jlkj - just punt.
         (cond ((eq code nil) string)
               ((eq code t) nil)
               (t t)))
        ;; Otherwise use Info-read-node-completion-table - e.g. Mac OS
        ((eq code nil)
         (try-completion string Info-read-node-completion-table predicate))
        ((eq code t)
         (all-completions string Info-read-node-completion-table predicate))
        (t (test-completion string Info-read-node-completion-table predicate))))

I think this is an improvement and it or something like it should be
incorporated as a fix for this bug. Again, please test etc.

I hope you'll reconsider the policy wrt support for the invariants I suggested,
instead of encouraging (yes) n'importe quoi. If there is truly no implementation
choice in some particular case, then so be it, but it shouldn't be the policy to
not even try to do something clean. FWIW, I'm not convinced there are any cases
where there is really no choice.

We should also add a guideline to the doc encouraging people to respect the
invariants mentioned when they write code with functional TABLE args.








reply via email to

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