From 9a8a2096303c702f86f5175cb332e0938dd420d0 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 13 May 2026 20:14:41 -0500 Subject: feat(org-agenda): add VERIFICATION and IN-PROGRESS blocks around SCHEDULE The main "d" agenda view grows two new blocks. A VERIFICATION block lists tasks in the VERIFY TODO state, placed just above the day's SCHEDULE. An IN-PROGRESS block lists tasks in the DOING TODO state, placed just under SCHEDULE. The full block order is now: OVERDUE -> HIGH PRIORITY -> VERIFICATION -> SCHEDULE -> IN-PROGRESS -> PRIORITY B. Scope matches the other blocks (every entry in `org-agenda-files`). Scheduled and deadlined entries are included -- a VERIFY task with a date appears in both VERIFICATION and SCHEDULE, mirroring how HIGH PRIORITY behaves. Habits are skipped via `cj/org-skip-subtree-if-habit`; PROJECT-keyword parents wouldn't match `(todo "VERIFY")` exact-state filters anyway, so no extra skip there. Two new header defvars (`cj/main-agenda-verify-title`, `cj/main-agenda-doing-title`) for symmetry with the existing four. Both blocks reference the shared `cj/--main-agenda-prefix-format` so a format tweak still lands in one place. Five new tests in `test-org-agenda-config-skip-functions.el` lock the block order, each new block's header / prefix-format / skip-function, and the include-scheduled-entries contract. --- modules/org-agenda-config.el | 25 +++++++- tests/test-org-agenda-config-skip-functions.el | 86 ++++++++++++++++++++++++++ todo.org | 47 +++++++++++++- 3 files changed, 154 insertions(+), 4 deletions(-) diff --git a/modules/org-agenda-config.el b/modules/org-agenda-config.el index 9ff2fd72..9e64a04b 100644 --- a/modules/org-agenda-config.el +++ b/modules/org-agenda-config.el @@ -279,11 +279,22 @@ If the current buffer isn't an org buffer, inform the user." (defvar cj/main-agenda-tasks-title "PRIORITY B" "String to announce the schedule section of the main agenda.") +(defvar cj/main-agenda-verify-title "VERIFICATION" + "String to announce the VERIFY section of the main agenda. +Lists tasks in the VERIFY TODO state waiting on a manual check. +Block sits above the day's schedule.") + +(defvar cj/main-agenda-doing-title "IN-PROGRESS" + "String to announce the DOING section of the main agenda. +Lists tasks in the DOING TODO state -- work actively in flight. +Block sits just under the day's schedule.") + (defvar cj/--main-agenda-prefix-format " %i %-15:c%?-15t% s" "Prefix format string shared by all blocks of the main daily agenda. -Inlined across the overdue / high-priority / schedule / priority-B -blocks of `org-agenda-custom-commands' before the extraction. Keep -the four blocks pointing here so a format tweak lands in one place.") +Inlined across the overdue / high-priority / VERIFICATION / schedule / +IN-PROGRESS / priority-B blocks of `org-agenda-custom-commands' before +the extraction. Keep the six blocks pointing here so a format tweak +lands in one place.") (defun cj/org-skip-subtree-if-habit () "Skip an agenda entry if it has a STYLE property equal to \"habit\"." @@ -342,6 +353,10 @@ KEYWORDS must be a list of strings." ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header cj/main-agenda-hipri-title) (org-agenda-prefix-format cj/--main-agenda-prefix-format))) + (todo "VERIFY" + ((org-agenda-skip-function 'cj/org-skip-subtree-if-habit) + (org-agenda-overriding-header cj/main-agenda-verify-title) + (org-agenda-prefix-format cj/--main-agenda-prefix-format))) (agenda "" ((org-agenda-start-day "0d") (org-agenda-span 8) @@ -352,6 +367,10 @@ KEYWORDS must be a list of strings." '(org-agenda-skip-entry-if 'todo '("CANCELLED"))) (org-agenda-overriding-header cj/main-agenda-schedule-title) (org-agenda-prefix-format cj/--main-agenda-prefix-format))) + (todo "DOING" + ((org-agenda-skip-function 'cj/org-skip-subtree-if-habit) + (org-agenda-overriding-header cj/main-agenda-doing-title) + (org-agenda-prefix-format cj/--main-agenda-prefix-format))) (alltodo "" ((org-agenda-skip-function '(or (cj/org-skip-subtree-if-habit) (cj/org-skip-subtree-if-priority ?A) diff --git a/tests/test-org-agenda-config-skip-functions.el b/tests/test-org-agenda-config-skip-functions.el index 3c044adb..aec1e71b 100644 --- a/tests/test-org-agenda-config-skip-functions.el +++ b/tests/test-org-agenda-config-skip-functions.el @@ -264,5 +264,91 @@ regression where one block diverges from the others on the format." (fmt-form (cadr (assoc 'org-agenda-prefix-format opts)))) (should (eq fmt-form 'cj/--main-agenda-prefix-format)))))) +;;; ---------- VERIFICATION and IN-PROGRESS blocks ---------- + +;;; Normal Cases + +(ert-deftest test-org-agenda-config-d-command-has-six-blocks-in-expected-order () + "Normal: the \"d\" command runs six blocks in the expected order -- +OVERDUE -> HIGH PRIORITY -> VERIFICATION -> SCHEDULE -> IN-PROGRESS -> PRIORITY B." + (let* ((entry (assoc "d" org-agenda-custom-commands)) + (blocks (nth 2 entry)) + (shapes (mapcar (lambda (b) (list (car b) (cadr b))) blocks))) + (should (equal shapes + '((alltodo "") + (tags "PRIORITY=\"A\"") + (todo "VERIFY") + (agenda "") + (todo "DOING") + (alltodo "")))))) + +(ert-deftest test-org-agenda-config-verify-block-options () + "Normal: the VERIFY block carries the VERIFICATION header, the shared +prefix format, and the habit skip function." + (let* ((entry (assoc "d" org-agenda-custom-commands)) + (blocks (nth 2 entry)) + (verify (seq-find + (lambda (b) (and (eq (car b) 'todo) + (equal (cadr b) "VERIFY"))) + blocks)) + (opts (nth 2 verify))) + (should verify) + (should (eq (cadr (assoc 'org-agenda-overriding-header opts)) + 'cj/main-agenda-verify-title)) + (should (equal cj/main-agenda-verify-title "VERIFICATION")) + (should (eq (cadr (assoc 'org-agenda-prefix-format opts)) + 'cj/--main-agenda-prefix-format)) + (should (equal (cadr (assoc 'org-agenda-skip-function opts)) + ''cj/org-skip-subtree-if-habit)))) + +(ert-deftest test-org-agenda-config-doing-block-options () + "Normal: the DOING block carries the IN-PROGRESS header, the shared +prefix format, and the habit skip function." + (let* ((entry (assoc "d" org-agenda-custom-commands)) + (blocks (nth 2 entry)) + (doing (seq-find + (lambda (b) (and (eq (car b) 'todo) + (equal (cadr b) "DOING"))) + blocks)) + (opts (nth 2 doing))) + (should doing) + (should (eq (cadr (assoc 'org-agenda-overriding-header opts)) + 'cj/main-agenda-doing-title)) + (should (equal cj/main-agenda-doing-title "IN-PROGRESS")) + (should (eq (cadr (assoc 'org-agenda-prefix-format opts)) + 'cj/--main-agenda-prefix-format)) + (should (equal (cadr (assoc 'org-agenda-skip-function opts)) + ''cj/org-skip-subtree-if-habit)))) + +;;; Boundary Cases + +(ert-deftest test-org-agenda-config-verify-block-includes-scheduled-entries () + "Boundary: the VERIFY block has no scheduled/deadline skip, so a VERIFY +task with a scheduled date appears here as well as in the SCHEDULE block. +Mirrors the HIGH PRIORITY block's behaviour." + (let* ((entry (assoc "d" org-agenda-custom-commands)) + (blocks (nth 2 entry)) + (verify (seq-find + (lambda (b) (and (eq (car b) 'todo) + (equal (cadr b) "VERIFY"))) + blocks)) + (opts (nth 2 verify)) + (skip (cadr (assoc 'org-agenda-skip-function opts)))) + ;; Single skip function (no compound `or' with scheduled/deadline). + (should (equal skip ''cj/org-skip-subtree-if-habit)))) + +(ert-deftest test-org-agenda-config-doing-block-includes-scheduled-entries () + "Boundary: same contract as VERIFY -- no scheduled/deadline skip, so a +DOING task with a scheduled date appears in both blocks." + (let* ((entry (assoc "d" org-agenda-custom-commands)) + (blocks (nth 2 entry)) + (doing (seq-find + (lambda (b) (and (eq (car b) 'todo) + (equal (cadr b) "DOING"))) + blocks)) + (opts (nth 2 doing)) + (skip (cadr (assoc 'org-agenda-skip-function opts)))) + (should (equal skip ''cj/org-skip-subtree-if-habit)))) + (provide 'test-org-agenda-config-skip-functions) ;;; test-org-agenda-config-skip-functions.el ends here diff --git a/todo.org b/todo.org index 598692cb..f65bcb3d 100644 --- a/todo.org +++ b/todo.org @@ -70,6 +70,51 @@ Decide whether to (a) leave it asymmetric and let the row fill in as new launchers arrive, (b) move an existing icon down to balance 5/5/2 or similar, or (c) reorganize by category (work / read / chat / play). Surfaced when Telegram landed in Row 3 alone. +** DONE [#B] Add VERIFY and DOING blocks to the main agenda view :feature: + +The main agenda "d" command (=cj/main-agenda-display=, F8) currently +renders four blocks: OVERDUE -> HIGH PRIORITY UNRESOLVED -> SCHEDULE +-> PRIORITY B. Insert two new blocks around SCHEDULE so a glance at +the daily view also surfaces what's in flight and what's waiting on a +manual check: + +- Above SCHEDULE: all tasks with TODO state VERIFY (header: + =VERIFICATION=). +- Below SCHEDULE: all tasks with TODO state DOING (header: + =IN-PROGRESS=). + +Resulting block order: + + OVERDUE -> HIGH PRIORITY -> *VERIFICATION* -> SCHEDULE -> *IN-PROGRESS* -> PRIORITY B + +Decisions: +- *Scope*: same as the other blocks -- every entry in + =org-agenda-files=, no per-project filter. +- *Scheduled / deadlined entries*: included. A VERIFY task with a + scheduled date for today appears in both the VERIFICATION block and + the SCHEDULE block. Mirrors the HIGH PRIORITY block's behavior. +- *Habit / PROJECT skips*: skip habits via + =cj/org-skip-subtree-if-habit=. Don't skip PROJECT-keyword entries + (the =(todo "VERIFY")= and =(todo "DOING")= match is keyword-exact + so PROJECT parents wouldn't appear anyway, and a PROJECT in VERIFY + state would be deliberate). + +Implementation locations: +- =modules/org-agenda-config.el= -- two new entries inside + =org-agenda-custom-commands= "d" block, each a =(todo "STATE" ...)= + with =org-agenda-overriding-header=, the shared + =cj/--main-agenda-prefix-format=, and the habit skip-function. +- =modules/org-agenda-config.el= -- two header defvars + (=cj/main-agenda-verify-title= / =cj/main-agenda-doing-title=) for + symmetry with =cj/main-agenda-overdue-title= etc. + +Regression coverage: +- Extend =tests/test-org-agenda-config-skip-functions.el= with + structural assertions: the "d" command has six blocks in the + expected order, the new VERIFICATION / IN-PROGRESS blocks reference + the shared prefix-format symbol, carry the right + =org-agenda-overriding-header=, and run the habit skip. + ** DONE [#A] Org Agenda fixes :bug: *** 2026-05-13 Wed @ 13:05:21 -0500 Skip CANCELLED entries from main agenda SCHEDULE see the following screenshot @@ -208,7 +253,7 @@ created (=one-window-p= still t). Existing tests dropped their =pop-to-buffer= stub since =switch-to-buffer= works directly in batch. Full =make test-unit= green. -** TODO [#B] Add ERT coverage for modules below 70% :tests: +p** TODO [#B] Add ERT coverage for modules below 70% :tests: Coverage snapshot from =make coverage-summary= on 2026-05-13 (post-push): =4716/6853= executable lines covered (=68.8%=) across 73 tracked module files. -- cgit v1.2.3