X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0b1c32a15f983fdb6691de0a99b256cab4a3f03f..b2a577ecba1690db0f631f5fcf514685a7be06aa:/lisp/dired-aux.el diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index e08094ff2d..ccf8548f47 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -1,8 +1,9 @@ ;;; dired-aux.el --- less commonly used parts of dired -*-byte-compile-dynamic: t;-*- -;; Copyright (C) 1985, 1986, 1992, 1994 Free Software Foundation, Inc. +;; Copyright (C) 1985, 1986, 1992, 1994, 1998 Free Software Foundation, Inc. ;; Author: Sebastian Kremer . +;; Maintainer: FSF ;; This file is part of GNU Emacs. @@ -17,8 +18,9 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. ;;; Commentary: @@ -97,7 +99,10 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'." (setq failures (dired-bunch-files 10000 (function dired-check-process) - (list operation program new-attribute) + (append + (list operation program new-attribute) + (if (string-match "gnu" system-configuration) + '("--") nil)) files)) (dired-do-redisplay arg);; moves point if ARG is an integer (if failures @@ -240,7 +245,7 @@ with a prefix argument." (defun dired-map-dired-file-lines (fun) ;; Perform FUN with point at the end of each non-directory line. - ;; FUN takes one argument, the filename (complete pathname). + ;; FUN takes one argument, the absolute filename. (save-excursion (let (file buffer-read-only) (goto-char (point-min)) @@ -263,7 +268,7 @@ with a prefix argument." ;;The caller may want to flag some of these files for deletion. (let* ((base-versions (concat (file-name-nondirectory fn) ".~")) - (bv-length (length base-versions)) + (backup-extract-version-start (length base-versions)) (possibilities (file-name-all-completions base-versions (file-name-directory fn))) @@ -287,18 +292,6 @@ with a prefix argument." (insert dired-del-marker))))) ;;; Shell commands -;;>>> install (move this function into simple.el) -(defun dired-shell-quote (filename) - "Quote a file name for inferior shell (see variable `shell-file-name')." - ;; Quote everything except POSIX filename characters. - ;; This should be safe enough even for really weird shells. - (let ((result "") (start 0) end) - (while (string-match "[^-0-9a-zA-Z_./]" filename start) - (setq end (match-beginning 0) - result (concat result (substring filename start end) - "\\" (substring filename end (1+ end))) - start (1+ end))) - (concat result (substring filename start)))) (defun dired-read-shell-command (prompt arg files) ;; "Read a dired shell command prompting with PROMPT (using read-string). @@ -314,7 +307,7 @@ with a prefix argument." ;; The in-background argument is only needed in Emacs 18 where ;; shell-command doesn't understand an appended ampersand `&'. ;;;###autoload -(defun dired-do-shell-command (command &optional arg) +(defun dired-do-shell-command (command &optional arg file-list) "Run a shell command COMMAND on the marked files. If no files are marked or a specific numeric prefix arg is given, the next ARG files are used. Just \\[universal-argument] means the current file. @@ -334,16 +327,17 @@ The shell command has the top level directory as working directory, so output files usually are created there instead of in a subdir." ;;Functions dired-run-shell-command and dired-shell-stuff-it do the ;;actual work and can be redefined for customization. - (interactive (list - ;; Want to give feedback whether this file or marked files are used: - (dired-read-shell-command (concat "! on " - "%s: ") - current-prefix-arg - (dired-get-marked-files - t current-prefix-arg)) - current-prefix-arg)) - (let* ((on-each (not (string-match "\\*" command))) - (file-list (dired-get-marked-files t arg))) + (interactive + (let ((files (dired-get-marked-files t current-prefix-arg))) + (list + ;; Want to give feedback whether this file or marked files are used: + (dired-read-shell-command (concat "! on " + "%s: ") + current-prefix-arg + files) + current-prefix-arg + files))) + (let* ((on-each (not (string-match "\\*" command)))) (if on-each (dired-bunch-files (- 10000 (length command)) @@ -381,8 +375,8 @@ output files usually are created there instead of in a subdir." (dired-replace-in-string "\\*" x command))) (function (lambda (x) (concat command " " x)))))) (if on-each - (mapconcat stuff-it (mapcar 'dired-shell-quote file-list) ";") - (let ((fns (mapconcat 'dired-shell-quote + (mapconcat stuff-it (mapcar 'shell-quote-argument file-list) ";") + (let ((fns (mapconcat 'shell-quote-argument file-list dired-mark-separator))) (if (> (length file-list) 1) (setq fns (concat dired-mark-prefix fns dired-mark-postfix))) @@ -390,7 +384,11 @@ output files usually are created there instead of in a subdir." ;; This is an extra function so that it can be redefined by ange-ftp. (defun dired-run-shell-command (command) - (shell-command command) + (let ((handler + (find-file-name-handler (directory-file-name default-directory) + 'shell-command))) + (if handler (apply handler 'shell-command (list command)) + (shell-command command))) ;; Return nil for sake of nconc in dired-bunch-files. nil) @@ -399,7 +397,13 @@ output files usually are created there instead of in a subdir." (defun dired-call-process (program discard &rest arguments) ; "Run PROGRAM with output to current buffer unless DISCARD is t. ;Remaining arguments are strings passed as command arguments to PROGRAM." - (apply 'call-process program nil (not discard) nil arguments)) + ;; Look for a handler for default-directory in case it is a remote file name. + (let ((handler + (find-file-name-handler (directory-file-name default-directory) + 'dired-call-process))) + (if handler (apply handler 'dired-call-process + program discard arguments) + (apply 'call-process program nil (not discard) nil arguments)))) (defun dired-check-process (msg program &rest arguments) ; "Display MSG while running PROGRAM, and check for output. @@ -507,45 +511,74 @@ and use this command with a prefix argument (the value does not matter)." (dired-log (concat "Failed to compress" from-file)) from-file))) +(defvar dired-compress-file-suffixes + '(("\\.gz\\'" "" "gunzip") + ("\\.tgz\\'" ".tar" "gunzip") + ("\\.Z\\'" "" "uncompress") + ;; For .z, try gunzip. It might be an old gzip file, + ;; or it might be from compact? pack? (which?) but gunzip handles both. + ("\\.z\\'" "" "gunzip") + ("\\.bz2\\'" "" "bunzip2") + ;; This item controls naming for compression. + ("\\.tar\\'" ".tgz" nil)) + "Control changes in file name suffixes for compression and uncompression. +Each element specifies one transformation rule, and has the form: + (REGEXP NEW-SUFFIX PROGRAM) +The rule applies when the old file name matches REGEXP. +The new file name is computed by deleting the part that matches REGEXP + (as well as anything after that), then adding NEW-SUFFIX in its place. +If PROGRAM is non-nil, the rule is an uncompression rule, +and uncompression is done by running PROGRAM. +Otherwise, the rule is a compression rule, and compression is done with gzip.") + ;;;###autoload (defun dired-compress-file (file) ;; Compress or uncompress FILE. ;; Return the name of the compressed or uncompressed file. ;; Return nil if no change in files. - (let ((handler (find-file-name-handler file 'dired-compress-file))) + (let ((handler (find-file-name-handler file 'dired-compress-file)) + suffix newname + (suffixes dired-compress-file-suffixes)) + ;; See if any suffix rule matches this file name. + (while suffixes + (let (case-fold-search) + (if (string-match (car (car suffixes)) file) + (setq suffix (car suffixes) suffixes nil)) + (setq suffixes (cdr suffixes)))) + ;; If so, compute desired new name. + (if suffix + (setq newname (concat (substring file 0 (match-beginning 0)) + (nth 1 suffix)))) (cond (handler (funcall handler 'dired-compress-file file)) ((file-symlink-p file) nil) - ((let (case-fold-search) - (string-match "\\.Z$" file)) - (if (not (dired-check-process (concat "Uncompressing " file) - "uncompress" file)) - (substring file 0 -2))) - ((let (case-fold-search) - (string-match "\\.gz$" file)) + ((and suffix (nth 2 suffix)) + ;; We found an uncompression rule. (if (not (dired-check-process (concat "Uncompressing " file) - "gunzip" file)) - (substring file 0 -3))) - ;; For .z, try gunzip. It might be an old gzip file, - ;; or it might be from compact? pack? (which?) but gunzip handles - ;; both. - ((let (case-fold-search) - (string-match "\\.z$" file)) - (if (not (dired-check-process (concat "Uncompressing " file) - "gunzip" file)) - (substring file 0 -2))) + (nth 2 suffix) file)) + newname)) (t + ;;; We don't recognize the file as compressed, so compress it. ;;; Try gzip; if we don't have that, use compress. (condition-case nil (if (not (dired-check-process (concat "Compressing " file) "gzip" "-f" file)) - (cond ((file-exists-p (concat file ".gz")) - (concat file ".gz")) - (t (concat file ".z")))) + (let ((out-name + (if (file-exists-p (concat file ".gz")) + (concat file ".gz") + (concat file ".z")))) + ;; Rename the compressed file to NEWNAME + ;; if it hasn't got that name already. + (if (and newname (not (equal newname out-name))) + (progn + (rename-file out-name newname t) + newname) + out-name))) (file-error (if (not (dired-check-process (concat "Compressing " file) "compress" "-f" file)) + ;; Don't use NEWNAME with `compress'. (concat file ".Z")))))))) (defun dired-mark-confirm (op-symbol arg) @@ -554,7 +587,8 @@ and use this command with a prefix argument (the value does not matter)." ;; Confirmation consists in a y-or-n question with a file list ;; pop-up unless OP-SYMBOL is a member of `dired-no-confirm'. ;; The files used are determined by ARG (as in dired-get-marked-files). - (or (memq op-symbol dired-no-confirm) + (or (eq dired-no-confirm t) + (memq op-symbol dired-no-confirm) (let ((files (dired-get-marked-files t arg)) (string (if (eq op-symbol 'compress) "Compress or uncompress" (capitalize (symbol-name op-symbol))))) @@ -649,6 +683,8 @@ and use this command with a prefix argument (the value does not matter)." (error (setq failure err))) (setq elc-file (byte-compile-dest-file filename)) + (or (file-exists-p elc-file) + (setq failure t)) (if failure (progn (dired-log "Byte compile error for %s:\n%s\n" filename failure) @@ -715,16 +751,20 @@ a prefix arg lets you edit the `ls' switches used for the new listing." (delete-region (point) (progn (forward-line 1) (point))) (if file (progn - (dired-add-entry file) + (dired-add-entry file nil t) ;; Replace space by old marker without moving point. ;; Faster than goto+insdel inside a save-excursion? (subst-char-in-region opoint (1+ opoint) ?\040 char)))) (dired-move-to-filename)) -(defun dired-fun-in-all-buffers (directory fun &rest args) +(defun dired-fun-in-all-buffers (directory file fun &rest args) ;; In all buffers dired'ing DIRECTORY, run FUN with ARGS. + ;; If the buffer has a wildcard pattern, check that it matches FILE. + ;; (FILE does not include a directory component.) + ;; FILE may be nil, in which case ignore it. ;; Return list of buffers where FUN succeeded (i.e., returned non-nil). - (let ((buf-list (dired-buffers-for-dir (expand-file-name directory))) + (let ((buf-list (dired-buffers-for-dir (expand-file-name directory) + file)) (obuf (current-buffer)) buf success-list) (while buf-list @@ -741,10 +781,10 @@ a prefix arg lets you edit the `ls' switches used for the new listing." ;;;###autoload (defun dired-add-file (filename &optional marker-char) (dired-fun-in-all-buffers - (file-name-directory filename) + (file-name-directory filename) (file-name-nondirectory filename) (function dired-add-entry) filename marker-char)) -(defun dired-add-entry (filename &optional marker-char) +(defun dired-add-entry (filename &optional marker-char relative) ;; Add a new entry for FILENAME, optionally marking it ;; with MARKER-CHAR (a character, else dired-marker-char is used). ;; Note that this adds the entry `out of order' if files sorted by @@ -754,12 +794,15 @@ a prefix arg lets you edit the `ls' switches used for the new listing." ;; Hidden subdirs are exposed if a file is added there. (setq filename (directory-file-name filename)) ;; Entry is always for files, even if they happen to also be directories - (let ((opoint (point)) + (let* ((opoint (point)) (cur-dir (dired-current-directory)) (orig-file-name filename) - (directory (file-name-directory filename)) + (directory (if relative cur-dir (file-name-directory filename))) reason) - (setq filename (file-name-nondirectory filename) + (setq filename + (if relative + (file-relative-name filename directory) + (file-name-nondirectory filename)) reason (catch 'not-found (if (string= directory cur-dir) @@ -846,7 +889,8 @@ a prefix arg lets you edit the `ls' switches used for the new listing." ;;;###autoload (defun dired-remove-file (file) (dired-fun-in-all-buffers - (file-name-directory file) (function dired-remove-entry) file)) + (file-name-directory file) (file-name-nondirectory file) + (function dired-remove-entry) file)) (defun dired-remove-entry (file) (save-excursion @@ -858,11 +902,12 @@ a prefix arg lets you edit the `ls' switches used for the new listing." ;;;###autoload (defun dired-relist-file (file) (dired-fun-in-all-buffers (file-name-directory file) + (file-name-nondirectory file) (function dired-relist-entry) file)) (defun dired-relist-entry (file) ;; Relist the line for FILE, or just add it if it did not exist. - ;; FILE must be an absolute pathname. + ;; FILE must be an absolute file name. (let (buffer-read-only marker) ;; If cursor is already on FILE's line delete-region will cause ;; save-excursion to fail because of floating makers, @@ -878,9 +923,13 @@ a prefix arg lets you edit the `ls' switches used for the new listing." ;;; Copy, move/rename, making hard and symbolic links -(defvar dired-backup-overwrite nil +(defcustom dired-backup-overwrite nil "*Non-nil if Dired should ask about making backups before overwriting files. -Special value `always' suppresses confirmation.") +Special value `always' suppresses confirmation." + :type '(choice (const :tag "off" nil) + (const :tag "suppress" always) + (other :tag "ask" t)) + :group 'dired) (defvar dired-overwrite-confirmed) @@ -888,19 +937,24 @@ Special value `always' suppresses confirmation.") ;; Save old version of a to be overwritten file TO. ;; `dired-overwrite-confirmed' and `overwrite-backup-query' are fluid vars ;; from dired-create-files. - (if (and dired-backup-overwrite - dired-overwrite-confirmed - (or (eq 'always dired-backup-overwrite) - (dired-query 'overwrite-backup-query - (format "Make backup for existing file `%s'? " to)))) - (let ((backup (car (find-backup-file-name to)))) - (rename-file to backup 0) ; confirm overwrite of old backup - (dired-relist-entry backup)))) + (let (backup) + (if (and dired-backup-overwrite + dired-overwrite-confirmed + (setq backup (car (find-backup-file-name to))) + (or (eq 'always dired-backup-overwrite) + (dired-query 'overwrite-backup-query + (format "Make backup for existing file `%s'? " to)))) + (progn + (rename-file to backup 0) ; confirm overwrite of old backup + (dired-relist-entry backup))))) ;;;###autoload (defun dired-copy-file (from to ok-flag) (dired-handle-overwrite to) - (copy-file from to ok-flag dired-copy-preserve-time)) + (condition-case () + (copy-file from to ok-flag dired-copy-preserve-time) + (file-date-error (message "Can't set date") + (sit-for 1)))) ;;;###autoload (defun dired-rename-file (from to ok-flag) @@ -908,11 +962,8 @@ Special value `always' suppresses confirmation.") (rename-file from to ok-flag) ; error is caught in -create-files ;; Silently rename the visited file of any buffer visiting this file. (and (get-file-buffer from) - (save-excursion - (set-buffer (get-file-buffer from)) - (let ((modflag (buffer-modified-p))) - (set-visited-file-name to) - (set-buffer-modified-p modflag)))) + (with-current-buffer (get-file-buffer from) + (set-visited-file-name to nil t))) (dired-remove-file from) ;; See if it's an inserted subdir, and rename that, too. (dired-rename-subdir from to)) @@ -920,7 +971,7 @@ Special value `always' suppresses confirmation.") (defun dired-rename-subdir (from-dir to-dir) (setq from-dir (file-name-as-directory from-dir) to-dir (file-name-as-directory to-dir)) - (dired-fun-in-all-buffers from-dir + (dired-fun-in-all-buffers from-dir nil (function dired-rename-subdir-1) from-dir to-dir) ;; Update visited file name of all affected buffers (let ((expanded-from-dir (expand-file-name from-dir)) @@ -1006,13 +1057,13 @@ Special value `always' suppresses confirmation.") ;; which will be added. The user will be queried if the file already ;; exists. If oldfile is removed by FILE-CREATOR (i.e, it is a ;; rename), it is FILE-CREATOR's responsibility to update dired -;; buffers. FILE-CREATOR must abort by signalling a file-error if it +;; buffers. FILE-CREATOR must abort by signaling a file-error if it ;; could not create newfile. The error is caught and logged. ;; OPERATION (a capitalized string, e.g. `Copy') describes the ;; operation performed. It is used for error logging. -;; FN-LIST is the list of files to copy (full absolute pathnames). +;; FN-LIST is the list of files to copy (full absolute file names). ;; NAME-CONSTRUCTOR returns a newfile for every oldfile, or nil to ;; skip. If it skips files for other reasons than a direct user @@ -1249,7 +1300,7 @@ When renaming multiple or marked files, you specify a directory." ;; ARG as in dired-get-marked-files. ;; Matches each marked file against REGEXP and constructs the new ;; filename from NEWNAME (like in function replace-match). - ;; Optional arg WHOLE-PATH means match/replace the whole pathname + ;; Optional arg WHOLE-PATH means match/replace the whole file name ;; instead of only the non-directory part of the file. ;; Optional arg MARKER-CHAR as in dired-create-files. (let* ((fn-list (dired-get-marked-files nil arg)) @@ -1320,9 +1371,9 @@ As each match is found, the user must type a character saying what to do with it. For directions, type \\[help-command] at that time. NEWNAME may contain \\=\\ or \\& as in `query-replace-regexp'. REGEXP defaults to the last regexp used. -With a zero prefix arg, renaming by regexp affects the complete - pathname - usually only the non-directory part of file names is used - and changed." + +With a zero prefix arg, renaming by regexp affects the absolute file name. +Normally, only the non-directory part of the file name is used and changed." (interactive (dired-mark-read-regexp "Rename")) (dired-do-create-files-regexp (function dired-rename-file) @@ -1595,7 +1646,7 @@ This function takes some pains to conform to `ls -lR' output." (run-hooks 'dired-after-readin-hook)))))) (defun dired-tree-lessp (dir1 dir2) - ;; Lexicographic order on pathname components, like `ls -lR': + ;; Lexicographic order on file name components, like `ls -lR': ;; DIR1 < DIR2 iff DIR1 comes *before* DIR2 in an `ls -lR' listing, ;; i.e., iff DIR1 is a (grand)parent dir of DIR2, ;; or DIR1 and DIR2 are in the same parentdir and their last @@ -1701,7 +1752,9 @@ The next char is either \\n, or \\r if DIR is hidden." ;;;###autoload (defun dired-mark-subdir-files () - "Mark all files except `.' and `..'." + "Mark all files except `.' and `..' in current subdirectory. +If the Dired buffer shows multiple directories, this command +marks the files listed in the subdirectory that point is in." (interactive) (let ((p-min (dired-subdir-min))) (dired-mark-files-in-region p-min (dired-subdir-max))))