From: Keith David Bershatsky <esq@lawlist.com>
To: 31601@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 [thread overview]
Message-ID: <m21sdzghii.wl%esq@lawlist.com> (raw)
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
next reply other threads:[~2018-05-26 4:36 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-26 4:36 Keith David Bershatsky [this message]
2018-05-26 9:02 ` bug#31601: Dired/Wdired: Play nicely with recursive list of files and directories Tino Calancha
2018-05-26 18:51 ` Keith David Bershatsky
2018-05-28 23:11 ` Keith David Bershatsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=m21sdzghii.wl%esq@lawlist.com \
--to=esq@lawlist.com \
--cc=31601@debbugs.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.