branch: elpa/gnosis
commit 34b96986b54a45e660387c873a004175680772b2
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>
[Refactor] dashboard: Improve performance.
* Implement cache.
* Load entries async.
---
gnosis-dashboard.el | 337 ++++++++++++++++++++++++++++++++++++++++------------
gnosis.el | 36 +++---
2 files changed, 278 insertions(+), 95 deletions(-)
diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el
index 74f83b5c7c..2ccb38e13f 100644
--- a/gnosis-dashboard.el
+++ b/gnosis-dashboard.el
@@ -68,6 +68,11 @@ When non-nil, sort in ascending order (smaller values
first)."
(defvar gnosis-dashboard--selected-ids nil
"Selected ids from the tabulated list.")
+(defvar gnosis-dashboard--entry-cache (make-hash-table :test 'equal)
+ "Cache mapping thema id to its formatted tabulated-list entry.
+Populated by `gnosis-dashboard--output-themata', invalidated on
+edit, delete, and suspend.")
+
(defvar gnosis-dashboard-themata-mode)
(defvar gnosis-dashboard-modules
@@ -78,6 +83,10 @@ When non-nil, sort in ascending order (smaller values
first)."
(defvar gnosis-dashboard-themata-history nil
"Stack of previous themata views for navigation history.")
+(defvar gnosis-dashboard--view-history nil
+ "Stack of previous dashboard views for cross-mode navigation.
+Each entry is a function to restore that view (e.g.
`gnosis-dashboard-output-decks').")
+
(defvar gnosis-dashboard-themata-current-ids nil
"Current list of thema IDs being displayed.")
@@ -87,6 +96,9 @@ When non-nil, sort in ascending order (smaller values first)."
(defvar gnosis-dashboard-nodes-current-ids nil
"Current list of node IDs being displayed.")
+(defvar gnosis-dashboard--load-generation 0
+ "Generation counter to cancel stale async loads.")
+
(defvar gnosis-dashboard-module-header
(lambda ()
(insert "\n"
@@ -96,26 +108,27 @@ When non-nil, sort in ascending order (smaller values
first)."
(defvar gnosis-dashboard-module-today-stats
(lambda ()
- (insert
- (gnosis-center-string
- (format "\nReviewed today: %s (New: %s)"
- (propertize
- (number-to-string (gnosis-get-date-total-themata))
- 'face 'success)
- (propertize
- (number-to-string (gnosis-get-date-new-themata))
- 'face 'font-lock-keyword-face)))
- "\n"
- (gnosis-center-string
- (format "Due themata: %s (Overdue: %s)"
- (propertize
- (number-to-string
- (length (mapcar #'car (gnosis-review-get--due-themata))))
- 'face 'error)
- (propertize
- (number-to-string
- (length (gnosis-review-get-overdue-themata)))
- 'face 'warning))))))
+ (let* ((due (gnosis-review-get--due-themata))
+ (due-count (length due))
+ (today (gnosis-algorithm-date))
+ (overdue-count (cl-count-if-not
+ (lambda (thema) (equal (cadr thema) today))
+ due)))
+ (insert
+ (gnosis-center-string
+ (format "\nReviewed today: %s (New: %s)"
+ (propertize
+ (number-to-string (gnosis-get-date-total-themata))
+ 'face 'success)
+ (propertize
+ (number-to-string (gnosis-get-date-new-themata))
+ 'face 'font-lock-keyword-face)))
+ "\n"
+ (gnosis-center-string
+ (format "Due themata: %s (Overdue: %s)"
+ (propertize (number-to-string due-count) 'face 'error)
+ (propertize (number-to-string overdue-count)
+ 'face 'warning)))))))
(defvar gnosis-dashboard-module-average-rev
(lambda ()
@@ -140,13 +153,18 @@ When non-nil, sort in ascending order (smaller values
first)."
(gnosis-center-string
(format "Latest WPM: %.2f" gnosis-monkeytype-wpm-result))))))
+(defvar-local gnosis-dashboard--base-header-line nil
+ "Base `header-line-format' before count badge is prepended.")
+
(defun gnosis-dashboard--set-header-line (count)
- "Prepend COUNT badge to the tabulated-list column headers."
- (let ((badge (concat (propertize (format " %d " count)
+ "Set COUNT badge in the tabulated-list column headers.
+Safe to call multiple times; always rebuilds from the base header."
+ (let ((base (or gnosis-dashboard--base-header-line header-line-format))
+ (badge (concat (propertize (format " %d " count)
'face '(:inherit shadow))
" ")))
- (setq-local header-line-format
- (list badge header-line-format))))
+ (setq-local gnosis-dashboard--base-header-line base)
+ (setq-local header-line-format (list badge base))))
(defun gnosis-dashboard-return (&optional current-values)
"Return to dashboard for CURRENT-VALUES."
@@ -244,7 +262,8 @@ With prefix arg, prompt for count. Default 0 (never
reviewed)."
(let ((ids (gnosis-get-themata-by-reviews max-reviews)))
(if ids
(progn
- (setq gnosis-dashboard-themata-history nil)
+ (setq gnosis-dashboard-themata-history nil
+ gnosis-dashboard--view-history nil)
(gnosis-dashboard-output-themata ids))
(message "No themata with at most %d reviews" max-reviews))))
@@ -286,6 +305,9 @@ With prefix arg, prompt for count. Default 0 (never
reviewed)."
gnosis-dashboard-themata-mode
gnosis-dashboard-nodes-history)
(gnosis-dashboard-nodes-back))
+ ;; If view history exists, go back to previous view (decks, tags, etc.)
+ (gnosis-dashboard--view-history
+ (funcall (pop gnosis-dashboard--view-history)))
;; Otherwise go to main dashboard
(t
(gnosis-dashboard))))
@@ -333,33 +355,51 @@ With prefix arg, prompt for count. Default 0 (never
reviewed)."
"Minor mode for gnosis dashboard themata output."
:keymap gnosis-dashboard-themata-mode-map)
+(defun gnosis-dashboard--format-entry (row)
+ "Format a single database ROW into a tabulated-list entry.
+ROW is (id keimenon hypothesis answer tags type suspend)."
+ (let* ((fields (cl-loop for item in (cdr row)
+ if (listp item)
+ collect (mapconcat (lambda (x) (format "%s" x)) item
",")
+ else collect
+ (let ((formatted (replace-regexp-in-string "\n" " "
(format "%s" item))))
+ (replace-regexp-in-string
+ "\\[\\[id:[^]]+\\]\\[\\(.*?\\)\\]\\]"
+ "\\1" formatted)))))
+ (list (car row)
+ (vconcat (append (butlast fields)
+ (list (if (equal (car (last fields)) "1")
+ "Yes" "No")))))))
+
(defun gnosis-dashboard--output-themata (thema-ids)
- "Output tabulated-list format for THEMA-IDS."
+ "Output tabulated-list format for THEMA-IDS.
+Uses `gnosis-dashboard--entry-cache' to avoid re-querying known entries."
(cl-assert (listp thema-ids))
- (let ((entries (emacsql gnosis-db
- `[:select
- [themata:id themata:keimenon themata:hypothesis
themata:answer
- themata:tags themata:type
review-log:suspend]
- :from themata
- :join review-log :on (= themata:id review-log:id)
- :where (in themata:id ,(vconcat thema-ids))])))
- (cl-loop for sublist in entries
- for fields = (cl-loop for item in (cdr sublist)
- if (listp item)
- collect (mapconcat (lambda (x) (format "%s"
x)) item ",")
- else collect
- (let ((formatted (replace-regexp-in-string
"\n" " " (format "%s" item))))
- (replace-regexp-in-string
- "\\[\\[id:[^]]+\\]\\[\\(.*?\\)\\]\\]"
- "\\1" formatted)))
- ;; Last field is suspend (0/1) — format as Yes/No
- collect (list (car sublist)
- (vconcat (append (butlast fields)
- (list (if (equal (car (last
fields)) "1")
- "Yes" "No"))))))))
+ (let* ((uncached (cl-remove-if
+ (lambda (id) (gethash id gnosis-dashboard--entry-cache))
+ thema-ids)))
+ ;; Fetch and cache only the missing entries
+ (when uncached
+ (let ((rows (emacsql gnosis-db
+ `[:select
+ [themata:id themata:keimenon themata:hypothesis
themata:answer
+ themata:tags themata:type
review-log:suspend]
+ :from themata
+ :join review-log :on (= themata:id review-log:id)
+ :where (in themata:id ,(vconcat uncached))])))
+ (dolist (row rows)
+ (puthash (car row) (gnosis-dashboard--format-entry row)
+ gnosis-dashboard--entry-cache))))
+ ;; Return all requested entries from cache (preserving order)
+ (cl-loop for id in thema-ids
+ for entry = (gethash id gnosis-dashboard--entry-cache)
+ when entry collect entry)))
(defun gnosis-dashboard--update-entries (ids)
"Re-fetch and update tabulated-list entries for IDS."
+ ;; Invalidate cache so entries are re-queried
+ (dolist (id ids)
+ (remhash id gnosis-dashboard--entry-cache))
(let* ((new-entries (gnosis-dashboard--output-themata ids))
(update-map (make-hash-table :test 'equal)))
(dolist (entry new-entries)
@@ -374,7 +414,8 @@ With prefix arg, prompt for count. Default 0 (never
reviewed)."
"Remove tabulated-list entries for IDS."
(let ((id-set (make-hash-table :test 'equal)))
(dolist (id ids)
- (puthash id t id-set))
+ (puthash id t id-set)
+ (remhash id gnosis-dashboard--entry-cache))
(setq tabulated-list-entries
(cl-remove-if (lambda (entry) (gethash (car entry) id-set))
tabulated-list-entries))
@@ -383,21 +424,121 @@ With prefix arg, prompt for count. Default 0 (never
reviewed)."
gnosis-dashboard-thema-ids))
(tabulated-list-print t)))
+(defun gnosis-dashboard--refresh-cache-entry (id)
+ "Silently re-cache the formatted entry for thema ID.
+Does not touch any buffer — only updates `gnosis-dashboard--entry-cache'."
+ (remhash id gnosis-dashboard--entry-cache)
+ (gnosis-dashboard--output-themata (list id)))
+
(defun gnosis-dashboard-update-entry (id)
"Update the tabulated-list entry for thema ID in place.
-Called from `gnosis-save-hook'."
- (when gnosis-dashboard-themata-mode
- (gnosis-dashboard--update-entries (list id))
- (goto-char (point-min))
- (while (and (not (eobp))
- (not (equal (tabulated-list-get-id) id)))
- (forward-line 1))))
+Called from `gnosis-save-hook'.
+When in themata view, updates the visible list. Otherwise silently
+refreshes the cache so the next themata view is current."
+ (if gnosis-dashboard-themata-mode
+ (progn
+ (gnosis-dashboard--update-entries (list id))
+ (goto-char (point-min))
+ (while (and (not (eobp))
+ (not (equal (tabulated-list-get-id) id)))
+ (forward-line 1)))
+ (gnosis-dashboard--refresh-cache-entry id)))
(add-hook 'gnosis-save-hook #'gnosis-dashboard-update-entry)
+(defcustom gnosis-dashboard-chunk-size 500
+ "Number of themata to insert per async chunk in dashboard loading.
+Each chunk appends this many entries then yields to the event loop
+for redisplay."
+ :type 'integer
+ :group 'gnosis)
+
+(defun gnosis-dashboard--load-themata-chunk (entries-remaining buffer gen
inserted total)
+ "Append one chunk of ENTRIES-REMAINING to BUFFER and schedule next.
+GEN: generation counter to cancel stale loads.
+INSERTED: count of entries appended so far. TOTAL: total count."
+ (when (and (buffer-live-p buffer)
+ (= gen (buffer-local-value
+ 'gnosis-dashboard--load-generation buffer))
+ entries-remaining)
+ (let ((chunk-size gnosis-dashboard-chunk-size)
+ (count 0))
+ (with-current-buffer buffer
+ (let ((inhibit-read-only t)
+ (saved-point (point)))
+ (goto-char (point-max))
+ (while (and entries-remaining (< count chunk-size))
+ (let ((entry (car entries-remaining)))
+ (tabulated-list-print-entry (car entry) (cadr entry)))
+ (setq entries-remaining (cdr entries-remaining))
+ (cl-incf count))
+ (goto-char saved-point)))
+ (let ((new-inserted (+ inserted count)))
+ (gnosis-dashboard--set-header-line new-inserted)
+ (if entries-remaining
+ (run-with-timer 0.01 nil
+ #'gnosis-dashboard--load-themata-chunk
+ entries-remaining buffer gen new-inserted total)
+ (message "Loaded %d themata" new-inserted))))))
+
+(defun gnosis-dashboard--warm-cache-chunk (chunks total warmed)
+ "Process one chunk of thema IDs for background cache warming.
+CHUNKS: remaining list of id-sublists. TOTAL: total thema count.
+WARMED: count of entries processed so far.
+Continues as long as the dashboard buffer exists."
+ (when (and (get-buffer gnosis-dashboard-buffer-name) chunks)
+ (let* ((ids (car chunks))
+ (uncached (cl-remove-if
+ (lambda (id) (gethash id gnosis-dashboard--entry-cache))
+ ids))
+ (new-warmed (+ warmed (length ids))))
+ (when uncached
+ (let ((rows (emacsql gnosis-db
+ `[:select
+ [themata:id themata:keimenon themata:hypothesis
themata:answer
+ themata:tags themata:type
review-log:suspend]
+ :from themata
+ :join review-log :on (= themata:id review-log:id)
+ :where (in themata:id ,(vconcat uncached))])))
+ (dolist (row rows)
+ (puthash (car row) (gnosis-dashboard--format-entry row)
+ gnosis-dashboard--entry-cache))))
+ (if (cdr chunks)
+ (progn
+ (message "Warming cache... %d/%d" new-warmed total)
+ (run-with-timer gnosis-dashboard-timer-delay nil
+ #'gnosis-dashboard--warm-cache-chunk
+ (cdr chunks) total new-warmed))
+ (message "Cache warmed (%d themata)" total)))))
+
+(defun gnosis-dashboard-warm-cache ()
+ "Warm the entry cache for all themata in the background.
+Continues as long as the dashboard buffer exists, regardless of
+which view the user navigates to."
+ (let* ((all-ids (gnosis-select 'id 'themata nil t))
+ (chunks (let (result (rest all-ids))
+ (while rest
+ (push (seq-take rest gnosis-dashboard-chunk-size) result)
+ (setq rest (nthcdr gnosis-dashboard-chunk-size rest)))
+ (nreverse result))))
+ (when chunks
+ (run-with-timer gnosis-dashboard-timer-delay nil
+ #'gnosis-dashboard--warm-cache-chunk
+ chunks (length all-ids) 0))))
+
+(defun gnosis-dashboard-rebuild-cache ()
+ "Clear and rebuild the themata entry cache."
+ (interactive)
+ (clrhash gnosis-dashboard--entry-cache)
+ (message "Cache cleared, rebuilding...")
+ (gnosis-dashboard-warm-cache))
+
(defun gnosis-dashboard-output-themata (thema-ids)
- "Return THEMA-IDS contents on gnosis dashboard."
+ "Return THEMA-IDS contents on gnosis dashboard.
+For large datasets, loads asynchronously in chunks of
+`gnosis-dashboard-chunk-size' using `run-with-timer'."
(cl-assert (listp thema-ids) t "`thema-ids' must be a list of thema ids.")
+ (cl-incf gnosis-dashboard--load-generation)
(pop-to-buffer-same-window gnosis-dashboard-buffer-name)
(gnosis-dashboard-enable-mode)
;; Disable other dashboard modes
@@ -419,15 +560,24 @@ Called from `gnosis-save-hook'."
tabulated-list-sort-key nil) ; Clear sort key when switching views
(make-local-variable 'tabulated-list-entries)
(tabulated-list-init-header)
- (let ((inhibit-read-only t)
- (entries (gnosis-dashboard--output-themata thema-ids)))
+ (setq-local gnosis-dashboard--base-header-line header-line-format)
+ (setf gnosis-dashboard--current
+ `(:type themata :ids ,thema-ids))
+ (let ((total (length thema-ids))
+ (inhibit-read-only t))
(erase-buffer)
- (insert (format "Loading %s themata..." (length thema-ids)))
- (setq tabulated-list-entries entries)
- (tabulated-list-print t)
- (gnosis-dashboard--set-header-line (length entries))
- (setf gnosis-dashboard--current
- `(:type themata :ids ,thema-ids))))
+ (let ((entries (gnosis-dashboard--output-themata thema-ids)))
+ (setq tabulated-list-entries entries)
+ (if (<= total gnosis-dashboard-chunk-size)
+ ;; Small dataset: print synchronously
+ (progn
+ (tabulated-list-print t)
+ (gnosis-dashboard--set-header-line (length entries)))
+ ;; Large dataset: append entries via timer-based chunks
+ (run-with-timer 0.01 nil
+ #'gnosis-dashboard--load-themata-chunk
+ entries (current-buffer)
+ gnosis-dashboard--load-generation 0 total)))))
(defun gnosis-dashboard-deck-thema-count (id)
"Return total thema count for deck with ID."
@@ -502,6 +652,7 @@ Called from `gnosis-save-hook'."
(let ((tag (or tag (tabulated-list-get-id))))
;; Clear history for fresh start from tags
(setq gnosis-dashboard-themata-history nil)
+ (push #'gnosis-dashboard-output-tags gnosis-dashboard--view-history)
(gnosis-dashboard-output-themata (gnosis-get-tag-themata tag))))
(transient-define-prefix gnosis-dashboard-tags-mode-menu ()
@@ -645,6 +796,7 @@ When called with a prefix, unsuspend all themata of deck."
(let ((deck-id (or deck-id (string-to-number (tabulated-list-get-id)))))
;; Clear history for fresh start from decks
(setq gnosis-dashboard-themata-history nil)
+ (push #'gnosis-dashboard-output-decks gnosis-dashboard--view-history)
(gnosis-dashboard-output-themata (gnosis-collect-thema-ids :deck
deck-id))))
(defun gnosis-dashboard-history (&optional history)
@@ -689,6 +841,7 @@ When called with a prefix, unsuspend all themata of deck."
;; Navigate
"n" #'gnosis-dashboard-menu-nodes
"t" #'gnosis-dashboard-menu-themata
+ "D" #'gnosis-dashboard-output-decks
;; Actions
"r" #'gnosis-review
"a" #'gnosis-add-thema
@@ -736,8 +889,7 @@ DASHBOARD-TYPE: either Themata or Decks to display the
respective dashboard."
("themata" (gnosis-dashboard-output-themata (gnosis-collect-thema-ids)))
("decks" (gnosis-dashboard-output-decks))
("tags" (gnosis-dashboard-output-themata (gnosis-collect-thema-ids
:tags t)))
- ("search" (gnosis-dashboard-search-thema))))
- (tabulated-list-print t)))
+ ("search" (gnosis-dashboard-search-thema))))))
(defun gnosis-dashboard-mark-toggle ()
"Toggle mark on the current item in the tabulated-list."
@@ -829,7 +981,8 @@ DASHBOARD-TYPE: either Themata or Decks to display the
respective dashboard."
(cl-remove-duplicates (mapcar #'car orphaned-rows)))))
(if thema-ids
(progn
- (setq gnosis-dashboard-themata-history nil)
+ (setq gnosis-dashboard-themata-history nil
+ gnosis-dashboard--view-history nil)
(gnosis-dashboard-output-themata thema-ids))
(message "No themata with orphaned links"))))
@@ -837,7 +990,8 @@ DASHBOARD-TYPE: either Themata or Decks to display the
respective dashboard."
"Transient menu for themata operations."
[["Themata"
("a" "View all themata" (lambda () (interactive)
- (setq gnosis-dashboard-themata-history nil)
+ (setq gnosis-dashboard-themata-history nil
+ gnosis-dashboard--view-history nil)
(gnosis-dashboard-output-themata
(gnosis-collect-thema-ids))))
("s" "Search themata" gnosis-dashboard-suffix-query)
("d" "View by decks" (lambda () (interactive)
@@ -853,6 +1007,7 @@ DASHBOARD-TYPE: either Themata or Decks to display the
respective dashboard."
[["Navigate"
("n" "Nodes" gnosis-dashboard-menu-nodes)
("t" "Themata" gnosis-dashboard-menu-themata)
+ ("D" "Decks" gnosis-dashboard-output-decks)
("q" "Quit" quit-window)]
["Actions"
("r" "Review" gnosis-review)
@@ -867,26 +1022,52 @@ DASHBOARD-TYPE: either Themata or Decks to display the
respective dashboard."
("s" "Sync nodes" org-gnosis-db-sync)
("S" "Rebuild nodes" (lambda () (interactive) (org-gnosis-db-sync t)))
("l" "Link health" gnosis-links-check)
- ("L" "Link sync" gnosis-links-sync)]])
+ ("L" "Link sync" gnosis-links-sync)
+ ("c" "Rebuild cache" gnosis-dashboard-rebuild-cache)]])
+
+(defun gnosis-dashboard--load-stats (buffer marker generation)
+ "Load dashboard statistics into BUFFER at MARKER position.
+GENERATION prevents stale updates when the user navigates away."
+ (when (and (buffer-live-p buffer)
+ (= generation gnosis-dashboard--load-generation))
+ (with-current-buffer buffer
+ (let ((inhibit-read-only t))
+ (delete-region marker (point-max))
+ (goto-char marker)
+ (let ((first t))
+ (dolist (module (cdr gnosis-dashboard-modules))
+ (if first
+ (setq first nil)
+ (gnosis-insert-separator))
+ (funcall (symbol-value module))))
+ (goto-char (point-min))))))
;;;###autoload
(defun gnosis-dashboard ()
"Launch gnosis dashboard."
(interactive)
+ (cl-incf gnosis-dashboard--load-generation)
(let* ((buffer (get-buffer-create gnosis-dashboard-buffer-name))
(inhibit-read-only t))
(with-current-buffer buffer
(erase-buffer)
(gnosis-dashboard-mode)
- (let ((modules gnosis-dashboard-modules))
- (when modules
- (funcall (symbol-value (car modules)))
- (dolist (module (cdr modules))
- (gnosis-insert-separator)
- (funcall (symbol-value module)))))
- (pop-to-buffer-same-window buffer)
- (goto-char (point-min))
- (gnosis-dashboard-enable-mode)
+ ;; Show header immediately
+ (funcall (symbol-value (car gnosis-dashboard-modules)))
+ (gnosis-insert-separator)
+ (let ((stats-start (point-marker))
+ (gen gnosis-dashboard--load-generation))
+ (insert (gnosis-center-string "Loading statistics..."))
+ (pop-to-buffer-same-window buffer)
+ (goto-char (point-min))
+ (gnosis-dashboard-enable-mode)
+ ;; Defer expensive stats modules
+ (run-with-timer gnosis-dashboard-timer-delay nil
+ #'gnosis-dashboard--load-stats
+ buffer stats-start gen)
+ ;; Start background cache warming after stats have a head start
+ (run-with-timer (* 2 gnosis-dashboard-timer-delay) nil
+ #'gnosis-dashboard-warm-cache))
(gnosis-dashboard-menu))))
(defun gnosis-dashboard-sort-count (entry1 entry2)
diff --git a/gnosis.el b/gnosis.el
index 3eac214887..fe6523624f 100644
--- a/gnosis.el
+++ b/gnosis.el
@@ -875,14 +875,15 @@ If DUE is t, return only due themata."
collect thema)
themata)))
+(defun gnosis--date-to-int (date)
+ "Convert DATE list (year month day) to YYYYMMDD integer for fast comparison."
+ (+ (* (nth 0 date) 10000) (* (nth 1 date) 100) (nth 2 date)))
+
(defun gnosis-past-or-present-p (date)
"Compare the input DATE with the current date.
Return t if DATE is today or in the past, nil if it's in the future.
DATE is a list of the form (year month day)."
- (let* ((now (gnosis-algorithm-date))
- (time-now (encode-time 0 0 0 (nth 2 now) (nth 1 now) (nth 0 now)))
- (time-date (encode-time 0 0 0 (nth 2 date) (nth 1 date) (nth 0
date))))
- (not (time-less-p time-now time-date))))
+ (<= (gnosis--date-to-int date) (gnosis--date-to-int
(gnosis-algorithm-date))))
(defun gnosis-tags--update (tags)
"Update db for TAGS."
@@ -1045,20 +1046,21 @@ well."
(defun gnosis-review-get--due-themata ()
"Return due thema IDs & due dates."
- (let* ((old-themata (cl-loop for thema in
- (gnosis-select '[id next-rev] 'review-log
- '(and (> n 0)
- (= suspend 0))
- nil)
- when (gnosis-past-or-present-p (cadr thema))
- collect thema))
+ (let* ((today (gnosis--date-to-int (gnosis-algorithm-date)))
+ (old-themata (cl-loop for thema in
+ (gnosis-select '[id next-rev] 'review-log
+ '(and (> n 0)
+ (= suspend 0))
+ nil)
+ when (<= (gnosis--date-to-int (cadr thema))
today)
+ collect thema))
(new-themata (cl-loop for thema in
- (gnosis-select '[id next-rev] 'review-log
- '(and (= n 0)
- (= suspend 0))
- nil)
- when (gnosis-past-or-present-p (cadr thema))
- collect thema)))
+ (gnosis-select '[id next-rev] 'review-log
+ '(and (= n 0)
+ (= suspend 0))
+ nil)
+ when (<= (gnosis--date-to-int (cadr thema))
today)
+ collect thema)))
(if gnosis-review-new-first
(append (cl-subseq new-themata 0 gnosis-new-themata-limit) old-themata)
(append old-themata (cl-subseq new-themata 0
gnosis-new-themata-limit)))))