diff lisp/efs/dired-cmpr.el @ 22:8fc7fe29b841 r19-15b94

Import from CVS: tag r19-15b94
author cvs
date Mon, 13 Aug 2007 08:50:29 +0200
parents
children 7e54bd776075 9f59509498e1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/efs/dired-cmpr.el	Mon Aug 13 08:50:29 2007 +0200
@@ -0,0 +1,315 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; File:          dired-cmpr.el
+;; Dired Version: $Revision: 1.1 $
+;; RCS:
+;; Description:   Commands for compressing marked files.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Requirements and provisions
+(provide 'dired-cmpr)
+(require 'dired)
+
+;;; Entry points.
+
+(defun dired-do-compress (&optional arg files)
+  "Compress or uncompress marked (or next ARG) files.
+With a zero prefix, prompts for a new value of `dired-compression-method'."
+  (interactive
+   (let ((arg (prefix-numeric-value current-prefix-arg))
+	 files)
+     (if (zerop arg)
+	 (let ((new (completing-read
+		     (format "Set compression method (currently %s): "
+			     dired-compression-method)
+		     (mapcar
+		      (function
+		       (lambda (x)
+			 (cons (symbol-name (car x)) nil)))
+		      dired-compression-method-alist)
+		     nil t)))
+	   (or (string-equal new "")
+	       (setq dired-compression-method (intern new))))
+       (setq files (dired-get-marked-files nil current-prefix-arg))
+       (or (memq 'compress dired-no-confirm)
+	   (let* ((dir (dired-current-directory))
+		  (rfiles (mapcar (function
+				   (lambda (fn)
+				     (dired-make-relative fn dir t)))
+				    files))
+		  (prompt "")
+		  (comp 0)
+		  (uncomp nil)
+		  (total (length files))
+		  elt)
+	     (mapcar (function
+		      (lambda (fn)
+			(if (listp (setq elt
+					 (dired-make-compressed-filename fn)))
+			    (let* ((method (car (nth 3 elt)))
+				   (count (assoc method uncomp)))
+			      (if count
+				  (setcdr count (1+ (cdr count)))
+				(setq uncomp (cons (cons method 1) uncomp))))
+			  (setq comp (1+ comp)))))
+		     files)
+	     (if (/= comp 0)
+		 (setq prompt
+		       (format "%s %d"
+			       (car
+				(nth 2
+				     (assq dired-compression-method
+					   dired-compression-method-alist)))
+			       comp)))
+	     (if uncomp
+		 (let ((case-fold-search t)
+		       method)
+		   (or (string-equal prompt "")
+		       (setq prompt (concat prompt "; ")))
+		   (setq uncomp
+			 (sort
+			  (mapcar
+			   (function
+			    (lambda (elt)
+			      (setq method (car elt))
+			      (if (string-equal method "gzip")
+				  (setq method "gunzip")
+				(or (string-match "^un" method)
+				    (setq method (concat "un" method))))
+			      (setcar elt method)
+			      elt))
+			   uncomp)
+			  (function
+			   (lambda (x y)
+			     (string< (car x) (car y))))))
+		   (setq prompt
+			 (concat prompt
+				 (mapconcat
+				  (function
+				   (lambda (elt)
+				     (format "%s %d" (car elt) (cdr elt))))
+				  uncomp ", ")))))
+	     (cond
+	      ((= (length rfiles) 1)
+	       (setq prompt (format "%s %s? "
+				    ;; Don't need the number 1
+				    (substring prompt 0 -2)
+				    (car rfiles))))
+	      ((or (> (length uncomp) 1) (and (/= 0 comp) uncomp))
+	       (setq prompt (format "%s? Total: %d file%s " prompt total
+				    (dired-plural-s total))))
+	      ((setq prompt (format "%s file%s? " prompt
+				    (dired-plural-s total)))))
+	     (or (dired-mark-pop-up nil 'compress rfiles 'y-or-n-p prompt)
+		 (setq arg 0)))))
+     (list arg files)))
+       
+  (if (not (zerop arg))
+      (dired-create-files
+       'dired-compress-file
+       "Compress or Uncompress"
+       files
+       (function
+	(lambda (fn)
+	  (let ((cfn (dired-make-compressed-filename fn)))
+	    (if (stringp cfn)
+		cfn
+	      (substring fn 0 (- (length (nth 1 cfn))))))))
+       dired-keep-marker-compress nil t)))
+
+(defun dired-compress-subdir-files (&optional uncompress)
+  "Compress all uncompressed files in the current subdirectory.
+With a prefix argument uncompresses all compressed files."
+  (interactive "P")
+  (let ((dir (dired-current-directory))
+	files methods uncomp elt)
+    (save-excursion
+      (save-restriction
+	(narrow-to-region (dired-subdir-min) (dired-subdir-max))
+	(dired-map-dired-file-lines
+	 (function
+	  (lambda (f)
+	    (if uncompress
+		(and (listp (setq uncomp (dired-make-compressed-filename f)))
+		     (let ((program (car (nth 3 uncomp))))
+		       (setq files (cons f files))
+		       (if (setq elt (assoc program methods))
+			   (setcdr elt (1+ (cdr elt)))
+			 (setq methods (cons (cons program 1) methods)))))
+	      (and (stringp (dired-make-compressed-filename f))
+		   (setq files (cons f files)))))))))
+    (if files
+	(let ((total (length files))
+	      (rfiles (mapcar
+		       (function
+			(lambda (fn)
+			  (dired-make-relative fn dir t)))
+		       files))
+	      prompt)
+	  (if uncompress
+	      (progn
+		(setq prompt (mapconcat
+			      (function
+			       (lambda (x)
+				 (format "%s %d"
+					 (if (string-equal (car x) "gzip")
+					     "gunzip"
+					   (if (string-match "^un" (car x))
+					       (car x)
+					     (concat "un" (car x))))
+					 (cdr x))))
+			      methods ", "))
+		(cond
+		 ((= total 1)
+		  (setq prompt
+			(concat (substring prompt 0 -1) (car rfiles) "? ")))
+		 ((= (length methods) 1)
+		  (setq prompt
+			(format "%s file%s? " prompt (dired-plural-s total))))
+		 (t
+		  (setq prompt (format "%s? Total: %d file%s " prompt total
+				       (dired-plural-s total))))))
+	    (setq prompt
+		  (if (= total 1)
+		      (format "%s %s? " dired-compression-method (car rfiles))
+		    (format "%s %d file%s? "
+			    dired-compression-method total
+			    (dired-plural-s total)))))
+	  (if (dired-mark-pop-up nil 'compress rfiles 'y-or-n-p prompt)
+	      (dired-create-files
+	       'dired-compress-file
+	       "Compress or Uncompress"
+	       files
+	       (function
+		(lambda (fn)
+		  (let ((cfn (dired-make-compressed-filename fn)))
+		    (if (stringp cfn)
+			cfn
+		      (substring fn 0 (- (length (nth 1 cfn))))))))
+	       dired-keep-marker-compress nil t)))
+      (message "No files need %scompressing in %s."
+	       (if uncompress "un" "")
+	       (dired-abbreviate-file-name dir)))))
+
+(defun dired-compress-file (file ok-flag)
+  ;; Compress or uncompress FILE.
+  ;; If ok-flag is non-nil, it is OK to overwrite an existing
+  ;; file. How well this actually works may depend on the compression
+  ;; program.
+  ;; Return the name of the compressed or uncompressed file.
+  (let ((handler (find-file-name-handler file 'dired-compress-file)))
+    (if handler
+	(funcall handler 'dired-compress-file file ok-flag)
+      (let ((compressed-fn (dired-make-compressed-filename file))
+	    (err-buff (get-buffer-create " *dired-check-process output*")))
+	(save-excursion
+	  (set-buffer err-buff)
+	  (erase-buffer)
+	  (cond ((file-symlink-p file)
+		 (signal 'file-error (list "Error compressing file"
+					   file "a symbolic link")))
+		((listp compressed-fn)
+		 (message "Uncompressing %s..." file)
+		 (let* ((data (nth 3 compressed-fn))
+			(ret
+			 (apply 'call-process
+				(car data) file t nil
+				(append (cdr data)
+					(and ok-flag
+					     (list (nth 4 compressed-fn)))
+					(list file)))))
+		   (if (or (and (integerp ret) (/= ret 0))
+			   (not (bobp)))
+		       (signal 'file-error
+			       (nconc
+				(list "Error uncompressing file"
+				      file)
+				(and (not (bobp))
+				     (list
+				      (progn
+					(goto-char (point-min))
+					(buffer-substring
+					 (point) (progn (end-of-line)
+							(point))))))))))
+		 (message "Uncompressing %s...done" file)
+		 (dired-remove-file file)
+		 (let ((to (substring file 0
+				      (- (length (nth 1 compressed-fn))))))
+		   ;; rename any buffers
+		   (and (get-file-buffer file)
+			(save-excursion
+			  (set-buffer (get-file-buffer file))
+			  (let ((modflag (buffer-modified-p)))
+			    ;; kills write-file-hooks
+			    (set-visited-file-name to)	
+			    (set-buffer-modified-p modflag))))
+		   to))
+		((stringp compressed-fn)
+		 (message "Compressing %s..." file)
+		 (let* ((data (assq dired-compression-method
+				    dired-compression-method-alist))
+			(compr-args (nth 2 data))
+			(ret
+			 (apply 'call-process
+				(car compr-args) file t nil
+				(append (cdr compr-args)
+					(and ok-flag
+					     (list (nth 4 data)))
+					(list file)))))
+		   (if (or (and (integerp ret) (/= ret 0))
+			   (not (bobp)))
+		       (signal 'file-error
+			       (nconc
+				(list "Error compressing file"
+				      file)
+				(and (not (bobp))
+				     (list
+				      (progn
+					(goto-char (point-min))
+					(buffer-substring
+					 (point) (progn (end-of-line)
+							(point))))))))))
+		 (message "Compressing %s...done" file)
+		 (dired-remove-file file)
+		 ;; rename any buffers
+		 (and (get-file-buffer file)
+		      (save-excursion
+			(set-buffer (get-file-buffer file))
+			(let ((modflag (buffer-modified-p)))
+			  ;; kills write-file-hooks
+			  (set-visited-file-name compressed-fn)	
+			  (set-buffer-modified-p modflag))))
+		 compressed-fn)
+		(t (error "Strange error in dired-compress-file."))))))))
+
+(defun dired-make-compressed-filename (name &optional method)
+  ;; If NAME is in the syntax of a compressed file (according to
+  ;; dired-compression-method-alist), return the data (a list) from this
+  ;; alist on how to uncompress it. Otherwise, return a string, the
+  ;; compressed form of this file name. This is computed using the optional
+  ;; argument METHOD (a symbol). If METHOD is nil, the ambient value of
+  ;; dired-compression-method is used.
+  (let ((handler (find-file-name-handler
+		  name 'dired-make-compressed-filename)))
+    (if handler
+	(funcall handler 'dired-make-compressed-filename name method)
+      (let ((alist dired-compression-method-alist)
+	    (len (length name))
+	    ext ext-len result)
+	(while alist
+	  (if (and (> len
+		      (setq ext-len (length (setq ext (nth 1 (car alist))))))
+		   (string-equal ext (substring name (- ext-len))))
+	      (setq result (car alist)
+		    alist nil)
+	    (setq alist (cdr alist))))
+	(or result
+	    (concat name
+		    (nth 1 (or (assq (or method dired-compression-method)
+				     dired-compression-method-alist)
+			       (error "Unknown compression method: %s"
+				      (or method dired-compression-method))))))
+	))))
+
+;;; end of dired-cmpr.el