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

    Add optional "last modified" sort to denote-dired and denote-query-sorting
---
 README.org | 20 ++++++++++++--------
 denote.el  | 26 +++++++++++++++++++++-----
 2 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/README.org b/README.org
index f969eea6ed..b2fc3b181b 100644
--- a/README.org
+++ b/README.org
@@ -3581,13 +3581,15 @@ Here are some examples:
 :CUSTOM_ID: h:c958e087-1d23-4a25-afdd-db7bf5606b4c
 :END:
 
-When sorting by =title=, =keywords=, =signature=, =identifier=, or
-=random= with the ~denote-dired~ command (alias ~denote-sort-dired~),
+[ The =random= and =last-modified= sort are part of {{{development-version}}}. 
]
+
+When sorting by =title=, =keywords=, =signature=, =identifier=,
+=random=, or =last-modified= with the ~denote-dired~ command (alias 
~denote-sort-dired~),
 Denote will internally apply a sorting function that is specific to
 each component ([[#h:a34228cb-484f-48fe-9cbc-8e41f313127b][Configure what 
extra prompts ~denote-sort-dired~ issues]]).
 
-With the exception of =random=, the sorting of file name components
-is subject to user configuration:
+With the exception of =random= and =last-modified=, the sorting of
+file name components is subject to user configuration:
 
 #+vindex: denote-sort-identifier-comparison-function
 - ~denote-sort-identifier-comparison-function~ :: The function to sort
@@ -3786,10 +3788,12 @@ the ~denote-grep~ command:
 By default, no sorting of matching files is performed. They appear in
 the query buffer in the order they were retrieved.
 
-The ~denote-query-sorting~ can be set to a symbol among =title=,
-=keywords=, =signature=, or =identifier= to sort by the given file
-name component ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The file-naming 
scheme]]). The symbol =random= produces
-a random order each time.
+#+vindex: denote-sort-components
+The ~denote-query-sorting~ can be set to a symbol among those listed
+in the value of the variable ~denote-sort-components~ to sort by the
+given file name component ([[#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d][The 
file-naming scheme]]). The symbol
+=random= produces a random order each time, while =last-modified=
+relies on the file system to sort by the modification time.
 
 The ~denote-query-sorting~ can also be set to the symbol of a
 function. In that case, the given function is used to perform the
diff --git a/denote.el b/denote.el
index e3a4a14a60..4d0fc65130 100644
--- a/denote.el
+++ b/denote.el
@@ -1527,7 +1527,7 @@ is a special buffer."
 (defconst denote-sort-comparison-fallback-function #'string-collate-lessp
   "String comparison function used by `denote-sort-files' subroutines.")
 
-(defconst denote-sort-components '(title keywords signature identifier random)
+(defconst denote-sort-components '(title keywords signature identifier random 
last-modified)
   "List of sorting keys applicable for `denote-sort-files' and related.")
 
 (defcustom denote-sort-identifier-comparison-function 
denote-sort-comparison-fallback-function
@@ -1650,6 +1650,19 @@ The `%s' performs the comparison."
         (push element shuffled-list)))
     shuffled-list))
 
+(defun denote-sort-modified-time-greaterp (file1 file2)
+  "Return non-nil if FILE1 modified time is greater than that of FILE2."
+  (let* ((attributes1 (file-attributes file1))
+         (mod-time1-raw (file-attribute-modification-time attributes1))
+         (mod-time1-seconds (time-to-seconds mod-time1-raw))
+         (attributes2 (file-attributes file2))
+         (mod-time2-raw (file-attribute-modification-time attributes2))
+         (mod-time2-seconds (time-to-seconds mod-time2-raw)))
+    ;; NOTE 2025-06-23: We normally sort using a "less" approach, but
+    ;; here we want to capture the semantics of "last modified"
+    ;; without relying on a reverse sort.
+    (> mod-time1-seconds mod-time2-seconds)))
+
 ;;;###autoload
 (defun denote-sort-files (files component &optional reverse)
   "Returned sorted list of Denote FILES.
@@ -1673,7 +1686,8 @@ With optional REVERSE as a non-nil value, reverse the 
sort order."
                         ('identifier #'denote-sort-identifier-lessp)
                         ('title #'denote-sort-title-lessp)
                         ('keywords #'denote-sort-keywords-lessp)
-                        ('signature #'denote-sort-signature-lessp)))
+                        ('signature #'denote-sort-signature-lessp)
+                        ('last-modified #'denote-sort-modified-time-greaterp)))
              (sorted-files (if sort-fn
                                (sort files sort-fn)
                              files-to-sort)))
@@ -1746,9 +1760,10 @@ OMIT-CURRENT have been applied."
                       ("keywords" "The keywords of the file name")
                       ("signature" "The signature of the file name")
                       ("identifier" "The identifier of the file name")
-                      ("random" "Random file sort"))))
+                      ("random" "Random file sort")
+                      ("last-modified" "File last modification time"))))
     (format "%s-- %s"
-            (propertize " " 'display '(space :align-to 12))
+            (propertize " " 'display '(space :align-to 15))
             (propertize text 'face 'completions-annotations))))
 
 (defun denote-sort-component-prompt ()
@@ -5430,7 +5445,8 @@ order to sort file names interactively in the query 
buffer."
           (const :tag "Sort by title" title)
           (const :tag "Sort by keywords" keywords)
           (const :tag "Sort by signature" signature)
-          (const :tag "Random order" random))
+          (const :tag "Random order" random)
+          (const :tag "Last modified" last-modified))
   :package-version '(denote . "4.1.0")
   :group 'denote-query)
 

Reply via email to