emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

compare-directories


From: Juri Linkov
Subject: compare-directories
Date: 29 Aug 2003 09:36:00 +0300
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3.50

Many file managers (e.g. GNU Midnight Commander and other
"Commander"-like file managers) provide the functionality to mark
different files in two panels based on their attributes (time, size).
I would like to propose one function that adds same functionality to
Emacs dired.  It could be added either to dired-aux.el (after
`dired-diff') or to dired-x.el (after `dired-mark-sexp').

This function compares file attributes of files in the current
directory with file attributes in second directory using given
predicate on pairs of files with the same name.  It does this
by applying the mutual set-difference operation on two lists of files
with their attributes from two dired buffers.  Files for which
predicate returns non-nil are marked by mark character.

The implementation of this function is terse and elegant, but
at the cost of using function `set-difference' from cl-seq.el.
I followed the recent discussion about extracting useful functions
from the cl package.  I think that set functions should be extracted
in the first place.  Or maybe, it makes sense to rewrite these functions
from scratch to make them cl-free?

================================================================
(defun dired-compare-directories (dir2 predicate)
  "Mark files with different file attributes in two dired buffers.
Compare file attributes of files in the current directory
with file attributes in directory DIR2 using PREDICATE on pairs of files
with the same name.  Mark files for which PREDICATE returns non-nil.

PREDICATE is a lisp expression that can refer to the following symbols:

    size1, size2   - file size in bytes
    mtime1, mtime2 - last modification time in seconds
    fa1, fa2       - list of file attributes
                     returned by function `file-attributes'

    where 1 refers to attribute of file in the current dired buffer
    and 2 to attribute of file in second dired buffer.

Examples of PREDICATE:

    (> mtime1 mtime2) - mark newer files
    (not (= size1 size2)) - mark files with different sizes
    (not (string= (nth 8 fa1) (nth 8 fa2))) - mark files with different modes
    (not (and (= (nth 2 fa1) (nth 2 fa2))   - mark files with different UID
              (= (nth 3 fa1) (nth 3 fa2))))   and GID."
  (interactive
   (list (read-file-name (format "Compare %s with: "
                                 (dired-current-directory))
                         (dired-dwim-target-directory))
         (read-minibuffer "Mark if (lisp expr): ")))
  (let* ((dir1 (dired-current-directory))
         (file-alist1 (dired-files-attributes dir1))
         (file-alist2 (dired-files-attributes dir2))
         (file-list1 (mapcar
                      (lambda (f) (cadr f))
                      (set-difference
                       file-alist1 file-alist2
                       :test '(lambda (file1 file2)
                                (let* ((fa1 (caddr file1))
                                       (fa2 (caddr file2))
                                       (size1 (nth 7 fa1))
                                       (size2 (nth 7 fa2))
                                       (mtime1 (float-time (nth 5 fa1)))
                                       (mtime2 (float-time (nth 5 fa2))))
                                  (and
                                   (equal (car file1) (car file2))
                                   (not (eval predicate))))))))
         (file-list2 (mapcar
                      (lambda (f) (cadr f))
                      (set-difference
                       file-alist2 file-alist1
                       :test '(lambda (file1 file2)
                                (let* ((fa1 (caddr file1))
                                       (fa2 (caddr file2))
                                       (size1 (nth 7 fa1))
                                       (size2 (nth 7 fa2))
                                       (mtime1 (float-time (nth 5 fa1)))
                                       (mtime2 (float-time (nth 5 fa2))))
                                  (and
                                   (equal (car file1) (car file2))
                                   (not (eval predicate)))))))))
    (dired-fun-in-all-buffers
     dir1 nil
     (lambda ()
       (dired-mark-if
        (member (dired-get-filename nil t) file-list1) nil)))
    (dired-fun-in-all-buffers
     dir2 nil
     (lambda ()
       (dired-mark-if
        (member (dired-get-filename nil t) file-list2) nil)))
    (message "Marked in dir1: %s files, in dir2: %s files"
             (length file-list1)
             (length file-list2))))

(defun dired-files-attributes (dir)
  "Return a list of all file names and attributes from DIR.
List has a form of (file-name full-file-name (attribute-list))"
  (mapcar
   (lambda (file-name)
     (let ((full-file-name (expand-file-name file-name dir)))
       (list file-name
             full-file-name
             (file-attributes full-file-name))))
   (directory-files dir)))
================================================================

-- 
http://www.jurta.org/emacs/





reply via email to

[Prev in Thread] Current Thread [Next in Thread]