Subject: bug#7924: 23.2.91; Documentation about CDPATH is a little misleading

From: "Andrew W. Nosenko" <[email-masked]>
Date: Tue, 22 Feb 2011 13:25:16 +0200

On Wed, Feb 2, 2011 at 00:11, Stefan Monnier <[email-masked]> wrote:
>>> Both in the manual and in the docstring for `cd', one might reasonably
>>> infer (as I did!) that CDPATH will be searched when completing relative
>>> directory names, but this is not the case.
>>>
>>> Is there in fact any way to get this to work? It’s something that one
>>> can do nicely in bash in a terminal, for example, but not in shell-mode.
>
>> I think this needs new code in `read-file-name-internal' (the completion
>> function for read-file-name).
>
> The patch below seems to work in my brief testing.
>
>
>        Stefan
>
>
> === modified file 'lisp/files.el'
> --- lisp/files.el       2011-02-01 20:53:09 +0000
> +++ lisp/files.el       2011-02-01 22:06:43 +0000
> @@ -700,25 +700,36 @@
>  `path-separator') when resolving a relative directory name.
>  The path separator is colon in GNU and GNU-like systems."
>   (interactive
> -   (list (read-directory-name "Change default directory: "
> +   (list
> +    ;; FIXME: There's a subtle bug in the completion below.  Seems linked
> +    ;; to a fundamental difficulty of implementing `predicate' correctly.
> +    ;; The manifestation is that TAB may list non-directories in the case where
> +    ;; those files also correspond to valid directories (if your cd-path is (A/
> +    ;; B/) and you have A/a a file and B/a a directory, then both `a' and `a/'
> +    ;; will be listed as valid completions).
> +    ;; This is because `a' (listed because of A/a) is indeed a valid choice
> +    ;; (which will lead to the use of B/a).
> +    (minibuffer-with-setup-hook
> +        (lambda ()
> +          (setq minibuffer-completion-table
> +                (apply-partially #'locate-file-completion-table
> +                                 cd-path nil))
> +          (setq minibuffer-completion-predicate
> +                (lambda (dir)
> +                  (locate-file dir cd-path nil
> +                               (lambda (f) (and (file-directory-p f) 'dir-ok))))))
> +      (unless cd-path
> +        (setq cd-path (or (parse-colon-path (getenv "CDPATH"))
> +                          (list "./"))))
> +      (read-directory-name "Change default directory: "
>                         default-directory default-directory
> -                        (and (member cd-path '(nil ("./")))
> -                             (null (getenv "CDPATH"))))))
> -  (if (file-name-absolute-p dir)
> -      (cd-absolute (expand-file-name dir))
> -    (if (null cd-path)
> -       (let ((trypath (parse-colon-path (getenv "CDPATH"))))
> -         (setq cd-path (or trypath (list "./")))))
> -    (if (not (catch 'found
> -              (mapc
> -               (function (lambda (x)
> -                           (let ((f (expand-file-name (concat x dir))))
> -                             (if (file-directory-p f)
> -                                 (progn
> -                                   (cd-absolute f)
> -                                   (throw 'found t))))))
> -               cd-path)
> -              nil))
> +                           t))))
> +  (unless cd-path
> +    (setq cd-path (or (parse-colon-path (getenv "CDPATH"))
> +                      (list "./"))))
> +  (cd-absolute
> +   (or (locate-file dir cd-path nil
> +                    (lambda (f) (and (file-directory-p f) 'dir-ok)))
>        (error "No such directory found via CDPATH environment variable"))))
>
>  (defun load-file (file)
>
> === modified file 'src/lread.c'
> --- src/lread.c 2011-01-31 18:47:03 +0000
> +++ src/lread.c 2011-02-01 21:57:03 +0000
> @@ -1223,7 +1223,9 @@
>  file name when searching.
>  If non-nil, PREDICATE is used instead of `file-readable-p'.
>  PREDICATE can also be an integer to pass to the access(2) function,
> -in which case file-name-handlers are ignored.  */)
> +in which case file-name-handlers are ignored.
> +This function will normally skip directories, so if you want it to find
> +directories, make sure the PREDICATE function return `dir-ok' for them.  */)
>   (Lisp_Object filename, Lisp_Object path, Lisp_Object suffixes, Lisp_Object predicate)
>  {
>   Lisp_Object file;
> @@ -1233,6 +1235,7 @@
>   return file;
>  }
>
> +static Lisp_Object Qdir_ok;
>
>  /* Search for a file whose name is STR, looking in directories
>    in the Lisp list PATH, and trying suffixes from SUFFIX.
> @@ -1350,9 +1353,12 @@
>              if (NILP (predicate))
>                exists = !NILP (Ffile_readable_p (string));
>              else
> -               exists = !NILP (call1 (predicate, string));
> -             if (exists && !NILP (Ffile_directory_p (string)))
> -               exists = 0;
> +               {
> +                 Lisp_Object tmp = call1 (predicate, string);
> +                 exists = !NILP (tmp)
> +                   && (EQ (tmp, Qdir_ok)
> +                       || !NILP (Ffile_directory_p (string)));
> +               }
>
>              if (exists)
>                {
> @@ -4369,6 +4375,9 @@
>   Qfile_truename = intern_c_string ("file-truename");
>   staticpro (&Qfile_truename) ;
>
> +  Qdir_ok = intern_c_string ("dir-ok");
> +  staticpro (&Qdir_ok);
> +
>   Qdo_after_load_evaluation = intern_c_string ("do-after-load-evaluation");
>   staticpro (&Qdo_after_load_evaluation) ;
>

This patch breaks spell checking.  Now ispell-word unable to find
installed aspell, tries to use ispell (as fallback?) and fails because
ispell is absent indeed.

    Starting new Ispell process [default] ...
    apply: Searching for program: no such file or directory, ispell

-- 
Andrew W. Nosenko <[email-masked]>