branch: externals/ivy
commit 33b82a09db63abba6fa248ae027e343dda11b368
Author: Basil L. Contovounesios <[email protected]>
Commit: Basil L. Contovounesios <[email protected]>
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))