branch: externals/ivy
commit 33b82a09db63abba6fa248ae027e343dda11b368
Author: Basil L. Contovounesios <ba...@contovou.net>
Commit: Basil L. Contovounesios <ba...@contovou.net>

    Try to load libraries more lazily
    
    On my system this reduces the time for loading
    Ivy from ~50ms to ~13ms, and
    Counsel from ~180ms to ~80ms (#3019).
    
    * colir.el: Don't load color library; autoload color-rgb-to-hex
    instead.
    
    * counsel.el: Don't load 'compile' and 'dired' at top level.
    Autoload dired-jump in older Emacs versions.
    (static-if): Also add polyfill here.
    (counsel--push-xref-marker, counsel-find-file, counsel-dired)
    (counsel-compile, counsel-compilation-errors): Load library
    dependencies only when called.
    (counsel-cmd-to-dired, counsel-find-file-delete)
    (counsel-compile--update-history, counsel-compile--action): Declare
    library definitions used.
    (counsel-find-file-copy, counsel-find-file-move): Depend on Dired's
    autoloads instead of loading dired-aux.
    (counsel--find-file-1, counsel--rg-targets): Use derived-mode-p.
    (counsel-recentf, counsel-buffer-or-recentf-candidates): Remove
    redundant require.
    (counsel--imenu-candidates): Limit dynvar scope.
    
    * ivy-overlay.el: Reword Commentary.  Remove redundant defvar
    declarations.
    (ivy-cursor): Move face from here...
    * ivy-faces.el: ...to here, with all the other Ivy faces.
    * ivy.el: Autoload ivy-overlay entrypoints instead of loading the
    library.  Don't load ring or delsel libraries; similarly depend on
    autoloading.
    (ivy--regex-function): #'-quote function symbol.
    (ivy--flx-available-p): New variable and function.
    (ivy--sort, ivy--recompute-index, ivy--highlight-fuzzy): Use it to
    defer loading 'flx' until it's needed.
    (ivy-reverse-i-search-kill, ivy-history-contents): Declare
    non-autoloaded ring.el functions.
---
 colir.el       |  6 ++++-
 counsel.el     | 85 +++++++++++++++++++++++++++++++++++++++++-----------------
 ivy-faces.el   |  7 +++++
 ivy-overlay.el | 16 +++--------
 ivy.el         | 38 +++++++++++++++++---------
 5 files changed, 101 insertions(+), 51 deletions(-)

diff --git a/colir.el b/colir.el
index a30046f0cc..a06e49584d 100644
--- a/colir.el
+++ b/colir.el
@@ -32,7 +32,11 @@
 ;;; Code:
 
 (require 'cl-lib)
-(require 'color)
+
+(eval-and-compile
+  ;; Autoloaded since Emacs 31.
+  (unless (fboundp 'color-rgb-to-hex)
+    (autoload 'color-rgb-to-hex "color")))
 
 (defcustom colir-compose-method #'colir-compose-alpha
   "The method `colir-blend' uses to compose two color channels."
diff --git a/counsel.el b/counsel.el
index d01007f1c8..33dcbda9e3 100644
--- a/counsel.el
+++ b/counsel.el
@@ -44,12 +44,19 @@
 (require 'ivy)
 (require 'swiper)
 
-(require 'compile)
-(require 'dired)
-
 (eval-when-compile
   (require 'subr-x))
 
+(eval-when-compile
+  (unless (fboundp 'static-if)
+    (defmacro static-if (condition then-form &rest else-forms)
+      "Expand to THEN-FORM or ELSE-FORMS based on compile-time CONDITION.
+Polyfill for Emacs 30 `static-if'."
+      (declare (debug (sexp sexp &rest sexp)) (indent 2))
+      (if (eval condition lexical-binding)
+          then-form
+        (macroexp-progn else-forms)))))
+
 (defgroup counsel nil
   "Completion functions using Ivy."
   :group 'matching
@@ -462,17 +469,21 @@ Used by commands `counsel-describe-symbol',
   (interactive)
   (ivy-exit-with-action #'counsel-info-lookup-symbol))
 
-(defvar find-tag-marker-ring)
-(declare-function xref-push-marker-stack "xref")
-
-(defalias 'counsel--push-xref-marker
-  ;; Added in Emacs 25.1.
-  (if (require 'xref nil t)
-      #'xref-push-marker-stack
-    (require 'etags)
-    (lambda (&optional m)
-      (ring-insert (with-no-warnings find-tag-marker-ring) (or m 
(point-marker)))))
-  "Compatibility shim for `xref-push-marker-stack'.")
+(defun counsel--push-xref-marker (&optional m)
+  "Compatibility shim for `xref-push-marker-stack'."
+  (static-if (require 'xref nil t)
+      ;; Added in Emacs 25.1.
+      (progn
+        (unless (fboundp 'xref-push-marker-stack)
+          (require 'xref))
+        (xref-push-marker-stack m))
+    (unless (boundp 'find-tag-marker-ring)
+      (require 'etags))
+    (unless (fboundp 'ring-insert)
+      (require 'ring))
+    (defvar find-tag-marker-ring)
+    (declare-function ring-insert "ring" (ring item))
+    (ring-insert find-tag-marker-ring (or m (point-marker)))))
 
 (defun counsel--find-symbol (x)
   "Find symbol definition that corresponds to string X."
@@ -1357,6 +1368,10 @@ INITIAL-INPUT can be given as the initial minibuffer 
input."
   (let ((inhibit-read-only t))
     (erase-buffer)
     (dired-mode default-directory counsel-dired-listing-switches)
+    (defvar dired-sort-inhibit)
+    (defvar dired-subdir-alist)
+    (declare-function dired-insert-set-properties "dired")
+    (declare-function dired-move-to-filename "dired")
     (insert "  " default-directory ":\n")
     (let ((point (point)))
       (insert "  " full-cmd "\n")
@@ -1926,7 +1941,8 @@ choose between `yes-or-no-p' and `y-or-n-p'; otherwise 
default to
 
 (defun counsel-find-file-copy (x)
   "Copy file X."
-  (require 'dired-aux)
+  ;; Autoloaded by `dired'.
+  (declare-function dired-copy-file "dired-aux")
   (counsel--find-file-1 "Copy file to: "
                         ivy--directory
                         (lambda (new-name)
@@ -1935,6 +1951,9 @@ choose between `yes-or-no-p' and `y-or-n-p'; otherwise 
default to
 
 (defun counsel-find-file-delete (x)
   "Delete file X."
+  (defvar dired-recursive-deletes)
+  (declare-function dired-clean-up-after-deletion "dired")
+  (declare-function dired-delete-file "dired")
   (when (or delete-by-moving-to-trash
             ;; `dired-delete-file', which see, already prompts for directories
             (eq t (car (file-attributes x)))
@@ -1947,7 +1966,8 @@ choose between `yes-or-no-p' and `y-or-n-p'; otherwise 
default to
 
 (defun counsel-find-file-move (x)
   "Move or rename file X."
-  (require 'dired-aux)
+  ;; Autoloaded by `dired'.
+  (declare-function dired-rename-file "dired-aux")
   (counsel--find-file-1 "Rename file to: "
                         ivy--directory
                         (lambda (new-name)
@@ -2067,8 +2087,9 @@ The preselect behavior can be customized via user options
         (file-name-nondirectory buffer-file-name))))
 
 (defun counsel--find-file-1 (prompt initial-input action caller)
+  (declare-function dired-current-directory "dired")
   (let ((default-directory
-         (if (eq major-mode 'dired-mode)
+         (if (derived-mode-p 'dired-mode)
              (dired-current-directory)
            default-directory)))
     (ivy-read prompt #'read-file-name-internal
@@ -2086,6 +2107,7 @@ The preselect behavior can be customized via user options
   "Forward to `find-file'.
 When INITIAL-INPUT is non-nil, use it in the minibuffer during completion."
   (interactive)
+  (require 'dired)
   (defvar tramp-archive-enabled)
   (let ((tramp-archive-enabled nil)
         (default-directory (or initial-directory default-directory)))
@@ -2316,13 +2338,13 @@ result as a URL."
        counsel-url-expansions-alist))))
 
 ;;** `counsel-dired'
-(declare-function dired "dired")
 
 ;;;###autoload
 (defun counsel-dired (&optional initial-input)
   "Forward to `dired'.
 When INITIAL-INPUT is non-nil, use it in the minibuffer during completion."
   (interactive)
+  (require 'dired)
   (let ((counsel--find-file-predicate #'file-directory-p))
     (counsel--find-file-1
      "Dired (directory): " initial-input
@@ -2348,7 +2370,6 @@ 
https://www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec";))
 (defun counsel-recentf ()
   "Find a file on `recentf-list'."
   (interactive)
-  (require 'recentf)
   (recentf-mode)
   (ivy-read "Recentf: " (counsel-recentf-candidates)
             :action (lambda (f)
@@ -2438,7 +2459,6 @@ This function uses the `dom' library from Emacs 25.1 or 
later."
 
 (defun counsel-buffer-or-recentf-candidates ()
   "Return candidates for `counsel-buffer-or-recentf'."
-  (require 'recentf)
   (recentf-mode)
   (let ((buffers (delq nil (mapcar #'buffer-file-name (buffer-list)))))
     (nconc
@@ -2637,7 +2657,10 @@ string - the full shell command to run."
 
 (defalias 'counsel-find-file-extern #'counsel-locate-action-extern)
 
-(declare-function dired-jump "dired-x")
+(eval-and-compile
+  ;; Autoloaded by `dired' since Emacs 28.
+  (unless (fboundp 'dired-jump)
+    (autoload 'dired-jump "dired-x" nil t)))
 
 (defun counsel-locate-action-dired (x)
   "Use `dired-jump' on X."
@@ -3268,7 +3291,9 @@ Note: don't use single quotes for the regexp."
 
 (defun counsel--rg-targets ()
   "Return a list of files to operate on, based on `dired-mode' marks."
-  (when (eq major-mode 'dired-mode)
+  (when (derived-mode-p 'dired-mode)
+    (declare-function dired-get-marked-files "dired")
+    (declare-function dired-toggle-marks "dired")
     (let ((files
            (dired-get-marked-files 'no-dir nil nil t)))
       (when (or (cdr files)
@@ -4777,13 +4802,13 @@ S will be of the form \"[register]: content\"."
      (replace-regexp-in-string "\\`\\[.*?]: " "" s t t))))
 
 ;;** `counsel-imenu'
-(defvar imenu-auto-rescan)
-(defvar imenu-auto-rescan-maxout)
 (declare-function imenu--subalist-p "imenu")
 (declare-function imenu--make-index-alist "imenu")
 
 (defun counsel--imenu-candidates ()
   (require 'imenu)
+  (defvar imenu-auto-rescan)
+  (defvar imenu-auto-rescan-maxout)
   (let* ((imenu-auto-rescan t)
          (imenu-auto-rescan-maxout (if current-prefix-arg
                                        (buffer-size)
@@ -6761,6 +6786,8 @@ This is determined by `counsel-compile-local-builds', 
which see."
 ;; things like infer `default-directory' from 'cd's in the string.
 (defun counsel-compile--update-history (_proc)
   "Update `counsel-compile-history' from the compilation state."
+  (defvar compilation-arguments)
+  (defvar compilation-environment)
   (let* ((srcdir (counsel--compile-root))
          (blddir default-directory)
          (bldenv compilation-environment)
@@ -6789,6 +6816,7 @@ edited the command, thus losing our embedded state.")
 If CMD has the `recursive' property set we call `counsel-compile'
 again to further refine the compile options in the directory
 specified by the `blddir' property."
+  (defvar compilation-environment)
   (let ((blddir (get-text-property 0 'blddir cmd))
         (bldenv (get-text-property 0 'bldenv cmd)))
     (if (get-text-property 0 'recursive cmd)
@@ -6838,6 +6866,8 @@ Additional actions:
 
 \\{counsel-compile-map}"
   (interactive)
+  (require 'compile)
+  (require 'dired) ;; For face `dired-directory'.
   (setq counsel-compile--current-build-dir (or dir
                                                (counsel--compile-root)
                                                default-directory))
@@ -7123,6 +7153,12 @@ The user options `counsel-search-engine' and
     #'counsel-search "0.13.2 (2019-10-17)")
 
 ;;** `counsel-compilation-errors'
+
+(declare-function compilation--message->loc "compile")
+(declare-function compilation-buffer-p "compile")
+(declare-function compilation-next-single-property-change "compile")
+(declare-function compile-goto-error "compile")
+
 (defun counsel--compilation-errors-buffer (buf)
   (with-current-buffer buf
     (let ((res nil)
@@ -7156,6 +7192,7 @@ The user options `counsel-search-engine' and
 (defun counsel-compilation-errors ()
   "Compilation errors."
   (interactive)
+  (require 'compile)
   (ivy-read "compilation errors: " (counsel-compilation-errors-cands)
             :require-match t
             :action #'counsel-compilation-errors-action
diff --git a/ivy-faces.el b/ivy-faces.el
index 1a25cfc0a9..5f76ba952e 100644
--- a/ivy-faces.el
+++ b/ivy-faces.el
@@ -27,6 +27,13 @@
   :group 'ivy
   :group 'faces)
 
+(defface ivy-cursor
+  '((((class color) (background light))
+     :background "black" :foreground "white")
+    (((class color) (background dark))
+     :background "white" :foreground "black"))
+  "Cursor face for inline completion.")
+
 (defface ivy-current-match
   '((((class color) (background light))
      :background "#1a4b77" :foreground "white" :extend t)
diff --git a/ivy-overlay.el b/ivy-overlay.el
index f52b5ecbee..d25dc6d9c2 100644
--- a/ivy-overlay.el
+++ b/ivy-overlay.el
@@ -20,9 +20,9 @@
 
 ;;; Commentary:
 
-;; This package allows to setup Ivy's completion at point to actually
-;; show the candidates and the input at point, instead of in the
-;; minibuffer.
+;; Normally, Ivy displays completion candidates and entered text in
+;; the minibuffer.  This file enables in-buffer completion to be
+;; displayed at point instead.
 
 ;;; Code:
 
@@ -30,14 +30,6 @@
   (require 'cl-lib)
   (require 'subr-x))
 
-(defface ivy-cursor
-  '((((class color) (background light))
-     :background "black" :foreground "white")
-    (((class color) (background dark))
-     :background "white" :foreground "black"))
-  "Cursor face for inline completion."
-  :group 'ivy-faces)
-
 (defvar ivy--old-cursor-type t)
 
 (defvar ivy-overlay-at nil
@@ -90,12 +82,10 @@ Then attach the overlay to the character before point."
 (declare-function org-current-level "org")
 (declare-function org-at-heading-p "org")
 (defvar org-indent-indentation-per-level)
-(defvar ivy-height)
 (defvar ivy-last)
 (defvar ivy-text)
 (defvar ivy-completion-beg)
 (declare-function ivy--get-window "ivy")
-(declare-function ivy-state-current "ivy")
 (declare-function ivy-state-window "ivy")
 
 (defun ivy-overlay--current-column ()
diff --git a/ivy.el b/ivy.el
index 3be4b96867..e54bc02899 100644
--- a/ivy.el
+++ b/ivy.el
@@ -40,11 +40,11 @@
 ;;; Code:
 
 (require 'colir)
-(require 'ivy-overlay)
 (require 'ivy-faces)
+(autoload 'ivy-overlay-cleanup "ivy-overlay")
+(autoload 'ivy-display-function-overlay "ivy-overlay")
 
 (require 'cl-lib)
-(require 'ring)
 
 (eval-when-compile
   (require 'subr-x)
@@ -311,7 +311,11 @@ This is a global variable that is set by ivy functions for 
use in
 action functions.")
 
 ;;* Keymap
-(require 'delsel)
+
+(autoload 'minibuffer-keyboard-quit "delsel" nil t)
+(autoload 'hydra-ivy/body "ivy-hydra" nil t)
+(autoload 'ivy-hydra-read-action "ivy-hydra" nil t)
+
 (defun ivy-define-key (keymap key def)
   "Forward to (`define-key' KEYMAP KEY DEF).
 Remove DEF from `counsel-M-x' list."
@@ -376,8 +380,6 @@ Remove DEF from `counsel-M-x' list."
     (ivy-define-key map "$" #'ivy-magic-read-file-env)
     map)
   "Keymap used in the minibuffer.")
-(autoload 'hydra-ivy/body "ivy-hydra" "" t)
-(autoload 'ivy-hydra-read-action "ivy-hydra" "" t)
 
 (defvar ivy-mode-map
   (let ((map (make-sparse-keymap)))
@@ -488,7 +490,7 @@ This allows RET to reverse consecutive DEL.")
 (defvar ivy-regex ""
   "Store the regex value that corresponds to `ivy-text'.")
 
-(defvar ivy--regex-function 'ivy--regex
+(defvar ivy--regex-function #'ivy--regex
   "Current function for building a regex.")
 
 (defun ivy-set-text (str)
@@ -3773,7 +3775,12 @@ The alist VAL is a sorting function with the signature of
   (let ((default-directory ivy--directory))
     (sort (copy-sequence candidates) #'file-newer-than-file-p)))
 
-(defvar ivy--flx-featurep (require 'flx nil 'noerror))
+(defvar ivy--flx-available-p)
+(defun ivy--flx-available-p ()
+  "Try to load package `flx' once; return non-nil on success."
+  (if (boundp 'ivy--flx-available-p)
+      ivy--flx-available-p
+    (setq ivy--flx-available-p (require 'flx nil t))))
 
 (defun ivy--sort (name candidates)
   "Re-sort candidates by NAME.
@@ -3781,8 +3788,8 @@ All CANDIDATES are assumed to match NAME."
   (let (fun)
     (cond ((setq fun (ivy-alist-setting ivy-sort-matches-functions-alist))
            (funcall fun name candidates))
-          ((and ivy--flx-featurep
-                (eq ivy--regex-function 'ivy--regex-fuzzy))
+          ((and (eq ivy--regex-function #'ivy--regex-fuzzy)
+                (ivy--flx-available-p))
            (ivy--flx-sort name candidates))
           (t
            candidates))))
@@ -3881,8 +3888,8 @@ CANDS are the current candidates."
                           0))
                      ((and (not empty)
                            (not (eq caller 'swiper))
-                           (not (and ivy--flx-featurep
-                                     (eq ivy--regex-function 'ivy--regex-fuzzy)
+                           (not (and (eq ivy--regex-function 
#'ivy--regex-fuzzy)
+                                     (ivy--flx-available-p)
                                      ;; Limit to configured number of 
candidates
                                      (null (nthcdr ivy-flx-limit cands))))
                            ;; If there was a preselected candidate, don't try 
to
@@ -4156,8 +4163,8 @@ with the extended highlighting of 
`ivy-format-function-line'."
 
 (defun ivy--highlight-fuzzy (str)
   "Highlight STR, using the fuzzy method."
-  (if (and ivy--flx-featurep
-           (eq (ivy-alist-setting ivy-re-builders-alist) 'ivy--regex-fuzzy))
+  (if (and (eq (ivy-alist-setting ivy-re-builders-alist) #'ivy--regex-fuzzy)
+           (ivy--flx-available-p))
       (let ((flx-name (string-remove-prefix "^" ivy-text)))
         (ivy--flx-propertize
          (cons (flx-score str flx-name ivy--flx-cache) str)))
@@ -4979,6 +4986,9 @@ This list can be rotated with 
`ivy-rotate-preferred-builders'."
             ((symbolp history)
              (set history (delete current (symbol-value history))))
             ((ring-p history)
+             ;; `ring-p' is autoloaded.
+             (declare-function ring-member "ring")
+             (declare-function ring-remove "ring")
              (ring-remove history (ring-member history current)))))
     (ivy--kill-current-candidate)))
 
@@ -4996,6 +5006,8 @@ Also set `ivy--reverse-i-search-history' to HISTORY."
                 ((symbolp history)
                  (copy-sequence (symbol-value history)))
                 ((ring-p history)
+                 ;; `ring-p' is autoloaded.
+                 (declare-function ring-elements "ring")
                  (ring-elements history))
                 ((sequencep history)
                  (copy-sequence history))

Reply via email to