Ihor Radchenko <[email protected]> writes:

> Morgan Smith <[email protected]> writes:
>>> The new code will throw an error when point is not on heading, unlike
>>> the old code.
>>
>> Darn.  I tried my best to ensure the API switchover didn't change behavior.
>>
>> I had foolishly assumed that "(org-is-habit-p (point))" would error when
>> not on a heading.  I was wrong.
>>
>> I've attached a patch that fixes the issue.  Let me know what you think.
>> ...
>> +  (let ((todo (org-element-at-point (or epom 
>> (org-entry-beginning-position)))))
>
> This defeats the point of using element API. You can just use 
> org-element-lineage.

Does the regex search near the end of org-habit-parse-todo not also
defeat the point of using element API?  I'm not sure exactly what you
mean by "defeats the point".

Regardless, here are two patches.

They pass the ever growing CI Morgan (Will share new improvements soon).

>From bb207726240fcf5a8e628da513495b85ff089f84 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Wed, 15 Jul 2026 10:49:19 -0400
Subject: [PATCH 1/2] Testing: org-habit: Run tests on inlinetasks as well

* testing/lisp/test-org-habit.el
(org-test-habit-agenda-string): Add functionality to generate inline
tasks.
(org-test-habit): Also run tests on inlinetasks.
---
 testing/lisp/test-org-habit.el | 36 ++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/testing/lisp/test-org-habit.el b/testing/lisp/test-org-habit.el
index 20f9a4522..d3d140082 100644
--- a/testing/lisp/test-org-habit.el
+++ b/testing/lisp/test-org-habit.el
@@ -22,6 +22,7 @@
 (require 'org-test "../testing/org-test")
 (require 'org-agenda)
 (require 'org-habit)
+(require 'org-inlinetask)
 (eval-when-compile
   (require 'test-org-agenda "../testing/lisp/test-org-agenda"))
 (eval-when-compile
@@ -39,12 +40,19 @@ org-test-habit-no-fluff-agenda
       (org-agenda-todo-keyword-format "")
       (org-agenda-prefix-format "")))))
 
-(defun org-test-habit-agenda-string (repeater-type-string repeater-deadline?)
+(defun org-test-habit-agenda-string (repeater-type-string
+                                     repeater-deadline?
+                                     &optional
+                                     headline-depth
+                                     inlinetask-p)
   "Return an org habit test string.
 REPEATER-TYPE-STRING is used as the repeater type (ex.  \".+\").
 When REPEATER-DEADLINE? is non-nil, add a repeater deadline.
 Order is determined by `org-log-states-order-reversed'."
+  (unless headline-depth
+    (setq headline-depth 1))
   (concat
+   (make-string headline-depth ?*)
    "* TODO Shave
 SCHEDULED: <2009-10-17 Sat " repeater-type-string "2d"
    (if repeater-deadline?
@@ -80,7 +88,11 @@ org-test-habit-agenda-string
 - CLOSING NOTE [2009-10-10 Sat] \\
   this style occurs when `org-log-done' is `note'.
 - State \"DONE\"       from \"TODO\"       [2009-10-12 Mon]
-- State \"DONE\"       from \"TODO\"       [2009-10-15 Thu]")))
+- State \"DONE\"       from \"TODO\"       [2009-10-15 Thu]")
+   (if inlinetask-p
+       (concat
+        "\n" (make-string headline-depth ?*) " end")
+     "")))
 
 (defmacro org-test-habit (&rest body)
   "Run BODY multiple times for testing habits.
@@ -90,14 +102,18 @@ org-test-habit
 Use habit data from `org-test-habit-agenda-string' both with and without
 a repeater deadline and the log data reversed and not-reversed."
   (declare (indent 0))
-  `(let ((org-agenda-custom-commands
-          org-test-habit-no-fluff-agenda))
-     (dolist (org-log-states-order-reversed '(t nil))
-       (dolist (repeater-deadline? '(nil t))
-         (dolist (repeater-type-string '(".+" "+" "++"))
-           (org-test-agenda-with-agenda
-               (org-test-habit-agenda-string repeater-type-string repeater-deadline?)
-             ,@body))))))
+  `(dolist (inlinetask-p '(nil t))
+     (let ((org-agenda-custom-commands
+            org-test-habit-no-fluff-agenda)
+           (org-inlinetask-min-level 3)
+           (headline-depth (if inlinetask-p 3 1)))
+       (dolist (org-log-states-order-reversed '(t nil))
+         (dolist (repeater-deadline? '(nil t))
+           (dolist (repeater-type-string '(".+" "+" "++"))
+             (org-test-agenda-with-agenda
+              (org-test-habit-agenda-string repeater-type-string repeater-deadline?
+                                            headline-depth inlinetask-p)
+              ,@body)))))))
 
 (ert-deftest test-org-habit/simple-habit ()
   "Test the agenda view for a simple habit."

base-commit: 55913131192c8304efaf921c4ccd982e709f1b08
-- 
2.54.0

>From 9af3de2037f732afc6b30369c7e01bc9650c1845 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Wed, 15 Jul 2026 10:55:11 -0400
Subject: [PATCH 2/2] org-habit: Correctly parse habit when not at heading

This worked before e55fdd953.

* lisp/org-habit.el (org-habit-parse-todo): Fix when not at heading.
---
 lisp/org-habit.el | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lisp/org-habit.el b/lisp/org-habit.el
index bf52e50e8..3ce4459f0 100644
--- a/lisp/org-habit.el
+++ b/lisp/org-habit.el
@@ -197,7 +197,11 @@ org-habit-parse-todo
   5: Repeater type as a string
 
 This list represents a \"habit\" for the rest of this module."
-  (let ((todo (org-element-at-point epom)))
+  (let ((todo (if epom
+                  (org-element-at-point epom)
+                (or (org-element-lineage (org-element-at-point) '(headline inlinetask) t)
+                    (user-error "Before first headline at position %d in buffer %s"
+                                (point) (current-buffer))))))
     (cl-assert (org-is-habit-p todo))
     (let* ((habit-entry (org-no-properties (org-element-property :title todo)))
            (scheduled
-- 
2.54.0

Reply via email to