branch: elpa/gnosis
commit 51fe86757ac443b20aa488b6df5e8c973170a0bd
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>

    [Refactor] dashboard: use gnosis-tl.
---
 gnosis-dashboard.el | 145 ++++++++++++++++++++++++++++------------------------
 1 file changed, 79 insertions(+), 66 deletions(-)

diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el
index 2ccb38e13f..71d3107740 100644
--- a/gnosis-dashboard.el
+++ b/gnosis-dashboard.el
@@ -29,6 +29,7 @@
 
 (require 'gnosis-monkeytype)
 (require 'gnosis)
+(require 'gnosis-tl)
 (require 'org-gnosis)
 
 (defface gnosis-face-dashboard-header
@@ -55,6 +56,8 @@ When non-nil, sort in ascending order (smaller values first)."
   :type 'boolean
   :group 'gnosis)
 
+(defvar gnosis-dashboard-timer-delay 0.01)
+
 (defvar gnosis-dashboard-thema-ids nil
   "Store thema ids for dashboard.")
 
@@ -73,6 +76,16 @@ When non-nil, sort in ascending order (smaller values 
first)."
 Populated by `gnosis-dashboard--output-themata', invalidated on
 edit, delete, and suspend.")
 
+(defvar-local gnosis-dashboard--rendered-ids nil
+  "Thema IDs of the last rendered view.")
+
+(defvar-local gnosis-dashboard--rendered-width nil
+  "Window width of the last rendered view.")
+
+(defvar-local gnosis-dashboard--rendered-text nil
+  "Cached buffer text (with properties) of the last rendered view.")
+
+
 (defvar gnosis-dashboard-themata-mode)
 
 (defvar gnosis-dashboard-modules
@@ -85,7 +98,8 @@ edit, delete, and suspend.")
 
 (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').")
+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.")
@@ -349,7 +363,8 @@ With prefix arg, prompt for count.  Default 0 (never 
reviewed)."
   "m" #'gnosis-dashboard-mark-toggle
   "M" #'gnosis-dashboard-mark-all
   "u" #'gnosis-dashboard-mark-toggle
-  "U" #'gnosis-dashboard-unmark-all)
+  "U" #'gnosis-dashboard-unmark-all
+)
 
 (define-minor-mode gnosis-dashboard-themata-mode
   "Minor mode for gnosis dashboard themata output."
@@ -396,10 +411,11 @@ Uses `gnosis-dashboard--entry-cache' to avoid re-querying 
known entries."
             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
+  "Re-fetch and update tabulated-list entries for IDS.
+Replaces only the affected lines in the buffer via `gnosis-tl-replace-entry'."
   (dolist (id ids)
     (remhash id gnosis-dashboard--entry-cache))
+  (setq gnosis-dashboard--rendered-text nil)
   (let* ((new-entries (gnosis-dashboard--output-themata ids))
          (update-map (make-hash-table :test 'equal)))
     (dolist (entry new-entries)
@@ -408,21 +424,25 @@ Uses `gnosis-dashboard--entry-cache' to avoid re-querying 
known entries."
           (mapcar (lambda (entry)
                     (or (gethash (car entry) update-map) entry))
                   tabulated-list-entries))
-    (tabulated-list-print t)))
+    (dolist (entry new-entries)
+      (gnosis-tl-replace-entry (car entry) (cadr entry)))))
 
 (defun gnosis-dashboard--remove-entries (ids)
-  "Remove tabulated-list entries for IDS."
+  "Remove tabulated-list entries for IDS.
+Deletes only the affected lines in the buffer via `gnosis-tl-delete-entry'."
   (let ((id-set (make-hash-table :test 'equal)))
     (dolist (id ids)
       (puthash id t id-set)
       (remhash id gnosis-dashboard--entry-cache))
+    (setq gnosis-dashboard--rendered-text nil)
     (setq tabulated-list-entries
           (cl-remove-if (lambda (entry) (gethash (car entry) id-set))
                         tabulated-list-entries))
     (setq gnosis-dashboard-thema-ids
           (cl-remove-if (lambda (id) (gethash id id-set))
                         gnosis-dashboard-thema-ids))
-    (tabulated-list-print t)))
+    (dolist (id ids)
+      (gnosis-tl-delete-entry id))))
 
 (defun gnosis-dashboard--refresh-cache-entry (id)
   "Silently re-cache the formatted entry for thema ID.
@@ -447,40 +467,11 @@ refreshes the cache so the next themata view is current."
 (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."
+  "Number of themata per chunk for background cache warming.
+Each chunk fetches this many entries then yields to the event loop."
   :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.
@@ -530,13 +521,28 @@ which view the user navigates to."
   "Clear and rebuild the themata entry cache."
   (interactive)
   (clrhash gnosis-dashboard--entry-cache)
+  (setq gnosis-dashboard--rendered-text nil)
   (message "Cache cleared, rebuilding...")
   (gnosis-dashboard-warm-cache))
 
+(defun gnosis-dashboard--set-column-format ()
+  "Set `tabulated-list-format' based on current window width.
+Distributes available width (minus padding and column gaps)
+proportionally so all columns fit within the window."
+  (let* ((w (window-width))
+         ;; Reserve: tabulated-list-padding (2) + 5 column gaps (1 each)
+         (avail (- w 7)))
+    (setf tabulated-list-format
+          `[("Keimenon"   ,(max 10 (/ (* avail 28) 100)) t)
+            ("Hypothesis" ,(max 8  (/ (* avail 16) 100)) t)
+            ("Answer"     ,(max 8  (/ (* avail 16) 100)) t)
+            ("Tags"       ,(max 8  (/ (* avail 18) 100)) t)
+            ("Type"       ,(max 5  (/ (* avail 10) 100)) t)
+            ("Suspend"    ,(max 3  (/ (* avail 8) 100)) t)])))
+
+
 (defun gnosis-dashboard-output-themata (thema-ids)
-  "Return THEMA-IDS contents on gnosis dashboard.
-For large datasets, loads asynchronously in chunks of
-`gnosis-dashboard-chunk-size' using `run-with-timer'."
+  "Display THEMA-IDS in the gnosis dashboard."
   (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)
@@ -549,35 +555,42 @@ For large datasets, loads asynchronously in chunks of
   (gnosis-dashboard-themata-mode 1)
   ;; Store current thema IDs for history
   (setq gnosis-dashboard-themata-current-ids thema-ids)
-  (setf tabulated-list-format `[("Keimenon" ,(/ (window-width) 4) t)
-                                ("Hypothesis" ,(/ (window-width) 6) t)
-                                ("Answer" ,(/ (window-width) 6) t)
-                                ("Tags" ,(/ (window-width) 5) t)
-                                ("Type" ,(/ (window-width) 10) t)
-                                ("Suspend" ,(/ (window-width) 6) t)]
-        gnosis-dashboard-thema-ids thema-ids
-        tabulated-list-entries nil
-        tabulated-list-sort-key nil)  ; Clear sort key when switching views
+  (gnosis-dashboard--set-column-format)
+  (setf gnosis-dashboard-thema-ids thema-ids
+        tabulated-list-sort-key nil)
   (make-local-variable 'tabulated-list-entries)
   (tabulated-list-init-header)
   (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))
+  (let ((inhibit-read-only t))
     (erase-buffer)
-    (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)))))
+    (if (and gnosis-dashboard--rendered-text
+             (equal thema-ids gnosis-dashboard--rendered-ids)
+             (= (window-width) gnosis-dashboard--rendered-width))
+        ;; Cache hit — insert cached text and restore entries from data cache
+        (progn
+          (insert gnosis-dashboard--rendered-text)
+          (setq tabulated-list-entries
+                (gnosis-dashboard--output-themata thema-ids)))
+      ;; Cache miss — compute entries and render
+      (let ((entries (gnosis-dashboard--output-themata thema-ids)))
+        (setq tabulated-list-entries entries)
+        (tabulated-list-print)
+        ;; Defer rendered text cache to idle time
+        (let ((buf (current-buffer))
+              (ids (copy-sequence thema-ids))
+              (w (window-width)))
+          (run-with-idle-timer
+           0.5 nil
+           (lambda ()
+             (when (buffer-live-p buf)
+               (with-current-buffer buf
+                 (setq gnosis-dashboard--rendered-ids ids
+                       gnosis-dashboard--rendered-width w
+                       gnosis-dashboard--rendered-text
+                       (buffer-substring (point-min) (point-max))))))))))
+    (gnosis-dashboard--set-header-line (length thema-ids))))
 
 (defun gnosis-dashboard-deck-thema-count (id)
   "Return total thema count for deck with ID."
@@ -975,7 +988,7 @@ DASHBOARD-TYPE: either Themata or Decks to display the 
respective dashboard."
 
 (defun gnosis-dashboard-themata-show-orphaned ()
   "Show themata with orphaned links (referencing deleted org-gnosis nodes)."
-  (interactive)
+  (interactive nil gnosis-dashboard-themata-mode)
   (let* ((orphaned-rows (gnosis--orphaned-links))
          (thema-ids (when orphaned-rows
                       (cl-remove-duplicates (mapcar #'car orphaned-rows)))))
@@ -1007,7 +1020,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)
+    ("D" "Decks" (lambda () (interactive) (gnosis-dashboard-output-decks)))
     ("q" "Quit" quit-window)]
    ["Actions"
     ("r" "Review" gnosis-review)

Reply via email to