Hi everybody,

I'm using org-mode for a long time, and I never understood quite well how headline data were supposed to be indented, however I was happy with what emerged to me as the default of 2 spaces (with my emacs and org-mode version at the time). I recently updated my old emacs to =9.5.3=, and what I thought was a default indentation was removed.

Suddenly, I had no indentation at all for these headline-data and this bugged me.

I went through documentation, and code, and (re-)discovered `org-adapt-indentation' that was nil in my case and is intended to stay this way as far as I am concerned : I'm looking for a fixed indentation whatever the depth of my outlines.

I'm far from sure it was a default one day, but sure it was at least suggested/enforced in my workflow with my emacs at some time. And even if it didn't feel like it was clad in iron, it seems I'm not the only one who was using that as I can find some examples remaining in the current 'testing/examples' org files.

This indentation concerns only what is called "headline data" in the documentation of `org-adapt-indentation'. To be precise: schedules ("SCHEDULE:", "DEADLINE:"...), clock drawer (":LOGBOOK:..."), property drawer (":PROPERTY:..."). These are "data" appearing after the headline as I understand them.

If I'm a user of org-mode, I'm fairly new in the emacs lisp and hacking community and I need to know:
- if my proposal is useful and has any chance to be accepted,
- if there are any pitfalls I delved into in matter of coding, conventions, ...
- if it make sense for others to include this,

Many thanks !
From 54ee0ce45c4a0c31a8a701047d4d56c1592fb5bb Mon Sep 17 00:00:00 2001
From: Valentin Lab <valentin....@kalysto.org>
Date: Fri, 1 Jul 2022 14:03:41 +0200
Subject: [PATCH] org-el: Add fixed indentation of headline data

* lisp/org.el (org-headline-data-fixed-indent-level): Definition of
new customizable variable and doc.
(org-add-planning-info): When creating planning line, force a
`org-indent-line' to indent it correctly.
(org--get-expected-indentation): If variable
`org-headline-data-fixed-indent-level' is set and line is header,
inform `org-indent-line' to indent from specified amount.
(org-adapt-indentation): Update documentation to mention new
`org-headline-data-fixed-indent-level'.

TINYCHANGE

Signed-off-by: Valentin Lab <valentin....@kalysto.org>
---
 lisp/org.el              |  22 ++++++-
 testing/lisp/test-org.el | 139 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+), 2 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 38a50d231..377a54edd 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -1428,7 +1428,8 @@ The following issues are influenced by this variable:
   indentation is not changed at all.
 
 - Property drawers and planning information is inserted indented
-  when this variable is set.  When nil, they will not be indented.
+  when this variable is set.  When nil, they will be indented
+  following `org-headline-data-fixed-indent-level'.
 
 - TAB indents a line relative to current level.  The lines below
   a headline will be indented when this variable is set to t.
@@ -1445,6 +1446,19 @@ time in Emacs."
 	  (const :tag "Do not adapt indentation at all" nil))
   :safe (lambda (x) (memq x '(t nil headline-data))))
 
+(defcustom org-headline-data-fixed-indent-level nil
+  "Indentation level for org property drawer.
+
+`org-adapt-indentation' need to be set to nil for this value
+to be considered.
+
+Note that this is all about true indentation, by adding and
+removing space characters.  See also \"org-indent.el\" which does
+level-dependent indentation in a virtual way, i.e. at display
+time in Emacs."
+  :group 'org-edit-structure
+  :type 'integer)
+
 (defvaralias 'org-special-ctrl-a 'org-special-ctrl-a/e)
 
 (defcustom org-special-ctrl-a/e nil
@@ -10060,7 +10074,8 @@ WHAT entry will also be removed."
 		    (eq what 'closed)
 		    nil nil (list org-end-time-was-given))))
 	   (unless (eolp) (insert " "))
-	   ts))))))
+	   ts))
+        (org-indent-line)))))
 
 (defvar org-log-note-marker (make-marker)
   "Marker pointing at the entry where the note is to be inserted.")
@@ -18371,6 +18386,9 @@ ELEMENT."
 			    ;; a footnote definition.
 			    (org--get-expected-indentation
 			     (org-element-property :parent previous) t))))))))))
+      ((and (not (eq org-headline-data-fixed-indent-level nil))
+         (memq type '(drawer property-drawer planning node-property clock)))
+         org-headline-data-fixed-indent-level)
       ;; Otherwise, move to the first non-blank line above.
       (t
        (beginning-of-line)
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index fcf2d0b5f..600d647e4 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -1069,6 +1069,49 @@
 	 " #+BEGIN_CENTER\n<point>  Contents\n#+END_CENTER"
 	 (org-indent-line)
 	 (org-get-indentation)))))
+  (let ((org-adapt-indentation nil)
+         (org-headline-data-fixed-indent-level 3))
+    (should
+     ;; First line should be indented using
+     ;; `org-headline-data-fixed-indent-level'.
+     (= 3
+        (org-test-with-temp-text "* H\n<point>:PROPERTY:\n:END:"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    (should
+     (= 3
+        (org-test-with-temp-text "* H\n<point>SCHEDULED:\n"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    (should
+     (= 3
+        (org-test-with-temp-text "* H\n<point>:LOGBOOK:\n:END:\n"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    ;; same for old format on CLOCKing (no LOGBOOK drawer).
+    (should
+     (= 3
+        (org-test-with-temp-text "* H\n<point>CLOCK:\n"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    ;; Lines that are not the first should not use `org-headline-data-fixed-indent-level'
+    (should
+     (= 0
+        (org-test-with-temp-text "* H\n:PROPERTY:\n<point>:foo: 1\n:END:"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    (should
+     (= 0
+        (org-test-with-temp-text "* H\n<point> foo"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    ;; First lines that are not planning/drawers/clocking should not be incremented
+    (should
+     (= 0
+        (org-test-with-temp-text "* H\n:LOGBOOK:\n<point>:foo: 1\n:END:"
+	  (org-indent-line)
+	  (org-get-indentation))))
+    )
   ;; Within code part of a source block, use language major mode if
   ;; `org-src-tab-acts-natively' is non-nil.  Otherwise, indent
   ;; according to line above.
@@ -1216,6 +1259,13 @@
             (org-test-with-temp-text "* H\n:PROPERTIES:\n:key:\n:END:"
               (org-indent-region (point-min) (point-max))
               (buffer-string)))))
+  ;; ;; Indent property drawers according to `org-adapt-indentation'.
+  ;; (let ((org-adapt-indentation 'headline-data))
+  ;;   (should
+  ;;    (equal "* H\n  :PROPERTIES:\n  :key:\n  :END:\n\ncontent2"
+  ;;           (org-test-with-temp-text "* H\n:PROPERTIES:\n:key:\n:END:\n\ncontent"
+  ;;             (org-indent-region (point-min) (point-max))
+  ;;             (buffer-string)))))
   ;; Indent plain lists.
   (let ((org-adapt-indentation t))
     (should
@@ -1228,6 +1278,33 @@
 	    (org-test-with-temp-text " - A\n\n - B"
 	      (org-indent-region (point-min) (point-max))
 	      (buffer-string)))))
+  ;; Increment list's indent level freely without following
+  ;; `org-headline-data-fixed-indent-level' if `org-adapt-indentation'
+  ;; is nil.
+  (let ((org-adapt-indentation nil)
+        (org-headline-data-fixed-indent-level nil))
+    (should
+     (equal "  - A\n    B\n    - C\n\n      X"
+	    (org-test-with-temp-text "- A\n   B\n  - C\n\n     X"
+	      (org-indent-region (point-min) (point-max))
+	      (buffer-string))))
+    (should
+     (equal "   - A\n\n   - B"
+	    (org-test-with-temp-text " - A\n\n - B"
+	      (org-indent-region (point-min) (point-max))
+	      (buffer-string)))))
+  (let ((org-adapt-indentation nil)
+        (org-headline-data-fixed-indent-level 3))
+    (should
+     (equal "  - A\n    B\n    - C\n\n      Y"
+	    (org-test-with-temp-text "- A\n   B\n  - C\n\n     Y"
+	      (org-indent-region (point-min) (point-max))
+	      (buffer-string))))
+    (should
+     (equal "     - A\n\n     - B"
+	    (org-test-with-temp-text "   - A\n\n   - B"
+	      (org-indent-region (point-min) (point-max))
+	      (buffer-string)))))
   ;; Indent footnote definitions.
   (should
    (equal "[fn:1] Definition\n\nDefinition"
@@ -5291,6 +5368,17 @@ Text.
 	    (replace-regexp-in-string
 	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
 	     nil nil 1))))
+  ;; Create deadline when `org-adapt-indentation' is nil and
+  ;; `org-headline-data-fixed-indent-level' is non-nil
+  (should
+   (equal "* H\n   DEADLINE: <2015-06-25>\nParagraph"
+	  (org-test-with-temp-text "* H\nParagraph<point>"
+	    (let ((org-adapt-indentation nil)
+                   (org-headline-data-fixed-indent-level 3))
+	      (org-add-planning-info 'deadline "<2015-06-25 Thu>"))
+	    (replace-regexp-in-string
+	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
+	     nil nil 1))))
   ;; Update deadline when `org-adapt-indentation' is non-nil.
   (should
    (equal "* H\n  DEADLINE: <2015-06-25>\nParagraph"
@@ -5315,6 +5403,20 @@ Paragraph<point>"
 	    (replace-regexp-in-string
 	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
 	     nil nil 1))))
+  ;; Update deadline when `org-adapt-indentation' is nil and
+  ;; `org-headline-data-fixed-indent-level' is non-nil
+  (should
+   (equal "* H\n   DEADLINE: <2015-06-25>\nParagraph"
+	  (org-test-with-temp-text "\
+* H
+DEADLINE: <2015-06-24 Wed>
+Paragraph<point>"
+	    (let ((org-adapt-indentation nil)
+                  (org-headline-data-fixed-indent-level 3))
+	      (org-add-planning-info 'deadline "<2015-06-25 Thu>"))
+	    (replace-regexp-in-string
+	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
+	     nil nil 1))))
   ;; Schedule when `org-adapt-indentation' is non-nil.
   (should
    (equal "* H\n  SCHEDULED: <2015-06-25>\nParagraph"
@@ -5333,6 +5435,17 @@ Paragraph<point>"
 	    (replace-regexp-in-string
 	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
 	     nil nil 1))))
+  ;; Schedule when `org-adapt-indentation' is nil and
+  ;; `org-headline-data-fixed-indent-level' is non-nil
+  (should
+   (equal "* H\n   SCHEDULED: <2015-06-25>\nParagraph"
+	  (org-test-with-temp-text "* H\nParagraph<point>"
+	    (let ((org-adapt-indentation nil)
+                   (org-headline-data-fixed-indent-level 3))
+	      (org-add-planning-info 'scheduled "<2015-06-25 Thu>"))
+	    (replace-regexp-in-string
+	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
+	     nil nil 1))))
   ;; Add deadline when scheduled.
   (should
    (equal "\
@@ -5425,6 +5538,32 @@ Paragraph<point>"
 	    (replace-regexp-in-string
 	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
 	     nil nil 1))))
+  ;; Remove closed when `org-adapt-indentation' is nil and
+  ;; `org-headline-data-fixed-indent-level' is non-nil
+  (should
+   (equal "* H\n   DEADLINE: <2015-06-25>\nParagraph"
+	  (org-test-with-temp-text "\
+* H
+CLOSED: [2015-06-25 Thu] DEADLINE: <2015-06-25 Thu>
+Paragraph<point>"
+	    (let ((org-adapt-indentation nil)
+                   (org-headline-data-fixed-indent-level 3))
+	      (org-add-planning-info nil nil 'closed))
+	    (replace-regexp-in-string
+	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
+	     nil nil 1))))
+  (should
+   (equal "* H\nParagraph"
+	  (org-test-with-temp-text "\
+* H
+  CLOSED: [2015-06-25 Thu]
+Paragraph<point>"
+	    (let ((org-adapt-indentation nil)
+                   (org-headline-data-fixed-indent-level 3))
+	      (org-add-planning-info nil nil 'closed))
+	    (replace-regexp-in-string
+	     "\\( [.A-Za-z]+\\)>" "" (buffer-string)
+	     nil nil 1))))
   ;; Remove closed entry and delete empty line.
   (should
    (equal "\
-- 
2.25.1

Reply via email to