# HG changeset patch # User Juri Linkov # Date 1259169319 0 # Node ID 16d3ef458ae11906bf3be4fac08e8c8bb9eec509 # Parent 0ac473df1bd124f97dc7da630dec8908d02a1018 Provide additional default values (directories at other Dired windows) via M-n in the minibuffer of some Dired commands. * dired-aux.el (dired-diff, dired-compare-directories) (dired-do-create-files): Use `dired-dwim-target-defaults' to set `minibuffer-default' in `minibuffer-with-setup-hook'. (dired-dwim-target-directory): Find a window that displays Dired buffer instead of failing when the next window is not Dired. Use `get-window-with-predicate' to find for the next Dired window. (dired-dwim-target-defaults): New function. * ediff-util.el (ediff-read-file-name): Use `dired-dwim-target-defaults' to set `minibuffer-default' in `minibuffer-with-setup-hook'. diff -r 0ac473df1bd1 -r 16d3ef458ae1 etc/NEWS --- a/etc/NEWS Wed Nov 25 17:11:29 2009 +0000 +++ b/etc/NEWS Wed Nov 25 17:15:19 2009 +0000 @@ -152,7 +152,9 @@ ** M-n provides more default values in the minibuffer of commands that read a file and directory name: a file name at point (when ffap is loaded -without ffap-bindings), a file name on the current line in the Dired buffer. +without ffap-bindings), a file name on the current line in the Dired buffer, +a directory name of adjacent Dired windows for Dired commands that can +operate on several directories (copy, rename, diff). ** M-r is bound to the new `move-to-window-line-top-bottom' to mirror the new behavior of C-l in Emacs-23.1. diff -r 0ac473df1bd1 -r 16d3ef458ae1 lisp/ChangeLog --- a/lisp/ChangeLog Wed Nov 25 17:11:29 2009 +0000 +++ b/lisp/ChangeLog Wed Nov 25 17:15:19 2009 +0000 @@ -1,3 +1,20 @@ +2009-11-25 Juri Linkov + + Provide additional default values (directories at other Dired + windows) via M-n in the minibuffer of some Dired commands. + + * dired-aux.el (dired-diff, dired-compare-directories) + (dired-do-create-files): Use `dired-dwim-target-defaults' to set + `minibuffer-default' in `minibuffer-with-setup-hook'. + (dired-dwim-target-directory): Find a window that displays Dired + buffer instead of failing when the next window is not Dired. + Use `get-window-with-predicate' to find for the next Dired window. + (dired-dwim-target-defaults): New function. + + * ediff-util.el (ediff-read-file-name): + Use `dired-dwim-target-defaults' to set `minibuffer-default' + in `minibuffer-with-setup-hook'. + 2009-11-25 Juri Linkov Provide additional default values (file name at point or at the diff -r 0ac473df1bd1 -r 16d3ef458ae1 lisp/dired-aux.el --- a/lisp/dired-aux.el Wed Nov 25 17:11:29 2009 +0000 +++ b/lisp/dired-aux.el Wed Nov 25 17:15:19 2009 +0000 @@ -59,30 +59,27 @@ With prefix arg, prompt for second argument SWITCHES, which is options for `diff'." (interactive - (let ((current (dired-get-filename t)) - (default (if (mark t) - (save-excursion (goto-char (mark t)) - (dired-get-filename t t))))) - (if (or (equal default current) - (and (not (equal (dired-dwim-target-directory) - (dired-current-directory))) - (not mark-active))) - (setq default nil)) + (let* ((current (dired-get-filename t)) + (target-dir (dired-dwim-target-directory)) + (marked (and (mark t) (save-excursion + (goto-char (mark t)) + (dired-get-filename nil t)))) + (defaults + (append (dired-dwim-target-defaults nil target-dir) + ;; Additional file with the mark. + (and marked (list marked))))) (require 'diff) - (list (read-file-name (format "Diff %s with%s: " - current - (if default - (concat " (default " default ")") - "")) - (if default - (dired-current-directory) - (dired-dwim-target-directory)) - default t) - (if current-prefix-arg - (read-string "Options for diff: " - (if (stringp diff-switches) - diff-switches - (mapconcat 'identity diff-switches " "))))))) + (list + (minibuffer-with-setup-hook + (lambda () + (set (make-local-variable 'minibuffer-default-add-function) nil) + (setq minibuffer-default defaults)) + (read-file-name (format "Diff %s with: " current) target-dir nil t)) + (if current-prefix-arg + (read-string "Options for diff: " + (if (stringp diff-switches) + diff-switches + (mapconcat 'identity diff-switches " "))))))) (diff file (dired-get-filename t) switches)) ;;;###autoload @@ -128,11 +125,17 @@ (not (and (= (nth 2 fa1) (nth 2 fa2)) - mark files with different UID (= (nth 3 fa1) (nth 3 fa2)))) and GID." (interactive - (list (read-directory-name (format "Compare %s with: " - (dired-current-directory)) - (dired-dwim-target-directory) - (dired-dwim-target-directory)) - (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil"))) + (list + (let* ((target-dir (dired-dwim-target-directory)) + (defaults (dired-dwim-target-defaults nil target-dir))) + (minibuffer-with-setup-hook + (lambda () + (set (make-local-variable 'minibuffer-default-add-function) nil) + (setq minibuffer-default defaults)) + (read-directory-name (format "Compare %s with: " + (dired-current-directory)) + target-dir target-dir t))) + (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil"))) (let* ((dir1 (dired-current-directory)) (file-alist1 (dired-files-attributes dir1)) (file-alist2 (dired-files-attributes dir2)) @@ -1463,10 +1466,15 @@ (default (and dired-one-file (expand-file-name (file-name-nondirectory (car fn-list)) target-dir))) + (defaults (dired-dwim-target-defaults fn-list target-dir)) (target (expand-file-name ; fluid variable inside dired-create-files - (dired-mark-read-file-name - (concat (if dired-one-file op1 operation) " %s to: ") - target-dir op-symbol arg rfn-list default))) + (minibuffer-with-setup-hook + (lambda () + (set (make-local-variable 'minibuffer-default-add-function) nil) + (setq minibuffer-default defaults)) + (dired-mark-read-file-name + (concat (if dired-one-file op1 operation) " %s to: ") + target-dir op-symbol arg rfn-list default)))) (into-dir (cond ((null how-to) ;; Allow DOS/Windows users to change the letter ;; case of a directory. If we don't test these @@ -1523,18 +1531,69 @@ (defun dired-dwim-target-directory () ;; Try to guess which target directory the user may want. - ;; If there is a dired buffer displayed in the next window, use - ;; its current subdir, else use current subdir of this dired buffer. + ;; If there is a dired buffer displayed in one of the next windows, + ;; use its current subdir, else use current subdir of this dired buffer. (let ((this-dir (and (eq major-mode 'dired-mode) (dired-current-directory)))) ;; non-dired buffer may want to profit from this function, e.g. vm-uudecode (if dired-dwim-target - (let* ((other-buf (window-buffer (next-window))) - (other-dir (with-current-buffer other-buf - (and (eq major-mode 'dired-mode) - (dired-current-directory))))) + (let* ((other-win (get-window-with-predicate + (lambda (window) + (with-current-buffer (window-buffer window) + (eq major-mode 'dired-mode))))) + (other-dir (and other-win + (with-current-buffer (window-buffer other-win) + (and (eq major-mode 'dired-mode) + (dired-current-directory)))))) (or other-dir this-dir)) this-dir))) + +(defun dired-dwim-target-defaults (fn-list target-dir) + ;; Return a list of default values for file-reading functions in Dired. + ;; This list may contain directories from Dired buffers in other windows. + ;; `fn-list' is a list of file names used to build a list of defaults. + ;; When nil or more than one element, a list of defaults will + ;; contain only directory names. `target-dir' is a directory name + ;; to exclude from the returned list, for the case when this + ;; directory name is already presented in initial input. + ;; For Dired operations that support `dired-dwim-target', + ;; the argument `target-dir' should have the value returned + ;; from `dired-dwim-target-directory'. + (let ((dired-one-file + (and (consp fn-list) (null (cdr fn-list)) (car fn-list))) + (current-dir (and (eq major-mode 'dired-mode) + (dired-current-directory))) + dired-dirs) + ;; Get a list of directories of visible buffers in dired-mode. + (walk-windows (lambda (w) + (with-current-buffer (window-buffer w) + (and (eq major-mode 'dired-mode) + (push (dired-current-directory) dired-dirs))))) + ;; Force the current dir to be the first in the list. + (setq dired-dirs + (delete-dups (delq nil (cons current-dir (nreverse dired-dirs))))) + ;; Remove the target dir (if specified) or the current dir from + ;; default values, because it should be already in initial input. + (setq dired-dirs (delete (or target-dir current-dir) dired-dirs)) + ;; Return a list of default values. + (if dired-one-file + ;; For one file operation, provide a list that contains + ;; other directories, other directories with the appended filename + ;; and the current directory with the appended filename, e.g. + ;; 1. /TARGET-DIR/ + ;; 2. /TARGET-DIR/FILENAME + ;; 3. /CURRENT-DIR/FILENAME + (append dired-dirs + (mapcar (lambda (dir) + (expand-file-name + (file-name-nondirectory (car fn-list)) dir)) + (reverse dired-dirs)) + (list (expand-file-name + (file-name-nondirectory (car fn-list)) + (or target-dir current-dir)))) + ;; For multi-file operation, return only a list of other directories. + dired-dirs))) + ;;;###autoload (defun dired-create-directory (directory) diff -r 0ac473df1bd1 -r 16d3ef458ae1 lisp/ediff-util.el --- a/lisp/ediff-util.el Wed Nov 25 17:11:29 2009 +0000 +++ b/lisp/ediff-util.el Wed Nov 25 17:15:19 2009 +0000 @@ -3113,21 +3113,25 @@ (if (string= default-file "") (setq default-file nil)) - (let (f) - (setq f (expand-file-name - (read-file-name - (format "%s%s " - prompt - (cond (default-file - (concat " (default " default-file "):")) - (t (concat " (default " default-dir "):")))) - default-dir - (or default-file default-dir) - t ; must match, no-confirm - (if default-file (file-name-directory default-file)) - ) - default-dir - )) + (let ((defaults (and (fboundp 'dired-dwim-target-defaults) + (dired-dwim-target-defaults + (and default-file (list default-file)) + default-dir))) + f) + (setq f (minibuffer-with-setup-hook + (lambda () (when defaults + (setq minibuffer-default defaults))) + (read-file-name + (format "%s%s " + prompt + (cond (default-file + (concat " (default " default-file "):")) + (t (concat " (default " default-dir "):")))) + default-dir + (or default-file default-dir) + t ; must match, no-confirm + (if default-file (file-name-directory default-file))))) + (setq f (expand-file-name f default-dir)) ;; If user entered a directory name, expand the default file in that ;; directory. This allows the user to enter a directory name for the ;; B-file and diff against the default-file in that directory instead