branch: externals/dired-duplicates
commit 7d14d727e909aef8d4cde8a52adcb833c662c227
Author: Harald Judt <[email protected]>
Commit: Harald Judt <[email protected]>

    Implement searching for non-duplicate files using a prefix-argument
    
    Sometimes directories might contain a lot of identical files, for which one
    only wants to find all files without any duplicates.
    
    These non-duplicate files can be found by calling C-u M-x dired-duplicates 
and
    will be shown in a results buffer that behaves like a traditional dired 
buffer
    and only provides the additional dired-duplicates-map derived from 
dired-map.
    
    Signed-off-by: Harald Judt <[email protected]>
---
 dired-duplicates.el | 59 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/dired-duplicates.el b/dired-duplicates.el
index 3bf0de3352..0377ce6082 100644
--- a/dired-duplicates.el
+++ b/dired-duplicates.el
@@ -202,8 +202,8 @@ The results will be cached in the hash TABLE for faster 
access."
           exec)
       path)))
 
-(defun dired-duplicates--detect-duplicates (files)
-  "Find duplicates given a list of FILES.
+(defun dired-duplicates--detect-duplicates (files &optional inversep)
+  "Find duplicates (non-duplicates when INVERSEP is t), given a list of FILES.
 
 Any file filter functions will be applied before checking for
 duplicates.  Return a hash-table with the checksums as keys and a
@@ -211,12 +211,14 @@ list of size and duplicate files as values."
   (cl-loop with files = (dired-duplicates--apply-file-filter-functions files)
            and same-size-table = (make-hash-table)
            and checksum-table = (make-hash-table :test 'equal)
+           and inverse-table = (make-hash-table :test 'equal)
            for f in files
            for size = (file-attribute-size (file-attributes f))
            initially do
            (message "Collecting sizes of %d files..." (length files))
            do (setf (gethash size same-size-table)
                     (push f (gethash size same-size-table)))
+           when inversep do (setf (gethash f inverse-table) t)
            finally
            (cl-loop with checksum-exec-paths = (make-hash-table :test 'equal)
                     for same-size-files being the hash-value in 
same-size-table using (hash-key size)
@@ -235,11 +237,18 @@ list of size and duplicate files as values."
            (cl-loop for same-files being the hash-value in checksum-table 
using (hash-key checksum)
                     do
                     (if (cdr same-files)
-                        (setf (gethash checksum checksum-table)
-                              (cons (file-attribute-size (file-attributes (car 
same-files)))
-                                    (sort same-files #'string<)))
+                        (progn
+                          (setf (gethash checksum checksum-table)
+                                (cons (file-attribute-size (file-attributes 
(car same-files)))
+                                      (sort same-files #'string<)))
+                          (when inversep
+                            (dolist (f same-files)
+                              (remhash f inverse-table))))
                       (remhash checksum checksum-table)))
-           (cl-return checksum-table)))
+           (cl-return
+            (if inversep
+                (sort (cl-loop for k being the hash-keys in inverse-table 
collect k) #'string<)
+              checksum-table))))
 
 (defun dired-duplicates--generate-grouped-results (&optional directories)
   "Generate a list of grouped duplicate files in DIRECTORIES."
@@ -341,19 +350,33 @@ The results will be shown in a Dired buffer."
   (let* ((directories (if (listp directories)
                           (cl-remove-duplicates (mapcar #'expand-file-name 
directories)
                                                 :test #'string=)
-                        (list directories))))
-    (message "Finding duplicate files in %s..." (string-join directories ", "))
-    (if-let ((default-directory "/")
-             (results (dired-duplicates--generate-grouped-results 
directories)))
+                        (list directories)))
+         (inversep current-prefix-arg))
+    (if (not inversep)
         (progn
-          (message "Found %d files having duplicates." (length results))
-          (dired (cons "/" (flatten-list results)))
-          (set-keymap-parent dired-duplicates-map dired-mode-map)
-          (use-local-map dired-duplicates-map)
-          (setq-local dired-duplicates-directories directories)
-          (dired-duplicates--post-process-dired-buffer results)
-          (setq-local revert-buffer-function 'dired-duplicates-dired-revert))
-      (message "No duplicate files found."))))
+          (message "Finding duplicate files in %s..." (string-join directories 
", "))
+          (if-let ((default-directory "/")
+                   (results (dired-duplicates--generate-grouped-results 
directories)))
+              (progn
+                (message "Found %d files having duplicates." (length results))
+                (dired (cons "/" (flatten-list results)))
+                (set-keymap-parent dired-duplicates-map dired-mode-map)
+                (use-local-map dired-duplicates-map)
+                (setq-local dired-duplicates-directories directories)
+                (dired-duplicates--post-process-dired-buffer results)
+                (setq-local revert-buffer-function 
'dired-duplicates-dired-revert))
+            (message "No duplicate files found.")))
+      (message "Finding non-duplicate files in %s..." (string-join directories 
", "))
+      (if-let ((default-directory "/")
+               (results (dired-duplicates--detect-duplicates
+                         (dired-duplicates--find-files directories)
+                         t)))
+          (progn
+            (message "Found %d files having no duplicates." (length results))
+            (dired (cons "/" results))
+            (set-keymap-parent dired-duplicates-map dired-mode-map)
+            (use-local-map dired-duplicates-map))
+        (message "No non-duplicate files found.")))))
 
 (provide 'dired-duplicates)
 

Reply via email to