diff options
| author | Richard M. Stallman | 2003-12-01 01:56:19 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 2003-12-01 01:56:19 +0000 |
| commit | d1c553c832d66677f2c1bd6d4e6394275cbe25e6 (patch) | |
| tree | 6fbd0d036c888f68c3de5a49f49dc864d1f20e10 | |
| parent | 2a75d75d3fb2ed0da8031f0de912b1694ee1be1d (diff) | |
| download | emacs-d1c553c832d66677f2c1bd6d4e6394275cbe25e6.tar.gz emacs-d1c553c832d66677f2c1bd6d4e6394275cbe25e6.zip | |
(dired-do-query-replace-regexp): Report files visited read-only.
(dired-compare-directories): New command.
(dired-file-set-difference, dired-files-attributes): New functions.
| -rw-r--r-- | lisp/dired-aux.el | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index ab3b65abac0..d12410afae5 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el | |||
| @@ -88,6 +88,101 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'." | |||
| 88 | nil)) | 88 | nil)) |
| 89 | (diff-backup (dired-get-filename) switches)) | 89 | (diff-backup (dired-get-filename) switches)) |
| 90 | 90 | ||
| 91 | (defun dired-compare-directories (dir2 predicate) | ||
| 92 | "Mark files with different file attributes in two dired buffers. | ||
| 93 | Compare file attributes of files in the current directory | ||
| 94 | with file attributes in directory DIR2 using PREDICATE on pairs of files | ||
| 95 | with the same name. Mark files for which PREDICATE returns non-nil. | ||
| 96 | |||
| 97 | PREDICATE is a Lisp expression that can refer to the following variables: | ||
| 98 | |||
| 99 | size1, size2 - file size in bytes | ||
| 100 | mtime1, mtime2 - last modification time in seconds, as a float | ||
| 101 | fa1, fa2 - list of file attributes | ||
| 102 | returned by function `file-attributes' | ||
| 103 | |||
| 104 | where 1 refers to attribute of file in the current dired buffer | ||
| 105 | and 2 to attribute of file in second dired buffer. | ||
| 106 | |||
| 107 | Examples of PREDICATE: | ||
| 108 | |||
| 109 | (> mtime1 mtime2) - mark newer files | ||
| 110 | (not (= size1 size2)) - mark files with different sizes | ||
| 111 | (not (string= (nth 8 fa1) (nth 8 fa2))) - mark files with different modes | ||
| 112 | (not (and (= (nth 2 fa1) (nth 2 fa2)) - mark files with different UID | ||
| 113 | (= (nth 3 fa1) (nth 3 fa2)))) and GID." | ||
| 114 | (interactive | ||
| 115 | (list (read-file-name (format "Compare %s with: " | ||
| 116 | (dired-current-directory)) | ||
| 117 | (dired-dwim-target-directory)) | ||
| 118 | (read-minibuffer "Mark if (lisp expr): "))) | ||
| 119 | (let* ((dir1 (dired-current-directory)) | ||
| 120 | (file-alist1 (dired-files-attributes dir1)) | ||
| 121 | (file-alist2 (dired-files-attributes dir2)) | ||
| 122 | (file-list1 (mapcar | ||
| 123 | 'cadr | ||
| 124 | (dired-file-set-difference | ||
| 125 | file-alist1 file-alist2 | ||
| 126 | predicate))) | ||
| 127 | (file-list2 (mapcar | ||
| 128 | 'cadr | ||
| 129 | (dired-file-set-difference | ||
| 130 | file-alist2 file-alist1 | ||
| 131 | predicate)))) | ||
| 132 | (dired-fun-in-all-buffers | ||
| 133 | dir1 nil | ||
| 134 | (lambda () | ||
| 135 | (dired-mark-if | ||
| 136 | (member (dired-get-filename nil t) file-list1) nil))) | ||
| 137 | (dired-fun-in-all-buffers | ||
| 138 | dir2 nil | ||
| 139 | (lambda () | ||
| 140 | (dired-mark-if | ||
| 141 | (member (dired-get-filename nil t) file-list2) nil))) | ||
| 142 | (message "Marked in dir1: %s files, in dir2: %s files" | ||
| 143 | (length file-list1) | ||
| 144 | (length file-list2)))) | ||
| 145 | |||
| 146 | (defun dired-file-set-difference (list1 list2 predicate) | ||
| 147 | "Combine LIST1 and LIST2 using a set-difference operation. | ||
| 148 | The result list contains all file items that appear in LIST1 but not LIST2. | ||
| 149 | This is a non-destructive function; it makes a copy of the data if necessary | ||
| 150 | to avoid corrupting the original LIST1 and LIST2. | ||
| 151 | PREDICATE (see `dired-compare-directories') is an additional match | ||
| 152 | condition. Two file items are considered to match if they are equal | ||
| 153 | *and* PREDICATE evaluates to t." | ||
| 154 | (if (or (null list1) (null list2)) | ||
| 155 | list1 | ||
| 156 | (let (res) | ||
| 157 | (dolist (file1 list1) | ||
| 158 | (unless (let ((list list2)) | ||
| 159 | (while (and list | ||
| 160 | (not (let* ((file2 (car list)) | ||
| 161 | (fa1 (caddr file1)) | ||
| 162 | (fa2 (caddr file2)) | ||
| 163 | (size1 (nth 7 fa1)) | ||
| 164 | (size2 (nth 7 fa2)) | ||
| 165 | (mtime1 (float-time (nth 5 fa1))) | ||
| 166 | (mtime2 (float-time (nth 5 fa2)))) | ||
| 167 | (and | ||
| 168 | (equal (car file1) (car file2)) | ||
| 169 | (not (eval predicate)))))) | ||
| 170 | (setq list (cdr list))) | ||
| 171 | list) | ||
| 172 | (setq res (cons file1 res)))) | ||
| 173 | (nreverse res)))) | ||
| 174 | |||
| 175 | (defun dired-files-attributes (dir) | ||
| 176 | "Return a list of all file names and attributes from DIR. | ||
| 177 | List has a form of (file-name full-file-name (attribute-list))" | ||
| 178 | (mapcar | ||
| 179 | (lambda (file-name) | ||
| 180 | (let ((full-file-name (expand-file-name file-name dir))) | ||
| 181 | (list file-name | ||
| 182 | full-file-name | ||
| 183 | (file-attributes full-file-name)))) | ||
| 184 | (directory-files dir))) | ||
| 185 | |||
| 91 | (defun dired-do-chxxx (attribute-name program op-symbol arg) | 186 | (defun dired-do-chxxx (attribute-name program op-symbol arg) |
| 92 | ;; Change file attributes (mode, group, owner) of marked files and | 187 | ;; Change file attributes (mode, group, owner) of marked files and |
| 93 | ;; refresh their file lines. | 188 | ;; refresh their file lines. |
| @@ -2015,6 +2110,11 @@ If you exit (\\[keyboard-quit], RET or q), you can resume the query replace | |||
| 2015 | with the command \\[tags-loop-continue]." | 2110 | with the command \\[tags-loop-continue]." |
| 2016 | (interactive | 2111 | (interactive |
| 2017 | "sQuery replace in marked files (regexp): \nsQuery replace %s by: \nP") | 2112 | "sQuery replace in marked files (regexp): \nsQuery replace %s by: \nP") |
| 2113 | (dolist (file (dired-get-marked-files nil nil 'dired-nondirectory-p)) | ||
| 2114 | (let ((buffer (get-file-buffer file))) | ||
| 2115 | (if (and buffer (with-current-buffer buffer | ||
| 2116 | buffer-read-only)) | ||
| 2117 | (error "File `%s' is visited read-only")))) | ||
| 2018 | (tags-query-replace from to delimited | 2118 | (tags-query-replace from to delimited |
| 2019 | '(dired-get-marked-files nil nil 'dired-nondirectory-p))) | 2119 | '(dired-get-marked-files nil nil 'dired-nondirectory-p))) |
| 2020 | 2120 | ||