Use cache in org-up-heading-safe
* lisp/org.el (org-up-heading-safe): Use buffer-local cache to store positions of parent headings. The cache is invalidated when buffer text is changed, according to `buffer-chars-modified-tick'. (org--up-heading-cache): Buffer-local hash-table storing the cache. (org--up-heading-cache-tick): The buffer modification state for currently active `org--up-heading-cache'. The optimisation is critical when running agenda or org-entry-get queries using property/tag inheritance. In such scenarios `org-up-heading-safe' can be called thousands of times. For example, building todo agenda on large number of headings lead to the following benchmark results: Benchmark: 1. (elp-instrument-function #'org-up-heading-safe) 2. Run agenda 3. (elp-results) ;; function, # calls, total time, avg time Without cache: org-up-heading-safe 27555 8.4234025759 0.0003056941 With cache, first run: org-up-heading-safe 23227 0.5300747539 2.282...e-05 With cache, second run on unchanged buffer: org-up-heading-safe 23227 0.1447754880 6.233...e-06 The final speedup is 1-2 orders of magnitude (~15-56 times).
This commit is contained in:
parent
24473b5e08
commit
8f39743ce6
30
lisp/org.el
30
lisp/org.el
|
@ -20460,6 +20460,10 @@ This function considers both visible and invisible heading lines.
|
|||
With argument, move up ARG levels."
|
||||
(outline-up-heading arg t))
|
||||
|
||||
(defvar-local org--up-heading-cache nil
|
||||
"Buffer-local `org-up-heading-safe' cache.")
|
||||
(defvar-local org--up-heading-cache-tick nil
|
||||
"Buffer `buffer-chars-modified-tick' in `org--up-heading-cache'.")
|
||||
(defun org-up-heading-safe ()
|
||||
"Move to the heading line of which the present line is a subheading.
|
||||
This version will not throw an error. It will return the level of the
|
||||
|
@ -20469,10 +20473,28 @@ Also, this function will be a lot faster than `outline-up-heading',
|
|||
because it relies on stars being the outline starters. This can really
|
||||
make a significant difference in outlines with very many siblings."
|
||||
(when (ignore-errors (org-back-to-heading t))
|
||||
(let ((level-up (1- (funcall outline-level))))
|
||||
(and (> level-up 0)
|
||||
(re-search-backward (format "^\\*\\{1,%d\\} " level-up) nil t)
|
||||
(funcall outline-level)))))
|
||||
(let (level-cache)
|
||||
(unless org--up-heading-cache
|
||||
(setq org--up-heading-cache (make-hash-table)))
|
||||
(if (and (eq (buffer-chars-modified-tick) org--up-heading-cache-tick)
|
||||
(setq level-cache (gethash (point) org--up-heading-cache)))
|
||||
(when (<= (point-min) (car level-cache) (point-max))
|
||||
;; Parent is inside accessible part of the buffer.
|
||||
(progn (goto-char (car level-cache))
|
||||
(cdr level-cache)))
|
||||
;; Buffer modified. Invalidate cache.
|
||||
(unless (eq (buffer-chars-modified-tick) org--up-heading-cache-tick)
|
||||
(setq-local org--up-heading-cache-tick
|
||||
(buffer-chars-modified-tick))
|
||||
(clrhash org--up-heading-cache))
|
||||
(let* ((level-up (1- (funcall outline-level)))
|
||||
(pos (point))
|
||||
(result (and (> level-up 0)
|
||||
(re-search-backward
|
||||
(format "^\\*\\{1,%d\\} " level-up) nil t)
|
||||
(funcall outline-level))))
|
||||
(when result (puthash pos (cons (point) result) org--up-heading-cache))
|
||||
result)))))
|
||||
|
||||
(defun org-up-heading-or-point-min ()
|
||||
"Move to the heading line of which the present is a subheading, or point-min.
|
||||
|
|
Loading…
Reference in New Issue