diff --git a/lisp/org.el b/lisp/org.el index 7da82a1f6..9b3999e19 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -20570,15 +20570,25 @@ heading. This version will not throw an error. It will return the level of the headline found, or nil if no higher level is found. +When no higher level is found, the still move point to the containing +heading, if there is any in the accessible portion of the buffer. + When narrowing is in effect, ignore headings starting before the available portion of the buffer." - (let ((heading (org-element-parent - (org-element-lineage - (org-element-at-point) - '(headline inlinetask) 'with-self)))) - (when (and heading (<= (point-min) (org-element-begin heading))) - (goto-char (org-element-begin heading)) - (org-element-property :level heading)))) + (let* ((current-heading (org-element-lineage + (org-element-at-point) + '(headline inlinetask) + 'with-self)) + (parent (org-element-lineage current-heading 'headline))) + (if (and parent + (<= (point-min) (org-element-begin parent))) + (progn + (goto-char (org-element-begin parent)) + (org-element-property :level parent)) + (when (and current-heading + (<= (point-min) (org-element-begin current-heading))) + (goto-char (org-element-begin current-heading)) + nil)))) (defun org-up-heading-or-point-min () "Move to the heading line of which the present is a subheading, or point-min. diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 9bfbe5965..50c9968a3 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -2399,6 +2399,56 @@ Test (org-back-to-heading) (should (= 11 (point)))))) +(ert-deftest test-org/up-heading-safe () + "Test `org-up-heading-safe' specifications." + ;; Jump to parent. Simple case. + (org-test-with-temp-text " +* H1 +** H2" + (should (= 1 (org-up-heading-safe))) + (should (looking-at-p "^\\* H1"))) + ;; Do not jump beyond the level 1 heading. + (org-test-with-temp-text " +Text. +* Heading " + (let ((pos (point))) + (should-not (org-up-heading-safe)) + (should (looking-at-p "^\\* Heading")))) + ;; Jump from inside a heading. + (org-test-with-temp-text " +* H1 +** H2 +Text " + (should (= 1 (org-up-heading-safe))) + (should (looking-at-p "^\\* H1"))) + ;; Test inlinetask. + (let ((org-inlinetask-min-level 3)) + (org-test-with-temp-text " +** Heading +Text. +*** Inlinetask +Text +*** END" + (should (= 2 (org-up-heading-safe))) + (should (looking-at-p "^\\*\\{2\\} Heading")))) + (let ((org-inlinetask-min-level 3)) + (org-test-with-temp-text " +** Heading +Text. +*** Inlinetask" + (should (= 2 (org-up-heading-safe))) + (should (looking-at-p "^\\*\\{2\\} Heading")))) + ;; Respect narrowing. + (org-test-with-temp-text " +* H1 +** text +** H2" + (save-excursion + (search-backward "** text") + (narrow-to-region (point) (point-max))) + (should-not (org-up-heading-safe)) + (should (looking-at-p "^\\*\\* H2")))) + (ert-deftest test-org/get-heading () "Test `org-get-heading' specifications." ;; Return current heading, even if point is not on it.