diff options
| author | Richard M. Stallman | 1992-06-24 02:13:56 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1992-06-24 02:13:56 +0000 |
| commit | 492d2437106fe6c55d7c643a51ec1ae532b2ea8a (patch) | |
| tree | a85c00e58b5901bf2b9fe8765dc6dafba2c7d396 | |
| parent | d207b766c850f4adb0ed4994949b956b967e9314 (diff) | |
| download | emacs-492d2437106fe6c55d7c643a51ec1ae532b2ea8a.tar.gz emacs-492d2437106fe6c55d7c643a51ec1ae532b2ea8a.zip | |
*** empty log message ***
| -rw-r--r-- | lisp/dired.el | 2557 |
1 files changed, 1950 insertions, 607 deletions
diff --git a/lisp/dired.el b/lisp/dired.el index 16a86f72b26..19ef7a3a233 100644 --- a/lisp/dired.el +++ b/lisp/dired.el | |||
| @@ -1,10 +1,5 @@ | |||
| 1 | ;;; dired.el --- DIRED commands for Emacs | 1 | ;; DIRED commands for Emacs. $Revision: 5.234 $ |
| 2 | 2 | ;; Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc. | |
| 3 | ;;; Missing: P command, sorting, setting file modes. | ||
| 4 | ;;; Dired buffer containing multiple directories gets totally confused | ||
| 5 | ;;; Implement insertion of subdirectories in situ --- tree dired | ||
| 6 | |||
| 7 | ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc. | ||
| 8 | 3 | ||
| 9 | ;; This file is part of GNU Emacs. | 4 | ;; This file is part of GNU Emacs. |
| 10 | 5 | ||
| @@ -22,276 +17,816 @@ | |||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to | 17 | ;; along with GNU Emacs; see the file COPYING. If not, write to |
| 23 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| 24 | 19 | ||
| 20 | ;; Rewritten in 1990/1991 to add tree features, file marking and | ||
| 21 | ;; sorting by Sebastian Kremer <sk@thp.uni-koeln.de>. | ||
| 22 | ;; Finished up by rms in 1992. | ||
| 23 | |||
| 24 | (provide 'dired) | ||
| 25 | |||
| 26 | ;; compatibility package when using Emacs 18.55 | ||
| 27 | (defvar dired-emacs-19-p (equal (substring emacs-version 0 2) "19")) | ||
| 28 | ;;;>>> install (is there a better way to test for Emacs 19?) | ||
| 29 | (or dired-emacs-19-p | ||
| 30 | (require 'emacs-19)) | ||
| 31 | |||
| 32 | ;;; Customizable variables | ||
| 33 | |||
| 34 | ;;; The funny comments are for autoload.el, to automagically update | ||
| 35 | ;;; loaddefs. | ||
| 25 | 36 | ||
| 26 | ;;;###autoload | 37 | ;;;###autoload |
| 27 | (defvar dired-listing-switches "-al" "\ | 38 | (defvar dired-listing-switches "-al" |
| 28 | Switches passed to ls for dired. MUST contain the `l' option. | 39 | "*Switches passed to `ls' for dired. MUST contain the `l' option. |
| 29 | CANNOT contain the `F' option.") | 40 | May contain all other options that don't contradict `-l'; |
| 41 | may contain even `F', `b', `i' and `s'.") | ||
| 30 | 42 | ||
| 43 | ; Don't use absolute paths as /bin should be in any PATH and people | ||
| 44 | ; may prefer /usr/local/gnu/bin or whatever. However, chown is | ||
| 45 | ; usually not in PATH. | ||
| 46 | |||
| 47 | ;;;###autoload | ||
| 31 | (defvar dired-chown-program | 48 | (defvar dired-chown-program |
| 32 | (if (memq system-type '(hpux usg-unix-v)) | 49 | (if (memq system-type '(hpux dgux usg-unix-v)) "chown" "/etc/chown") |
| 33 | "/bin/chown" "/etc/chown") | 50 | "Name of chown command (usully `chown' or `/etc/chown').") |
| 34 | "Pathname of chown command.") | 51 | |
| 52 | ;;;###autoload | ||
| 53 | (defvar dired-ls-program "ls" | ||
| 54 | "Absolute or relative name of the `ls' program used by dired.") | ||
| 35 | 55 | ||
| 36 | (defvar dired-directory nil) | 56 | ;;;###autoload |
| 57 | (defvar dired-ls-F-marks-symlinks nil | ||
| 58 | "*Informs dired about how `ls -lF' marks symbolic links. | ||
| 59 | Set this to t if `dired-ls-program' with `-lF' marks the symbolic link | ||
| 60 | itself with a trailing @ (usually the case under Ultrix). | ||
| 37 | 61 | ||
| 38 | (defun dired-readin (dirname buffer) | 62 | Example: if `ln -s foo bar; ls -F bar' gives `bar -> foo', set it to |
| 63 | nil (the default), if it gives `bar@ -> foo', set it to t. | ||
| 64 | |||
| 65 | Dired checks if there is really a @ appended. Thus, if you have a | ||
| 66 | marking `ls' program on one host and a non-marking on another host, and | ||
| 67 | don't care about symbolic links which really end in a @, you can | ||
| 68 | always set this variable to t.") | ||
| 69 | |||
| 70 | ;;;###autoload | ||
| 71 | (defvar dired-trivial-filenames "^\\.\\.?$\\|^#" | ||
| 72 | "*Regexp of files to skip when finding first file of a directory. | ||
| 73 | A value of nil means move to the subdir line. | ||
| 74 | A value of t means move to first file.") | ||
| 75 | |||
| 76 | ;;;###autoload | ||
| 77 | (defvar dired-keep-marker-rename t | ||
| 78 | ;; Use t as default so that moved files "take their markers with them". | ||
| 79 | "*Controls marking of renamed files. | ||
| 80 | If t, files keep their previous marks when they are renamed. | ||
| 81 | If a character, renamed files (whether previously marked or not) | ||
| 82 | are afterward marked with that character.") | ||
| 83 | |||
| 84 | ;;;###autoload | ||
| 85 | (defvar dired-keep-marker-copy ?C | ||
| 86 | "*Controls marking of copied files. | ||
| 87 | If t, copied files are marked if and as the corresponding original files were. | ||
| 88 | If a character, copied files are unconditionally marked with that character.") | ||
| 89 | |||
| 90 | ;;;###autoload | ||
| 91 | (defvar dired-keep-marker-hardlink ?H | ||
| 92 | "*Controls marking of newly made hard links. | ||
| 93 | If t, they are marked if and as the files linked to were marked. | ||
| 94 | If a character, new links are unconditionally marked with that character.") | ||
| 95 | |||
| 96 | ;;;###autoload | ||
| 97 | (defvar dired-keep-marker-symlink ?Y | ||
| 98 | "*Controls marking of newly made symbolic links. | ||
| 99 | If t, they are marked if and as the files linked to were marked. | ||
| 100 | If a character, new links are unconditionally marked with that character.") | ||
| 101 | |||
| 102 | ;;;###autoload | ||
| 103 | (defvar dired-dwim-target nil | ||
| 104 | "*If non-nil, dired tries to guess a default target directory. | ||
| 105 | This means: if there is a dired buffer displayed in the next window, | ||
| 106 | use its current subdir, instead of the current subdir of this dired buffer. | ||
| 107 | |||
| 108 | The target is used in the prompt for file copy, rename etc.") | ||
| 109 | |||
| 110 | ;;;###autoload | ||
| 111 | (defvar dired-copy-preserve-time t | ||
| 112 | "*If non-nil, Dired preserves the last-modified time in a file copy. | ||
| 113 | \(This works on only some systems.)") | ||
| 114 | |||
| 115 | ;;; Hook variables | ||
| 116 | |||
| 117 | (defvar dired-load-hook nil | ||
| 118 | "Run after loading dired. | ||
| 119 | You can customize key bindings or load extensions with this.") | ||
| 120 | |||
| 121 | (defvar dired-mode-hook nil | ||
| 122 | "Run at the very end of dired-mode.") | ||
| 123 | |||
| 124 | (defvar dired-before-readin-hook nil | ||
| 125 | "This hook is run before a dired buffer is read in (created or reverted).") | ||
| 126 | |||
| 127 | (defvar dired-after-readin-hook nil | ||
| 128 | "Hook run after each time a file or directory is read by Dired. | ||
| 129 | After each listing of a file or directory, this hook is run | ||
| 130 | with the buffer narrowed to the listing.") | ||
| 131 | ;; Note this can't simply be run inside function `dired-ls' as the hook | ||
| 132 | ;; functions probably depend on the dired-subdir-alist to be OK. | ||
| 133 | |||
| 134 | ;;; Internal variables | ||
| 135 | |||
| 136 | (defvar dired-marker-char ?* ; the answer is 42 | ||
| 137 | ;; so that you can write things like | ||
| 138 | ;; (let ((dired-marker-char ?X)) | ||
| 139 | ;; ;; great code using X markers ... | ||
| 140 | ;; ) | ||
| 141 | ;; For example, commands operating on two sets of files, A and B. | ||
| 142 | ;; Or marking files with digits 0-9. This could implicate | ||
| 143 | ;; concentric sets or an order for the marked files. | ||
| 144 | ;; The code depends on dynamic scoping on the marker char. | ||
| 145 | "In Dired, the current mark character. | ||
| 146 | This is what the `do' commands look for and what the `mark' commands store.") | ||
| 147 | |||
| 148 | (defvar dired-del-marker ?D | ||
| 149 | "Character used to flag files for deletion.") | ||
| 150 | |||
| 151 | (defvar dired-shrink-to-fit | ||
| 152 | (if (fboundp 'baud-rate) (> (baud-rate) search-slow-speed) t) | ||
| 153 | "Non-nil means Dired shrinks the display buffer to fit the marked files.") | ||
| 154 | |||
| 155 | (defvar dired-flagging-regexp nil);; Last regexp used to flag files. | ||
| 156 | |||
| 157 | (defvar dired-directory nil | ||
| 158 | "The directory name or shell wildcard that was used as argument to `ls'. | ||
| 159 | Local to each dired buffer.") | ||
| 160 | |||
| 161 | (defvar dired-actual-switches nil | ||
| 162 | "The value of `dired-listing-switches' used to make this buffer's text.") | ||
| 163 | |||
| 164 | (defvar dired-re-inode-size "[0-9 \t]*" | ||
| 165 | "Regexp for optional initial inode and file size as made by `ls -i -s'.") | ||
| 166 | |||
| 167 | ;; These regexps must be tested at beginning-of-line, but are also | ||
| 168 | ;; used to search for next matches, so neither omitting "^" nor | ||
| 169 | ;; replacing "^" by "\n" (to make it slightly faster) will work. | ||
| 170 | |||
| 171 | (defvar dired-re-mark "^[^ \n]") | ||
| 172 | ;; "Regexp matching a marked line. | ||
| 173 | ;; Important: the match ends just after the marker." | ||
| 174 | (defvar dired-re-maybe-mark "^. ") | ||
| 175 | (defvar dired-re-dir (concat dired-re-maybe-mark dired-re-inode-size "d")) | ||
| 176 | (defvar dired-re-sym (concat dired-re-maybe-mark dired-re-inode-size "l")) | ||
| 177 | (defvar dired-re-exe;; match ls permission string of an executable file | ||
| 178 | (mapconcat (function | ||
| 179 | (lambda (x) | ||
| 180 | (concat dired-re-maybe-mark dired-re-inode-size x))) | ||
| 181 | '("-[-r][-w][xs][-r][-w].[-r][-w]." | ||
| 182 | "-[-r][-w].[-r][-w][xs][-r][-w]." | ||
| 183 | "-[-r][-w].[-r][-w].[-r][-w][xst]") | ||
| 184 | "\\|")) | ||
| 185 | (defvar dired-re-dot "^.* \\.\\.?$") | ||
| 186 | |||
| 187 | (defvar dired-subdir-alist nil | ||
| 188 | "Association list of subdirectories and their buffer positions. | ||
| 189 | Each subdirectory has an element: (DIRNAME . STARTMARKER). | ||
| 190 | The order of elements is the reverse of the order in the buffer.") | ||
| 191 | |||
| 192 | (defvar dired-subdir-regexp "^. \\([^ \n\r]+\\)\\(:\\)[\n\r]" | ||
| 193 | "Regexp matching a maybe hidden subdirectory line in `ls -lR' output. | ||
| 194 | Subexpression 1 is the subdirectory proper, no trailing colon. | ||
| 195 | The match starts at the beginning of the line and ends after the end | ||
| 196 | of the line (\\n or \\r). | ||
| 197 | Subexpression 2 must end right before the \\n or \\r.") | ||
| 198 | |||
| 199 | |||
| 200 | ;;; Macros must be defined before they are used, for the byte compiler. | ||
| 201 | |||
| 202 | ;; Mark all files for which CONDITION evals to non-nil. | ||
| 203 | ;; CONDITION is evaluated on each line, with point at beginning of line. | ||
| 204 | ;; MSG is a noun phrase for the type of files being marked. | ||
| 205 | ;; It should end with a noun that can be pluralized by adding `s'. | ||
| 206 | ;; Return value is the number of files marked, or nil if none were marked. | ||
| 207 | (defmacro dired-mark-if (predicate msg) | ||
| 208 | (` (let (buffer-read-only count) | ||
| 209 | (save-excursion | ||
| 210 | (setq count 0) | ||
| 211 | (if (, msg) (message "Marking %ss..." (, msg))) | ||
| 212 | (goto-char (point-min)) | ||
| 213 | (while (not (eobp)) | ||
| 214 | (if (, predicate) | ||
| 215 | (progn | ||
| 216 | (delete-char 1) | ||
| 217 | (insert dired-marker-char) | ||
| 218 | (setq count (1+ count)))) | ||
| 219 | (forward-line 1)) | ||
| 220 | (if (, msg) (message "%s %s%s %s%s." | ||
| 221 | count | ||
| 222 | (, msg) | ||
| 223 | (dired-plural-s count) | ||
| 224 | (if (eq dired-marker-char ?\040) "un" "") | ||
| 225 | (if (eq dired-marker-char dired-del-marker) | ||
| 226 | "flagged" "marked")))) | ||
| 227 | (and (> count 0) count)))) | ||
| 228 | |||
| 229 | (defmacro dired-map-over-marks (body arg &optional show-progress) | ||
| 230 | ;; "Macro: Perform BODY with point somewhere on each marked line | ||
| 231 | ;;and return a list of BODY's results. | ||
| 232 | ;;If no marked file could be found, execute BODY on the current line. | ||
| 233 | ;; If ARG is an integer, use the next ARG (or previous -ARG, if ARG<0) | ||
| 234 | ;; files instead of the marked files. | ||
| 235 | ;; In that case point is dragged along. This is so that commands on | ||
| 236 | ;; the next ARG (instead of the marked) files can be chained easily. | ||
| 237 | ;; If ARG is otherwise non-nil, use current file instead. | ||
| 238 | ;;If optional third arg SHOW-PROGRESS evaluates to non-nil, | ||
| 239 | ;; redisplay the dired buffer after each file is processed. | ||
| 240 | ;;No guarantee is made about the position on the marked line. | ||
| 241 | ;; BODY must ensure this itself if it depends on this. | ||
| 242 | ;;Search starts at the beginning of the buffer, thus the car of the list | ||
| 243 | ;; corresponds to the line nearest to the buffer's bottom. This | ||
| 244 | ;; is also true for (positive and negative) integer values of ARG. | ||
| 245 | ;;BODY should not be too long as it is expanded four times." | ||
| 246 | ;; | ||
| 247 | ;;Warning: BODY must not add new lines before point - this may cause an | ||
| 248 | ;;endless loop. | ||
| 249 | ;;This warning should not apply any longer, sk 2-Sep-1991 14:10. | ||
| 250 | (` (prog1 | ||
| 251 | (let (buffer-read-only case-fold-search found results) | ||
| 252 | (if (, arg) | ||
| 253 | (if (integerp (, arg)) | ||
| 254 | (progn;; no save-excursion, want to move point. | ||
| 255 | (dired-repeat-over-lines | ||
| 256 | (, arg) | ||
| 257 | (function (lambda () | ||
| 258 | (if (, show-progress) (sit-for 0)) | ||
| 259 | (setq results (cons (, body) results))))) | ||
| 260 | (if (< (, arg) 0) | ||
| 261 | (nreverse results) | ||
| 262 | results)) | ||
| 263 | ;; non-nil, non-integer ARG means use current file: | ||
| 264 | (list (, body))) | ||
| 265 | (let ((regexp (dired-marker-regexp)) next-position) | ||
| 266 | (save-excursion | ||
| 267 | (goto-char (point-min)) | ||
| 268 | ;; remember position of next marked file before BODY | ||
| 269 | ;; can insert lines before the just found file, | ||
| 270 | ;; confusing us by finding the same marked file again | ||
| 271 | ;; and again and... | ||
| 272 | (setq next-position (and (re-search-forward regexp nil t) | ||
| 273 | (point-marker)) | ||
| 274 | found (not (null next-position))) | ||
| 275 | (while next-position | ||
| 276 | (goto-char next-position) | ||
| 277 | (if (, show-progress) (sit-for 0)) | ||
| 278 | (setq results (cons (, body) results)) | ||
| 279 | ;; move after last match | ||
| 280 | (goto-char next-position) | ||
| 281 | (forward-line 1) | ||
| 282 | (set-marker next-position nil) | ||
| 283 | (setq next-position (and (re-search-forward regexp nil t) | ||
| 284 | (point-marker))))) | ||
| 285 | (if found | ||
| 286 | results | ||
| 287 | (list (, body)))))) | ||
| 288 | ;; save-excursion loses, again | ||
| 289 | (dired-move-to-filename)))) | ||
| 290 | |||
| 291 | (defun dired-get-marked-files (&optional localp arg) | ||
| 292 | "Return the marked files' names as list of strings. | ||
| 293 | The list is in the same order as the buffer, that is, the car is the | ||
| 294 | first marked file. | ||
| 295 | Values returned are normally absolute pathnames. | ||
| 296 | Optional arg LOCALP as in `dired-get-filename'. | ||
| 297 | Optional second argument ARG forces to use other files. If ARG is an | ||
| 298 | integer, use the next ARG files. If ARG is otherwise non-nil, use | ||
| 299 | current file. Usually ARG comes from the current prefix arg." | ||
| 39 | (save-excursion | 300 | (save-excursion |
| 40 | (message "Reading directory %s..." dirname) | 301 | (nreverse (dired-map-over-marks (dired-get-filename localp) arg)))) |
| 41 | (set-buffer buffer) | ||
| 42 | (let ((buffer-read-only nil)) | ||
| 43 | (widen) | ||
| 44 | (erase-buffer) | ||
| 45 | (setq dirname (expand-file-name dirname)) | ||
| 46 | (if (eq system-type 'vax-vms) | ||
| 47 | (vms-read-directory dirname dired-listing-switches buffer) | ||
| 48 | (if (file-directory-p dirname) | ||
| 49 | (call-process "ls" nil buffer nil | ||
| 50 | dired-listing-switches dirname) | ||
| 51 | (if (not (file-readable-p (directory-file-name (file-name-directory dirname)))) | ||
| 52 | (insert "Directory " dirname " inaccessible or nonexistent.\n") | ||
| 53 | (let ((default-directory (file-name-directory dirname))) | ||
| 54 | (call-process shell-file-name nil buffer nil | ||
| 55 | "-c" (concat "ls -d " dired-listing-switches " " | ||
| 56 | (file-name-nondirectory dirname))))))) | ||
| 57 | (goto-char (point-min)) | ||
| 58 | (indent-rigidly (point-min) (point-max) 2)) | ||
| 59 | (set-buffer-modified-p nil) | ||
| 60 | (message "Reading directory %s...done" dirname))) | ||
| 61 | 302 | ||
| 62 | (defun dired-find-buffer (dirname) | 303 | |
| 63 | (let ((blist (buffer-list)) | 304 | ;; Function dired-ls is redefinable for VMS, ange-ftp, Prospero or |
| 64 | found) | 305 | ;; other special applications. |
| 65 | (while blist | 306 | |
| 66 | (save-excursion | 307 | ;; dired-ls |
| 67 | (set-buffer (car blist)) | 308 | ;; - must insert _exactly_one_line_ describing FILE if WILDCARD and |
| 68 | (if (and (eq major-mode 'dired-mode) | 309 | ;; FULL-DIRECTORY-P is nil. |
| 69 | (equal dired-directory dirname)) | 310 | ;; The single line of output must display FILE's name as it was |
| 70 | (setq found (car blist) | 311 | ;; given, namely, an absolute path name. |
| 71 | blist nil) | 312 | ;; - must insert exactly one line for each file if WILDCARD or |
| 72 | (setq blist (cdr blist))))) | 313 | ;; FULL-DIRECTORY-P is t, plus one optional "total" line |
| 73 | (or found | 314 | ;; before the file lines, plus optional text after the file lines. |
| 74 | (create-file-buffer (directory-file-name dirname))))) | 315 | ;; Lines are delimited by "\n", so filenames containing "\n" are not |
| 316 | ;; allowed. | ||
| 317 | ;; File lines should display the basename, not a path name. | ||
| 318 | ;; - must drag point after inserted text | ||
| 319 | ;; - must be consistent with | ||
| 320 | ;; - functions dired-move-to-filename, (these two define what a file line is) | ||
| 321 | ;; dired-move-to-end-of-filename, | ||
| 322 | ;; dired-between-files, (shortcut for (not (dired-move-to-filename))) | ||
| 323 | ;; dired-insert-headerline | ||
| 324 | ;; dired-after-subdir-garbage (defines what a "total" line is) | ||
| 325 | ;; - variables dired-subdir-regexp | ||
| 326 | (defun dired-ls (file switches &optional wildcard full-directory-p) | ||
| 327 | ; "Insert `ls' output of FILE, formatted according to SWITCHES. | ||
| 328 | ;Optional third arg WILDCARD means treat FILE as shell wildcard. | ||
| 329 | ;Optional fourth arg FULL-DIRECTORY-P means file is a directory and | ||
| 330 | ;switches do not contain `d', so that a full listing is expected. | ||
| 331 | ; | ||
| 332 | ;Uses dired-ls-program (and shell-file-name if WILDCARD) to do the work." | ||
| 333 | (if wildcard | ||
| 334 | (let ((default-directory (file-name-directory file))) | ||
| 335 | (call-process shell-file-name nil t nil | ||
| 336 | "-c" (concat dired-ls-program " -d " switches " " | ||
| 337 | (file-name-nondirectory file)))) | ||
| 338 | (call-process dired-ls-program nil t nil switches file))) | ||
| 339 | |||
| 340 | ;; The dired command | ||
| 341 | |||
| 342 | (defun dired-read-dir-and-switches (str) | ||
| 343 | ;; For use in interactive. | ||
| 344 | (reverse (list | ||
| 345 | (if current-prefix-arg | ||
| 346 | (read-string "Dired listing switches: " | ||
| 347 | dired-listing-switches)) | ||
| 348 | (read-file-name (format "Dired %s(directory): " str) | ||
| 349 | nil default-directory nil)))) | ||
| 75 | 350 | ||
| 351 | ;;;###autoload (define-key ctl-x-map "d" 'dired) | ||
| 76 | ;;;###autoload | 352 | ;;;###autoload |
| 77 | (defun dired (dirname) | 353 | (defun dired (dirname &optional switches) |
| 78 | "\"Edit\" directory DIRNAME--delete, rename, print, etc. some files in it. | 354 | "\"Edit\" directory DIRNAME--delete, rename, print, etc. some files in it. |
| 79 | Dired displays the list of files in DIRNAME. | 355 | Optional second argument SWITCHES specifies the `ls' options used. |
| 80 | You can move around in it with the usual movement commands. | 356 | \(Interactively, use a prefix argument to be able to specify SWITCHES.) |
| 81 | You can flag files for deletion with \\<dired-mode-map>\\[dired-flag-file-deleted] | 357 | Dired displays a list of files in DIRNAME (which may also have |
| 82 | and then delete them by typing `x'. | 358 | shell wildcards appended to select certain files). |
| 83 | Type `h' after entering dired for more info." | 359 | You can move around in it with the usual commands. |
| 84 | (interactive (list (read-file-name "Dired (directory): " | 360 | You can flag files for deletion with \\<dired-mode-map>\\[dired-flag-file-deletion] and then delete them by |
| 85 | nil default-directory nil))) | 361 | typing \\[dired-do-flagged-delete]. |
| 86 | (switch-to-buffer (dired-noselect dirname))) | 362 | Type \\[describe-mode] after entering dired for more info. |
| 87 | ;;;###autoload | ||
| 88 | (define-key ctl-x-map "d" 'dired) | ||
| 89 | 363 | ||
| 364 | If DIRNAME is already in a dired buffer, that buffer is used without refresh." | ||
| 365 | ;; Cannot use (interactive "D") because of wildcards. | ||
| 366 | (interactive (dired-read-dir-and-switches "")) | ||
| 367 | (switch-to-buffer (dired-noselect dirname switches))) | ||
| 368 | |||
| 369 | ;;;###autoload (define-key ctl-x-4-map "d" 'dired-other-window) | ||
| 90 | ;;;###autoload | 370 | ;;;###autoload |
| 91 | (defun dired-other-window (dirname) | 371 | (defun dired-other-window (dirname &optional switches) |
| 92 | "\"Edit\" directory DIRNAME. Like `dired' but selects in another window." | 372 | "\"Edit\" directory DIRNAME. Like `dired' but selects in another window." |
| 93 | (interactive (list (read-file-name "Dired in other window (directory): " | 373 | (interactive (dired-read-dir-and-switches "in other window ")) |
| 94 | nil default-directory nil))) | 374 | (switch-to-buffer-other-window (dired-noselect dirname switches))) |
| 95 | (switch-to-buffer-other-window (dired-noselect dirname))) | ||
| 96 | ;;;###autoload | ||
| 97 | (define-key ctl-x-4-map "d" 'dired-other-window) | ||
| 98 | 375 | ||
| 99 | ;;;###autoload | 376 | ;;;###autoload |
| 100 | (defun dired-noselect (dirname) | 377 | (defun dired-noselect (dirname &optional switches) |
| 101 | "Like `dired' but returns the dired buffer as value, does not select it." | 378 | "Like `dired' but returns the dired buffer as value, does not select it." |
| 102 | (or dirname (setq dirname default-directory)) | 379 | (or dirname (setq dirname default-directory)) |
| 380 | ;; This loses the distinction between "/foo/*/" and "/foo/*" that | ||
| 381 | ;; some shells make: | ||
| 103 | (setq dirname (expand-file-name (directory-file-name dirname))) | 382 | (setq dirname (expand-file-name (directory-file-name dirname))) |
| 104 | (if (file-directory-p dirname) | 383 | (if (file-directory-p dirname) |
| 105 | (setq dirname (file-name-as-directory dirname))) | 384 | (setq dirname (file-name-as-directory dirname))) |
| 106 | (let ((buffer (dired-find-buffer dirname))) | 385 | (dired-internal-noselect dirname switches)) |
| 107 | (save-excursion | 386 | |
| 108 | (set-buffer buffer) | 387 | ;; Separate function from dired-noselect for the sake of dired-vms.el. |
| 109 | (dired-readin dirname buffer) | 388 | (defun dired-internal-noselect (dirname &optional switches) |
| 110 | (while (and (not (dired-move-to-filename)) (not (eobp))) | 389 | ;; If there is an existing dired buffer for DIRNAME, just leave |
| 111 | (forward-line 1)) | 390 | ;; buffer as it is (don't even call dired-revert). |
| 112 | (dired-mode dirname)) | 391 | ;; This saves time especially for deep trees or with ange-ftp. |
| 392 | ;; The user can type `g'easily, and it is more consistent with find-file. | ||
| 393 | ;; But if SWITCHES are given they are probably different from the | ||
| 394 | ;; buffer's old value, so call dired-sort-other, which does | ||
| 395 | ;; revert the buffer. | ||
| 396 | ;; A pity we can't possibly do "Directory has changed - refresh? " | ||
| 397 | ;; like find-file does. | ||
| 398 | (let* ((buffer (dired-find-buffer-nocreate dirname)) | ||
| 399 | ;; note that buffer already is in dired-mode, if found | ||
| 400 | (new-buffer-p (not buffer)) | ||
| 401 | (old-buf (current-buffer))) | ||
| 402 | (or buffer | ||
| 403 | (let ((default-major-mode 'fundamental-mode)) | ||
| 404 | ;; We don't want default-major-mode to run hooks and set auto-fill | ||
| 405 | ;; or whatever, now that dired-mode does not | ||
| 406 | ;; kill-all-local-variables any longer. | ||
| 407 | (setq buffer (create-file-buffer (directory-file-name dirname))))) | ||
| 408 | (set-buffer buffer) | ||
| 409 | (if (not new-buffer-p) ; existing buffer ... | ||
| 410 | (if switches ; ... but new switches | ||
| 411 | (dired-sort-other switches)) ; this calls dired-revert | ||
| 412 | ;; Else a new buffer | ||
| 413 | (setq default-directory (if (file-directory-p dirname) | ||
| 414 | dirname | ||
| 415 | (file-name-directory dirname))) | ||
| 416 | (or switches (setq switches dired-listing-switches)) | ||
| 417 | (dired-mode dirname switches) | ||
| 418 | ;; default-directory and dired-actual-switches are set now | ||
| 419 | ;; (buffer-local), so we can call dired-readin: | ||
| 420 | (let ((failed t)) | ||
| 421 | (unwind-protect | ||
| 422 | (progn (dired-readin dirname buffer) | ||
| 423 | (setq failed nil)) | ||
| 424 | ;; dired-readin can fail if parent directories are inaccessible. | ||
| 425 | ;; Don't leave an empty buffer around in that case. | ||
| 426 | (if failed (kill-buffer buffer)))) | ||
| 427 | ;; No need to narrow since the whole buffer contains just | ||
| 428 | ;; dired-readin's output, nothing else. The hook can | ||
| 429 | ;; successfully use dired functions (e.g. dired-get-filename) | ||
| 430 | ;; as the subdir-alist has been built in dired-readin. | ||
| 431 | (run-hooks 'dired-after-readin-hook) | ||
| 432 | (goto-char (point-min)) | ||
| 433 | (dired-initial-position dirname)) | ||
| 434 | (set-buffer old-buf) | ||
| 113 | buffer)) | 435 | buffer)) |
| 114 | 436 | ||
| 437 | ;; This differs from dired-buffers-for-dir in that it does not consider | ||
| 438 | ;; subdirs of default-directory and searches for the first match only | ||
| 439 | (defun dired-find-buffer-nocreate (dirname) | ||
| 440 | (let (found (blist (buffer-list))) | ||
| 441 | (while blist | ||
| 442 | (save-excursion | ||
| 443 | (set-buffer (car blist)) | ||
| 444 | (if (and (eq major-mode 'dired-mode) | ||
| 445 | (equal dired-directory dirname)) | ||
| 446 | (setq found (car blist) | ||
| 447 | blist nil) | ||
| 448 | (setq blist (cdr blist))))) | ||
| 449 | found)) | ||
| 450 | |||
| 451 | |||
| 452 | ;; Read in a new dired buffer | ||
| 453 | |||
| 454 | ;; dired-readin differs from dired-insert-subdir in that it accepts | ||
| 455 | ;; wildcards, erases the buffer, and builds the subdir-alist anew | ||
| 456 | ;; (including making it buffer-local and clearing it first). | ||
| 457 | (defun dired-readin (dirname buffer) | ||
| 458 | ;; default-directory and dired-actual-switches must be buffer-local | ||
| 459 | ;; and initialized by now. | ||
| 460 | ;; Thus we can test (equal default-directory dirname) instead of | ||
| 461 | ;; (file-directory-p dirname) and save a filesystem transaction. | ||
| 462 | ;; Also, we can run this hook which may want to modify the switches | ||
| 463 | ;; based on default-directory, e.g. with ange-ftp to a SysV host | ||
| 464 | ;; where ls won't understand -Al switches. | ||
| 465 | (setq dirname (expand-file-name dirname)) | ||
| 466 | (run-hooks 'dired-before-readin-hook) | ||
| 467 | (save-excursion | ||
| 468 | (message "Reading directory %s..." dirname) | ||
| 469 | (set-buffer buffer) | ||
| 470 | (let (buffer-read-only (failed t)) | ||
| 471 | (widen) | ||
| 472 | (erase-buffer) | ||
| 473 | (dired-readin-insert dirname) | ||
| 474 | (indent-rigidly (point-min) (point-max) 2) | ||
| 475 | ;; We need this to make the root dir have a header line as all | ||
| 476 | ;; other subdirs have: | ||
| 477 | (goto-char (point-min)) | ||
| 478 | (dired-insert-headerline default-directory) | ||
| 479 | ;; can't run dired-after-readin-hook here, it may depend on the subdir | ||
| 480 | ;; alist to be OK. | ||
| 481 | ) | ||
| 482 | (message "Reading directory %s...done" dirname) | ||
| 483 | (set-buffer-modified-p nil) | ||
| 484 | ;; Must first make alist buffer local and set it to nil because | ||
| 485 | ;; dired-build-subdir-alist will call dired-clear-alist first | ||
| 486 | (set (make-local-variable 'dired-subdir-alist) nil) | ||
| 487 | (dired-build-subdir-alist))) | ||
| 488 | |||
| 489 | ;; Subroutines of dired-readin | ||
| 490 | |||
| 491 | (defun dired-readin-insert (dirname) | ||
| 492 | ;; Just insert listing for DIRNAME, assuming a clean buffer. | ||
| 493 | (if (equal default-directory dirname);; i.e., (file-directory-p dirname) | ||
| 494 | (dired-ls dirname dired-actual-switches nil t) | ||
| 495 | (if (not (file-readable-p | ||
| 496 | (directory-file-name (file-name-directory dirname)))) | ||
| 497 | (error "Directory %s inaccessible or nonexistent" dirname) | ||
| 498 | ;; else assume it contains wildcards: | ||
| 499 | (dired-ls dirname dired-actual-switches t) | ||
| 500 | (save-excursion;; insert wildcard instead of total line: | ||
| 501 | (goto-char (point-min)) | ||
| 502 | (insert "wildcard " (file-name-nondirectory dirname) "\n"))))) | ||
| 503 | |||
| 504 | (defun dired-insert-headerline (dir);; also used by dired-insert-subdir | ||
| 505 | ;; Insert DIR's headerline with no trailing slash, exactly like ls | ||
| 506 | ;; would, and put cursor where dired-build-subdir-alist puts subdir | ||
| 507 | ;; boundaries. | ||
| 508 | (save-excursion (insert " " (directory-file-name dir) ":\n"))) | ||
| 509 | |||
| 510 | |||
| 511 | ;; Reverting a dired buffer | ||
| 512 | |||
| 115 | (defun dired-revert (&optional arg noconfirm) | 513 | (defun dired-revert (&optional arg noconfirm) |
| 514 | ;; Reread the dired buffer. Must also be called after | ||
| 515 | ;; dired-actual-switches have changed. | ||
| 516 | ;; Should not fail even on completely garbaged buffers. | ||
| 517 | ;; Preserves old cursor, marks/flags, hidden-p. | ||
| 518 | (widen) ; just in case user narrowed | ||
| 116 | (let ((opoint (point)) | 519 | (let ((opoint (point)) |
| 117 | (ofile (dired-get-filename t t)) | 520 | (ofile (dired-get-filename nil t)) |
| 118 | (buffer-read-only nil) | 521 | (mark-alist nil) ; save marked files |
| 119 | delete-list already-deleted column-dots) | 522 | (hidden-subdirs (dired-remember-hidden)) |
| 120 | (goto-char 1) | 523 | (old-subdir-alist (cdr (reverse dired-subdir-alist))) ; except pwd |
| 121 | (if (re-search-forward "^D" nil t) | 524 | (case-fold-search nil) ; we check for upper case ls flags |
| 122 | (progn | 525 | buffer-read-only) |
| 123 | (beginning-of-line) | 526 | (goto-char (point-min)) |
| 124 | (while (re-search-forward "^D" nil t) | 527 | (setq mark-alist;; only after dired-remember-hidden since this unhides: |
| 125 | (setq delete-list (cons (dired-get-filename t) delete-list))))) | 528 | (dired-remember-marks (point-min) (point-max))) |
| 529 | ;; treat top level dir extra (it may contain wildcards) | ||
| 126 | (dired-readin dired-directory (current-buffer)) | 530 | (dired-readin dired-directory (current-buffer)) |
| 127 | (while (and (not (dired-move-to-filename)) (not (eobp))) | 531 | (let ((dired-after-readin-hook nil)) |
| 128 | (forward-line 1)) | 532 | ;; don't run that hook for each subdir... |
| 129 | (setq column-dots (concat "^" (make-string (current-column) ?.)) | 533 | (dired-insert-old-subdirs old-subdir-alist)) |
| 130 | delete-list (nreverse delete-list)) | 534 | (dired-mark-remembered mark-alist) ; mark files that were marked |
| 131 | (while delete-list | 535 | ;; ... run the hook for the whole buffer, and only after markers |
| 132 | ;; assumptions: the directory was reread with the files listed in the | 536 | ;; have been reinserted (else omitting in dired-x would omit marked files) |
| 133 | ;; same order as they were originally. the string of "."s is rather silly | 537 | (run-hooks 'dired-after-readin-hook) ; no need to narrow |
| 134 | ;; but it seems the fastest way to avoid messing with -F flags and | 538 | (or (and ofile (dired-goto-file ofile)) ; move cursor to where it |
| 135 | ;; matches that occur in places other than the filename column | 539 | (goto-char opoint)) ; was before |
| 136 | (if (re-search-forward | ||
| 137 | (concat column-dots (regexp-quote (car delete-list))) nil t) | ||
| 138 | (progn (beginning-of-line) | ||
| 139 | (delete-char 1) | ||
| 140 | (insert "D")) | ||
| 141 | (setq already-deleted (cons (car delete-list) already-deleted))) | ||
| 142 | (setq delete-list (cdr delete-list))) | ||
| 143 | (goto-char 0) | ||
| 144 | (or (and ofile (re-search-forward (concat column-dots (regexp-quote ofile)) | ||
| 145 | nil t)) | ||
| 146 | (goto-char opoint)) | ||
| 147 | (dired-move-to-filename) | 540 | (dired-move-to-filename) |
| 148 | (if already-deleted (message "Already deleted: %s" | 541 | (save-excursion ; hide subdirs that were hidden |
| 149 | (prin1-to-string (reverse already-deleted)))))) | 542 | (mapcar (function (lambda (dir) |
| 543 | (if (dired-goto-subdir dir) | ||
| 544 | (dired-hide-subdir 1)))) | ||
| 545 | hidden-subdirs))) | ||
| 546 | ;; outside of the let scope | ||
| 547 | ;;; Might as well not override the user if the user changed this. | ||
| 548 | ;;; (setq buffer-read-only t) | ||
| 549 | ) | ||
| 550 | |||
| 551 | ;; Subroutines of dired-revert | ||
| 552 | ;; Some of these are also used when inserting subdirs. | ||
| 553 | |||
| 554 | (defun dired-remember-marks (beg end) | ||
| 555 | ;; Return alist of files and their marks, from BEG to END. | ||
| 556 | (if selective-display ; must unhide to make this work. | ||
| 557 | (let (buffer-read-only) | ||
| 558 | (subst-char-in-region beg end ?\r ?\n))) | ||
| 559 | (let (fil chr alist) | ||
| 560 | (save-excursion | ||
| 561 | (goto-char beg) | ||
| 562 | (while (re-search-forward dired-re-mark end t) | ||
| 563 | (if (setq fil (dired-get-filename nil t)) | ||
| 564 | (setq chr (preceding-char) | ||
| 565 | alist (cons (cons fil chr) alist))))) | ||
| 566 | alist)) | ||
| 567 | |||
| 568 | ;; Mark all files remembered in ALIST. | ||
| 569 | ;; Each element of ALIST looks like (FILE . MARKERCHAR). | ||
| 570 | (defun dired-mark-remembered (alist) | ||
| 571 | (let (elt fil chr) | ||
| 572 | (while alist | ||
| 573 | (setq elt (car alist) | ||
| 574 | alist (cdr alist) | ||
| 575 | fil (car elt) | ||
| 576 | chr (cdr elt)) | ||
| 577 | (if (dired-goto-file fil) | ||
| 578 | (save-excursion | ||
| 579 | (beginning-of-line) | ||
| 580 | (delete-char 1) | ||
| 581 | (insert chr)))))) | ||
| 582 | |||
| 583 | ;; Return a list of names of subdirs currently hidden. | ||
| 584 | (defun dired-remember-hidden () | ||
| 585 | (let ((l dired-subdir-alist) dir pos result) | ||
| 586 | (while l | ||
| 587 | (setq dir (car (car l)) | ||
| 588 | pos (cdr (car l)) | ||
| 589 | l (cdr l)) | ||
| 590 | (goto-char pos) | ||
| 591 | (skip-chars-forward "^\r\n") | ||
| 592 | (if (eq (following-character) ?\r) | ||
| 593 | (setq result (cons dir result)))) | ||
| 594 | result)) | ||
| 595 | |||
| 596 | ;; Try to insert all subdirs that were displayed before, | ||
| 597 | ;; according to the former subdir alist OLD-SUBDIR-ALIST. | ||
| 598 | (defun dired-insert-old-subdirs (old-subdir-alist) | ||
| 599 | (or (string-match "R" dired-actual-switches) | ||
| 600 | (let (elt dir) | ||
| 601 | (while old-subdir-alist | ||
| 602 | (setq elt (car old-subdir-alist) | ||
| 603 | old-subdir-alist (cdr old-subdir-alist) | ||
| 604 | dir (car elt)) | ||
| 605 | (condition-case () | ||
| 606 | (dired-insert-subdir dir) | ||
| 607 | (error nil)))))) | ||
| 608 | |||
| 609 | ;; dired mode key bindings and initialization | ||
| 150 | 610 | ||
| 151 | (defvar dired-mode-map nil "Local keymap for dired-mode buffers.") | 611 | (defvar dired-mode-map nil "Local keymap for dired-mode buffers.") |
| 152 | (if dired-mode-map | 612 | (if dired-mode-map |
| 153 | nil | 613 | nil |
| 614 | ;; Force `f' rather than `e' in the mode doc: | ||
| 615 | (fset 'dired-advertised-find-file 'dired-find-file) | ||
| 616 | ;; This looks ugly when substitute-command-keys uses C-d instead d: | ||
| 617 | ;; (define-key dired-mode-map "\C-d" 'dired-flag-file-deletion) | ||
| 618 | |||
| 154 | (setq dired-mode-map (make-keymap)) | 619 | (setq dired-mode-map (make-keymap)) |
| 155 | (suppress-keymap dired-mode-map) | 620 | (suppress-keymap dired-mode-map) |
| 156 | (define-key dired-mode-map "r" 'dired-rename-file) | 621 | ;; Commands to mark or flag certain categories of files |
| 157 | (define-key dired-mode-map "\C-d" 'dired-flag-file-deleted) | ||
| 158 | (define-key dired-mode-map "d" 'dired-flag-file-deleted) | ||
| 159 | (define-key dired-mode-map "v" 'dired-view-file) | ||
| 160 | (define-key dired-mode-map "e" 'dired-find-file) | ||
| 161 | (define-key dired-mode-map "f" 'dired-find-file) | ||
| 162 | (define-key dired-mode-map "o" 'dired-find-file-other-window) | ||
| 163 | (define-key dired-mode-map "u" 'dired-unflag) | ||
| 164 | (define-key dired-mode-map "x" 'dired-do-deletions) | ||
| 165 | (define-key dired-mode-map "\177" 'dired-backup-unflag) | ||
| 166 | (define-key dired-mode-map "?" 'dired-summary) | ||
| 167 | (define-key dired-mode-map "c" 'dired-copy-file) | ||
| 168 | (define-key dired-mode-map "#" 'dired-flag-auto-save-files) | 622 | (define-key dired-mode-map "#" 'dired-flag-auto-save-files) |
| 169 | (define-key dired-mode-map "~" 'dired-flag-backup-files) | 623 | (define-key dired-mode-map "*" 'dired-mark-executables) |
| 170 | (define-key dired-mode-map "F" 'dired-flag-regexp-files) | ||
| 171 | (define-key dired-mode-map "." 'dired-clean-directory) | 624 | (define-key dired-mode-map "." 'dired-clean-directory) |
| 625 | (define-key dired-mode-map "/" 'dired-mark-directories) | ||
| 626 | (define-key dired-mode-map "@" 'dired-mark-symlinks) | ||
| 627 | (define-key dired-mode-map "~" 'dired-flag-backup-files) | ||
| 628 | ;; Upper case keys (except !, c) for operating on the marked files | ||
| 629 | (define-key dired-mode-map "C" 'dired-do-copy) | ||
| 630 | (define-key dired-mode-map "B" 'dired-do-byte-compile) | ||
| 631 | (define-key dired-mode-map "D" 'dired-do-delete) | ||
| 632 | (define-key dired-mode-map "G" 'dired-do-chgrp) | ||
| 633 | (define-key dired-mode-map "H" 'dired-do-hardlink) | ||
| 634 | (define-key dired-mode-map "L" 'dired-do-load) | ||
| 635 | (define-key dired-mode-map "M" 'dired-do-chmod) | ||
| 636 | (define-key dired-mode-map "O" 'dired-do-chown) | ||
| 637 | (define-key dired-mode-map "P" 'dired-do-print) | ||
| 638 | (define-key dired-mode-map "R" 'dired-do-rename) | ||
| 639 | (define-key dired-mode-map "S" 'dired-do-symlink) | ||
| 640 | (define-key dired-mode-map "X" 'dired-do-shell-command) | ||
| 641 | (define-key dired-mode-map "Z" 'dired-do-compress) | ||
| 642 | (define-key dired-mode-map "!" 'dired-do-shell-command) | ||
| 643 | ;; Comparison commands | ||
| 644 | (define-key dired-mode-map "=" 'dired-diff) | ||
| 645 | (define-key dired-mode-map "\M-=" 'dired-backup-diff) | ||
| 646 | ;; Tree Dired commands | ||
| 647 | (define-key dired-mode-map "\M-\C-?" 'dired-unmark-all-files) | ||
| 648 | (define-key dired-mode-map "\M-\C-d" 'dired-tree-down) | ||
| 649 | (define-key dired-mode-map "\M-\C-u" 'dired-tree-up) | ||
| 650 | (define-key dired-mode-map "\M-\C-n" 'dired-next-subdir) | ||
| 651 | (define-key dired-mode-map "\M-\C-p" 'dired-prev-subdir) | ||
| 652 | ;; move to marked files | ||
| 653 | (define-key dired-mode-map "\M-{" 'dired-prev-marked-file) | ||
| 654 | (define-key dired-mode-map "\M-}" 'dired-next-marked-file) | ||
| 655 | ;; kill marked files | ||
| 656 | (define-key dired-mode-map "\M-k" 'dired-do-kill-lines) | ||
| 657 | ;; Make all regexp commands share a `%' prefix: | ||
| 658 | (fset 'dired-regexp-prefix (make-sparse-keymap)) | ||
| 659 | (define-key dired-mode-map "%" 'dired-regexp-prefix) | ||
| 660 | (define-key dired-mode-map "%u" 'dired-upcase) | ||
| 661 | (define-key dired-mode-map "%l" 'dired-downcase) | ||
| 662 | (define-key dired-mode-map "%d" 'dired-flag-files-regexp) | ||
| 663 | (define-key dired-mode-map "%m" 'dired-mark-files-regexp) | ||
| 664 | (define-key dired-mode-map "%r" 'dired-do-rename-regexp) | ||
| 665 | (define-key dired-mode-map "%C" 'dired-do-copy-regexp) | ||
| 666 | (define-key dired-mode-map "%H" 'dired-do-hardlink-regexp) | ||
| 667 | (define-key dired-mode-map "%R" 'dired-do-rename-regexp) | ||
| 668 | (define-key dired-mode-map "%S" 'dired-do-symlink-regexp) | ||
| 669 | ;; Lower keys for commands not operating on all the marked files | ||
| 670 | (define-key dired-mode-map "d" 'dired-flag-file-deletion) | ||
| 671 | (define-key dired-mode-map "e" 'dired-find-file) | ||
| 672 | (define-key dired-mode-map "f" 'dired-advertised-find-file) | ||
| 673 | (define-key dired-mode-map "g" 'revert-buffer) | ||
| 172 | (define-key dired-mode-map "h" 'describe-mode) | 674 | (define-key dired-mode-map "h" 'describe-mode) |
| 675 | (define-key dired-mode-map "i" 'dired-maybe-insert-subdir) | ||
| 676 | (define-key dired-mode-map "k" 'dired-kill-line-or-subdir) | ||
| 677 | (define-key dired-mode-map "l" 'dired-do-redisplay) | ||
| 678 | (define-key dired-mode-map "m" 'dired-mark) | ||
| 679 | (define-key dired-mode-map "n" 'dired-next-line) | ||
| 680 | (define-key dired-mode-map "o" 'dired-find-file-other-window) | ||
| 681 | (define-key dired-mode-map "p" 'dired-previous-line) | ||
| 682 | (define-key dired-mode-map "q" 'dired-quit) | ||
| 683 | (define-key dired-mode-map "s" 'dired-sort-toggle-or-edit) | ||
| 684 | (define-key dired-mode-map "u" 'dired-unmark) | ||
| 685 | (define-key dired-mode-map "v" 'dired-view-file) | ||
| 686 | (define-key dired-mode-map "x" 'dired-do-flagged-delete) | ||
| 687 | (define-key dired-mode-map "+" 'dired-create-directory) | ||
| 688 | ;; moving | ||
| 689 | (define-key dired-mode-map "<" 'dired-prev-dirline) | ||
| 690 | (define-key dired-mode-map ">" 'dired-next-dirline) | ||
| 691 | (define-key dired-mode-map "^" 'dired-up-directory) | ||
| 173 | (define-key dired-mode-map " " 'dired-next-line) | 692 | (define-key dired-mode-map " " 'dired-next-line) |
| 174 | (define-key dired-mode-map "\C-n" 'dired-next-line) | 693 | (define-key dired-mode-map "\C-n" 'dired-next-line) |
| 175 | (define-key dired-mode-map "\C-p" 'dired-previous-line) | 694 | (define-key dired-mode-map "\C-p" 'dired-previous-line) |
| 176 | (define-key dired-mode-map "n" 'dired-next-line) | 695 | ;; hiding |
| 177 | (define-key dired-mode-map "p" 'dired-previous-line) | 696 | (define-key dired-mode-map "$" 'dired-hide-subdir) |
| 178 | (define-key dired-mode-map "g" 'revert-buffer) | 697 | (define-key dired-mode-map "\M-$" 'dired-hide-all) |
| 179 | (define-key dired-mode-map "D" 'dired-create-directory) | 698 | ;; misc |
| 180 | (define-key dired-mode-map "m" 'dired-move-file) | 699 | (define-key dired-mode-map "?" 'dired-summary) |
| 181 | (define-key dired-mode-map "C" 'dired-compress) | 700 | (define-key dired-mode-map "\177" 'dired-unmark-backward) |
| 182 | (define-key dired-mode-map "U" 'dired-uncompress) | 701 | (define-key dired-mode-map "\C-_" 'dired-undo) |
| 183 | (define-key dired-mode-map "B" 'dired-byte-recompile) | 702 | (define-key dired-mode-map "\C-xu" 'dired-undo) |
| 184 | (define-key dired-mode-map "M" 'dired-chmod) | 703 | ) |
| 185 | (define-key dired-mode-map "G" 'dired-chgrp) | ||
| 186 | (define-key dired-mode-map "O" 'dired-chown) | ||
| 187 | (define-key dired-mode-map "=" 'dired-diff) | ||
| 188 | (define-key dired-mode-map "<" 'dired-up-directory)) | ||
| 189 | |||
| 190 | 704 | ||
| 705 | (or (member '(dired-sort-mode dired-sort-mode) minor-mode-alist) | ||
| 706 | ;; Test whether this has already been done in case dired is reloaded | ||
| 707 | ;; There may be several elements with dired-sort-mode as car. | ||
| 708 | (setq minor-mode-alist | ||
| 709 | (cons '(dired-sort-mode dired-sort-mode) | ||
| 710 | ;; dired-sort-mode is nil outside dired | ||
| 711 | minor-mode-alist))) | ||
| 712 | |||
| 191 | ;; Dired mode is suitable only for specially formatted data. | 713 | ;; Dired mode is suitable only for specially formatted data. |
| 192 | (put 'dired-mode 'mode-class 'special) | 714 | (put 'dired-mode 'mode-class 'special) |
| 193 | 715 | ||
| 194 | (defun dired-mode (&optional dirname) | 716 | (defun dired-mode (&optional dirname switches) |
| 195 | "Mode for \"editing\" directory listings. | 717 | "\ |
| 196 | In dired, you are \"editing\" a list of the files in a directory. | 718 | Mode for \"editing\" directory listings. |
| 197 | You can move using the usual cursor motion commands. | 719 | In dired, you are \"editing\" a list of the files in a directory and |
| 198 | Letters no longer insert themselves. | 720 | \(optionally) its subdirectories, in the format of `ls -lR'. |
| 199 | Instead, use the following commands: | 721 | Each directory is a page: use \\[backward-page] and \\[forward-page] to move pagewise. |
| 722 | \"Editing\" means that you can run shell commands on files, visit, | ||
| 723 | compress, load or byte-compile them, change their file attributes | ||
| 724 | and insert subdirectories into the same buffer. You can \"mark\" | ||
| 725 | files for later commands or \"flag\" them for deletion, either file | ||
| 726 | by file or all files matching certain criteria. | ||
| 727 | You can move using the usual cursor motion commands.\\<dired-mode-map> | ||
| 728 | Letters no longer insert themselves. Digits are prefix arguments. | ||
| 729 | Instead, type \\[dired-flag-file-deletion] to flag a file for Deletion. | ||
| 730 | Type \\[dired-mark] to Mark a file or subdirectory for later commands. | ||
| 731 | Most commands operate on the marked files and use the current file | ||
| 732 | if no files are marked. Use a numeric prefix argument to operate on | ||
| 733 | the next ARG (or previous -ARG if ARG<0) files, or just `1' | ||
| 734 | to operate on the current file only. Prefix arguments override marks. | ||
| 735 | Mark-using commands display a list of failures afterwards. Type \\[dired-summary] | ||
| 736 | to see why something went wrong. | ||
| 737 | Type \\[dired-unmark] to Unmark a file or all files of a subdirectory. | ||
| 738 | Type \\[dired-unmark-backward] to back up one line and unflag. | ||
| 739 | Type \\[dired-do-flagged-delete] to eXecute the deletions requested. | ||
| 740 | Type \\[dired-advertised-find-file] to Find the current line's file | ||
| 741 | (or dired it in another buffer, if it is a directory). | ||
| 742 | Type \\[dired-find-file-other-window] to find file or dired directory in Other window. | ||
| 743 | Type \\[dired-maybe-insert-subdir] to Insert a subdirectory in this buffer. | ||
| 744 | Type \\[dired-do-rename] to Rename a file or move the marked files to another directory. | ||
| 745 | Type \\[dired-do-copy] to Copy files. | ||
| 746 | Type \\[dired-sort-toggle-or-edit] to toggle sorting by name/date or change the `ls' switches. | ||
| 747 | Type \\[revert-buffer] to read all currently expanded directories again. | ||
| 748 | This retains all marks and hides subdirs again that were hidden before. | ||
| 749 | SPC and DEL can be used to move down and up by lines. | ||
| 750 | |||
| 751 | If dired ever gets confused, you can either type \\[revert-buffer] \ | ||
| 752 | to read the | ||
| 753 | directories again, type \\[dired-do-redisplay] \ | ||
| 754 | to relist a single or the marked files or a | ||
| 755 | subdirectory, or type \\[dired-build-subdir-alist] to parse the buffer | ||
| 756 | again for the directory tree. | ||
| 757 | |||
| 758 | Customization variables (rename this buffer and type \\[describe-variable] on each line | ||
| 759 | for more info): | ||
| 760 | |||
| 761 | dired-listing-switches | ||
| 762 | dired-trivial-filenames | ||
| 763 | dired-shrink-to-fit | ||
| 764 | dired-marker-char | ||
| 765 | dired-del-marker | ||
| 766 | dired-keep-marker-rename | ||
| 767 | dired-keep-marker-copy | ||
| 768 | dired-keep-marker-hardlink | ||
| 769 | dired-keep-marker-symlink | ||
| 770 | |||
| 771 | Hooks (use \\[describe-variable] to see their documentation): | ||
| 772 | |||
| 773 | dired-before-readin-hook | ||
| 774 | dired-after-readin-hook | ||
| 775 | dired-mode-hook | ||
| 776 | dired-load-hook | ||
| 777 | |||
| 778 | Keybindings: | ||
| 200 | \\{dired-mode-map}" | 779 | \\{dired-mode-map}" |
| 201 | (interactive) | 780 | ;; Not to be called interactively (e.g. dired-directory will be set |
| 781 | ;; to default-directory, which is wrong with wildcards). | ||
| 202 | (kill-all-local-variables) | 782 | (kill-all-local-variables) |
| 203 | (make-local-variable 'revert-buffer-function) | ||
| 204 | (setq revert-buffer-function 'dired-revert) | ||
| 205 | (setq major-mode 'dired-mode) | ||
| 206 | (setq mode-name "Dired") | ||
| 207 | (make-local-variable 'dired-directory) | ||
| 208 | (setq dired-directory (or dirname default-directory)) | ||
| 209 | (make-local-variable 'list-buffers-directory) | ||
| 210 | (setq list-buffers-directory dired-directory) | ||
| 211 | (set (make-local-variable 'dired-used-F) | ||
| 212 | (string-match "F" dired-listing-switches)) | ||
| 213 | (if dirname | ||
| 214 | (setq default-directory | ||
| 215 | (if (file-directory-p dirname) | ||
| 216 | dirname (file-name-directory dirname)))) | ||
| 217 | (setq mode-line-buffer-identification '("Dired: %17f")) | ||
| 218 | (setq case-fold-search nil) | ||
| 219 | (setq buffer-read-only t) | ||
| 220 | (use-local-map dired-mode-map) | 783 | (use-local-map dired-mode-map) |
| 784 | (dired-advertise) ; default-directory is already set | ||
| 785 | (setq major-mode 'dired-mode | ||
| 786 | mode-name "Dired" | ||
| 787 | case-fold-search nil | ||
| 788 | buffer-read-only t | ||
| 789 | selective-display t ; for subdirectory hiding | ||
| 790 | mode-line-buffer-identification '("Dired: %17b")) | ||
| 791 | (set (make-local-variable 'revert-buffer-function) | ||
| 792 | (function dired-revert)) | ||
| 793 | (set (make-local-variable 'page-delimiter) | ||
| 794 | "\n\n") | ||
| 795 | (set (make-local-variable 'dired-directory) | ||
| 796 | (or dirname default-directory)) | ||
| 797 | ;; list-buffers uses this to display the dir being edited in this buffer. | ||
| 798 | (set (make-local-variable 'list-buffers-directory) | ||
| 799 | dired-directory) | ||
| 800 | (set (make-local-variable 'dired-actual-switches) | ||
| 801 | (or switches dired-listing-switches)) | ||
| 802 | (make-local-variable 'dired-sort-mode) | ||
| 803 | (dired-sort-other dired-actual-switches t) | ||
| 221 | (run-hooks 'dired-mode-hook)) | 804 | (run-hooks 'dired-mode-hook)) |
| 222 | 805 | ||
| 223 | ;; FUNCTION receives no arguments | 806 | ;; Ideosyncratic dired commands that don't deal with marks. |
| 224 | ;; and should return t iff it deletes the current line from the buffer. | ||
| 225 | (defun dired-repeat-over-lines (arg function) | ||
| 226 | (beginning-of-line) | ||
| 227 | (while (and (> arg 0) (not (eobp))) | ||
| 228 | (setq arg (1- arg)) | ||
| 229 | (let (deleted) | ||
| 230 | (save-excursion | ||
| 231 | (beginning-of-line) | ||
| 232 | (and (bobp) (looking-at " total") | ||
| 233 | (error "No file on this line")) | ||
| 234 | (setq deleted (funcall function))) | ||
| 235 | (or deleted | ||
| 236 | (forward-line 1))) | ||
| 237 | (dired-move-to-filename)) | ||
| 238 | (while (and (< arg 0) (not (bobp))) | ||
| 239 | (setq arg (1+ arg)) | ||
| 240 | (forward-line -1) | ||
| 241 | (dired-move-to-filename) | ||
| 242 | (save-excursion | ||
| 243 | (beginning-of-line) | ||
| 244 | (funcall function)))) | ||
| 245 | 807 | ||
| 246 | (defun dired-flag-file-deleted (arg) | 808 | (defun dired-quit () |
| 247 | "In dired, flag the current line's file for deletion. | 809 | "Bury the current dired buffer." |
| 248 | With prefix arg, repeat over several lines." | 810 | (interactive) |
| 249 | (interactive "p") | 811 | (bury-buffer)) |
| 250 | (dired-repeat-over-lines arg | ||
| 251 | '(lambda () | ||
| 252 | (let ((buffer-read-only nil)) | ||
| 253 | (delete-char 1) | ||
| 254 | (insert "D") | ||
| 255 | nil)))) | ||
| 256 | |||
| 257 | (defun dired-flag-regexp-files (regexp) | ||
| 258 | "In dired, flag all files matching the specified REGEXP for deletion." | ||
| 259 | (interactive "sFlagging regexp: ") | ||
| 260 | (save-excursion | ||
| 261 | (let ((buffer-read-only nil)) | ||
| 262 | (goto-char (point-min)) | ||
| 263 | (while (not (eobp)) | ||
| 264 | (and (not (looking-at " d")) | ||
| 265 | (not (eolp)) | ||
| 266 | (let ((fn (dired-get-filename t t))) | ||
| 267 | (if fn (string-match regexp fn))) | ||
| 268 | (progn (beginning-of-line) | ||
| 269 | (delete-char 1) | ||
| 270 | (insert "D"))) | ||
| 271 | (forward-line 1))))) | ||
| 272 | 812 | ||
| 273 | (defun dired-summary () | 813 | (defun dired-summary () |
| 814 | "Summarize basic Dired commands and show recent Dired errors." | ||
| 274 | (interactive) | 815 | (interactive) |
| 816 | (dired-why) | ||
| 275 | ;>> this should check the key-bindings and use substitute-command-keys if non-standard | 817 | ;>> this should check the key-bindings and use substitute-command-keys if non-standard |
| 276 | (message | 818 | (message |
| 277 | "d-elete, u-ndelete, x-ecute, f-ind, o-ther window, r-ename, c-opy, v-iew")) | 819 | "d-elete, u-ndelete, x-punge, f-ind, o-ther window, r-ename, C-opy, h-elp")) |
| 278 | 820 | ||
| 279 | (defun dired-unflag (arg) | 821 | (defun dired-undo () |
| 280 | "In dired, remove the current line's delete flag then move to next line." | 822 | "Undo in a dired buffer. |
| 281 | (interactive "p") | 823 | This doesn't recover lost files, it just undoes changes in the buffer itself. |
| 282 | (dired-repeat-over-lines arg | 824 | You can use it to recover marks, killed lines or subdirs. |
| 283 | '(lambda () | 825 | In the latter case, you have to do \\[dired-build-subdir-alist] to |
| 284 | (let ((buffer-read-only nil)) | 826 | parse the buffer again." |
| 285 | (delete-char 1) | 827 | (interactive) |
| 286 | (insert " ") | 828 | (let (buffer-read-only) |
| 287 | (forward-char -1) | 829 | (undo))) |
| 288 | nil)))) | ||
| 289 | |||
| 290 | (defun dired-backup-unflag (arg) | ||
| 291 | "In dired, move up lines and remove deletion flag there. | ||
| 292 | Optional prefix ARG says how many lines to unflag; default is one line." | ||
| 293 | (interactive "p") | ||
| 294 | (dired-unflag (- arg))) | ||
| 295 | 830 | ||
| 296 | (defun dired-next-line (arg) | 831 | (defun dired-next-line (arg) |
| 297 | "Move down lines then position at filename. | 832 | "Move down lines then position at filename. |
| @@ -307,10 +842,36 @@ Optional prefix ARG says how many lines to move; default is one line." | |||
| 307 | (previous-line arg) | 842 | (previous-line arg) |
| 308 | (dired-move-to-filename)) | 843 | (dired-move-to-filename)) |
| 309 | 844 | ||
| 845 | (defun dired-next-dirline (arg &optional opoint) | ||
| 846 | "Goto ARG'th next directory file line." | ||
| 847 | (interactive "p") | ||
| 848 | (or opoint (setq opoint (point))) | ||
| 849 | (if (if (> arg 0) | ||
| 850 | (re-search-forward dired-re-dir nil t arg) | ||
| 851 | (beginning-of-line) | ||
| 852 | (re-search-backward dired-re-dir nil t (- arg))) | ||
| 853 | (dired-move-to-filename) ; user may type `i' or `f' | ||
| 854 | (goto-char opoint) | ||
| 855 | (error "No more subdirectories"))) | ||
| 856 | |||
| 857 | (defun dired-prev-dirline (arg) | ||
| 858 | "Goto ARG'th previous directory file line." | ||
| 859 | (interactive "p") | ||
| 860 | (dired-next-dirline (- arg))) | ||
| 861 | |||
| 310 | (defun dired-up-directory () | 862 | (defun dired-up-directory () |
| 311 | "Run dired on the parent of the current directory." | 863 | "Run dired on parent directory of current directory. |
| 864 | Find the parent directory either in this buffer or another buffer. | ||
| 865 | Creates a buffer if necessary." | ||
| 312 | (interactive) | 866 | (interactive) |
| 313 | (find-file "..")) | 867 | (let* ((dir (dired-current-directory)) |
| 868 | (up (file-name-directory (directory-file-name dir)))) | ||
| 869 | (or (dired-goto-file (directory-file-name dir)) | ||
| 870 | (and dired-subdir-alist | ||
| 871 | (dired-goto-subdir up)) | ||
| 872 | (progn | ||
| 873 | (dired up) | ||
| 874 | (dired-goto-file dir))))) | ||
| 314 | 875 | ||
| 315 | (defun dired-find-file () | 876 | (defun dired-find-file () |
| 316 | "In dired, visit the file or directory named on this line." | 877 | "In dired, visit the file or directory named on this line." |
| @@ -318,111 +879,817 @@ Optional prefix ARG says how many lines to move; default is one line." | |||
| 318 | (find-file (dired-get-filename))) | 879 | (find-file (dired-get-filename))) |
| 319 | 880 | ||
| 320 | (defun dired-view-file () | 881 | (defun dired-view-file () |
| 321 | "In dired, examine a file in view mode, returning to dired when done." | 882 | "In dired, examine a file in view mode, returning to dired when done. |
| 883 | When file is a directory, show it in this buffer if it is inserted; | ||
| 884 | otherwise, display it in another buffer." | ||
| 322 | (interactive) | 885 | (interactive) |
| 323 | (if (file-directory-p (dired-get-filename)) | 886 | (if (file-directory-p (dired-get-filename)) |
| 324 | (dired (dired-get-filename)) | 887 | (or (and dired-subdir-alist (dired-goto-subdir (dired-get-filename))) |
| 888 | (dired (dired-get-filename))) | ||
| 325 | (view-file (dired-get-filename)))) | 889 | (view-file (dired-get-filename)))) |
| 326 | 890 | ||
| 327 | (defun dired-find-file-other-window () | 891 | (defun dired-find-file-other-window () |
| 328 | "In dired, visit this file or directory in another window." | 892 | "In dired, visit this file or directory in another window." |
| 329 | (interactive) | 893 | (interactive) |
| 330 | (find-file-other-window (dired-get-filename))) | 894 | (find-file-other-window (dired-get-filename))) |
| 895 | |||
| 896 | ;;; Functions for extracting and manipulating file names in dired buffers. | ||
| 331 | 897 | ||
| 332 | (defun dired-get-filename (&optional localp no-error-if-not-filep) | 898 | (defun dired-get-filename (&optional localp no-error-if-not-filep) |
| 333 | "In dired, return name of file mentioned on this line. | 899 | "In dired, return name of file mentioned on this line. |
| 334 | Value returned normally includes the directory name. | 900 | Value returned normally includes the directory name. |
| 335 | Optional arg LOCALP means don't include it. | 901 | Optional arg LOCALP with value `no-dir' means don't include directory |
| 336 | Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename | 902 | name in result. A value of t means construct name relative to |
| 337 | on this line, otherwise an error occurs." | 903 | `default-directory', which still may contain slashes if in a subdirectory. |
| 338 | (let (eol file type ex (case-fold-search nil)) | 904 | Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on |
| 905 | this line, otherwise an error occurs." | ||
| 906 | (let (case-fold-search file p1 p2) | ||
| 339 | (save-excursion | 907 | (save-excursion |
| 340 | (end-of-line) | 908 | (if (setq p1 (dired-move-to-filename (not no-error-if-not-filep))) |
| 341 | (setq eol (point)) | 909 | (setq p2 (dired-move-to-end-of-filename no-error-if-not-filep)))) |
| 342 | (beginning-of-line) | 910 | ;; nil if no file on this line, but no-error-if-not-filep is t: |
| 343 | (if (eq system-type 'vax-vms) | 911 | (if (setq file (and p1 p2 (buffer-substring p1 p2))) |
| 344 | ;; Non-filename lines don't match | 912 | ;; Check if ls quoted the names, and unquote them. |
| 345 | ;; because they have lower case letters. | 913 | ;; Using read to unquote is much faster than substituting |
| 346 | (if (re-search-forward "^..\\([][.A-Z-0-9_$;<>]+\\)" eol t) | 914 | ;; \007 (4 chars) -> ^G (1 char) etc. in a lisp loop. |
| 347 | (setq file (buffer-substring (match-beginning 1) (match-end 1)))) | 915 | (cond ((string-match "b" dired-actual-switches) ; System V ls |
| 348 | ;; Unix case | 916 | ;; This case is about 20% slower than without -b. |
| 349 | (if (not (re-search-forward | 917 | (setq file |
| 350 | "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+" | 918 | (read |
| 351 | eol t)) () | 919 | (concat "\"" |
| 352 | (skip-chars-forward " ") | 920 | ;; some ls -b don't escape quotes, argh! |
| 353 | (skip-chars-forward "^ " eol) | 921 | ;; This is not needed for GNU ls, though. |
| 354 | (skip-chars-forward " " eol) | 922 | (or (dired-string-replace-match |
| 355 | (setq file (buffer-substring (point) eol)) | 923 | "\\([^\\]\\)\"" file "\\1\\\\\"") |
| 356 | (re-search-backward "\\(.\\)[-r][-w]\\(.\\)[-r][-w]\\(.\\)[-r][-w]\\(.\\)") | 924 | file) |
| 357 | (setq flag (buffer-substring (match-beginning 1) (match-end 1)) | 925 | "\"")))) |
| 358 | ex (string-match "[xst]" ;; execute bit set anywhere? | 926 | ;; If you do this, update dired-insert-subdir-validate too |
| 359 | (concat | 927 | ;; ((string-match "Q" dired-actual-switches) ; GNU ls |
| 360 | (buffer-substring (match-beginning 2) (match-end 2)) | 928 | ;; (setq file (read file))) |
| 361 | (buffer-substring (match-beginning 3) (match-end 3)) | 929 | )) |
| 362 | (buffer-substring (match-beginning 4) (match-end 4))))) | 930 | (if (eq localp 'no-dir) |
| 363 | (cond | 931 | file |
| 364 | ((string= flag "l") | 932 | (and file (concat (dired-current-directory localp) file))))) |
| 365 | ;; strip the link name. Bombs if file contains " ->" | 933 | |
| 366 | (if (string-match " ->" file) | 934 | (defun dired-make-absolute (file &optional dir) |
| 367 | (setq file (substring file 0 (match-beginning 0))))) | 935 | ;;"Convert FILE (a pathname relative to DIR) to an absolute pathname." |
| 368 | ((and dired-used-F ;; strip off -F stuff if there | 936 | ;; We can't always use expand-file-name as this would get rid of `.' |
| 369 | (or (string= flag "d") (string= flag "s") ex)) | 937 | ;; or expand in / instead default-directory if DIR=="". |
| 370 | (setq file (substring file 0 -1))))))) | 938 | ;; This should be good enough for ange-ftp, but might easily be |
| 371 | (or no-error-if-not-filep file | 939 | ;; redefined (for VMS?). |
| 372 | (error "No file on this line")) | 940 | ;; It should be reasonably fast, though, as it is called in |
| 373 | ;; ??? uses default-directory, could lose on cd, multiple. | 941 | ;; dired-get-filename. |
| 374 | (or localp (setq file (expand-file-name file default-directory))) | 942 | (concat (or dir default-directory) file)) |
| 375 | file)) | 943 | |
| 376 | 944 | (defun dired-make-relative (file &optional dir no-error) | |
| 377 | (defun dired-move-to-filename () | 945 | ;;"Convert FILE (an absolute pathname) to a pathname relative to DIR. |
| 378 | "In dired, move to first char of filename on this line. | 946 | ;; Else error (unless NO-ERROR is non-nil, then FILE is returned unchanged) |
| 379 | Returns position (point) or nil if no filename on this line." | 947 | ;;DIR defaults to default-directory." |
| 380 | (let ((eol (progn (end-of-line) (point)))) | 948 | ;; DIR must be file-name-as-directory, as with all directory args in |
| 381 | (beginning-of-line) | 949 | ;; elisp code. |
| 382 | (if (re-search-forward | 950 | (or dir (setq dir default-directory)) |
| 383 | "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+" | 951 | (if (string-match (concat "^" (regexp-quote dir)) file) |
| 384 | eol t) | 952 | (substring file (match-end 0)) |
| 385 | (progn | 953 | (if no-error |
| 386 | (skip-chars-forward " ") | 954 | file |
| 387 | (skip-chars-forward "^ " eol) | 955 | (error "%s: not in directory tree growing at %s" file dir)))) |
| 388 | (skip-chars-forward " " eol) | 956 | |
| 389 | (point))))) | 957 | ;;; Functions for finding the file name in a dired buffer line. |
| 390 | 958 | ||
| 391 | (defun dired-map-dired-file-lines (fn) | 959 | ;; Move to first char of filename on this line. |
| 392 | "Perform function FN with point at the end of each non-directory line. | 960 | ;; Returns position (point) or nil if no filename on this line." |
| 393 | The arguments given to FN are the short and long filename" | 961 | (defun dired-move-to-filename (&optional raise-error eol) |
| 962 | ;; This is the UNIX version. | ||
| 963 | (or eol (setq eol (progn (end-of-line) (point)))) | ||
| 964 | (beginning-of-line) | ||
| 965 | (if (re-search-forward | ||
| 966 | "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+" | ||
| 967 | eol t) | ||
| 968 | (progn | ||
| 969 | (skip-chars-forward " ") ; there is one SPC after day of month | ||
| 970 | (skip-chars-forward "^ " eol) ; move after time of day (or year) | ||
| 971 | (skip-chars-forward " " eol) ; there is space before the file name | ||
| 972 | ;; Actually, if the year instead of clock time is displayed, | ||
| 973 | ;; there are (only for some ls programs?) two spaces instead | ||
| 974 | ;; of one before the name. | ||
| 975 | ;; If we could depend on ls inserting exactly one SPC we | ||
| 976 | ;; would not bomb on names _starting_ with SPC. | ||
| 977 | (point)) | ||
| 978 | (if raise-error | ||
| 979 | (error "No file on this line") | ||
| 980 | nil))) | ||
| 981 | |||
| 982 | (defun dired-move-to-end-of-filename (&optional no-error) | ||
| 983 | ;; Assumes point is at beginning of filename, | ||
| 984 | ;; thus the rwx bit re-search-backward below will succeed in *this* | ||
| 985 | ;; line if at all. So, it should be called only after | ||
| 986 | ;; (dired-move-to-filename t). | ||
| 987 | ;; On failure, signals an error (with non-nil NO-ERROR just returns nil). | ||
| 988 | ;; This is the UNIX version. | ||
| 989 | (let (opoint file-type executable symlink hidden case-fold-search used-F eol) | ||
| 990 | ;; case-fold-search is nil now, so we can test for capital F: | ||
| 991 | (setq used-F (string-match "F" dired-actual-switches) | ||
| 992 | opoint (point) | ||
| 993 | eol (save-excursion (end-of-line) (point)) | ||
| 994 | hidden (and selective-display | ||
| 995 | (save-excursion (search-forward "\r" eol t)))) | ||
| 996 | (if hidden | ||
| 997 | nil | ||
| 998 | (save-excursion;; Find out what kind of file this is: | ||
| 999 | ;; Restrict perm bits to be non-blank, | ||
| 1000 | ;; otherwise this matches one char to early (looking backward): | ||
| 1001 | ;; "l---------" (some systems make symlinks that way) | ||
| 1002 | ;; "----------" (plain file with zero perms) | ||
| 1003 | (if (re-search-backward | ||
| 1004 | "\\([^ ]\\)[-r][-w]\\([^ ]\\)[-r][-w]\\([^ ]\\)[-r][-w]\\([^ ]\\)" | ||
| 1005 | nil t) | ||
| 1006 | (setq file-type (char-after (match-beginning 1)) | ||
| 1007 | symlink (eq file-type ?l) | ||
| 1008 | ;; Only with -F we need to know whether it's an executable | ||
| 1009 | executable (and | ||
| 1010 | used-F | ||
| 1011 | (string-match | ||
| 1012 | "[xst]";; execute bit set anywhere? | ||
| 1013 | (concat | ||
| 1014 | (buffer-substring (match-beginning 2) | ||
| 1015 | (match-end 2)) | ||
| 1016 | (buffer-substring (match-beginning 3) | ||
| 1017 | (match-end 3)) | ||
| 1018 | (buffer-substring (match-beginning 4) | ||
| 1019 | (match-end 4)))))) | ||
| 1020 | (or no-error (error "No file on this line")))) | ||
| 1021 | ;; Move point to end of name: | ||
| 1022 | (if symlink | ||
| 1023 | (if (search-forward " ->" eol t) | ||
| 1024 | (progn | ||
| 1025 | (forward-char -3) | ||
| 1026 | (and used-F | ||
| 1027 | dired-ls-F-marks-symlinks | ||
| 1028 | (eq (preceding-char) ?@);; did ls really mark the link? | ||
| 1029 | (forward-char -1)))) | ||
| 1030 | (goto-char eol);; else not a symbolic link | ||
| 1031 | ;; ls -lF marks dirs, sockets and executables with exactly one | ||
| 1032 | ;; trailing character. (Executable bits on symlinks ain't mean | ||
| 1033 | ;; a thing, even to ls, but we know it's not a symlink.) | ||
| 1034 | (and used-F | ||
| 1035 | (or (memq file-type '(?d ?s)) | ||
| 1036 | executable) | ||
| 1037 | (forward-char -1)))) | ||
| 1038 | (or no-error | ||
| 1039 | (not (eq opoint (point))) | ||
| 1040 | (error (if hidden | ||
| 1041 | (substitute-command-keys | ||
| 1042 | "File line is hidden, type \\[dired-hide-subdir] to unhide") | ||
| 1043 | "No file on this line"))) | ||
| 1044 | (if (eq opoint (point)) | ||
| 1045 | nil | ||
| 1046 | (point)))) | ||
| 1047 | |||
| 1048 | |||
| 1049 | ;; Keeping Dired buffers in sync with the filesystem and with each other | ||
| 1050 | |||
| 1051 | (defvar dired-buffers nil | ||
| 1052 | ;; Enlarged by dired-advertise | ||
| 1053 | ;; Queried by function dired-buffers-for-dir. When this detects a | ||
| 1054 | ;; killed buffer, it is removed from this list. | ||
| 1055 | "Alist of directories and their associated dired buffers.") | ||
| 1056 | |||
| 1057 | (defun dired-buffers-for-dir (dir) | ||
| 1058 | ;; Return a list of buffers that dired DIR (top level or in-situ subdir). | ||
| 1059 | ;; The list is in reverse order of buffer creation, most recent last. | ||
| 1060 | ;; As a side effect, killed dired buffers for DIR are removed from | ||
| 1061 | ;; dired-buffers. | ||
| 1062 | (setq dir (file-name-as-directory dir)) | ||
| 1063 | (let ((alist dired-buffers) result elt) | ||
| 1064 | (while alist | ||
| 1065 | (setq elt (car alist)) | ||
| 1066 | (if (dired-in-this-tree dir (car elt)) | ||
| 1067 | (let ((buf (cdr elt))) | ||
| 1068 | (if (buffer-name buf) | ||
| 1069 | (if (assoc dir (save-excursion | ||
| 1070 | (set-buffer buf) | ||
| 1071 | dired-subdir-alist)) | ||
| 1072 | (setq result (cons buf result))) | ||
| 1073 | ;; else buffer is killed - clean up: | ||
| 1074 | (setq dired-buffers (delq elt dired-buffers))))) | ||
| 1075 | (setq alist (cdr alist))) | ||
| 1076 | result)) | ||
| 1077 | |||
| 1078 | (defun dired-advertise () | ||
| 1079 | ;;"Advertise in variable `dired-buffers' that we dired `default-directory'." | ||
| 1080 | ;; With wildcards we actually advertise too much. | ||
| 1081 | (if (memq (current-buffer) (dired-buffers-for-dir default-directory)) | ||
| 1082 | t ; we have already advertised ourselves | ||
| 1083 | (setq dired-buffers | ||
| 1084 | (cons (cons default-directory (current-buffer)) | ||
| 1085 | dired-buffers)))) | ||
| 1086 | |||
| 1087 | (defun dired-unadvertise (dir) | ||
| 1088 | ;; Remove DIR from the buffer alist in variable dired-buffers. | ||
| 1089 | ;; This has the effect of removing any buffer whose main directory is DIR. | ||
| 1090 | ;; It does not affect buffers in which DIR is a subdir. | ||
| 1091 | ;; Removing is also done as a side-effect in dired-buffer-for-dir. | ||
| 1092 | (setq dired-buffers | ||
| 1093 | (delq (assoc dir dired-buffers) dired-buffers))) | ||
| 1094 | |||
| 1095 | ;; Tree Dired | ||
| 1096 | |||
| 1097 | ;;; utility functions | ||
| 1098 | |||
| 1099 | (defun dired-in-this-tree (file dir) | ||
| 1100 | ;;"Is FILE part of the directory tree starting at DIR?" | ||
| 1101 | (let (case-fold-search) | ||
| 1102 | (string-match (concat "^" (regexp-quote dir)) file))) | ||
| 1103 | |||
| 1104 | (defun dired-normalize-subdir (dir) | ||
| 1105 | ;; Prepend default-directory to DIR if relative path name. | ||
| 1106 | ;; dired-get-filename must be able to make a valid filename from a | ||
| 1107 | ;; file and its directory DIR. | ||
| 1108 | (file-name-as-directory | ||
| 1109 | (if (file-name-absolute-p dir) | ||
| 1110 | dir | ||
| 1111 | (expand-file-name dir default-directory)))) | ||
| 1112 | |||
| 1113 | (defun dired-get-subdir () | ||
| 1114 | ;;"Return the subdir name on this line, or nil if not on a headerline." | ||
| 1115 | ;; Look up in the alist whether this is a headerline. | ||
| 1116 | (save-excursion | ||
| 1117 | (let ((cur-dir (dired-current-directory))) | ||
| 1118 | (beginning-of-line) ; alist stores b-o-l positions | ||
| 1119 | (and (zerop (- (point) | ||
| 1120 | (dired-get-subdir-min (assoc cur-dir | ||
| 1121 | dired-subdir-alist)))) | ||
| 1122 | cur-dir)))) | ||
| 1123 | |||
| 1124 | ;(defun dired-get-subdir-min (elt) | ||
| 1125 | ; (cdr elt)) | ||
| 1126 | ;; can't use macro, must be redefinable for other alist format in dired-nstd. | ||
| 1127 | (fset 'dired-get-subdir-min 'cdr) | ||
| 1128 | |||
| 1129 | (defun dired-get-subdir-max (elt) | ||
| 394 | (save-excursion | 1130 | (save-excursion |
| 395 | (let (filename longfilename (buffer-read-only nil)) | 1131 | (goto-char (dired-get-subdir-min elt)) |
| 1132 | (dired-subdir-max))) | ||
| 1133 | |||
| 1134 | (defun dired-clear-alist () | ||
| 1135 | (while dired-subdir-alist | ||
| 1136 | (set-marker (dired-get-subdir-min (car dired-subdir-alist)) nil) | ||
| 1137 | (setq dired-subdir-alist (cdr dired-subdir-alist)))) | ||
| 1138 | |||
| 1139 | (defun dired-build-subdir-alist () | ||
| 1140 | "Build `dired-subdir-alist' by parsing the buffer. | ||
| 1141 | Returns the new value of the alist." | ||
| 1142 | (interactive) | ||
| 1143 | (dired-clear-alist) | ||
| 1144 | (save-excursion | ||
| 1145 | (let ((count 0)) | ||
| 396 | (goto-char (point-min)) | 1146 | (goto-char (point-min)) |
| 397 | (while (not (eobp)) | 1147 | (setq dired-subdir-alist nil) |
| 1148 | (while (re-search-forward dired-subdir-regexp nil t) | ||
| 1149 | (setq count (1+ count)) | ||
| 1150 | (dired-alist-add-1 (buffer-substring (match-beginning 1) | ||
| 1151 | (match-end 1)) | ||
| 1152 | ;; Put subdir boundary between lines: | ||
| 1153 | (save-excursion | ||
| 1154 | (goto-char (match-beginning 0)) | ||
| 1155 | (beginning-of-line) | ||
| 1156 | (point-marker))) | ||
| 1157 | (message "%d" count)) | ||
| 1158 | (message "%d director%s" count (if (= 1 count) "y" "ies")) | ||
| 1159 | ;; We don't need to sort it because it is in buffer order per | ||
| 1160 | ;; constructionem. Return new alist: | ||
| 1161 | dired-subdir-alist))) | ||
| 1162 | |||
| 1163 | (defun dired-alist-add-1 (dir new-marker) | ||
| 1164 | ;; Add new DIR at NEW-MARKER. Don't sort. | ||
| 1165 | (setq dired-subdir-alist | ||
| 1166 | (cons (cons (dired-normalize-subdir dir) new-marker) | ||
| 1167 | dired-subdir-alist))) | ||
| 1168 | |||
| 1169 | (defun dired-goto-next-nontrivial-file () | ||
| 1170 | ;; Position point on first nontrivial file after point. | ||
| 1171 | (dired-goto-next-file);; so there is a file to compare with | ||
| 1172 | (if (stringp dired-trivial-filenames) | ||
| 1173 | (while (and (not (eobp)) | ||
| 1174 | (string-match dired-trivial-filenames | ||
| 1175 | (file-name-nondirectory | ||
| 1176 | (or (dired-get-filename nil t) "")))) | ||
| 1177 | (forward-line 1) | ||
| 1178 | (dired-move-to-filename)))) | ||
| 1179 | |||
| 1180 | (defun dired-goto-next-file () | ||
| 1181 | (let ((max (1- (dired-subdir-max)))) | ||
| 1182 | (while (and (not (dired-move-to-filename)) (< (point) max)) | ||
| 1183 | (forward-line 1)))) | ||
| 1184 | |||
| 1185 | (defun dired-goto-file (file) | ||
| 1186 | "Go to file line of FILE in this dired buffer." | ||
| 1187 | ;; Return value of point on success, else nil. | ||
| 1188 | ;; FILE must be an absolute pathname. | ||
| 1189 | ;; Loses if FILE contains control chars like "\007" for which ls | ||
| 1190 | ;; either inserts "?" or "\\007" into the buffer, so we won't find | ||
| 1191 | ;; it in the buffer. | ||
| 1192 | (interactive | ||
| 1193 | (prog1 ; let push-mark display its message | ||
| 1194 | (list (expand-file-name | ||
| 1195 | (read-file-name "Goto file: " | ||
| 1196 | (dired-current-directory)))) | ||
| 1197 | (push-mark))) | ||
| 1198 | (setq file (directory-file-name file)) ; does no harm if no directory | ||
| 1199 | (let (found case-fold-search dir) | ||
| 1200 | (setq dir (or (file-name-directory file) | ||
| 1201 | (error "Need absolute pathname for %s" file))) | ||
| 1202 | (save-excursion | ||
| 1203 | ;; The hair here is to get the result of dired-goto-subdir | ||
| 1204 | ;; without really calling it if we don't have any subdirs. | ||
| 1205 | (if (if (string= dir default-directory) | ||
| 1206 | (goto-char (point-min)) | ||
| 1207 | (and dired-subdir-alist | ||
| 1208 | (dired-goto-subdir dir))) | ||
| 1209 | (let ((base (file-name-nondirectory file)) | ||
| 1210 | (boundary (dired-subdir-max))) | ||
| 1211 | (while (and (not found) | ||
| 1212 | ;; filenames are preceded by SPC, this makes | ||
| 1213 | ;; the search faster (e.g. for the filename "-"!). | ||
| 1214 | (search-forward (concat " " base) boundary 'move)) | ||
| 1215 | ;; Match could have BASE just as initial substring or | ||
| 1216 | ;; or in permission bits or date or | ||
| 1217 | ;; not be a proper filename at all: | ||
| 1218 | (if (equal base (dired-get-filename 'no-dir t)) | ||
| 1219 | ;; Must move to filename since an (actually | ||
| 1220 | ;; correct) match could have been elsewhere on the | ||
| 1221 | ;; ;; line (e.g. "-" would match somewhere in the | ||
| 1222 | ;; permission bits). | ||
| 1223 | (setq found (dired-move-to-filename))))))) | ||
| 1224 | (and found | ||
| 1225 | ;; return value of point (i.e., FOUND): | ||
| 1226 | (goto-char found)))) | ||
| 1227 | |||
| 1228 | (defun dired-initial-position (dirname) | ||
| 1229 | ;; Where point should go in a new listing of DIRNAME. | ||
| 1230 | ;; Point assumed at beginning of new subdir line. | ||
| 1231 | ;; You may redefine this function as you wish, e.g. like in dired-x.el. | ||
| 1232 | (end-of-line) | ||
| 1233 | (if dired-trivial-filenames (dired-goto-next-nontrivial-file))) | ||
| 1234 | |||
| 1235 | ;; These are hooks which make tree dired work. | ||
| 1236 | ;; They are in this file because other parts of dired need to call them. | ||
| 1237 | ;; But they don't call the rest of tree dired unless there are subdirs loaded. | ||
| 1238 | |||
| 1239 | ;; This function is called for each retrieved filename. | ||
| 1240 | ;; It could stand to be faster, though it's mostly function call | ||
| 1241 | ;; overhead. Avoiding the function call seems to save about 10% in | ||
| 1242 | ;; dired-get-filename. Make it a defsubst? | ||
| 1243 | (defun dired-current-directory (&optional localp) | ||
| 1244 | "Return the name of the subdirectory to which this line belongs. | ||
| 1245 | This returns a string with trailing slash, like `default-directory'. | ||
| 1246 | Optional argument means return a file name relative to `default-directory'." | ||
| 1247 | (let ((here (point)) | ||
| 1248 | (alist (or dired-subdir-alist | ||
| 1249 | ;; probably because called in a non-dired buffer | ||
| 1250 | (error "No subdir-alist in %s" (current-buffer)))) | ||
| 1251 | elt dir) | ||
| 1252 | (while alist | ||
| 1253 | (setq elt (car alist) | ||
| 1254 | dir (car elt) | ||
| 1255 | ;; use `<=' (not `<') as subdir line is part of subdir | ||
| 1256 | alist (if (<= (dired-get-subdir-min elt) here) | ||
| 1257 | nil ; found | ||
| 1258 | (cdr alist)))) | ||
| 1259 | (if localp | ||
| 1260 | (dired-make-relative dir default-directory) | ||
| 1261 | dir))) | ||
| 1262 | |||
| 1263 | ;; Subdirs start at the beginning of their header lines and end just | ||
| 1264 | ;; before the beginning of the next header line (or end of buffer). | ||
| 1265 | |||
| 1266 | (defun dired-subdir-max () | ||
| 1267 | (save-excursion | ||
| 1268 | (if (or (null dired-subdir-alist) (not (dired-next-subdir 1 t t))) | ||
| 1269 | (point-max) | ||
| 1270 | (point)))) | ||
| 1271 | |||
| 1272 | ;; Deleting files | ||
| 1273 | |||
| 1274 | (defun dired-do-flagged-delete () | ||
| 1275 | "In dired, delete the files flagged for deletion." | ||
| 1276 | (interactive) | ||
| 1277 | (let* ((dired-marker-char dired-del-marker) | ||
| 1278 | (regexp (dired-marker-regexp)) | ||
| 1279 | case-fold-search) | ||
| 1280 | (if (save-excursion (goto-char (point-min)) | ||
| 1281 | (re-search-forward regexp nil t)) | ||
| 1282 | (dired-internal-do-deletions | ||
| 1283 | ;; this can't move point since ARG is nil | ||
| 1284 | (dired-map-over-marks (cons (dired-get-filename) (point)) | ||
| 1285 | nil) | ||
| 1286 | nil) | ||
| 1287 | (message "(No deletions requested)")))) | ||
| 1288 | |||
| 1289 | (defun dired-do-delete (&optional arg) | ||
| 1290 | "Delete all marked (or next ARG) files." | ||
| 1291 | ;; This is more consistent with the file marking feature than | ||
| 1292 | ;; dired-do-flagged-delete. | ||
| 1293 | (interactive "P") | ||
| 1294 | (dired-internal-do-deletions | ||
| 1295 | ;; this may move point if ARG is an integer | ||
| 1296 | (dired-map-over-marks (cons (dired-get-filename) (point)) | ||
| 1297 | arg) | ||
| 1298 | arg)) | ||
| 1299 | |||
| 1300 | (defvar dired-deletion-confirmer 'yes-or-no-p) ; or y-or-n-p? | ||
| 1301 | |||
| 1302 | (defun dired-internal-do-deletions (l arg) | ||
| 1303 | ;; L is an alist of files to delete, with their buffer positions. | ||
| 1304 | ;; ARG is the prefix arg. | ||
| 1305 | ;; Filenames are absolute (VMS needs this for logical search paths). | ||
| 1306 | ;; (car L) *must* be the *last* (bottommost) file in the dired buffer. | ||
| 1307 | ;; That way as changes are made in the buffer they do not shift the | ||
| 1308 | ;; lines still to be changed, so the (point) values in L stay valid. | ||
| 1309 | ;; Also, for subdirs in natural order, a subdir's files are deleted | ||
| 1310 | ;; before the subdir itself - the other way around would not work. | ||
| 1311 | (let ((files (mapcar (function car) l)) | ||
| 1312 | (count (length l)) | ||
| 1313 | (succ 0)) | ||
| 1314 | ;; canonicalize file list for pop up | ||
| 1315 | (setq files (nreverse (mapcar (function dired-make-relative) files))) | ||
| 1316 | (if (dired-mark-pop-up | ||
| 1317 | " *Deletions*" 'delete files dired-deletion-confirmer | ||
| 1318 | (format "Delete %s " (dired-mark-prompt arg files))) | ||
| 398 | (save-excursion | 1319 | (save-excursion |
| 399 | (and (not (looking-at " \\s *[0-9]*\\s *[0-9]* d")) | 1320 | (let (failures);; files better be in reverse order for this loop! |
| 400 | (not (eolp)) | 1321 | (while l |
| 401 | (setq filename (dired-get-filename t t) | 1322 | (goto-char (cdr (car l))) |
| 402 | longfilename (dired-get-filename nil t)) | 1323 | (let (buffer-read-only) |
| 403 | (progn (end-of-line) | 1324 | (condition-case err |
| 404 | (funcall fn filename longfilename)))) | 1325 | (let ((fn (car (car l)))) |
| 405 | (forward-line 1))))) | 1326 | ;; This test is equivalent to |
| 1327 | ;; (and (file-directory-p fn) (not (file-symlink-p fn))) | ||
| 1328 | ;; but more efficient | ||
| 1329 | (if (eq t (car (file-attributes fn))) | ||
| 1330 | (remove-directory fn) | ||
| 1331 | (delete-file fn)) | ||
| 1332 | ;; if we get here, removing worked | ||
| 1333 | (setq succ (1+ succ)) | ||
| 1334 | (message "%s of %s deletions" succ count) | ||
| 1335 | (delete-region (progn (beginning-of-line) (point)) | ||
| 1336 | (progn (forward-line 1) (point))) | ||
| 1337 | (dired-clean-up-after-deletion fn)) | ||
| 1338 | (error;; catch errors from failed deletions | ||
| 1339 | (dired-log "%s\n" err) | ||
| 1340 | (setq failures (cons (car (car l)) failures))))) | ||
| 1341 | (setq l (cdr l))) | ||
| 1342 | (if (not failures) | ||
| 1343 | (message "%d deletion%s done" count (dired-plural-s count)) | ||
| 1344 | (dired-log-summary | ||
| 1345 | (format "%d of %d deletion%s failed" | ||
| 1346 | (length failures) count | ||
| 1347 | (dired-plural-s count)) | ||
| 1348 | failures)))) | ||
| 1349 | (message "(No deletions performed)"))) | ||
| 1350 | (dired-move-to-filename)) | ||
| 1351 | |||
| 1352 | ;; This is a separate function for the sake of dired-x.el. | ||
| 1353 | (defun dired-clean-up-after-deletion (fn) | ||
| 1354 | ;; Clean up after a deleted file or directory FN. | ||
| 1355 | (save-excursion (and (dired-goto-subdir fn) | ||
| 1356 | (dired-kill-subdir)))) | ||
| 1357 | |||
| 1358 | ;; Confirmation | ||
| 1359 | |||
| 1360 | (defun dired-marker-regexp () | ||
| 1361 | (concat "^" (regexp-quote (char-to-string dired-marker-char)))) | ||
| 1362 | |||
| 1363 | (defun dired-plural-s (count) | ||
| 1364 | (if (= 1 count) "" "s")) | ||
| 1365 | |||
| 1366 | (defun dired-mark-prompt (arg files) | ||
| 1367 | ;; Return a string for use in a prompt, either the current file | ||
| 1368 | ;; name, or the marker and a count of marked files. | ||
| 1369 | (let ((count (length files))) | ||
| 1370 | (if (= count 1) | ||
| 1371 | (car files) | ||
| 1372 | ;; more than 1 file: | ||
| 1373 | (if (integerp arg) | ||
| 1374 | ;; abs(arg) = count | ||
| 1375 | ;; Perhaps this is nicer, but it also takes more screen space: | ||
| 1376 | ;;(format "[%s %d files]" (if (> arg 0) "next" "previous") | ||
| 1377 | ;; count) | ||
| 1378 | (format "[next %d files]" arg) | ||
| 1379 | (format "%c [%d files]" dired-marker-char count))))) | ||
| 1380 | |||
| 1381 | (defun dired-pop-to-buffer (buf) | ||
| 1382 | ;; Pop up buffer BUF. | ||
| 1383 | ;; If dired-shrink-to-fit is t, make its window fit its contents. | ||
| 1384 | (if (not dired-shrink-to-fit) | ||
| 1385 | (pop-to-buffer (get-buffer-create buf)) | ||
| 1386 | ;; let window shrink to fit: | ||
| 1387 | (let ((window (selected-window)) | ||
| 1388 | target-lines w2) | ||
| 1389 | (cond ;; if split-window-threshold is enabled, use the largest window | ||
| 1390 | ((and (> (window-height (setq w2 (get-largest-window))) | ||
| 1391 | split-height-threshold) | ||
| 1392 | (= (screen-width) (window-width w2))) | ||
| 1393 | (setq window w2)) | ||
| 1394 | ;; if the least-recently-used window is big enough, use it | ||
| 1395 | ((and (> (window-height (setq w2 (get-lru-window))) | ||
| 1396 | (* 2 window-min-height)) | ||
| 1397 | (= (screen-width) (window-width w2))) | ||
| 1398 | (setq window w2))) | ||
| 1399 | (save-excursion | ||
| 1400 | (set-buffer buf) | ||
| 1401 | (goto-char (point-max)) | ||
| 1402 | (skip-chars-backward "\n\r\t ") | ||
| 1403 | (setq target-lines (count-lines (point-min) (point)))) | ||
| 1404 | (if (<= (window-height window) (* 2 window-min-height)) | ||
| 1405 | ;; At this point, every window on the screen is too small to split. | ||
| 1406 | (setq w2 (display-buffer buf)) | ||
| 1407 | (setq w2 (split-window window | ||
| 1408 | (max window-min-height | ||
| 1409 | (- (window-height window) | ||
| 1410 | (1+ (max window-min-height target-lines))))))) | ||
| 1411 | (set-window-buffer w2 buf) | ||
| 1412 | (if (< (1- (window-height w2)) target-lines) | ||
| 1413 | (progn | ||
| 1414 | (select-window w2) | ||
| 1415 | (enlarge-window (- target-lines (1- (window-height w2)))))) | ||
| 1416 | (set-window-start w2 1) | ||
| 1417 | ))) | ||
| 1418 | |||
| 1419 | (defvar dired-no-confirm nil | ||
| 1420 | ;; "If non-nil, list of symbols for commands dired should not confirm. | ||
| 1421 | ;;It can be a sublist of | ||
| 1422 | ;; | ||
| 1423 | ;; '(byte-compile chgrp chmod chown compress copy delete hardlink load | ||
| 1424 | ;; move print shell symlink uncompress)" | ||
| 1425 | ) | ||
| 1426 | |||
| 1427 | (defun dired-mark-pop-up (bufname op-symbol files function &rest args) | ||
| 1428 | ;;"Args BUFNAME OP-SYMBOL FILES FUNCTION &rest ARGS. | ||
| 1429 | ;;Return FUNCTION's result on ARGS after popping up a window (in a buffer | ||
| 1430 | ;;named BUFNAME, nil gives \" *Marked Files*\") showing the marked | ||
| 1431 | ;;files. Uses function `dired-pop-to-buffer' to do that. | ||
| 1432 | ;; FUNCTION should not manipulate files. | ||
| 1433 | ;; It should only read input (an argument or confirmation). | ||
| 1434 | ;;The window is not shown if there is just one file or | ||
| 1435 | ;; OP-SYMBOL is a member of the list in `dired-no-confirm'. | ||
| 1436 | ;;FILES is the list of marked files." | ||
| 1437 | (or bufname (setq bufname " *Marked Files*")) | ||
| 1438 | (if (or (memq op-symbol dired-no-confirm) | ||
| 1439 | (= (length files) 1)) | ||
| 1440 | (apply function args) | ||
| 1441 | (save-excursion | ||
| 1442 | (set-buffer (get-buffer-create bufname)) | ||
| 1443 | (erase-buffer) | ||
| 1444 | (dired-format-columns-of-files files)) | ||
| 1445 | (save-window-excursion | ||
| 1446 | (dired-pop-to-buffer bufname) | ||
| 1447 | (apply function args)))) | ||
| 1448 | |||
| 1449 | (defun dired-format-columns-of-files (files) | ||
| 1450 | ;; Files should be in forward order for this loop. | ||
| 1451 | ;; i.e., (car files) = first file in buffer. | ||
| 1452 | ;; Returns the number of lines used. | ||
| 1453 | (let* ((maxlen (+ 2 (apply 'max (mapcar 'length files)))) | ||
| 1454 | (width (- (window-width (selected-window)) 2)) | ||
| 1455 | (columns (max 1 (/ width maxlen))) | ||
| 1456 | (nfiles (length files)) | ||
| 1457 | (rows (+ (/ nfiles columns) | ||
| 1458 | (if (zerop (% nfiles columns)) 0 1))) | ||
| 1459 | (i 0) | ||
| 1460 | (j 0)) | ||
| 1461 | (setq files (nconc (copy-sequence files) ; fill up with empty fns | ||
| 1462 | (make-list (- (* columns rows) nfiles) ""))) | ||
| 1463 | (setcdr (nthcdr (1- (length files)) files) files) ; make circular | ||
| 1464 | (while (< j rows) | ||
| 1465 | (while (< i columns) | ||
| 1466 | (indent-to (* i maxlen)) | ||
| 1467 | (insert (car files)) | ||
| 1468 | (setq files (nthcdr rows files) | ||
| 1469 | i (1+ i))) | ||
| 1470 | (insert "\n") | ||
| 1471 | (setq i 0 | ||
| 1472 | j (1+ j) | ||
| 1473 | files (cdr files))) | ||
| 1474 | rows)) | ||
| 1475 | |||
| 1476 | ;; Commands to mark or flag file(s) at or near current line. | ||
| 1477 | |||
| 1478 | (defun dired-repeat-over-lines (arg function) | ||
| 1479 | ;; This version skips non-file lines. | ||
| 1480 | (beginning-of-line) | ||
| 1481 | (while (and (> arg 0) (not (eobp))) | ||
| 1482 | (setq arg (1- arg)) | ||
| 1483 | (beginning-of-line) | ||
| 1484 | (while (and (not (eobp)) (dired-between-files)) (forward-line 1)) | ||
| 1485 | (save-excursion (funcall function)) | ||
| 1486 | (forward-line 1)) | ||
| 1487 | (while (and (< arg 0) (not (bobp))) | ||
| 1488 | (setq arg (1+ arg)) | ||
| 1489 | (forward-line -1) | ||
| 1490 | (while (and (not (bobp)) (dired-between-files)) (forward-line -1)) | ||
| 1491 | (beginning-of-line) | ||
| 1492 | (save-excursion (funcall function)) | ||
| 1493 | (dired-move-to-filename)) | ||
| 1494 | (dired-move-to-filename)) | ||
| 1495 | |||
| 1496 | (defun dired-between-files () | ||
| 1497 | ;; Point must be at beginning of line | ||
| 1498 | ;; Should be equivalent to (save-excursion (not (dired-move-to-filename))) | ||
| 1499 | ;; but is about 1.5..2.0 times as fast. (Actually that's not worth it) | ||
| 1500 | (or (looking-at "^$\\|^. *$\\|^. total\\|^. wildcard") | ||
| 1501 | (looking-at dired-subdir-regexp))) | ||
| 1502 | |||
| 1503 | (defun dired-next-marked-file (arg &optional wrap opoint) | ||
| 1504 | "Move to the next marked file, wrapping around the end of the buffer." | ||
| 1505 | (interactive "p\np") | ||
| 1506 | (or opoint (setq opoint (point)));; return to where interactively started | ||
| 1507 | (if (if (> arg 0) | ||
| 1508 | (re-search-forward dired-re-mark nil t arg) | ||
| 1509 | (beginning-of-line) | ||
| 1510 | (re-search-backward dired-re-mark nil t (- arg))) | ||
| 1511 | (dired-move-to-filename) | ||
| 1512 | (if (null wrap) | ||
| 1513 | (progn | ||
| 1514 | (goto-char opoint) | ||
| 1515 | (error "No next marked file")) | ||
| 1516 | (message "(Wraparound for next marked file)") | ||
| 1517 | (goto-char (if (> arg 0) (point-min) (point-max))) | ||
| 1518 | (dired-next-marked-file arg nil opoint)))) | ||
| 1519 | |||
| 1520 | (defun dired-prev-marked-file (arg &optional wrap) | ||
| 1521 | "Move to the previous marked file, wrapping around the end of the buffer." | ||
| 1522 | (interactive "p\np") | ||
| 1523 | (dired-next-marked-file (- arg) wrap)) | ||
| 1524 | |||
| 1525 | (defun dired-file-marker (file) | ||
| 1526 | ;; Return FILE's marker, or nil if unmarked. | ||
| 1527 | (save-excursion | ||
| 1528 | (and (dired-goto-file file) | ||
| 1529 | (progn | ||
| 1530 | (beginning-of-line) | ||
| 1531 | (if (not (equal ?\040 (following-char))) | ||
| 1532 | (following-char)))))) | ||
| 1533 | |||
| 1534 | (defun dired-mark-files-in-region (start end) | ||
| 1535 | (let (buffer-read-only) | ||
| 1536 | (if (> start end) | ||
| 1537 | (error "start > end")) | ||
| 1538 | (goto-char start) ; assumed at beginning of line | ||
| 1539 | (while (< (point) end) | ||
| 1540 | ;; Skip subdir line and following garbage like the `total' line: | ||
| 1541 | (while (and (< (point) end) (dired-between-files)) | ||
| 1542 | (forward-line 1)) | ||
| 1543 | (if (and (not (looking-at dired-re-dot)) | ||
| 1544 | (dired-get-filename nil t)) | ||
| 1545 | (progn | ||
| 1546 | (delete-char 1) | ||
| 1547 | (insert dired-marker-char))) | ||
| 1548 | (forward-line 1)))) | ||
| 1549 | |||
| 1550 | (defun dired-mark (arg) | ||
| 1551 | "Mark the current (or next ARG) files. | ||
| 1552 | If on a subdir headerline, mark all its files except `.' and `..'. | ||
| 1553 | |||
| 1554 | Use \\[dired-unmark-all-files] to remove all marks | ||
| 1555 | and \\[dired-unmark] on a subdir to remove the marks in | ||
| 1556 | this subdir." | ||
| 1557 | (interactive "P") | ||
| 1558 | (if (and dired-subdir-alist (dired-get-subdir)) | ||
| 1559 | (save-excursion (dired-mark-subdir-files)) | ||
| 1560 | (let (buffer-read-only) | ||
| 1561 | (dired-repeat-over-lines | ||
| 1562 | arg | ||
| 1563 | (function (lambda () (delete-char 1) (insert dired-marker-char))))))) | ||
| 1564 | |||
| 1565 | (defun dired-unmark (arg) | ||
| 1566 | "Unmark the current (or next ARG) files. | ||
| 1567 | If looking at a subdir, unmark all its files except `.' and `..'." | ||
| 1568 | (interactive "P") | ||
| 1569 | (let ((dired-marker-char ?\040)) | ||
| 1570 | (dired-mark arg))) | ||
| 1571 | |||
| 1572 | (defun dired-flag-file-deletion (arg) | ||
| 1573 | "In dired, flag the current line's file for deletion. | ||
| 1574 | With prefix arg, repeat over several lines. | ||
| 1575 | |||
| 1576 | If on a subdir headerline, mark all its files except `.' and `..'." | ||
| 1577 | (interactive "P") | ||
| 1578 | (let ((dired-marker-char dired-del-marker)) | ||
| 1579 | (dired-mark arg))) | ||
| 1580 | |||
| 1581 | (defun dired-unmark-backward (arg) | ||
| 1582 | "In dired, move up lines and remove deletion flag there. | ||
| 1583 | Optional prefix ARG says how many lines to unflag; default is one line." | ||
| 1584 | (interactive "p") | ||
| 1585 | (dired-unmark (- arg))) | ||
| 406 | 1586 | ||
| 407 | (defun dired-flag-auto-save-files (unflag-p) | 1587 | ;;; Commands to mark or flag files based on their characteristics or names. |
| 1588 | |||
| 1589 | (defun dired-read-regexp (prompt &optional initial) | ||
| 1590 | ;; This is an extra function so that gmhist can redefine it. | ||
| 1591 | (setq dired-flagging-regexp | ||
| 1592 | (read-string prompt (or initial dired-flagging-regexp)))) | ||
| 1593 | |||
| 1594 | (defun dired-mark-files-regexp (regexp &optional marker-char) | ||
| 1595 | "Mark all files matching REGEXP for use in later commands. | ||
| 1596 | A prefix argument means to unmark them instead. | ||
| 1597 | `.' and `..' are never marked. | ||
| 1598 | |||
| 1599 | REGEXP is an Emacs regexp, not a shell wildcard. Thus, use `\\.o$' for | ||
| 1600 | object files--just `.o' will mark more than you might think." | ||
| 1601 | (interactive | ||
| 1602 | (list (dired-read-regexp (concat (if current-prefix-arg "Unmark" "Mark") | ||
| 1603 | " files (regexp): ")) | ||
| 1604 | (if current-prefix-arg ?\040))) | ||
| 1605 | (let ((dired-marker-char (or marker-char dired-marker-char))) | ||
| 1606 | (dired-mark-if | ||
| 1607 | (and (not (looking-at dired-re-dot)) | ||
| 1608 | (not (eolp)) ; empty line | ||
| 1609 | (let ((fn (dired-get-filename nil t))) | ||
| 1610 | (and fn (string-match regexp (file-name-nondirectory fn))))) | ||
| 1611 | "matching file"))) | ||
| 1612 | |||
| 1613 | (defun dired-flag-files-regexp (regexp) | ||
| 1614 | "In dired, flag all files containing the specified REGEXP for deletion. | ||
| 1615 | The match is against the non-directory part of the filename. Use `^' | ||
| 1616 | and `$' to anchor matches. Exclude subdirs by hiding them. | ||
| 1617 | `.' and `..' are never flagged." | ||
| 1618 | (interactive (list (dired-read-regexp "Flag for deletion (regexp): "))) | ||
| 1619 | (dired-mark-files-regexp regexp dired-del-marker)) | ||
| 1620 | |||
| 1621 | (defun dired-mark-symlinks (unflag-p) | ||
| 1622 | "Mark all symbolic links. | ||
| 1623 | With prefix argument, unflag all those files." | ||
| 1624 | (interactive "P") | ||
| 1625 | (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char))) | ||
| 1626 | (dired-mark-if (looking-at dired-re-sym) "symbolic link"))) | ||
| 1627 | |||
| 1628 | (defun dired-mark-directories (unflag-p) | ||
| 1629 | "Mark all directory file lines except `.' and `..'. | ||
| 1630 | With prefix argument, unflag all those files." | ||
| 1631 | (interactive "P") | ||
| 1632 | (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char))) | ||
| 1633 | (dired-mark-if (and (looking-at dired-re-dir) | ||
| 1634 | (not (looking-at dired-re-dot))) | ||
| 1635 | "directory file"))) | ||
| 1636 | |||
| 1637 | (defun dired-mark-executables (unflag-p) | ||
| 1638 | "Mark all executable files. | ||
| 1639 | With prefix argument, unflag all those files." | ||
| 1640 | (interactive "P") | ||
| 1641 | (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char))) | ||
| 1642 | (dired-mark-if (looking-at dired-re-exe) "executable file"))) | ||
| 1643 | |||
| 1644 | ;; dired-x.el has a dired-mark-sexp interactive command: mark | ||
| 1645 | ;; files for which PREDICATE returns non-nil. | ||
| 1646 | |||
| 1647 | (defun dired-flag-auto-save-files (&optional unflag-p) | ||
| 408 | "Flag for deletion files whose names suggest they are auto save files. | 1648 | "Flag for deletion files whose names suggest they are auto save files. |
| 409 | A prefix argument says to unflag those files instead." | 1649 | A prefix argument says to unflag those files instead." |
| 410 | (interactive "P") | 1650 | (interactive "P") |
| 411 | (save-excursion | 1651 | (let ((dired-marker-char (if unflag-p ?\040 dired-del-marker))) |
| 412 | (let ((buffer-read-only nil)) | 1652 | (dired-mark-if |
| 413 | (goto-char (point-min)) | 1653 | (and (not (looking-at dired-re-dir)) |
| 414 | (while (not (eobp)) | 1654 | (let ((fn (dired-get-filename t t))) |
| 415 | (and (not (looking-at " \\s *[0-9]*\\s *[0-9]* d")) | 1655 | (if fn (auto-save-file-name-p |
| 416 | (not (eolp)) | 1656 | (file-name-nondirectory fn))))) |
| 417 | (if (fboundp 'auto-save-file-name-p) | 1657 | "auto save file"))) |
| 418 | (let ((fn (dired-get-filename t t))) | 1658 | |
| 419 | (if fn (auto-save-file-name-p fn))) | 1659 | (defun dired-flag-backup-files (&optional unflag-p) |
| 420 | (if (dired-move-to-filename) | 1660 | "Flag all backup files (names ending with `~') for deletion. |
| 421 | (looking-at "#"))) | 1661 | With prefix argument, unflag these files." |
| 422 | (progn (beginning-of-line) | 1662 | (interactive "P") |
| 423 | (delete-char 1) | 1663 | (let ((dired-marker-char (if unflag-p ?\040 dired-del-marker))) |
| 424 | (insert (if unflag-p " " "D")))) | 1664 | (dired-mark-if |
| 425 | (forward-line 1))))) | 1665 | (and (not (looking-at dired-re-dir)) |
| 1666 | (let ((fn (dired-get-filename t t))) | ||
| 1667 | (if fn (backup-file-name-p fn)))) | ||
| 1668 | "backup file"))) | ||
| 1669 | |||
| 1670 | (defun dired-unmark-all-files (flag &optional arg) | ||
| 1671 | "Remove a specific mark or any mark from every file. | ||
| 1672 | With an arg, queries for each marked file. | ||
| 1673 | Type \\[help-command] at that time for help." | ||
| 1674 | (interactive "sRemove mark: (default: all marks) \nP") | ||
| 1675 | (let ((count 0) | ||
| 1676 | (re (if (zerop (length flag)) dired-re-mark | ||
| 1677 | (concat "^" (regexp-quote flag))))) | ||
| 1678 | (save-excursion | ||
| 1679 | (let (buffer-read-only case-fold-search query | ||
| 1680 | (help-form "\ | ||
| 1681 | Type SPC or `y' to unflag one file, DEL or `n' to skip to next, | ||
| 1682 | `!' to unflag all remaining files with no more questions.")) | ||
| 1683 | (goto-char (point-min)) | ||
| 1684 | (while (re-search-forward re nil t) | ||
| 1685 | (if (or (not arg) | ||
| 1686 | (dired-query 'query "Unmark file `%s'? " | ||
| 1687 | (dired-get-filename t))) | ||
| 1688 | (progn (delete-char -1) (insert " ") (setq count (1+ count)))) | ||
| 1689 | (forward-line 1)))) | ||
| 1690 | (message "%s" (format "Flags removed: %d %s" count flag) ))) | ||
| 1691 | |||
| 1692 | ;;; Cleaning a directory: flagging some backups for deletion. | ||
| 426 | 1693 | ||
| 427 | (defun dired-clean-directory (keep) | 1694 | (defun dired-clean-directory (keep) |
| 428 | "Flag numerical backups for deletion. | 1695 | "Flag numerical backups for deletion. |
| @@ -437,11 +1704,13 @@ with a prefix argument." | |||
| 437 | (let ((early-retention (if (< keep 0) (- keep) kept-old-versions)) | 1704 | (let ((early-retention (if (< keep 0) (- keep) kept-old-versions)) |
| 438 | (late-retention (if (<= keep 0) dired-kept-versions keep)) | 1705 | (late-retention (if (<= keep 0) dired-kept-versions keep)) |
| 439 | (file-version-assoc-list ())) | 1706 | (file-version-assoc-list ())) |
| 1707 | (message "Cleaning numerical backups (keeping %d late, %d old)..." | ||
| 1708 | late-retention early-retention) | ||
| 440 | ;; Look at each file. | 1709 | ;; Look at each file. |
| 441 | ;; If the file has numeric backup versions, | 1710 | ;; If the file has numeric backup versions, |
| 442 | ;; put on file-version-assoc-list an element of the form | 1711 | ;; put on file-version-assoc-list an element of the form |
| 443 | ;; (FILENAME . VERSION-NUMBER-LIST) | 1712 | ;; (FILENAME . VERSION-NUMBER-LIST) |
| 444 | (dired-map-dired-file-lines 'dired-collect-file-versions) | 1713 | (dired-map-dired-file-lines (function dired-collect-file-versions)) |
| 445 | ;; Sort each VERSION-NUMBER-LIST, | 1714 | ;; Sort each VERSION-NUMBER-LIST, |
| 446 | ;; and remove the versions not to be deleted. | 1715 | ;; and remove the versions not to be deleted. |
| 447 | (let ((fval file-version-assoc-list)) | 1716 | (let ((fval file-version-assoc-list)) |
| @@ -457,12 +1726,30 @@ with a prefix argument." | |||
| 457 | (setq fval (cdr fval)))) | 1726 | (setq fval (cdr fval)))) |
| 458 | ;; Look at each file. If it is a numeric backup file, | 1727 | ;; Look at each file. If it is a numeric backup file, |
| 459 | ;; find it in a VERSION-NUMBER-LIST and maybe flag it for deletion. | 1728 | ;; find it in a VERSION-NUMBER-LIST and maybe flag it for deletion. |
| 460 | (dired-map-dired-file-lines 'dired-trample-file-versions))) | 1729 | (dired-map-dired-file-lines (function dired-trample-file-versions)) |
| 1730 | (message "Cleaning numerical backups...done"))) | ||
| 1731 | |||
| 1732 | ;;; Subroutines of dired-clean-directory. | ||
| 461 | 1733 | ||
| 462 | (defun dired-collect-file-versions (ignore fn) | 1734 | (defun dired-map-dired-file-lines (fun) |
| 463 | "If it looks like file FN has versions, return a list of the versions. | 1735 | ;; Perform FUN with point at the end of each non-directory line. |
| 464 | That is a list of strings which are file names. | 1736 | ;; FUN takes one argument, the filename (complete pathname). |
| 465 | The caller may want to flag some of these files for deletion." | 1737 | (save-excursion |
| 1738 | (let (file buffer-read-only) | ||
| 1739 | (goto-char (point-min)) | ||
| 1740 | (while (not (eobp)) | ||
| 1741 | (save-excursion | ||
| 1742 | (and (not (looking-at dired-re-dir)) | ||
| 1743 | (not (eolp)) | ||
| 1744 | (setq file (dired-get-filename nil t)) ; nil on non-file | ||
| 1745 | (progn (end-of-line) | ||
| 1746 | (funcall fun file)))) | ||
| 1747 | (forward-line 1))))) | ||
| 1748 | |||
| 1749 | (defun dired-collect-file-versions (fn) | ||
| 1750 | ;; "If it looks like file FN has versions, return a list of the versions. | ||
| 1751 | ;;That is a list of strings which are file names. | ||
| 1752 | ;;The caller may want to flag some of these files for deletion." | ||
| 466 | (let* ((base-versions | 1753 | (let* ((base-versions |
| 467 | (concat (file-name-nondirectory fn) ".~")) | 1754 | (concat (file-name-nondirectory fn) ".~")) |
| 468 | (bv-length (length base-versions)) | 1755 | (bv-length (length base-versions)) |
| @@ -474,7 +1761,7 @@ The caller may want to flag some of these files for deletion." | |||
| 474 | (setq file-version-assoc-list (cons (cons fn versions) | 1761 | (setq file-version-assoc-list (cons (cons fn versions) |
| 475 | file-version-assoc-list))))) | 1762 | file-version-assoc-list))))) |
| 476 | 1763 | ||
| 477 | (defun dired-trample-file-versions (ignore fn) | 1764 | (defun dired-trample-file-versions (fn) |
| 478 | (let* ((start-vn (string-match "\\.~[0-9]+~$" fn)) | 1765 | (let* ((start-vn (string-match "\\.~[0-9]+~$" fn)) |
| 479 | base-version-list) | 1766 | base-version-list) |
| 480 | (and start-vn | 1767 | (and start-vn |
| @@ -483,303 +1770,359 @@ The caller may want to flag some of these files for deletion." | |||
| 483 | file-version-assoc-list)) ; subversion | 1770 | file-version-assoc-list)) ; subversion |
| 484 | (not (memq (string-to-int (substring fn (+ 2 start-vn))) | 1771 | (not (memq (string-to-int (substring fn (+ 2 start-vn))) |
| 485 | base-version-list)) ; this one doesn't make the cut | 1772 | base-version-list)) ; this one doesn't make the cut |
| 486 | (dired-flag-this-line-for-DEATH)))) | 1773 | (progn (beginning-of-line) |
| 1774 | (delete-char 1) | ||
| 1775 | (insert dired-del-marker))))) | ||
| 1776 | |||
| 1777 | ;; Logging failures operating on files, and showing the results. | ||
| 487 | 1778 | ||
| 488 | (defun dired-flag-this-line-for-DEATH () | 1779 | (defvar dired-log-buffer "*Dired log*") |
| 489 | (beginning-of-line) | ||
| 490 | (delete-char 1) | ||
| 491 | (insert "D")) | ||
| 492 | 1780 | ||
| 493 | (defun dired-flag-backup-files (unflag-p) | 1781 | (defun dired-why () |
| 494 | "Flag all backup files (names ending with `~') for deletion. | 1782 | "Pop up a buffer with error log output from Dired. |
| 495 | With prefix argument, unflag these files." | 1783 | A group of errors from a single command ends with a formfeed. |
| 496 | (interactive "P") | 1784 | Thus, use \\[backward-page] to find the beginning of a group of errors." |
| 497 | (save-excursion | 1785 | (interactive) |
| 498 | (let ((buffer-read-only nil)) | 1786 | (if (get-buffer dired-log-buffer) |
| 499 | (goto-char (point-min)) | 1787 | (let ((owindow (selected-window)) |
| 500 | (while (not (eobp)) | 1788 | (window (display-buffer (get-buffer dired-log-buffer)))) |
| 501 | (and (not (looking-at " d")) | 1789 | (unwind-protect |
| 502 | (not (eolp)) | 1790 | (save-excursion |
| 503 | (if (fboundp 'backup-file-name-p) | 1791 | (select-window window) |
| 504 | (let ((fn (dired-get-filename t t))) | 1792 | (goto-char (point-max)) |
| 505 | (if fn (backup-file-name-p fn))) | 1793 | (recenter -1)) |
| 506 | (end-of-line) | 1794 | (select-window owindow))))) |
| 507 | (forward-char -1) | 1795 | |
| 508 | (looking-at "~")) | 1796 | (defun dired-log (log &rest args) |
| 509 | (progn (beginning-of-line) | 1797 | ;; Log a message or the contents of a buffer. |
| 510 | (delete-char 1) | 1798 | ;; If LOG is a string and there are more args, it is formatted with |
| 511 | (insert (if unflag-p " " "D")))) | 1799 | ;; those ARGS. Usually the LOG string ends with a \n. |
| 512 | (forward-line 1))))) | 1800 | ;; End each bunch of errors with (dired-log t): this inserts |
| 513 | 1801 | ;; current time and buffer, and a \f (formfeed). | |
| 514 | (defun dired-flag-backup-and-auto-save-files (unflag-p) | 1802 | (let ((obuf (current-buffer))) |
| 515 | "Flag all backup and temporary files for deletion. | 1803 | (unwind-protect ; want to move point |
| 516 | Backup files have names ending in `~'. | 1804 | (progn |
| 517 | Auto save file names usually start with `#'. | 1805 | (set-buffer (get-buffer-create dired-log-buffer)) |
| 518 | With prefix argument, unflag these files." | 1806 | (goto-char (point-max)) |
| 1807 | (let (buffer-read-only) | ||
| 1808 | (cond ((stringp log) | ||
| 1809 | (insert (if args | ||
| 1810 | (apply (function format) log args) | ||
| 1811 | log))) | ||
| 1812 | ((bufferp log) | ||
| 1813 | (insert-buffer log)) | ||
| 1814 | ((eq t log) | ||
| 1815 | (insert "\n\t" (current-time-string) | ||
| 1816 | "\tBuffer `" (buffer-name obuf) "'\n\f\n"))))) | ||
| 1817 | (set-buffer obuf)))) | ||
| 1818 | |||
| 1819 | (defun dired-log-summary (string failures) | ||
| 1820 | (message (if failures "%s--type ? for details (%s)" | ||
| 1821 | "%s--type ? for details") | ||
| 1822 | string failures) | ||
| 1823 | ;; Log a summary describing a bunch of errors. | ||
| 1824 | (dired-log (concat "\n" string)) | ||
| 1825 | (dired-log t)) | ||
| 1826 | |||
| 1827 | ;;; Sorting | ||
| 1828 | |||
| 1829 | ;; Most ls can only sort by name or by date (with -t), nothing else. | ||
| 1830 | ;; GNU ls sorts on size with -S, on extension with -X, and unsorted with -U. | ||
| 1831 | ;; So anything that does not contain these is sort "by name". | ||
| 1832 | |||
| 1833 | (defvar dired-ls-sorting-switches "SXU" | ||
| 1834 | "String of `ls' switches (single letters) except `t' that influence sorting.") | ||
| 1835 | |||
| 1836 | (defvar dired-sort-by-date-regexp | ||
| 1837 | (concat "^-[^" dired-ls-sorting-switches | ||
| 1838 | "]*t[^" dired-ls-sorting-switches "]*$") | ||
| 1839 | "Regexp recognized by dired to set `by date' mode.") | ||
| 1840 | |||
| 1841 | (defvar dired-sort-by-name-regexp | ||
| 1842 | (concat "^-[^t" dired-ls-sorting-switches "]+$") | ||
| 1843 | "Regexp recognized by dired to set `by name' mode.") | ||
| 1844 | |||
| 1845 | (defvar dired-sort-mode nil | ||
| 1846 | "Whether Dired sorts by name, date etc. (buffer-local).") | ||
| 1847 | ;; This is nil outside dired buffers so it can be used in the modeline | ||
| 1848 | |||
| 1849 | (defun dired-sort-set-modeline () | ||
| 1850 | ;; Set modeline display according to dired-actual-switches. | ||
| 1851 | ;; Modeline display of "by name" or "by date" guarantees the user a | ||
| 1852 | ;; match with the corresponding regexps. Non-matching switches are | ||
| 1853 | ;; shown literally. | ||
| 1854 | (setq dired-sort-mode | ||
| 1855 | (let (case-fold-search) | ||
| 1856 | (cond ((string-match dired-sort-by-name-regexp dired-actual-switches) | ||
| 1857 | " by name") | ||
| 1858 | ((string-match dired-sort-by-date-regexp dired-actual-switches) | ||
| 1859 | " by date") | ||
| 1860 | (t | ||
| 1861 | (concat " " dired-actual-switches))))) | ||
| 1862 | ;; update mode line: | ||
| 1863 | (set-buffer-modified-p (buffer-modified-p))) | ||
| 1864 | |||
| 1865 | (defun dired-sort-toggle-or-edit (&optional arg) | ||
| 1866 | "Toggle between sort by date/name and refresh the dired buffer. | ||
| 1867 | With a prefix argument you can edit the current listing switches instead." | ||
| 519 | (interactive "P") | 1868 | (interactive "P") |
| 520 | (dired-flag-backup-files unflag-p) | 1869 | (if arg |
| 521 | (dired-flag-auto-save-files unflag-p)) | 1870 | (dired-sort-other |
| 1871 | (read-string "ls switches (must contain -l): " dired-actual-switches)) | ||
| 1872 | (dired-sort-toggle))) | ||
| 1873 | |||
| 1874 | (defun dired-sort-toggle () | ||
| 1875 | ;; Toggle between sort by date/name. Reverts the buffer. | ||
| 1876 | (setq dired-actual-switches | ||
| 1877 | (let (case-fold-search) | ||
| 1878 | (concat | ||
| 1879 | "-l" | ||
| 1880 | (dired-replace-in-string (concat "[---lt" | ||
| 1881 | dired-ls-sorting-switches "]") | ||
| 1882 | "" | ||
| 1883 | dired-actual-switches) | ||
| 1884 | (if (string-match (concat "[t" dired-ls-sorting-switches "]") | ||
| 1885 | dired-actual-switches) | ||
| 1886 | "" | ||
| 1887 | "t")))) | ||
| 1888 | (dired-sort-set-modeline) | ||
| 1889 | (revert-buffer)) | ||
| 1890 | |||
| 1891 | (defun dired-replace-in-string (regexp newtext string) | ||
| 1892 | ;; Replace REGEXP with NEWTEXT everywhere in STRING and return result. | ||
| 1893 | ;; NEWTEXT is taken literally---no \\DIGIT escapes will be recognized. | ||
| 1894 | (let ((result "") (start 0) mb me) | ||
| 1895 | (while (string-match regexp string start) | ||
| 1896 | (setq mb (match-beginning 0) | ||
| 1897 | me (match-end 0) | ||
| 1898 | result (concat result (substring string start mb) newtext) | ||
| 1899 | start me)) | ||
| 1900 | (concat result (substring string start)))) | ||
| 1901 | |||
| 1902 | (defun dired-sort-other (switches &optional no-revert) | ||
| 1903 | ;; Specify new ls SWITCHES for current dired buffer. Values matching | ||
| 1904 | ;; `dired-sort-by-date-regexp' or `dired-sort-by-name-regexp' set the | ||
| 1905 | ;; minor mode accordingly, others appear literally in the mode line. | ||
| 1906 | ;; With optional second arg NO-REVERT, don't refresh the listing afterwards. | ||
| 1907 | (setq dired-actual-switches switches) | ||
| 1908 | (dired-sort-set-modeline) | ||
| 1909 | (or no-revert (revert-buffer))) | ||
| 522 | 1910 | ||
| 523 | (defun dired-create-directory (directory) | 1911 | ;; To make this file smaller, the less common commands |
| 1912 | ;; go in a separate file. But autoload them here | ||
| 1913 | ;; to make the separation invisible. | ||
| 1914 | |||
| 1915 | (autoload 'dired-diff "dired-aux" | ||
| 1916 | "Compare file at point with file FILE using `diff'. | ||
| 1917 | FILE defaults to the file at the mark. | ||
| 1918 | The prompted-for file is the first file given to `diff'. | ||
| 1919 | Prefix arg lets you edit the diff switches. See the command `diff'." | ||
| 1920 | t) | ||
| 1921 | |||
| 1922 | (autoload 'dired-backup-diff "dired-aux" | ||
| 1923 | "Diff this file with its backup file or vice versa. | ||
| 1924 | Uses the latest backup, if there are several numerical backups. | ||
| 1925 | If this file is a backup, diff it with its original. | ||
| 1926 | The backup file is the first file given to `diff'. | ||
| 1927 | Prefix arg lets you edit the diff switches. See the command `diff'." | ||
| 1928 | t) | ||
| 1929 | |||
| 1930 | (autoload 'dired-do-chmod "dired-aux" | ||
| 1931 | "Change the mode of the marked (or next ARG) files. | ||
| 1932 | This calls chmod, thus symbolic modes like `g+w' are allowed." | ||
| 1933 | t) | ||
| 1934 | |||
| 1935 | (autoload 'dired-do-chgrp "dired-aux" | ||
| 1936 | "Change the group of the marked (or next ARG) files." | ||
| 1937 | t) | ||
| 1938 | |||
| 1939 | (autoload 'dired-do-chown "dired-aux" | ||
| 1940 | "Change the owner of the marked (or next ARG) files." | ||
| 1941 | t) | ||
| 1942 | |||
| 1943 | (autoload 'dired-do-print "dired-aux" | ||
| 1944 | "Print the marked (or next ARG) files. | ||
| 1945 | Uses the shell command coming from variables `lpr-command' and | ||
| 1946 | `lpr-switches' as default." | ||
| 1947 | t) | ||
| 1948 | |||
| 1949 | (autoload 'dired-do-shell-command "dired-aux" | ||
| 1950 | "Run a shell command on the marked files. | ||
| 1951 | If there is output, it goes to a separate buffer. | ||
| 1952 | Normally the command is run on each file individually. | ||
| 1953 | However, if there is a `*' in the command then it is run | ||
| 1954 | just once with the entire file list substituted there. | ||
| 1955 | |||
| 1956 | If no files are marked or a specific numeric prefix arg is given, | ||
| 1957 | the next ARG files are used. Just \\[universal-argument] means the current file. | ||
| 1958 | The prompt mentions the file(s) or the marker, as appropriate. | ||
| 1959 | |||
| 1960 | No automatic redisplay is attempted, as the file names may have | ||
| 1961 | changed. Type \\[dired-do-redisplay] to redisplay the marked files. | ||
| 1962 | |||
| 1963 | The shell command has the top level directory as working directory, so | ||
| 1964 | output files usually are created there instead of in a subdir." | ||
| 1965 | t) | ||
| 1966 | |||
| 1967 | (autoload 'dired-kill-line-or-subdir "dired-aux" | ||
| 1968 | "Kill this line (but don't delete its file). | ||
| 1969 | Optional prefix argument is a repeat factor. | ||
| 1970 | If file is displayed as in situ subdir, kill that as well. | ||
| 1971 | If on a subdir headerline, kill whole subdir." | ||
| 1972 | t) | ||
| 1973 | |||
| 1974 | (autoload 'dired-do-kill-lines "dired-aux" | ||
| 1975 | "Kill all marked lines (not the files). | ||
| 1976 | With a prefix arg, kill all lines not marked or flagged." | ||
| 1977 | t) | ||
| 1978 | |||
| 1979 | (autoload 'dired-do-compress "dired-aux" | ||
| 1980 | "Compress or uncompress marked (or next ARG) files." | ||
| 1981 | t) | ||
| 1982 | |||
| 1983 | (autoload 'dired-do-byte-compile "dired-aux" | ||
| 1984 | "Byte compile marked (or next ARG) Emacs Lisp files." | ||
| 1985 | t) | ||
| 1986 | |||
| 1987 | (autoload 'dired-do-load "dired-aux" | ||
| 1988 | "Load the marked (or next ARG) Emacs Lisp files." | ||
| 1989 | t) | ||
| 1990 | |||
| 1991 | (autoload 'dired-do-redisplay "dired-aux" | ||
| 1992 | "Redisplay all marked (or next ARG) files. | ||
| 1993 | If on a subdir line, redisplay that subdirectory. In that case, | ||
| 1994 | a prefix arg lets you edit the `ls' switches used for the new listing." | ||
| 1995 | t) | ||
| 1996 | |||
| 1997 | (autoload 'dired-string-replace-match "dired-aux" | ||
| 1998 | "Replace first match of REGEXP in STRING with NEWTEXT. | ||
| 1999 | If it does not match, nil is returned instead of the new string. | ||
| 2000 | Optional arg LITERAL means to take NEWTEXT literally. | ||
| 2001 | Optional arg GLOBAL means to replace all matches." | ||
| 2002 | t) | ||
| 2003 | |||
| 2004 | (autoload 'dired-create-directory "dired-aux" | ||
| 524 | "Create a directory called DIRECTORY." | 2005 | "Create a directory called DIRECTORY." |
| 525 | (interactive "FCreate directory: ") | 2006 | t) |
| 526 | (let ((expanded (expand-file-name directory))) | ||
| 527 | (make-directory expanded) | ||
| 528 | (dired-add-entry (file-name-directory expanded) | ||
| 529 | (file-name-nondirectory expanded)) | ||
| 530 | (dired-next-line 1))) | ||
| 531 | |||
| 532 | (defun dired-move-file (to-dir &optional count) | ||
| 533 | "Move this file to directory TO-DIR. | ||
| 534 | Optional second argument COUNT (the prefix argument) | ||
| 535 | specifies moving several consecutive files." | ||
| 536 | (interactive | ||
| 537 | (let ((count (prefix-numeric-value current-prefix-arg))) | ||
| 538 | (list (read-file-name (format "Move %s to directory: " | ||
| 539 | (if (> count 1) | ||
| 540 | (format "%d files" count) | ||
| 541 | (file-name-nondirectory (dired-get-filename)))) | ||
| 542 | nil t) | ||
| 543 | count))) | ||
| 544 | (let ((dir (file-name-as-directory (expand-file-name to-dir)))) | ||
| 545 | (dired-repeat-over-lines | ||
| 546 | count | ||
| 547 | (function (lambda () | ||
| 548 | (let ((this (dired-get-filename))) | ||
| 549 | (rename-file this | ||
| 550 | (expand-file-name (file-name-nondirectory this) | ||
| 551 | dir))) | ||
| 552 | (let ((buffer-read-only nil)) | ||
| 553 | (beginning-of-line) | ||
| 554 | (delete-region (point) (progn (forward-line 1) (point)))) | ||
| 555 | t))))) | ||
| 556 | |||
| 557 | (defun dired-rename-file (to-file) | ||
| 558 | "Rename the current file to TO-FILE." | ||
| 559 | (interactive | ||
| 560 | (list (read-file-name (format "Rename %s to: " | ||
| 561 | (file-name-nondirectory (dired-get-filename))) | ||
| 562 | nil (dired-get-filename)))) | ||
| 563 | (setq to-file (expand-file-name to-file)) | ||
| 564 | (let ((filename (dired-get-filename)) | ||
| 565 | (buffer-read-only nil)) | ||
| 566 | (rename-file filename to-file) | ||
| 567 | (beginning-of-line) | ||
| 568 | (delete-region (point) (progn (forward-line 1) (point))) | ||
| 569 | (setq to-file (expand-file-name to-file)) | ||
| 570 | (dired-add-entry (file-name-directory to-file) | ||
| 571 | (file-name-nondirectory to-file)) | ||
| 572 | ;; Optionally rename the visited file of any buffer visiting this file. | ||
| 573 | (and (get-file-buffer filename) | ||
| 574 | (y-or-n-p (message "Change visited file name of buffer %s too? " | ||
| 575 | (buffer-name (get-file-buffer filename)))) | ||
| 576 | (save-excursion | ||
| 577 | (set-buffer (get-file-buffer filename)) | ||
| 578 | (let ((modflag (buffer-modified-p))) | ||
| 579 | (set-visited-file-name to-file) | ||
| 580 | (set-buffer-modified-p modflag)))))) | ||
| 581 | |||
| 582 | (defun dired-copy-file (to-file) | ||
| 583 | "Copy the current file to TO-FILE." | ||
| 584 | (interactive "FCopy to: ") | ||
| 585 | (copy-file (dired-get-filename) to-file) | ||
| 586 | (setq to-file (expand-file-name to-file)) | ||
| 587 | (dired-add-entry (file-name-directory to-file) | ||
| 588 | (file-name-nondirectory to-file))) | ||
| 589 | |||
| 590 | (defun dired-add-entry (directory filename) | ||
| 591 | ;; If tree dired is implemented, this function will have to do | ||
| 592 | ;; something smarter with the directory. Currently, just check | ||
| 593 | ;; default directory, if same, add the new entry at point. With tree | ||
| 594 | ;; dired, should call 'dired-current-directory' or similar. Note | ||
| 595 | ;; that this adds the entry 'out of order' if files sorted by time, | ||
| 596 | ;; etc. | ||
| 597 | (if (string-equal directory default-directory) | ||
| 598 | (let ((buffer-read-only nil)) | ||
| 599 | (beginning-of-line) | ||
| 600 | (call-process "ls" nil t nil | ||
| 601 | "-d" dired-listing-switches (concat directory filename)) | ||
| 602 | (forward-line -1) | ||
| 603 | (insert " ") | ||
| 604 | (dired-move-to-filename) | ||
| 605 | (let* ((beg (point)) | ||
| 606 | (end (progn (end-of-line) (point)))) | ||
| 607 | (setq filename (buffer-substring beg end)) | ||
| 608 | (delete-region beg end) | ||
| 609 | (insert (file-name-nondirectory filename))) | ||
| 610 | (beginning-of-line)))) | ||
| 611 | |||
| 612 | (defun dired-diff (point mark) | ||
| 613 | "Compare files at POINT1 and POINT2 by running `diff'. | ||
| 614 | Interactively, these are the files at point and mark. | ||
| 615 | The file at mark (POINT2) is the first file given to `diff'. | ||
| 616 | See the command `diff'." | ||
| 617 | (interactive "d\nm") | ||
| 618 | (let (name1 name2) | ||
| 619 | (setq name2 (dired-get-filename)) | ||
| 620 | (save-excursion | ||
| 621 | (goto-char mark) | ||
| 622 | (setq name1 (dired-get-filename))) | ||
| 623 | (diff name1 name2))) | ||
| 624 | 2007 | ||
| 625 | (defun dired-compress () | 2008 | (autoload 'dired-do-copy "dired-aux" |
| 626 | "Compress the current file." | 2009 | "Copy all marked (or next ARG) files, or copy the current file. |
| 627 | (interactive) | 2010 | Thus, a zero prefix argument copies nothing. But it toggles the |
| 628 | (let* ((buffer-read-only nil) | 2011 | variable `dired-copy-preserve-time' (which see)." |
| 629 | (error-buffer (get-buffer-create " *Dired compress output*")) | 2012 | t) |
| 630 | (from-file (dired-get-filename)) | 2013 | |
| 631 | (to-file (concat from-file ".Z"))) | 2014 | (autoload 'dired-do-symlink "dired-aux" |
| 632 | (if (string-match "\\.Z$" from-file) | 2015 | "Make symbolic links to current file or all marked (or next ARG) files. |
| 633 | (error "%s is already compressed!" from-file)) | 2016 | When operating on just the current file, you specify the new name. |
| 634 | (message "Compressing %s..." from-file) | 2017 | When operating on multiple or marked files, you specify a directory |
| 635 | (unwind-protect | 2018 | and new symbolic links are made in that directory |
| 636 | (progn | 2019 | with the same names that the files currently have." |
| 637 | (save-excursion | 2020 | t) |
| 638 | (set-buffer error-buffer) | 2021 | |
| 639 | (erase-buffer)) | 2022 | (autoload 'dired-do-hardlink "dired-aux" |
| 640 | ;; Must have default-directory of dired buffer in call-process | 2023 | "Add names (hard links) current file or all marked (or next ARG) files. |
| 641 | (call-process "compress" nil error-buffer nil "-f" from-file) | 2024 | When operating on just the current file, you specify the new name. |
| 642 | (if (save-excursion | 2025 | When operating on multiple or marked files, you specify a directory |
| 643 | (set-buffer error-buffer) | 2026 | and new hard links are made in that directory |
| 644 | (= 0 (buffer-size))) | 2027 | with the same names that the files currently have." |
| 645 | (progn | 2028 | t) |
| 646 | (message "Compressing %s... done" from-file) | 2029 | |
| 647 | (kill-buffer error-buffer)) | 2030 | (autoload 'dired-do-rename "dired-aux" |
| 648 | (display-buffer error-buffer) | 2031 | "Rename current file or all marked (or next ARG) files. |
| 649 | (setq error-buffer nil) | 2032 | When renaming just the current file, you specify the new name. |
| 650 | (error "Compress error on %s." from-file))) | 2033 | When renaming multiple or marked files, you specify a directory." |
| 651 | (if error-buffer (kill-buffer error-buffer))) | 2034 | t) |
| 652 | (dired-redisplay to-file))) | 2035 | |
| 653 | 2036 | (autoload 'dired-do-rename-regexp "dired-aux" | |
| 654 | (defun dired-uncompress () | 2037 | "Rename marked files containing REGEXP to NEWNAME. |
| 655 | "Uncompress the current file." | 2038 | As each match is found, the user must type a character saying |
| 656 | (interactive) | 2039 | what to do with it. For directions, type \\[help-command] at that time. |
| 657 | (let* ((buffer-read-only nil) | 2040 | NEWNAME may contain \\=\\<n> or \\& as in `query-replace-regexp'. |
| 658 | (error-buffer (get-buffer-create " *Dired compress output*")) | 2041 | REGEXP defaults to the last regexp used. |
| 659 | (from-file (dired-get-filename)) | 2042 | With a zero prefix arg, renaming by regexp affects the complete |
| 660 | (to-file (substring from-file 0 -2))) | 2043 | pathname - usually only the non-directory part of file names is used |
| 661 | (if (string-match "\\.Z$" from-file) nil | 2044 | and changed." |
| 662 | (error "%s is not compressed!" from-file)) | 2045 | t) |
| 663 | (message "Uncompressing %s..." from-file) | 2046 | |
| 664 | (unwind-protect | 2047 | (autoload 'dired-do-copy-regexp "dired-aux" |
| 665 | (progn | 2048 | "Copy all marked files containing REGEXP to NEWNAME. |
| 666 | (save-excursion | 2049 | See function `dired-rename-regexp' for more info." |
| 667 | (set-buffer error-buffer) | 2050 | t) |
| 668 | (erase-buffer)) | 2051 | |
| 669 | ;; Must have default-directory of dired buffer in call-process | 2052 | (autoload 'dired-do-hardlink-regexp "dired-aux" |
| 670 | (call-process "uncompress" nil error-buffer nil "-f" from-file) | 2053 | "Hardlink all marked files containing REGEXP to NEWNAME. |
| 671 | (if (save-excursion | 2054 | See function `dired-rename-regexp' for more info." |
| 672 | (set-buffer error-buffer) | 2055 | t) |
| 673 | (= 0 (buffer-size))) | 2056 | |
| 674 | (progn | 2057 | (autoload 'dired-do-symlink-regexp "dired-aux" |
| 675 | (message "Uncompressing %s... done" from-file) | 2058 | "Symlink all marked files containing REGEXP to NEWNAME. |
| 676 | (kill-buffer error-buffer)) | 2059 | See function `dired-rename-regexp' for more info." |
| 677 | (display-buffer error-buffer) | 2060 | t) |
| 678 | (setq error-buffer nil) | 2061 | |
| 679 | (error "Uncompress error on %s." from-file))) | 2062 | (autoload 'dired-upcase "dired-aux" |
| 680 | (if error-buffer (kill-buffer error-buffer))) | 2063 | "Rename all marked (or next ARG) files to upper case." |
| 681 | (dired-redisplay to-file))) | 2064 | t) |
| 682 | 2065 | ||
| 683 | (defun dired-byte-recompile () | 2066 | (autoload 'dired-downcase "dired-aux" |
| 684 | "Byte recompile the current file." | 2067 | "Rename all marked (or next ARG) files to lower case." |
| 685 | (interactive) | 2068 | t) |
| 686 | (let* ((buffer-read-only nil) | 2069 | |
| 687 | (from-file (dired-get-filename)) | 2070 | (autoload 'dired-maybe-insert-subdir "dired-aux" |
| 688 | (to-file (substring from-file 0 -3))) | 2071 | "Insert this subdirectory into the same dired buffer. |
| 689 | (if (string-match "\\.el$" from-file) nil | 2072 | If it is already present, just move to it (type \\[dired-do-redisplay] to refresh), |
| 690 | (error "%s is uncompilable!" from-file)) | 2073 | else inserts it at its natural place (as `ls -lR' would have done). |
| 691 | (byte-compile-file from-file))) | 2074 | With a prefix arg, you may edit the ls switches used for this listing. |
| 692 | 2075 | You can add `R' to the switches to expand the whole tree starting at | |
| 693 | (defun dired-chmod (mode) | 2076 | this subdirectory. |
| 694 | "Change mode of the current file to MODE." | 2077 | This function takes some pains to conform to `ls -lR' output." |
| 695 | (interactive "sChange to Mode: ") | 2078 | t) |
| 696 | (let ((buffer-read-only nil) | 2079 | |
| 697 | (file (dired-get-filename))) | 2080 | (autoload 'dired-next-subdir "dired-aux" |
| 698 | (call-process "/bin/chmod" nil nil nil mode file) | 2081 | "Go to next subdirectory, regardless of level." |
| 699 | (dired-redisplay file))) | 2082 | t) |
| 700 | 2083 | ||
| 701 | (defun dired-chgrp (group) | 2084 | (autoload 'dired-prev-subdir "dired-aux" |
| 702 | "Change group of the current file to GROUP." | 2085 | "Go to previous subdirectory, regardless of level. |
| 703 | (interactive "sChange to Group: ") | 2086 | When called interactively and not on a subdir line, go to this subdir's line." |
| 704 | (let ((buffer-read-only nil) | 2087 | t) |
| 705 | (file (dired-get-filename))) | 2088 | |
| 706 | (call-process "/bin/chgrp" nil nil nil group file) | 2089 | (autoload 'dired-goto-subdir "dired-aux" |
| 707 | (dired-redisplay file))) | 2090 | "Go to end of header line of DIR in this dired buffer. |
| 708 | 2091 | Return value of point on success, otherwise return nil. | |
| 709 | (defun dired-chown (owner) | 2092 | The next char is either \\n, or \\r if DIR is hidden." |
| 710 | "Change owner of the current file to OWNER." | 2093 | t) |
| 711 | (interactive "sChange to Owner: ") | 2094 | |
| 712 | (let ((buffer-read-only nil) | 2095 | (autoload 'dired-mark-subdir-files "dired-aux" |
| 713 | (file (dired-get-filename))) | 2096 | "Mark all files except `.' and `..'." |
| 714 | (call-process dired-chown-program | 2097 | t) |
| 715 | nil nil nil owner file) | 2098 | |
| 716 | (dired-redisplay file))) | 2099 | (autoload 'dired-kill-subdir "dired-aux" |
| 717 | 2100 | "Remove all lines of current subdirectory. | |
| 718 | (defun dired-redisplay (&optional file) | 2101 | Lower levels are unaffected." |
| 719 | "Delete the current line, and insert an entry for file FILE. | 2102 | t) |
| 720 | If FILE is nil, then just delete the current line." | 2103 | |
| 721 | (beginning-of-line) | 2104 | (autoload 'dired-tree-up "dired-aux" |
| 722 | (delete-region (point) (progn (forward-line 1) (point))) | 2105 | "Go up ARG levels in the dired tree." |
| 723 | (if file (dired-add-entry (file-name-directory file) | 2106 | t) |
| 724 | (file-name-nondirectory file))) | 2107 | |
| 725 | (dired-move-to-filename)) | 2108 | (autoload 'dired-tree-down "dired-aux" |
| 2109 | "Go down in the dired tree." | ||
| 2110 | t) | ||
| 2111 | |||
| 2112 | (autoload 'dired-hide-subdir "dired-aux" | ||
| 2113 | "Hide or unhide the current subdirectory and move to next directory. | ||
| 2114 | Optional prefix arg is a repeat factor. | ||
| 2115 | Use \\[dired-hide-all] to (un)hide all directories." | ||
| 2116 | t) | ||
| 2117 | |||
| 2118 | (autoload 'dired-hide-all "dired-aux" | ||
| 2119 | "Hide all subdirectories, leaving only their header lines. | ||
| 2120 | If there is already something hidden, make everything visible again. | ||
| 2121 | Use \\[dired-hide-subdir] to (un)hide a particular subdirectory." | ||
| 2122 | t) | ||
| 726 | 2123 | ||
| 727 | (defun dired-do-deletions () | 2124 | (if (eq system-type 'vax-vms) |
| 728 | "In dired, delete the files flagged for deletion." | 2125 | (load "dired-vms")) |
| 729 | (interactive) | ||
| 730 | (let (delete-list answer) | ||
| 731 | (save-excursion | ||
| 732 | (goto-char 1) | ||
| 733 | (while (re-search-forward "^D" nil t) | ||
| 734 | (setq delete-list | ||
| 735 | (cons (cons (dired-get-filename t) (1- (point))) | ||
| 736 | delete-list)))) | ||
| 737 | (if (null delete-list) | ||
| 738 | (message "(No deletions requested)") | ||
| 739 | (save-window-excursion | ||
| 740 | (set-buffer (get-buffer-create " *Deletions*")) | ||
| 741 | (funcall (if (> (length delete-list) (* (window-height) 2)) | ||
| 742 | 'switch-to-buffer 'switch-to-buffer-other-window) | ||
| 743 | (current-buffer)) | ||
| 744 | (erase-buffer) | ||
| 745 | (setq fill-column 70) | ||
| 746 | (let ((l (reverse delete-list))) | ||
| 747 | ;; Files should be in forward order for this loop. | ||
| 748 | (while l | ||
| 749 | (if (> (current-column) 59) | ||
| 750 | (insert ?\n) | ||
| 751 | (or (bobp) | ||
| 752 | (indent-to (* (/ (+ (current-column) 19) 20) 20) 1))) | ||
| 753 | (insert (car (car l))) | ||
| 754 | (setq l (cdr l)))) | ||
| 755 | (goto-char (point-min)) | ||
| 756 | (setq answer (yes-or-no-p "Delete these files? "))) | ||
| 757 | (if answer | ||
| 758 | (let ((l delete-list) | ||
| 759 | failures) | ||
| 760 | ;; Files better be in reverse order for this loop! | ||
| 761 | ;; That way as changes are made in the buffer | ||
| 762 | ;; they do not shift the lines still to be changed. | ||
| 763 | (while l | ||
| 764 | (goto-char (cdr (car l))) | ||
| 765 | (let ((buffer-read-only nil)) | ||
| 766 | (condition-case () | ||
| 767 | (let ((fn (concat default-directory (car (car l))))) | ||
| 768 | (if (file-directory-p fn) | ||
| 769 | (progn | ||
| 770 | (remove-directory fn) | ||
| 771 | (if (file-exists-p fn) (delete-file fn))) | ||
| 772 | (delete-file fn)) | ||
| 773 | (delete-region (point) | ||
| 774 | (progn (forward-line 1) (point)))) | ||
| 775 | (error (delete-char 1) | ||
| 776 | (insert " ") | ||
| 777 | (setq failures (cons (car (car l)) failures))))) | ||
| 778 | (setq l (cdr l))) | ||
| 779 | (if failures | ||
| 780 | (message "Deletions failed: %s" | ||
| 781 | (prin1-to-string failures)))))))) | ||
| 782 | 2126 | ||
| 783 | (provide 'dired) | 2127 | (run-hooks 'dired-load-hook) ; for your customizations |
| 784 | 2128 | ||
| 785 | ;;; dired.el ends here | ||