branch: master
commit cfbf48182b91e2b997f8dd597d1a9bd1ba9f126d
Author: Nathan Moreau <nathan.mor...@m4x.org>
Commit: Oleh Krehel <ohwoeo...@gmail.com>

    Lazy load ffap
    
    find-file-at-point is a heavyweight dependency (in terms of load
    time), which is rarely used. It happens to pop near the top of the
    slowest packages to load when benchmarking my config, because of the
    (require 'ffap) in ivy.
    
    This commit delays the load when needed.
    
    Fixes #2215
---
 Makefile    |  2 +-
 ivy-test.el | 20 ++++++++++++++++++++
 ivy.el      | 20 ++++++++++++++++----
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile
index aece67e..8cf9c54 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ deps:
        $(emacs) -batch -l targets/install-deps.el
 
 test:
-       $(emacs) -batch $(LOAD) -l ivy-test.el -f ert-run-tests-batch-and-exit
+       $(emacs) -batch $(LOAD) -l ivy-test.el -f ivy-test-run-tests
 
 checkdoc:
        $(emacs) -batch -l targets/checkdoc.el
diff --git a/ivy-test.el b/ivy-test.el
index 6ed6484..4b471f1 100644
--- a/ivy-test.el
+++ b/ivy-test.el
@@ -26,6 +26,12 @@
 
 ;;; Code:
 
+(defvar require-features nil)
+
+(defadvice require (before ivy-tests-require-hook (feature &rest _) activate)
+  "Record the requires into `require-features'."
+  (push feature require-features))
+
 (require 'ert)
 (require 'colir)
 
@@ -37,6 +43,14 @@
 
 (message "%s" (emacs-version))
 
+(ert-deftest ivy--lazy-load-ffap--ffap-url-p ()
+  (should (not (memq 'ffap require-features)))
+  (should (not (fboundp 'ffap-url-p)))
+  (should (string= (ivy-ffap-url-p "https://foo.org";)
+                   "https://foo.org";))
+  (should (memq 'ffap require-features))
+  (should (fboundp 'ffap-url-p)))
+
 (defvar ivy-expr nil
   "Holds a test expression to evaluate with `ivy-eval'.")
 
@@ -1390,6 +1404,12 @@ a buffer visiting a file."
                      (ivy--handle-directory "/sudo::"))
                    "/sudo::/tmp/")))
 
+(defun ivy-test-run-tests ()
+  ;; this test must run first as other tests might force a load
+  (ert-run-tests-batch 'ivy--lazy-load-ffap--ffap-url-p)
+  ;; run the rest of the tests
+  (ert-run-tests-batch-and-exit '(not ivy--lazy-load-ffap--ffap-url-p)))
+
 (provide 'ivy-test)
 
 ;;; ivy-test.el ends here
diff --git a/ivy.el b/ivy.el
index a0d2e7f..cd38911 100644
--- a/ivy.el
+++ b/ivy.el
@@ -39,7 +39,6 @@
 ;;; Code:
 
 (require 'cl-lib)
-(require 'ffap)
 (require 'ivy-overlay)
 (require 'colir)
 (require 'ring)
@@ -1515,7 +1514,7 @@ Call the permanent action if possible."
         (when (and (with-ivy-window (derived-mode-p 'prog-mode))
                    (eq (ivy-state-caller ivy-last) 'swiper)
                    (not (file-exists-p ivy--default))
-                   (not (ffap-url-p ivy--default))
+                   (not (ivy-ffap-url-p ivy--default))
                    (not (ivy-state-dynamic-collection ivy-last))
                    (> (point) (minibuffer-prompt-end)))
           (ivy--insert-symbol-boundaries)))
@@ -1533,7 +1532,7 @@ If so, move to that directory, while keeping only the 
file name."
   (when ivy--directory
     (let ((input (ivy--input))
           url)
-      (if (setq url (or (ffap-url-p input)
+      (if (setq url (or (ivy-ffap-url-p input)
                         (with-ivy-window
                           (cl-reduce
                            (lambda (a b)
@@ -1542,7 +1541,7 @@ If so, move to that directory, while keeping only the 
file name."
                            :initial-value nil))))
           (ivy-exit-with-action
            (lambda (_)
-             (funcall ffap-url-fetcher url)))
+             (ivy-ffap-url-fetcher url)))
         (setq input (expand-file-name input))
         (let ((file (file-name-nondirectory input))
               (dir (expand-file-name (file-name-directory input))))
@@ -4967,6 +4966,19 @@ make decisions based on the whole marked list."
     (view-mode)
     (goto-char (point-min))))
 
+(declare-function ffap-url-p "ffap")
+(defvar ffap-url-fetcher)
+
+(defun ivy-ffap-url-p (string)
+  "Forward to `ffap-url-p'."
+  (require 'ffap)
+  (ffap-url-p string))
+
+(defun ivy-ffap-url-fetcher (url)
+  "Calls `ffap-url-fetcher'."
+  (require 'ffap)
+  (funcall ffap-url-fetcher url))
+
 (provide 'ivy)
 
 ;;; ivy.el ends here

Reply via email to