Browse Source

org.el/org-end-of-subtree: Support cache and passing element arg

Ihor Radchenko 4 years ago
parent
commit
ec737554d0
1 changed files with 32 additions and 26 deletions
  1. 32 26
      lisp/org.el

+ 32 - 26
lisp/org.el

@@ -20847,8 +20847,8 @@ If there is no such heading, return nil."
       (unless (< (funcall outline-level) level)
         (point)))))
 
-(defun org-end-of-subtree (&optional invisible-ok to-heading)
-  "Goto to the end of a subtree."
+(defun org-end-of-subtree (&optional invisible-ok to-heading element)
+  "Goto to the end of a subtree at point or for ELEMENT heading."
   ;; This contains an exact copy of the original function, but it uses
   ;; `org-back-to-heading-or-point-min', to make it work also in invisible
   ;; trees and before first headline.  And is uses an invisible-ok argument.
@@ -20857,31 +20857,37 @@ If there is no such heading, return nil."
   ;; with many children and grandchildren etc, this can be much faster
   ;; than the outline version.
   (org-back-to-heading-or-point-min invisible-ok)
-  (let ((first t)
-	(level (funcall outline-level)))
-    (cond ((= level 0)
-	   (goto-char (point-max)))
-	  ((and (derived-mode-p 'org-mode) (< level 1000))
-	   ;; A true heading (not a plain list item), in Org
-	   ;; This means we can easily find the end by looking
-	   ;; only for the right number of stars.  Using a regexp to do
-	   ;; this is so much faster than using a Lisp loop.
-	   (let ((re (concat "^\\*\\{1," (number-to-string level) "\\} ")))
-	     (forward-char 1)
-	     (and (re-search-forward re nil 'move) (beginning-of-line 1))))
-	  (t
-	   ;; something else, do it the slow way
-	   (while (and (not (eobp))
-		       (or first (> (funcall outline-level) level)))
-	     (setq first nil)
-	     (outline-next-heading))))
-    (unless to-heading
+  (unless (and (org-element--cache-active-p)
+               (let ((cached (or element (org-element-at-point nil t))))
+                 (and cached
+                      (eq 'headline (org-element-type cached))
+                      (goto-char (org-element-property
+                                  :end cached)))))
+    (let ((first t)
+	  (level (funcall outline-level)))
+      (cond ((= level 0)
+	     (goto-char (point-max)))
+	    ((and (derived-mode-p 'org-mode) (< level 1000))
+	     ;; A true heading (not a plain list item), in Org
+	     ;; This means we can easily find the end by looking
+	     ;; only for the right number of stars.  Using a regexp to do
+	     ;; this is so much faster than using a Lisp loop.
+	     (let ((re (concat "^\\*\\{1," (number-to-string level) "\\} ")))
+	       (forward-char 1)
+	       (and (re-search-forward re nil 'move) (beginning-of-line 1))))
+	    (t
+	     ;; something else, do it the slow way
+	     (while (and (not (eobp))
+		         (or first (> (funcall outline-level) level)))
+	       (setq first nil)
+	       (outline-next-heading))))))
+  (unless to-heading
+    (when (memq (preceding-char) '(?\n ?\^M))
+      ;; Go to end of line before heading
+      (forward-char -1)
       (when (memq (preceding-char) '(?\n ?\^M))
-	;; Go to end of line before heading
-	(forward-char -1)
-	(when (memq (preceding-char) '(?\n ?\^M))
-	  ;; leave blank line before heading
-	  (forward-char -1)))))
+	;; leave blank line before heading
+	(forward-char -1))))
   (point))
 
 (defun org-end-of-meta-data (&optional full)