;;; +org-capture.el -*- lexical-binding: t; -*- ;;; Code: (require 'cl-lib) (require 'acdw) ;; We don't require `org-capture' here because I'll have to require this library ;; to init.el /before/ org-capture is fully needed. But I do need to declare ;; `org-capture-templates'. (defvar org-capture-templates nil) (defun +org-capture--get (key &optional list) "Find KEY in LIST, or return nil. LIST defaults to `org-capture-templates'." (alist-get key (or list org-capture-templates) nil nil #'equal)) ;; Set it up as a generic value. Based on the one for `alist-get'. (gv-define-expander +org-capture--get (lambda (do key &optional alist) (setq alist (or alist org-capture-templates)) (macroexp-let2 macroexp-copyable-p k key (gv-letplace (getter setter) alist (macroexp-let2 nil p `(assoc ,k ,getter 'equal) (funcall do `(cdr ,p) (lambda (v) (macroexp-let2 nil v v (let ((set-exp `(if ,p (setcdr ,p ,v) ,(funcall setter `(cons (setq ,p (cons ,k ,v)) ,getter))))) `(progn ,set-exp ,v)))))))))) (defun +org-capture-sort (&optional list) "Sort LIST by string keys. LIST is a symbol and defaults to `org-capture-templates'." (setq list (or list 'org-capture-templates)) (set list (sort (symbol-value list) (lambda (a b) (string< (car a) (car b)))))) (defun +org-capture-sort-after-init (&optional list) "Sort LIST with `+org-capture-sort' after Emacs init." (+ensure-after-init #'+org-capture-sort)) ;;;###autoload (defun +org-capture-templates-setf (key value &optional list sort-after) "Add KEY to LIST, using `setf'. LIST is a symbol and defaults to `org-capture-templates' -- so this function sets values on a list that's structured as such. Thus, KEY is a string key. If it's longer than one character, this function will search LIST for each successive run of characters before the final, ensuring sub-lists exist of the form (CHARS DESCRIPTION). For example, if KEY is \"abc\", first a LIST item of the form (a DESCRIPTION), if non-existant, will be added to the list (with a default description), then an item of the form (\"ab\" DESCRIPTION), before adding (KEY VALUE) to the LIST. VALUE is the template or group header required for `org-capture-templates', which see. SORT-AFTER, when set to t, will call `+org-capture-templates-sort' after setting, to ensure org can properly process the variable." ;; LIST defaults to `org-capture-templates' (declare (indent 2)) (unless list (setq list 'org-capture-templates)) ;; Ensure VALUE is a list to cons properly (unless (listp value) (setq value (list value))) (when (> (length key) 1) ;; Check for existence of groups. (let ((expected (cl-loop for i from 1 to (1- (length key)) collect (substring key 0 i) into keys finally return keys))) (cl-loop for ek in expected if (not (+org-capture--get ek (symbol-value list))) do (setf (+org-capture--get ek (symbol-value list)) (list (format "(Group %s)" ek)))))) (prog1 ;; Set KEY to VALUE (setf (+org-capture--get key (symbol-value list)) value) ;; Sort after, maybe (when sort-after (+org-capture-sort list)))) (provide '+org-capture) ;;; +org-capture.el ends here