# HG changeset patch # User Stefan Monnier # Date 1213462801 0 # Node ID 80ae3c334377de222eec054513dba1c236c27855 # Parent bda6cd3a64770a88012b435d698d25237a3f1b2b (wdired-do-renames): New function. (wdired-finish-edit): Use it to. (wdired-preprocess-files): Don't hardcode (point-min) == 1. diff -r bda6cd3a6477 -r 80ae3c334377 lisp/ChangeLog --- a/lisp/ChangeLog Sat Jun 14 16:01:38 2008 +0000 +++ b/lisp/ChangeLog Sat Jun 14 17:00:01 2008 +0000 @@ -1,3 +1,9 @@ +2008-06-14 Stefan Monnier + + * wdired.el (wdired-do-renames): New function. + (wdired-finish-edit): Use it to. + (wdired-preprocess-files): Don't hardcode (point-min) == 1. + 2008-06-14 Stefan Monnier * info.el (Info-insert-breadcrumbs): Don't break in apropos and toc. diff -r bda6cd3a6477 -r 80ae3c334377 lisp/wdired.el --- a/lisp/wdired.el Sat Jun 14 16:01:38 2008 +0000 +++ b/lisp/wdired.el Sat Jun 14 17:00:01 2008 +0000 @@ -271,7 +271,7 @@ ;; Protect the buffer so only the filenames can be changed, and put ;; properties so filenames (old and new) can be easily found. (defun wdired-preprocess-files () - (put-text-property 1 2 'front-sticky t) + (put-text-property (point-min) (1+ (point-min))'front-sticky t) (save-excursion (goto-char (point-min)) (let ((b-protection (point)) @@ -368,9 +368,9 @@ "Actually rename files based on your editing in the Dired buffer." (interactive) (wdired-change-to-dired-mode) - (let ((overwrite (or (not wdired-confirm-overwrite) 1)) - (changes nil) + (let ((changes nil) (files-deleted nil) + (file-renames ()) (errors 0) file-ori file-new tmp-value) (save-excursion @@ -388,29 +388,16 @@ (while (not (bobp)) (setq file-ori (wdired-get-filename nil t)) (when file-ori - (setq file-new (wdired-get-filename))) - (when (and file-ori (not (equal file-new file-ori))) - (setq changes t) - (if (not file-new) ;empty filename! - (setq files-deleted (cons file-ori files-deleted)) - (setq file-new (substitute-in-file-name file-new)) - (if wdired-use-interactive-rename - (wdired-search-and-rename file-ori file-new) - ;; If dired-rename-file autoloads dired-aux while - ;; dired-backup-overwrite is locally bound, - ;; dired-backup-overwrite won't be initialized. - ;; So we must ensure dired-aux is loaded. - (require 'dired-aux) - (condition-case err - (let ((dired-backup-overwrite nil)) - (dired-rename-file file-ori file-new - overwrite)) - (error - (setq errors (1+ errors)) - (dired-log (concat "Rename `" file-ori "' to `" - file-new "' failed:\n%s\n") - err)))))) + (setq file-new (wdired-get-filename)) + (unless (equal file-new file-ori) + (setq changes t) + (if (not file-new) ;empty filename! + (push file-ori files-deleted) + (push (cons file-ori (substitute-in-file-name file-new)) + file-renames)))) (forward-line -1))) + (when file-renames + (setq errors (+ errors (wdired-do-renames file-renames)))) (if changes (revert-buffer) ;The "revert" is necessary to re-sort the buffer (let ((inhibit-read-only t)) @@ -426,6 +413,67 @@ (set-buffer-modified-p nil) (setq buffer-undo-list nil)) +(defun wdired-do-renames (renames) + "Perform RENAMES in parallel." + (let ((residue ()) + (progress nil) + (errors 0) + (overwrite (or (not wdired-confirm-overwrite) 1))) + (while (or renames + ;; We've done one round through the renames, we have found + ;; some residue, but we also made some progress, so maybe + ;; some of the residue were resolved: try again. + (prog1 (setq renames residue) + (setq progress nil) + (setq residue nil))) + (let* ((rename (pop renames)) + (file-new (cdr rename))) + (cond + ((rassoc file-new renames) + (error "Trying to rename 2 files to the same name")) + ((assoc file-new renames) + ;; Renaming to a file name that already exists but will itself be + ;; renamed as well. Let's wait until that one gets renamed. + (push rename residue)) + ((and (assoc file-new residue) + ;; Make sure the file really exists: if it doesn't it's + ;; not really a conflict. It might be a temp-file generated + ;; specifically to break a circular renaming. + (file-exists-p file-new)) + ;; Renaming to a file name that already exists, needed to be renamed, + ;; but whose renaming could not be performed right away. + (if (or progress renames) + ;; There's still a chance the conflict will be resolved. + (push rename residue) + ;; We have not made any progress and we've reached the end of + ;; the renames, so we really have a circular conflict, and we + ;; have to forcefully break the cycle. + (message "Circular renaming: using temporary file name") + (let ((tmp (make-temp-name file-new))) + (push (cons (car rename) tmp) renames) + (push (cons tmp file-new) residue)))) + (t + (setq progress t) + (let ((file-ori (car rename))) + (if wdired-use-interactive-rename + (wdired-search-and-rename file-ori file-new) + ;; If dired-rename-file autoloads dired-aux while + ;; dired-backup-overwrite is locally bound, + ;; dired-backup-overwrite won't be initialized. + ;; So we must ensure dired-aux is loaded. + (require 'dired-aux) + (condition-case err + (let ((dired-backup-overwrite nil)) + (dired-rename-file file-ori file-new + overwrite)) + (error + (setq errors (1+ errors)) + (dired-log (concat "Rename `" file-ori "' to `" + file-new "' failed:\n%s\n") + err))))))))) + errors)) + + (defun wdired-exit () "Exit wdired and return to dired mode. Just return to dired mode if there are no changes. Otherwise, @@ -449,24 +497,22 @@ (save-excursion (goto-char (point-max)) (forward-line -1) - (let ((exit-while nil) + (let ((done nil) curr-filename) - (while (not exit-while) - (setq curr-filename (wdired-get-filename)) - (if (and curr-filename - (equal (substitute-in-file-name curr-filename) filename-new)) + (while (and (not done) (not (bobp))) + (setq curr-filename (wdired-get-filename nil t)) + (if (equal curr-filename filename-ori) (progn (setq exit-while t) (let ((inhibit-read-only t)) (dired-move-to-filename) (search-forward (wdired-get-filename t) nil t) (replace-match (file-name-nondirectory filename-ori) t t)) + (setq done) (dired-do-create-files-regexp (function dired-rename-file) "Move" 1 ".*" filename-new nil t)) - (forward-line -1) - (beginning-of-line) - (setq exit-while (bobp))))))) + (forward-line -1)))))) ;; marks a list of files for deletion (defun wdired-flag-for-deletion (filenames-ori)