emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Lawrence Mitchell <wence@gmx.li>
To: emacs-orgmode@gnu.org
Subject: [PATCH v2] ox: Cache locations of fuzzy links
Date: Thu, 02 May 2013 10:03:13 +0100	[thread overview]
Message-ID: <874nelycry.fsf_-_@gmx.li> (raw)
In-Reply-To: 87vc72idau.fsf@gmail.com

* 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, cache the
locations in the position independent case.
---
 lisp/ox.el | 42 +++++++++++++++++++++++++++++-------------
 1 file changed, 29 insertions(+), 13 deletions(-)

Changes since v1:

- Pull initialisation of link-cache into let
- Don't use cons cells for keys, just use the path
  - lift found check to top-level let since it's now common

Nicolas Goaziou wrote:
> Hello,

> Lawrence Mitchell <wence@gmx.li> writes:

>> * ox.el (org-export-resolve-fuzzy-link): Look for fuzzy link in a
>>   cache before trying to resolve it in the parse tree.

> Thanks for your patch. A few comments follow.

[...]

> Minor nitpick: I'd rather have this included in the (let ...), like:

>   (let (...
>         (link-cache
>          (or (plist-get info :fuzzy-link-cache)
>              (plist-get (setq info (plist-put info :fuzzy-link-cache
>                                               (make-hash-table :test 'eq)))
>                         :fuzzy-link-cache)))))

I've made this change.  Barring the eq test.

Remember, paths are strings and two strings are only eq or eql if
they are actually the same string (in memory).  In particular:

(let ((p "foo")) (eq (substring p 1) (substring p 1))) => nil
(let ((p "foo")) (eql (substring p 1) (substring p 1))) => nil
(let ((p "foo")) (equal (substring p 1) (substring p 1))) => t

Hence, we must use equal or string-equal as a test in the hash
table.  But string-equal isn't a predefined test, hence equal.

[...]

> I don't get why you need to use such a key. Simply use the link as key
> and `eq' as the test.

I was worried that I'd have the same key pointing to two
different places, but I see now that those worries were
unfounded, since if we didn't see it in the <<path>> case the
first time we never will.  I've simplified the key to just look
for the path.

diff --git a/lisp/ox.el b/lisp/ox.el
index 88b4122..6aa8617 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -3976,27 +3976,43 @@ 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)))
+	 ;; Cache for locations of fuzzy links that are not position dependent
+	 (link-cache
+	  (or (plist-get info :fuzzy-link-cache)
+	      (plist-get (setq info (plist-put info :fuzzy-link-cache
+	  				       (make-hash-table :test 'equal)))
+			 :fuzzy-link-cache)))
+	 (found-in-cache (gethash path link-cache 'fuzzy-link-not-found)))
     (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)))
+	   (or (not (eq found-in-cache 'fuzzy-link-not-found))
+	       (puthash 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)))
+	   (or (not (eq found-in-cache 'fuzzy-link-not-found))
+	       (puthash 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

  reply	other threads:[~2013-05-02  9:03 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-27 19:28 Exporting large documents Achim Gratz
2013-04-27 19:35 ` Carsten Dominik
2013-04-29 16:04   ` Lawrence Mitchell
2013-04-29 18:44     ` Achim Gratz
2013-05-01 12:18       ` [PATCH] ox: Cache locations of fuzzy links Lawrence Mitchell
2013-05-01 21:46         ` Nicolas Goaziou
2013-05-02  9:03           ` Lawrence Mitchell [this message]
2013-05-02 12:35             ` [PATCH v2] " Nicolas Goaziou
2013-05-02 12:53               ` Nicolas Goaziou
2013-05-03  8:43     ` Exporting large documents Carsten Dominik
2013-05-03 11:12       ` Lawrence Mitchell
     [not found]         ` <877gjfgnl9.fsf@gmail.com>
     [not found]           ` <0F877AB5-D488-4223-B0E7-F11B4B973614@gmail.com>
     [not found]             ` <87ip2xfd0x.fsf@gmail.com>
2013-05-06 11:07               ` Lawrence Mitchell
2013-05-06 16:15                 ` Lawrence Mitchell
2013-05-07 10:26                   ` Bastien
2013-05-06 18:41                 ` Achim Gratz
2013-05-06 19:17                   ` Nicolas Goaziou
2013-05-06 19:32                     ` Achim Gratz
2013-05-07 14:29                       ` Nicolas Goaziou

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=874nelycry.fsf_-_@gmx.li \
    --to=wence@gmx.li \
    --cc=emacs-orgmode@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).