emacs-devel
[Top][All Lists]
Advanced

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

Re: find-file-read-args


From: Juri Linkov
Subject: Re: find-file-read-args
Date: Mon, 23 Nov 2009 23:17:36 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1.50 (x86_64-pc-linux-gnu)

>>> so I'd like to understand how you reproduce it.
>
>> This can be reproduced by typing M-n in the minibuffer of commands
>> other than find-file-*, e.g. `insert-file', `append-to-file',
>> `write-file', `write-region', `load-file', `recode-file-name',
>> `make-directory', `delete-directory', `copy-directory'.
>
> I meant "how does your code reproduce the right behavior for C-x C-f".

Ah.  It reproduces the right behavior for C-x C-f by moving the logic of
setting minibuffer-default from `find-file-read-args' to `read-file-name'.

> But I think I'm beginning to understand why it works.
>
>>>> +     ((eq major-mode 'dired-mode)
>>>> +      (let ((filename (dired-get-filename nil t)))
>>>> +        (when filename
>>>> +          (if (file-directory-p filename)
>>>> +              (file-name-as-directory (abbreviate-file-name filename))
>>>> +            (abbreviate-file-name filename)))))))
>>> This is ugly.  Why does it have to be here rather than somewhere in dired?
>> I can't find a function in dired.el and dired-aux.el that uses
>> `abbreviate-file-name' necessary for the minibuffer reading a file name.
>
> We must be miscommunicating: I don't want to have dired-specific code
> (including no test for (eq major-mode 'dired-mode)) in read-file-name,
> because it's ugly.  Can't the same behavior be obtained by changing some
> code in dired rather than in minibuffer.el?

I have no idea how to get rid of `dired-get-filename'.
Grepping for `dired-get-filename' in the source tree shows that
there are many packages not directly related to Dired that call
`dired-get-filename'.

>> OK, I'll create a new function that could later be bound to a dedicated key.
>
> Thanks.  Tho it doesn't need to be a command (e.g. that function
> shouldn't want to insert anything into the buffer, so it'll probably be
> better to have a separate command, unless we want to rely on
> called-interactively-p).

Please see `minibuffer-insert-file-name-at-point' below.

>> I'll try to better detect this situation than checking for a cons.
>
> Yes, I think your solution is at least as good as the previous one.
> But please check explicitly for "default == initial input", that will
> make the code both safer and easier to understand.

Done below.

Index: lisp/files.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/files.el,v
retrieving revision 1.1101
diff -c -r1.1101 files.el
*** lisp/files.el       13 Nov 2009 22:19:51 -0000      1.1101
--- lisp/files.el       23 Nov 2009 21:14:12 -0000
***************
*** 411,416 ****
--- 411,424 ----
    :type '(hook :options (cvs-dired-noselect dired-noselect))
    :group 'find-file)
  
+ (defcustom file-name-at-point-functions '(ffap-guess-file-name-at-point)
+   "List of functions to try in sequence to get the file name at point.
+ Each function should return either nil or a file name found at the
+ location of point in the current buffer."
+   :type '(hook :options (ffap-guess-file-name-at-point))
+   :group 'find-file)
+ 
  ;;;It is not useful to make this a local variable.
  ;;;(put 'find-file-not-found-hooks 'permanent-local t)
  (defvar find-file-not-found-functions nil
***************
*** 1275,1283 ****
      ;;(make-frame-visible (window-frame old-window))
      ))
  
- (defvar find-file-default nil
-   "Used within `find-file-read-args'.")
- 
  (defmacro minibuffer-with-setup-hook (fun &rest body)
    "Add FUN to `minibuffer-setup-hook' while executing BODY.
  BODY should use the minibuffer at most once.
--- 1283,1288 ----
***************
*** 1298,1309 ****
         (remove-hook 'minibuffer-setup-hook ,hook)))))
  
  (defun find-file-read-args (prompt mustmatch)
!   (list (let ((find-file-default
!              (and buffer-file-name
!                   (abbreviate-file-name buffer-file-name))))
!         (minibuffer-with-setup-hook
!             (lambda () (setq minibuffer-default find-file-default))
!           (read-file-name prompt nil default-directory mustmatch)))
        t))
  
  (defun find-file (filename &optional wildcards)
--- 1303,1309 ----
         (remove-hook 'minibuffer-setup-hook ,hook)))))
  
  (defun find-file-read-args (prompt mustmatch)
!   (list (read-file-name prompt nil default-directory mustmatch)
        t))
  
  (defun find-file (filename &optional wildcards)

Index: lisp/ffap.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/ffap.el,v
retrieving revision 1.87
diff -c -r1.87 ffap.el
*** lisp/ffap.el        12 Nov 2009 10:41:53 -0000      1.87
--- lisp/ffap.el        23 Nov 2009 21:15:00 -0000
***************
*** 1893,1898 ****
--- 1893,1921 ----
      (call-interactively 'dired-at-point)))
  
  
+ ;;; Hooks to put in `file-name-at-point-functions':
+ 
+ ;;;###autoload
+ (progn (defun ffap-guess-file-name-at-point ()
+   "Try to get a file name at point.
+ This hook is inteneded to be put in `file-name-at-point-functions'."
+   (when (fboundp 'ffap-guesser)
+     ;; Logic from `ffap-read-file-or-url' and `dired-at-point-prompter'
+     (let ((guess (ffap-guesser)))
+       (setq guess
+           (if (or (not guess)
+                   (and (fboundp 'ffap-url-p)
+                        (ffap-url-p guess))
+                   (and (fboundp 'ffap-file-remote-p)
+                        (ffap-file-remote-p guess)))
+               guess
+             (abbreviate-file-name (expand-file-name guess))))
+       (when guess
+       (if (file-directory-p guess)
+           (file-name-as-directory guess)
+         guess))))))
+ 
+ 
  ;;; Offer default global bindings (`ffap-bindings'):
  
  (defvar ffap-bindings

Index: lisp/minibuffer.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/minibuffer.el,v
retrieving revision 1.99
diff -c -r1.99 minibuffer.el
*** lisp/minibuffer.el  19 Nov 2009 22:05:42 -0000      1.99
--- lisp/minibuffer.el  23 Nov 2009 21:15:32 -0000
***************
*** 1320,1325 ****
--- 1320,1359 ----
  ;; Not always defined, but only called if next-read-file-uses-dialog-p says 
so.
  (declare-function x-file-dialog "xfns.c"
                    (prompt dir &optional default-filename mustmatch 
only-dir-p))
+ (declare-function dired-get-filename "dired" (&optional localp 
no-error-if-not-filep))
+ 
+ (defun read-file-name-defaults (&optional dir initial)
+   (let ((default
+         (cond
+          ;; With non-nil `initial', use `dir' as the first default.
+          ;; Essentially, this mean reversing the normal order of the
+          ;; current directory name and the current file name, i.e.
+          ;; 1. with normal file reading:
+          ;; 1.1. initial input is the current directory
+          ;; 1.2. the first default is the current file name
+          ;; 2. with non-nil `initial' (for `find-alternate-file'):
+          ;; 2.2. initial input is the current file name
+          ;; 2.1. the first default is the current directory
+          (initial (abbreviate-file-name dir))
+          ;; In file buffers, try to get the current file name
+          (buffer-file-name
+           (abbreviate-file-name buffer-file-name))
+          ;; In Dired, get file name from the current line.
+          ((eq major-mode 'dired-mode)
+           (let ((filename (dired-get-filename nil t)))
+             (when filename
+               (if (file-directory-p filename)
+                   (file-name-as-directory (abbreviate-file-name filename))
+                 (abbreviate-file-name filename)))))))
+       (file-name-at-point
+        (run-hook-with-args-until-success 'file-name-at-point-functions)))
+     (when file-name-at-point
+       (setq default (delete-dups
+                    (delete "" (delq nil (list file-name-at-point default))))))
+     ;; Append new defaults to the end of existing `minibuffer-default'.
+     (append
+      (if (listp minibuffer-default) minibuffer-default (list 
minibuffer-default))
+      (if (listp default) default (list default)))))
  
  (defun read-file-name (prompt &optional dir default-filename mustmatch 
initial predicate)
    "Read file name, prompting with PROMPT and completing in directory DIR.
***************
*** 1404,1410 ****
                      (lexical-let ((dir (file-name-as-directory
                                          (expand-file-name dir))))
                        (minibuffer-with-setup-hook
!                           (lambda () (setq default-directory dir))
                          (completing-read prompt 'read-file-name-internal
                                           pred mustmatch insdef
                                           'file-name-history 
default-filename)))
--- 1438,1459 ----
                      (lexical-let ((dir (file-name-as-directory
                                          (expand-file-name dir))))
                        (minibuffer-with-setup-hook
!                           (lambda ()
!                           (setq default-directory dir)
!                           ;; When the first default in `minibuffer-default'
!                           ;; duplicates initial input `insdef',
!                           ;; reset `minibuffer-default' to nil.
!                           (when (equal (or (car-safe insdef) insdef)
!                                        (or (car-safe minibuffer-default)
!                                            minibuffer-default))
!                             (setq minibuffer-default nil))
!                           ;; On the first request on `M-n' fill 
`minibuffer-default'
!                           ;; with a list of defaults relevant for file-name 
reading.
!                           (set (make-local-variable 
'minibuffer-default-add-function)
!                                (lambda ()
!                                  (with-current-buffer
!                                      (window-buffer 
(minibuffer-selected-window))
!                                    (read-file-name-defaults dir initial)))))
                          (completing-read prompt 'read-file-name-internal
                                           pred mustmatch insdef
                                           'file-name-history 
default-filename)))
***************
*** 1997,2002 ****
--- 2046,2062 ----
      (when newstr
        (completion-pcm-try-completion newstr table pred (length newstr)))))
  
+ 
+ ;; Miscellaneous
+ 
+ (defun minibuffer-insert-file-name-at-point ()
+   "Get a file name from original buffer and insert it to the minibuffer."
+   (interactive)
+   (let ((file-name-at-point
+        (with-current-buffer (window-buffer (minibuffer-selected-window))
+          (run-hook-with-args-until-success 'file-name-at-point-functions))))
+     (when file-name-at-point
+       (insert file-name-at-point))))
  
  (provide 'minibuffer)

-- 
Juri Linkov
http://www.jurta.org/emacs/




reply via email to

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