* ox.el (org-export-resolve-fuzzy-link): Look for fuzzy link in a cache before trying to resolve it in the parse tree.
When a document contains a large number of identical fuzzy links, it doesn't make sense to continually search for them. Instead, as long as we're looking for position independent links, cache the locations and look there first. --- lisp/ox.el | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) Achim Gratz wrote: > Lawrence Mitchell writes: >> I did a bit of digging and here are the results. No potential >> fixes though. I couldn't see how to fix up org-export-data, but here's some band-aid to speed up resolving fuzzy links. It works much better for the fake test case (where there are many identical links) than the real org manual, but I do get a slight improvement (about 6%). As per elp: Before: org-latex-export-to-latex 1 373.02289908 373.02289908 org-export-resolve-fuzzy-link 281 42.108304211 0.1498516164 After: org-latex-export-to-latex 1 349.7238257 349.7238257 org-export-resolve-fuzzy-link 281 19.329938028 0.0687898150 Cheers, Lawrence diff --git a/lisp/ox.el b/lisp/ox.el index 88b4122..bb49512 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -3976,27 +3976,49 @@ significant." ;; Split PATH at white spaces so matches are space ;; insensitive. (path (org-split-string - (if match-title-p (substring raw-path 1) raw-path)))) + (if match-title-p (substring raw-path 1) raw-path))) + (link-cache (plist-get info :fuzzy-link-cache))) + ;; Cache for locations of fuzzy links that are not position dependent + (unless link-cache + (setq info (plist-put info :fuzzy-link-cache + (make-hash-table :test 'equal))) + (setq link-cache (plist-get info :fuzzy-link-cache))) (cond ;; First try to find a matching "<<path>>" unless user specified ;; he was looking for a headline (path starts with a "*" ;; character). ((and (not match-title-p) - (org-element-map (plist-get info :parse-tree) 'target - (lambda (blob) - (and (equal (org-split-string (org-element-property :value blob)) - path) - blob)) - info t))) + (let ((found (gethash (cons 'path path) + link-cache + 'fuzzy-link-not-found))) + (or (not (eq found 'fuzzy-link-not-found)) + (puthash (cons 'path path) + (org-element-map (plist-get info :parse-tree) 'target + (lambda (blob) + (and (equal (org-split-string + (org-element-property :value blob)) + path) + blob)) + info t) + link-cache))))) ;; Then try to find an element with a matching "#+NAME: path" ;; affiliated keyword. ((and (not match-title-p) - (org-element-map (plist-get info :parse-tree) - org-element-all-elements - (lambda (el) - (let ((name (org-element-property :name el))) - (when (and name (equal (org-split-string name) path)) el))) - info 'first-match))) + (let ((found (gethash (cons 'name path) + link-cache + 'fuzzy-link-not-found))) + (or (not (eq found 'fuzzy-link-not-found)) + (puthash (cons 'name path) + (org-element-map (plist-get info :parse-tree) + org-element-all-elements + (lambda (el) + (let ((name (org-element-property :name el))) + (when (and name (equal + (org-split-string name) + path)) + el))) + info 'first-match) + link-cache))))) ;; Last case: link either points to a headline or to nothingness. ;; Try to find the source, with priority given to headlines with ;; the closest common ancestor. If such candidate is found, -- 1.8.2-rc3