No Wayman <iarchivedmywholel...@gmail.com> writes:

It makes this sort of customization very simple

Famous last words. I forgot the agenda relies on text-properties for much of its functionality. I've attached a patch that addresses this and also removes the `save-excursion` around the funcall to the custom insertion function. I've noted in the documentation that if the function is moving point, it is responsible for making sure it ends up on the line before the next habit.

>From 93496b6b86d73a95512c277a1321005d5f1995d1 Mon Sep 17 00:00:00 2001
From: Nicholas Vollmer <iarchivedmywholel...@gmail.com>
Date: Thu, 20 Aug 2020 13:46:49 -0400
Subject: [PATCH] habit: add custom option for placing consistency graph

* lisp/org-habit.el (org-habit-insert-consistency-graphs): Add
`org-habit-insert-graph-function' defcustom.

Allow user to control consistency graph placement with a customizable
function.  See `org-habit-insert-graph-function` docstring for an
example.
---
 lisp/org-habit.el | 45 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 34 insertions(+), 11 deletions(-)

diff --git a/lisp/org-habit.el b/lisp/org-habit.el
index f76f0f213..99dfe8def 100644
--- a/lisp/org-habit.el
+++ b/lisp/org-habit.el
@@ -104,6 +104,27 @@ means of creating calendar-based reminders."
   :package-version '(Org . "9.3")
   :safe (lambda (v) (or (integerp v) (null v))))
 
+(defcustom org-habit-insert-graph-function nil
+  "Function called to place each consistency graph.
+It must accept the graph string as its sole argument.
+It is invoked with point on the current habit's line in the agenda buffer,
+and is responsible for placing point on the line before the next habit if point is moved.
+
+For example, to insert graphs on a new line below the habit:
+
+  (setq org-habit-insert-graph-function
+        (lambda (graph)
+          (let ((props (text-properties-at (point))))
+            (end-of-line)
+            ;; org-agenda functionality depends on current line's text properties
+            (insert (concat \"\\n\" (make-string (1+ (or org-habit-graph-column 0)) ? )))
+            (add-text-properties (line-beginning-position) (line-end-position) props)
+            (insert graph))))
+
+If nil, the graph is inserted on the current habit's line at `org-habit-graph-column'."
+  :group 'org-habit
+  :type 'function)
+
 (defface org-habit-clear-face
   '((((background light)) (:background "#8270f9"))
     (((background dark)) (:background "blue")))
@@ -430,17 +451,19 @@ current time."
       (while (not (eobp))
 	(let ((habit (get-text-property (point) 'org-habit-p)))
 	  (when habit
-	    (move-to-column org-habit-graph-column t)
-	    (delete-char (min (+ 1 org-habit-preceding-days
-				 org-habit-following-days)
-			      (- (line-end-position) (point))))
-	    (insert-before-markers
-	     (org-habit-build-graph
-	      habit
-	      (time-subtract moment (days-to-time org-habit-preceding-days))
-	      moment
-	      (time-add moment (days-to-time org-habit-following-days))))))
-	(forward-line)))))
+            (let ((graph (org-habit-build-graph
+                          habit
+                          (time-subtract moment (days-to-time org-habit-preceding-days))
+                          moment
+                          (time-add moment (days-to-time org-habit-following-days)))))
+              (if (functionp org-habit-insert-graph-function)
+                  (funcall org-habit-insert-graph-function graph)
+                (move-to-column org-habit-graph-column t)
+                (delete-char (min (+ 1 org-habit-preceding-days
+                                     org-habit-following-days)
+                                  (- (line-end-position) (point))))
+                (insert-before-markers graph)))))
+        (forward-line)))))
 
 (defun org-habit-toggle-habits ()
   "Toggle display of habits in an agenda buffer."
-- 
2.28.0

Reply via email to