Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom sort predicates for org-ql--sort-by? #366

Open
karlicoss opened this issue Aug 12, 2023 · 2 comments
Open

custom sort predicates for org-ql--sort-by? #366

karlicoss opened this issue Aug 12, 2023 · 2 comments
Assignees
Milestone

Comments

@karlicoss
Copy link

Apologies if it's a duplicate -- I searched over issues/prs and didn't find anything existing

I want to sort the results of org-ql-search by a "created" timestamp -- in my case it's either a CREATED property or just a first inactive timestamp in the outline (e.g. * [#B] [2022-08-01 Mon 00:38] some note).
I went through the source code

org-ql/org-ql.el

Lines 2400 to 2436 in eb53773

(defun org-ql--sort-by (items predicates)
"Return ITEMS sorted by PREDICATES.
PREDICATES is a list of one or more sorting methods, including:
`deadline', `scheduled', `closed' and `priority'."
;; MAYBE: Use macrolet instead of flet.
(cl-flet* ((sorter (symbol)
(pcase symbol
((or 'deadline 'scheduled 'closed)
(apply-partially #'org-ql--date-type< (intern (concat ":" (symbol-name symbol)))))
;; TODO: Rename `date' to `planning'. `date' should be something else.
('date #'org-ql--date<)
('priority #'org-ql--priority<)
('random (lambda (&rest _ignore)
(= 0 (random 2))))
;; NOTE: reverse and todo are handled below.
;; TODO: Add more.
(_ (user-error "Invalid sorting predicate: %s" symbol))))
(sort-by-todo-keyword (items)
(let* ((grouped-items (--group-by (when-let (keyword (org-element-property :todo-keyword it))
(substring-no-properties keyword))
items))
(sorted-groups (cl-sort grouped-items #'<
:key (lambda (keyword)
(or (cl-position (car keyword) org-todo-keywords-1 :test #'string=)
;; Put at end of list if not found
(1+ (length org-todo-keywords-1)))))))
(-flatten-n 1 (-map #'cdr sorted-groups)))))
(dolist (pred predicates)
(setq items (pcase pred
;; NOTE: Using `reverse' instead of `nreverse' because my gut
;; tells me that, while `nreverse' would be preferable and faster,
;; it would probably cause weird bugs, like items' order being
;; reversed every time a cached query is refreshed in a view.
('reverse (reverse items))
('todo (sort-by-todo-keyword items))
(_ (-sort (sorter pred) items)))))
items))
, and seems that it only supports predefined sorting predicates at the moment?

I'm happy to try and contribute support for custom predicates, just want to double check first that would fit into the library. E.g. I imagine it might have some impact on caching?

I imagine as a workaround I could abuse existing org-ql--date< sorting key and override it to extract the CREATED property or something like that.
Thanks!

@karlicoss
Copy link
Author

ended up with something like this for now..

(defun --my/org-get-created-ts (item)
  (let* ((created-prop-s (org-element-property :CREATED item))
         (created-prop-ts (when created-prop-s (ts-parse-org created-prop-s))))
    (if created-prop-ts created-prop-ts
      (let* ((created-title-el (car (org-element-map (org-element-property :title item) 'timestamp 'identity)))
             (created-title-ts (when created-title-el (ts-parse-org-element created-title-el))))
         created-title-ts))))

(defun --my/org-ql--created-date< (a b)
  (ts<
   ;; if we get nil, ts< will complain
   (or (--my/org-get-created-ts a) (make-ts :unix 0))
   (or (--my/org-get-created-ts b) (make-ts :unix 0))
))

(advice-add #'org-ql--date< :override #'--my/org-ql--created-date<)

@alphapapa
Copy link
Owner

Hi,

Yes, unlike search predicates with org-ql-defpred, there isn't yet support for easily adding custom sorters. However, there is a WIP branch that would make it easier:

org-ql/org-ql.el

Lines 412 to 423 in e8eff5d

;; Sort items
(pcase sort
(`nil items)
((guard (cl-subsetp (-list sort) '(date deadline scheduled closed todo priority random reverse)))
;; Default sorting functions
(org-ql--sort-by items (-list sort)))
;; Sort by user-given comparator.
((pred functionp) (-sort sort items))
;; FIXME: Test more carefully for sorters with arguments. In the meantime, just try to sort.
(_ (org-ql--sort-by items (-list sort)))
;; (_ (user-error "SORT must be either nil, one or a list of the defined sorting methods (see documentation), or a comparison function of two arguments"))
)))
The disadvantage is possibly providing less useful error messages if a user makes a mistake, but the additional flexibility would probably be worth it, so I'll probably merge something like that eventually.

@alphapapa alphapapa self-assigned this Aug 12, 2023
@alphapapa alphapapa added this to the 0.9 milestone Dec 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants