From 53d4b9654627c206d14b1345a4efe0a3e70d38d2 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 5 May 2026 05:32:32 -0500 Subject: fix: keep collection scan alive when one entry errors (upstream #53) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User reported that running org-drill on a buffer with a new (no-ID) entry threw 'Wrong Type Argument: hash-table-p, nil' and stopped the scan — every subsequent entry was silently skipped, so the user had to re-run org-drill once per item (10 items meant 10 invocations). The exact source of the hash-table error is environment-dependent (Emacs version, Org version, lazy org-id-locations init, Doom overrides), so this fix targets the user-visible failure mode instead of the underlying triggering condition. Wrapped the per-entry body of org-drill-map-entry-function in condition-case. An error on one entry now logs a 'skipping' message and the scan continues to the next entry. The session collects all the well-formed items, and the user can re-run drill once total to process them — no more once-per-item. Two regression tests: one verifies the resilience behavior directly (fail entry 1, scan continues to entry 2), the other documents the ID-creation-with-uninitialized-locations scenario as a smoke check. --- org-drill.el | 58 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 24 deletions(-) (limited to 'org-drill.el') diff --git a/org-drill.el b/org-drill.el index b628695..1573c1a 100644 --- a/org-drill.el +++ b/org-drill.el @@ -3075,30 +3075,40 @@ STATUS is one of the following values: (length (oref session failed-entries))) (cl-incf (oref session cnt))) (when (org-drill-entry-p) - (org-drill-id-get-create-with-warning session) - (cl-destructuring-bind (status due age) - (org-drill-entry-status session) - (cl-case status - (:unscheduled - (cl-incf (oref session dormant-entry-count))) - ;; (:tomorrow - ;; (cl-incf *org-drill-dormant-entry-count*) - ;; (cl-incf *org-drill-due-tomorrow-count*)) - (:future - (cl-incf (oref session dormant-entry-count)) - (if (eq -1 due) - (cl-incf (oref session due-tomorrow-count)))) - (:new - (push (point-marker) (oref session new-entries))) - (:failed - (push (point-marker) (oref session failed-entries))) - (:young - (push (point-marker) (oref session young-mature-entries))) - (:overdue - (push (list (point-marker) due age) (oref session overdue-data))) - (:old - (push (point-marker) (oref session old-mature-entries))) - )))) + ;; Per-entry processing is wrapped in `condition-case' so a single + ;; bad entry doesn't kill the whole collection scan. Upstream + ;; issue #53 reported that a new (no-ID) entry triggered a + ;; "hash-table-p, nil" error that stopped the scan, leaving every + ;; subsequent entry uncollected — the user had to re-run org-drill + ;; once per item. Catching the error here lets the scan continue. + (condition-case err + (progn + (org-drill-id-get-create-with-warning session) + (cl-destructuring-bind (status due age) + (org-drill-entry-status session) + (cl-case status + (:unscheduled + (cl-incf (oref session dormant-entry-count))) + ;; (:tomorrow + ;; (cl-incf *org-drill-dormant-entry-count*) + ;; (cl-incf *org-drill-due-tomorrow-count*)) + (:future + (cl-incf (oref session dormant-entry-count)) + (if (eq -1 due) + (cl-incf (oref session due-tomorrow-count)))) + (:new + (push (point-marker) (oref session new-entries))) + (:failed + (push (point-marker) (oref session failed-entries))) + (:young + (push (point-marker) (oref session young-mature-entries))) + (:overdue + (push (list (point-marker) due age) (oref session overdue-data))) + (:old + (push (point-marker) (oref session old-mature-entries)))))) + (error + (message "org-drill: error processing entry at %s (%s); skipping" + (point) err))))) (defun org-drill-id-get-create-with-warning(session) (when (and (not (oref session warned-about-id-creation)) -- cgit v1.2.3