Package: emacs;
Reported by: Keith David Bershatsky <esq <at> lawlist.com>
Date: Sat, 26 May 2018 04:38:02 UTC
Severity: minor
View this message in rfc822 format
From: Keith David Bershatsky <esq <at> lawlist.com> To: 31601 <at> debbugs.gnu.org Subject: bug#31601: Dired/Wdired: Play nicely with recursive list of files and directories. Date: Fri, 25 May 2018 21:36:37 -0700
I occasionally have the need to rename files and directories that are recursively located. I create a dired-mode buffer as follows: (dired (directory-files-recursively "/path/to/directory" "" 'include-directories)) Wdired: The first problem is that `wdired-get-filename' needs to be modified so that it handles absolute paths differently than relative filenames. Here is an example that works -- using `file-name-absolute-p`: (defun wdired-get-filename (&optional no-dir old) "Return the filename at line. Similar to `dired-get-filename' but it doesn't rely on regexps. It relies on WDired buffer's properties. Optional arg NO-DIR with value non-nil means don't include directory. Optional arg OLD with value non-nil means return old filename." ;; FIXME: Use dired-get-filename's new properties. (let (beg end file) (save-excursion (setq end (line-end-position)) (beginning-of-line) (setq beg (next-single-property-change (point) 'old-name nil end)) (unless (eq beg end) (if old (setq file (get-text-property beg 'old-name)) ;; In the following form changed `(1+ beg)' to `beg' so that ;; the filename end is found even when the filename is empty. ;; Fixes error and spurious newlines when marking files for ;; deletion. (if (= (point-at-eol) (point-max)) (setq end (point-max)) ;; fix for @lawlist eliminating final new line at eob. (setq end (next-single-property-change beg 'end-name))) (setq file (buffer-substring-no-properties (1+ beg) end))) (and file (setq file (wdired-normalize-filename file)))) (if (or no-dir old) file (cond ;;; When FILE is relative, concatenate default-directory to beginning. ((and file (> (length file) 0) (not (file-name-absolute-p file)) (concat (dired-current-directory) file))) ;;; When FILE is absolute, no need to concatenate the default-directory. ((and file (> (length file) 0) (file-name-absolute-p file) file))))))) Dired: The second problem is a dired-mode problem in that the `dired-directory' variable is not updated when renaming a file. I haven't tested deleting a file, but that probably suffers the same problem. Absent updating the `dired-directory` with the renamed filename, the `revert-buffer` will encounter errors because `ls` or `gls` will try to find files that no longer exist, and that errors will be inserted into the dired- buffer. A quick solution for renaming the file is to modify `dired-rename-file` as follows: ;;; (setq mylist '("apple" "pear" "peach" "nectarine" "watermelon")) ;;; (ar-replace--in-list "apple" "cherry" mylist) ;;; Written by @Andreas Röhler: https://emacs.stackexchange.com/a/41631/2287 (defun ar-replace--in-list (elem replacement list) "Expects a LIST of strings. ELEM: element to replace by arg REPLACEMENT" (let (newlist) (dolist (ele list) (if (string= ele elem) (push replacement newlist) (push ele newlist))) (nreverse newlist))) (defun dired-rename-file (file newname ok-if-already-exists) (dired-handle-overwrite newname) (rename-file file newname ok-if-already-exists) ; error is caught in -create-files ;;; Update the `dired-directory' (when (and (listp dired-directory) (member file dired-directory)) (setq dired-directory (ar-replace--in-list file newname dired-directory))) ;; Silently rename the visited file of any buffer visiting this file. (and (get-file-buffer file) (with-current-buffer (get-file-buffer file) (set-visited-file-name newname nil t))) (dired-remove-file file) ;; See if it's an inserted subdir, and rename that, too. (dired-rename-subdir file newname)) However, this is understandably slow if there are a lot of files. Perhaps a hash-table system would be better suited to keep track of files and directories instead of just a plain old list with file/directory names. I haven't yet figured out the best approach to modify a wdired-mode buffer that has a combination of directories and files. Presumably some portion of the absolute filename/directory-name will need read-only attributes .... But, that is as far as my thinking has gone on this issue. There may be many other situations that I haven't thought of because I've never used all of the features of dired-mode and/or wdired-mode. Thanks, Keith
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.