branch: externals/denote
commit 4eceb360a2663a8f0df537c7c9811a08f9ed43d6
Author: Protesilaos Stavrou <i...@protesilaos.com>
Commit: Protesilaos Stavrou <i...@protesilaos.com>

    Add sample code in the manual to find duplicate identifiers
---
 README.org | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/README.org b/README.org
index 20af57a7ed..9734989bed 100644
--- a/README.org
+++ b/README.org
@@ -1397,6 +1397,8 @@ line or switching between then with commands like 
~switch-to-buffer~.
 
 [[#h:3ca4db16-8f26-4d7d-b748-bac48ae32d69][Automatically rename Denote 
buffers]].
 
+[[#h:9051f15d-ea7e-4b17-adc2-bc6a749c721b][Find duplicate identifiers and put 
them in a Dired buffer]].
+
 ** Rename a single file
 :PROPERTIES:
 :CUSTOM_ID: h:7cc9e000-806a-48da-945c-711bbc7426b0
@@ -1815,6 +1817,57 @@ the signature altogether 
([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-na
   ~vertico-exit-input~ with empty contents. That Vertico command is
   bound to =M-RET= as of this writing on 2024-06-30 10:37 +0300. ]
 
+** Find duplicate identifiers and put them in a Dired buffer
+:PROPERTIES:
+:CUSTOM_ID: h:9051f15d-ea7e-4b17-adc2-bc6a749c721b
+:END:
+
+Denote takes care to create unique identifiers, though its mechanism
+relies on reading the existing identifiers in the ~denote-directory~
+or the current directory. When we are renaming files across different
+directories, there is a small chance that some files have the same
+attributes and are thus assigned identical identifiers. If those files
+ever make it into a consolidated ~denote-directory~, we will have
+duplicates, which break the linking mechanism.
+
+As this is an edge case, we do not include any code to address it in
+the Denote code base. Though here is a way to find duplicate
+identifiers inside the current directory:
+
+#+begin_src emacs-lisp
+(defun my-denote--get-files-in-dir (directory)
+  "Return file names in DIRECTORY."
+  (directory-files directory :full-paths directory-files-no-dot-files-regexp))
+
+(defun my-denote--same-identifier-p (file1 file2)
+  "Return non-nil if FILE1 and FILE2 have the same identifier."
+  (let ((id1 (denote-retrieve-filename-identifier file1))
+        (id2 (denote-retrieve-filename-identifier file2)))
+    (equal id1 id2)))
+
+(defun my-denote-find-duplicate-identifiers (directory)
+  "Find all files in DIRECTORY that need a new identifier."
+  (let* ((ids (my-denote--get-files-in-dir directory))
+         (unique-ids (seq-uniq ids #'my-denote--same-identifier-p)))
+    (seq-difference ids unique-ids #'equal)))
+
+(defun my-denote-dired-show-duplicate-identifiers (directory)
+  "Put duplicate identifiers from DIRECTORY in a dedicated Dired buffer."
+  (interactive
+   (list
+    (read-directory-name "Select DIRECTORY to check for duplicate identifiers: 
" default-directory)))
+  (if-let ((duplicates (my-denote-find-duplicate-identifiers directory)))
+      (dired (cons (format "Denote duplicate identifiers" directory) 
duplicates))
+    (message "No duplicates identifiers in `%s'" directory)))
+#+end_src
+
+Evaluate this code and then call the command 
~my-denote-dired-show-duplicate-identifiers~.
+If there are duplicates, it will put them in a dedicated Dired buffer.
+From there, you can view the file contents as usual, and manually edit
+the identifiers as you see fit (e.g. edit them one by one, or change
+to the writable Dired and record a keyboard macro that makes use of a
+counter to increment by 1---contact me if you need any help).
+
 ** Faces used by rename commands
 :PROPERTIES:
 :CUSTOM_ID: h:ab3f355a-f763-43ae-a4c9-179d2d9265a5

Reply via email to