branch: externals/ivy
commit edcbe4d965e534d86fadcbc57b49807e06e22214
Merge: 3dde6c6214 7c4fa07ea8
Author: Basil L. Contovounesios <[email protected]>
Commit: Basil L. Contovounesios <[email protected]>
Merge branch 'master' into externals/ivy
---
Makefile | 2 +-
README.md | 2 +-
colir.el | 2 +-
doc/Makefile | 2 +-
doc/ivy-ox.el | 2 +-
doc/ivy.org | 2 +-
doc/ivy.texi | 2 +-
ivy-faces.el | 2 +-
ivy-overlay.el | 2 +-
ivy-test.el | 23 ++-
ivy.el | 558 +++++++++++++++++++++++++++++++++++----------------------
11 files changed, 373 insertions(+), 226 deletions(-)
diff --git a/Makefile b/Makefile
index 53902c14ec..7aa9e6deaa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
# Build and test Ivy from a source checkout.
-# Copyright (C) 2015-2025 Free Software Foundation, Inc.
+# Copyright (C) 2015-2026 Free Software Foundation, Inc.
#
# This file is part of GNU Emacs.
#
diff --git a/README.md b/README.md
index 4e3c0457f1..5561081400 100644
--- a/README.md
+++ b/README.md
@@ -142,7 +142,7 @@ Install the `swiper` package from GNU ELPA or MELPA.
![Screenshot of Swiper in Emacs][swiper-shot]
-There's also a ~ten minute [video demo][swiper-demo].
+There’s also a ~ten minute [video demo][swiper-demo].
# Frequently asked questions
diff --git a/colir.el b/colir.el
index a06e49584d..2db912d3e2 100644
--- a/colir.el
+++ b/colir.el
@@ -1,6 +1,6 @@
;;; colir.el --- Color blending library -*- lexical-binding: t -*-
-;; Copyright (C) 2015-2025 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <[email protected]>
diff --git a/doc/Makefile b/doc/Makefile
index c6dbe40062..20139e6548 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,6 +1,6 @@
# Build and install Ivy Info manual from Org source.
-# Copyright (C) 2018-2025 Free Software Foundation, Inc.
+# Copyright (C) 2018-2026 Free Software Foundation, Inc.
#
# This file is part of GNU Emacs.
#
diff --git a/doc/ivy-ox.el b/doc/ivy-ox.el
index 3fdd3147d6..577dccbbb2 100644
--- a/doc/ivy-ox.el
+++ b/doc/ivy-ox.el
@@ -1,6 +1,6 @@
;;; ivy-ox.el --- org-export settings for Ivy -*- lexical-binding: t -*-
-;; Copyright (C) 2015-2025 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel
diff --git a/doc/ivy.org b/doc/ivy.org
index 8a7c0582b0..dfb2d9a6c4 100644
--- a/doc/ivy.org
+++ b/doc/ivy.org
@@ -70,7 +70,7 @@ final candidate is either through simple keyboard character
inputs or
through powerful regular expressions.
#+TEXINFO: @end ifnottex
-Copyright (C) 2015--2025 Free Software Foundation, Inc.
+Copyright (C) 2015--2026 Free Software Foundation, Inc.
#+BEGIN_QUOTE
Permission is granted to copy, distribute and/or modify this document
diff --git a/doc/ivy.texi b/doc/ivy.texi
index be3c1e1ed8..0c34c1e179 100644
--- a/doc/ivy.texi
+++ b/doc/ivy.texi
@@ -20,7 +20,7 @@ final candidate is either through simple keyboard character
inputs or
through powerful regular expressions.
@end ifnottex
-Copyright (C) 2015--2025 Free Software Foundation, Inc.
+Copyright (C) 2015--2026 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
diff --git a/ivy-faces.el b/ivy-faces.el
index 5f76ba952e..6abd4a2881 100644
--- a/ivy-faces.el
+++ b/ivy-faces.el
@@ -1,6 +1,6 @@
;;; ivy-faces.el --- Faces for Ivy -*- lexical-binding: t -*-
-;; Copyright (C) 2020-2025 Free Software Foundation, Inc.
+;; Copyright (C) 2020-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <[email protected]>
;; Keywords: convenience
diff --git a/ivy-overlay.el b/ivy-overlay.el
index 8803e60b64..667d6ba823 100644
--- a/ivy-overlay.el
+++ b/ivy-overlay.el
@@ -1,6 +1,6 @@
;;; ivy-overlay.el --- Overlay display functions for Ivy -*- lexical-binding:
t -*-
-;; Copyright (C) 2016-2025 Free Software Foundation, Inc.
+;; Copyright (C) 2016-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <[email protected]>
;; Keywords: convenience
diff --git a/ivy-test.el b/ivy-test.el
index 6e0a4dfd16..4af7e9f907 100644
--- a/ivy-test.el
+++ b/ivy-test.el
@@ -1,6 +1,6 @@
;;; ivy-test.el --- tests for ivy -*- lexical-binding: t -*-
-;; Copyright (C) 2015-2025 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel
@@ -79,8 +79,9 @@ Since `execute-kbd-macro' doesn't pick up a let-bound
`default-directory'.")
(interactive)
(let ((default-directory (or ivy-eval-dir default-directory)))
(setq ivy-result (eval ivy-expr))))
+(ivy--no-M-x #'ivy-eval #'ignore)
-(global-set-key (kbd "C-c e") 'ivy-eval)
+(global-set-key (kbd "C-c e") #'ivy-eval)
(defvar ivy-test-inhibit-message t)
@@ -518,6 +519,24 @@ Since `execute-kbd-macro' doesn't pick up a let-bound
`default-directory'.")
'(("foo")) t)
"^(?!.*foo)")))
+(ert-deftest counsel--M-x-prompt ()
+ "Test `counsel--M-x-prompt' behavior."
+ (should (equal (counsel--M-x-prompt ()) "M-x "))
+ (should (equal (counsel--M-x-prompt t) "M-x "))
+ (should (equal (counsel--M-x-prompt '(())) "M-x "))
+ (should (equal (counsel--M-x-prompt '(t)) "M-x "))
+ (should (equal (counsel--M-x-prompt -1) "-1 M-x "))
+ (should (equal (counsel--M-x-prompt '(-1)) "-1 M-x "))
+ (should (equal (counsel--M-x-prompt 0) "0 M-x "))
+ (should (equal (counsel--M-x-prompt '(0)) "0 M-x "))
+ (should (equal (counsel--M-x-prompt 1) "1 M-x "))
+ (should (equal (counsel--M-x-prompt '(1)) "1 M-x "))
+ (should (equal (counsel--M-x-prompt 4) "4 M-x "))
+ (should (equal (counsel--M-x-prompt '(4)) "C-u M-x "))
+ (should (equal (counsel--M-x-prompt 16) "16 M-x "))
+ (should (equal (counsel--M-x-prompt '(16)) "16 M-x "))
+ (should (equal (counsel--M-x-prompt '-) "- M-x ")))
+
(defmacro ivy--string-buffer (text &rest body)
"Test helper that wraps TEXT in a temp buffer while running BODY."
`(with-temp-buffer
diff --git a/ivy.el b/ivy.el
index 3c900c9542..47b3a36529 100644
--- a/ivy.el
+++ b/ivy.el
@@ -1,6 +1,6 @@
;;; ivy.el --- Incremental Vertical completYon -*- lexical-binding: t -*-
-;; Copyright (C) 2015-2025 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2026 Free Software Foundation, Inc.
;; Author: Oleh Krehel <[email protected]>
;; Maintainer: Basil L. Contovounesios <[email protected]>
@@ -313,79 +313,89 @@ action functions.")
;;; Keymap
-(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."
+ (declare (obsolete define-key "0.16.0"))
(function-put def 'no-counsel-M-x t)
(define-key keymap key def))
+(defun ivy--no-M-x (cmd pred &optional pred-only)
+ "Remove CMD from \\`M-x' completion.
+PRED is either a `completion-predicate' function or a list of
+`command-modes'. PRED-ONLY nil also excludes CMD from `counsel-M-x'."
+ ;; Avoid unknown defun property warnings with `declare' in Emacs < 28.
+ ;; Test for list rather than function since the latter may not yet be fbound
+ ;; at load time.
+ (let ((prop (if (listp pred) 'command-modes 'completion-predicate)))
+ (function-put cmd prop pred))
+ (unless pred-only
+ (function-put cmd 'no-counsel-M-x t)))
+
+(autoload 'minibuffer-keyboard-quit "delsel" nil t)
+(autoload 'hydra-ivy/body "ivy-hydra" nil t)
+(ivy--no-M-x #'hydra-ivy/body #'ivy--minibuffer-p)
+
(defvar ivy-minibuffer-map
(let ((map (make-sparse-keymap)))
- (ivy-define-key map (kbd "C-m") #'ivy-done)
- (define-key map [down-mouse-1] #'ignore)
- (ivy-define-key map [mouse-1] #'ivy-mouse-done)
- (ivy-define-key map [mouse-3] #'ivy-mouse-dispatching-done)
- (ivy-define-key map (kbd "C-M-m") #'ivy-call)
- (ivy-define-key map (kbd "C-j") #'ivy-alt-done)
- (ivy-define-key map (kbd "C-M-j") #'ivy-immediate-done)
- (ivy-define-key map (kbd "TAB") #'ivy-partial-or-done)
- (ivy-define-key map `[remap ,#'next-line] #'ivy-next-line)
- (ivy-define-key map `[remap ,#'previous-line] #'ivy-previous-line)
- (ivy-define-key map (kbd "C-r") #'ivy-reverse-i-search)
+ (define-key map (kbd "C-m") #'ivy-done)
+ (define-key map (kbd "<down-mouse-1>") #'ignore)
+ (define-key map (kbd "<mouse-1>") #'ivy-mouse-done)
+ (define-key map (kbd "<mouse-3>") #'ivy-mouse-dispatching-done)
+ (define-key map (kbd "C-M-m") #'ivy-call)
+ (define-key map (kbd "C-j") #'ivy-alt-done)
+ (define-key map (kbd "C-M-j") #'ivy-immediate-done)
+ (define-key map (kbd "TAB") #'ivy-partial-or-done)
+ (define-key map `[remap ,#'next-line] #'ivy-next-line)
+ (define-key map `[remap ,#'previous-line] #'ivy-previous-line)
+ (define-key map (kbd "C-r") #'ivy-reverse-i-search)
(define-key map (kbd "SPC") #'self-insert-command)
- (ivy-define-key map `[remap ,#'delete-backward-char]
- #'ivy-backward-delete-char)
- (ivy-define-key map `[remap ,#'backward-delete-char-untabify]
- #'ivy-backward-delete-char)
- (ivy-define-key map `[remap ,#'backward-kill-word]
#'ivy-backward-kill-word)
- (ivy-define-key map `[remap ,#'delete-char] #'ivy-delete-char)
- (ivy-define-key map `[remap ,#'forward-char] #'ivy-forward-char)
- (ivy-define-key map (kbd "<right>") #'ivy-forward-char)
- (ivy-define-key map `[remap ,#'kill-word] #'ivy-kill-word)
- (ivy-define-key map `[remap ,#'beginning-of-buffer]
- #'ivy-beginning-of-buffer)
- (ivy-define-key map `[remap ,#'end-of-buffer] #'ivy-end-of-buffer)
- (ivy-define-key map (kbd "M-n") #'ivy-next-history-element)
- (ivy-define-key map (kbd "M-p") #'ivy-previous-history-element)
+ (define-key map `[remap ,#'delete-backward-char]
#'ivy-backward-delete-char)
+ (define-key map `[remap ,#'backward-delete-char-untabify]
+ #'ivy-backward-delete-char)
+ (define-key map `[remap ,#'backward-kill-word] #'ivy-backward-kill-word)
+ (define-key map `[remap ,#'delete-char] #'ivy-delete-char)
+ (define-key map `[remap ,#'forward-char] #'ivy-forward-char)
+ (define-key map (kbd "<right>") #'ivy-forward-char)
+ (define-key map `[remap ,#'kill-word] #'ivy-kill-word)
+ (define-key map `[remap ,#'beginning-of-buffer] #'ivy-beginning-of-buffer)
+ (define-key map `[remap ,#'end-of-buffer] #'ivy-end-of-buffer)
+ (define-key map (kbd "M-n") #'ivy-next-history-element)
+ (define-key map (kbd "M-p") #'ivy-previous-history-element)
(define-key map (kbd "C-g") #'minibuffer-keyboard-quit)
- (ivy-define-key map `[remap ,#'scroll-up-command] #'ivy-scroll-up-command)
- (ivy-define-key map `[remap ,#'scroll-down-command]
- #'ivy-scroll-down-command)
- (ivy-define-key map (kbd "<next>") #'ivy-scroll-up-command)
- (ivy-define-key map (kbd "<prior>") #'ivy-scroll-down-command)
- (ivy-define-key map (kbd "C-v") #'ivy-scroll-up-command)
- (ivy-define-key map (kbd "M-v") #'ivy-scroll-down-command)
- (ivy-define-key map (kbd "C-M-n") #'ivy-next-line-and-call)
- (ivy-define-key map (kbd "C-M-p") #'ivy-previous-line-and-call)
- (ivy-define-key map (kbd "M-a") #'ivy-toggle-marks)
- (ivy-define-key map (kbd "M-r") #'ivy-toggle-regexp-quote)
- (ivy-define-key map (kbd "M-j") #'ivy-yank-word)
- (ivy-define-key map (kbd "M-i") #'ivy-insert-current)
- (ivy-define-key map (kbd "C-M-y") #'ivy-insert-current-full)
- (ivy-define-key map (kbd "C-o") #'hydra-ivy/body)
- (ivy-define-key map (kbd "M-o") #'ivy-dispatching-done)
- (ivy-define-key map (kbd "C-M-o") #'ivy-dispatching-call)
- (ivy-define-key map `[remap ,#'kill-line] #'ivy-kill-line)
- (ivy-define-key map `[remap ,#'kill-whole-line] #'ivy-kill-whole-line)
- (ivy-define-key map (kbd "S-SPC") #'ivy-restrict-to-matches)
- (ivy-define-key map `[remap ,#'kill-ring-save] #'ivy-kill-ring-save)
- (ivy-define-key map (kbd "C-M-a") #'ivy-read-action)
- (ivy-define-key map (kbd "C-c C-o") #'ivy-occur)
- (ivy-define-key map (kbd "C-c C-a") #'ivy-toggle-ignore)
- (ivy-define-key map (kbd "C-c C-s") #'ivy-rotate-sort)
- (ivy-define-key map `[remap ,#'describe-mode] #'ivy-help)
- (ivy-define-key map "$" #'ivy-magic-read-file-env)
+ (define-key map `[remap ,#'scroll-up-command] #'ivy-scroll-up-command)
+ (define-key map `[remap ,#'scroll-down-command] #'ivy-scroll-down-command)
+ (define-key map (kbd "<next>") #'ivy-scroll-up-command)
+ (define-key map (kbd "<prior>") #'ivy-scroll-down-command)
+ (define-key map (kbd "C-v") #'ivy-scroll-up-command)
+ (define-key map (kbd "M-v") #'ivy-scroll-down-command)
+ (define-key map (kbd "C-M-n") #'ivy-next-line-and-call)
+ (define-key map (kbd "C-M-p") #'ivy-previous-line-and-call)
+ (define-key map (kbd "M-a") #'ivy-toggle-marks)
+ (define-key map (kbd "M-r") #'ivy-toggle-regexp-quote)
+ (define-key map (kbd "M-j") #'ivy-yank-word)
+ (define-key map (kbd "M-i") #'ivy-insert-current)
+ (define-key map (kbd "C-M-y") #'ivy-insert-current-full)
+ (define-key map (kbd "C-o") #'hydra-ivy/body)
+ (define-key map (kbd "M-o") #'ivy-dispatching-done)
+ (define-key map (kbd "C-M-o") #'ivy-dispatching-call)
+ (define-key map `[remap ,#'kill-line] #'ivy-kill-line)
+ (define-key map `[remap ,#'kill-whole-line] #'ivy-kill-whole-line)
+ (define-key map (kbd "S-SPC") #'ivy-restrict-to-matches)
+ (define-key map `[remap ,#'kill-ring-save] #'ivy-kill-ring-save)
+ (define-key map (kbd "C-M-a") #'ivy-read-action)
+ (define-key map (kbd "C-c C-o") #'ivy-occur)
+ (define-key map (kbd "C-c C-a") #'ivy-toggle-ignore)
+ (define-key map (kbd "C-c C-s") #'ivy-rotate-sort)
+ (define-key map `[remap ,#'describe-mode] #'ivy-help)
+ (define-key map (kbd "$") #'ivy-magic-read-file-env)
map)
"Keymap used in the minibuffer.")
(defvar ivy-mode-map
(let ((map (make-sparse-keymap)))
- (ivy-define-key map `[remap ,#'switch-to-buffer] #'ivy-switch-buffer)
- (ivy-define-key map `[remap ,#'switch-to-buffer-other-window]
+ (define-key map `[remap ,#'switch-to-buffer] #'ivy-switch-buffer)
+ (define-key map `[remap ,#'switch-to-buffer-other-window]
#'ivy-switch-buffer-other-window)
map)
"Keymap for `ivy-mode'.")
@@ -393,25 +403,32 @@ Remove DEF from `counsel-M-x' list."
;;; Globals
(cl-defstruct ivy-state
+ "State representing a call to `ivy-read'."
prompt collection
predicate require-match initial-input
history preselect keymap update-fn sort
- ;; The frame in which `ivy-read' was called
- frame
- ;; The window in which `ivy-read' was called
- window
- ;; The buffer in which `ivy-read' was called
- buffer
- ;; The value of `ivy-text' to be used by `ivy-occur'
- text
+ (frame
+ nil :type frame :documentation
+ "The frame in which `ivy-read' was called.")
+ (window
+ nil :type window :documentation
+ "The window in which `ivy-read' was called.")
+ (buffer
+ nil :type buffer :documentation
+ "The buffer in which `ivy-read' was called.")
+ (text
+ nil :type string :documentation
+ "The value of `ivy-text' to be used by `ivy-occur'.")
action
unwind
re-builder
matcher
- ;; When this is non-nil, call it for each input change to get new candidates
- dynamic-collection
- ;; A lambda that transforms candidates only for display
- display-transformer-fn
+ (dynamic-collection
+ nil :documentation
+ "When non-nil, call collection anew for each input change.")
+ (display-transformer-fn
+ nil :documentation
+ "A function that formats candidates for display.")
directory
caller
current
@@ -746,6 +763,7 @@ candidate, not the prompt."
(setq ivy--prompt-extra " (match required)")
(insert ivy-text)
(ivy--exhibit))))))
+(ivy--no-M-x #'ivy-done #'ivy--minibuffer-p)
(defvar ivy-mouse-1-tooltip
"Exit the minibuffer with the selected candidate."
@@ -788,21 +806,23 @@ candidate, not the prompt."
offset)
nil))
-(defun ivy-mouse-done (event)
- (interactive "@e")
+(defun ivy--mouse-done (event done)
+ "Move to minibuffer mouse EVENT and call DONE."
(let ((offset (ivy-mouse-offset event)))
(when offset
(ivy-next-line offset)
(ivy--exhibit)
- (ivy-alt-done))))
+ (funcall done))))
+
+(defun ivy-mouse-done (event)
+ (interactive "@e")
+ (ivy--mouse-done event #'ivy-alt-done))
+(ivy--no-M-x #'ivy-mouse-done #'ivy--minibuffer-p)
(defun ivy-mouse-dispatching-done (event)
(interactive "@e")
- (let ((offset (ivy-mouse-offset event)))
- (when offset
- (ivy-next-line offset)
- (ivy--exhibit)
- (ivy-dispatching-done))))
+ (ivy--mouse-done event #'ivy-dispatching-done))
+(ivy--no-M-x #'ivy-mouse-dispatching-done #'ivy--minibuffer-p)
(defcustom ivy-read-action-format-function 'ivy-read-action-format-default
"Function used to transform the actions list into a docstring."
@@ -869,12 +889,13 @@ where KEY and DOC are strings."
(nreverse cols))
"\n"))))
+(autoload 'ivy-hydra-read-action "ivy-hydra")
(defcustom ivy-read-action-function #'ivy-read-action-by-key
"Function used to read an action."
- :type '(radio
- (function-item ivy-read-action-by-key)
- (function-item ivy-read-action-ivy)
- (function-item ivy-hydra-read-action)))
+ :type `(radio
+ (function-item ,#'ivy-read-action-by-key)
+ (function-item ,#'ivy-read-action-ivy)
+ (function-item ,#'ivy-hydra-read-action)))
(defun ivy-read-action ()
"Change the action to one of the available ones.
@@ -887,6 +908,7 @@ selection, non-nil otherwise."
t
(let ((ivy--directory ivy--directory))
(funcall ivy-read-action-function actions)))))
+(ivy--no-M-x #'ivy-read-action #'ivy--minibuffer-p)
(defvar set-message-function)
@@ -949,6 +971,7 @@ will be called for each element of this list.")
(when (ivy-read-action)
(ivy-done)))
(ivy-shrink-after-dispatching))
+(ivy--no-M-x #'ivy-dispatching-done #'ivy--minibuffer-p)
(defun ivy-dispatching-call ()
"Select one of the available actions and call `ivy-call'."
@@ -962,6 +985,7 @@ will be called for each element of this list.")
(ivy-call))
(ivy-set-action actions)))
(ivy-shrink-after-dispatching))
+(ivy--no-M-x #'ivy-dispatching-call #'ivy--minibuffer-p)
(defun ivy-build-tramp-name (x)
"Reconstruct X into a path.
@@ -981,10 +1005,11 @@ Is is a cons cell, related to
`tramp-get-completion-function'."
:type '(alist :key-type symbol :value-type function))
(defun ivy--completing-fname-p ()
- (let ((meta (ignore-errors
- (funcall (ivy-state-collection ivy-last) ivy-text nil
'metadata))))
- (and (consp meta)
- (eq 'file (cdr (assoc 'category meta))))))
+ (let* ((table (ivy-state-collection ivy-last))
+ (md (condition-case nil
+ (completion-metadata ivy-text table nil)
+ (error '(metadata)))))
+ (eq (ivy--metadata-get md 'category) 'file)))
(defun ivy-alt-done (&optional arg)
"Exit the minibuffer with the selected candidate.
@@ -1003,6 +1028,7 @@ of exiting. This function is otherwise like `ivy-done'."
(ivy--directory-done))
(t
(ivy-done)))))
+(ivy--no-M-x #'ivy-alt-done #'ivy--minibuffer-p)
(defun ivy--info-alt-done ()
(if (member (ivy-state-current ivy-last) '("(./)" "(../)"))
@@ -1154,6 +1180,7 @@ If the text hasn't changed as a result, forward to
`ivy-alt-done'."
(when (or (eq this-command last-command)
(eq ivy--length 1))
(ivy-alt-done))))))
+(ivy--no-M-x #'ivy-partial-or-done #'ivy--minibuffer-p)
(defun ivy--partial-cd-for-single-directory ()
(when (and
@@ -1171,16 +1198,14 @@ If the text hasn't changed as a result, forward to
`ivy-alt-done'."
"Complete the minibuffer text as much as possible."
(interactive)
(if (ivy-state-dynamic-collection ivy-last)
- (let* ((bnd
- (ignore-errors
- (funcall
- (ivy-state-collection ivy-last)
- ivy-text nil (cons 'boundaries (buffer-substring (point)
(line-end-position))))))
+ (let* ((table (ivy-state-collection ivy-last))
+ (suf (buffer-substring (point) (ivy--pos-eol)))
+ (bnd (ignore-errors
+ (completion-boundaries ivy-text table nil suf)))
(beg (+ (minibuffer-prompt-end)
- (if bnd (cadr bnd) 0))))
+ (or (car bnd) 0))))
(delete-region beg (point-max))
- (insert
- (ivy-state-current ivy-last))
+ (insert (ivy-state-current ivy-last))
t)
(let* ((parts (or (ivy--split-spaces ivy-text) (list "")))
(tail (last parts))
@@ -1209,6 +1234,7 @@ If the text hasn't changed as a result, forward to
`ivy-alt-done'."
(insert ivy-text)
(ivy--partial-cd-for-single-directory)
t)))))
+(ivy--no-M-x #'ivy-partial #'ivy--minibuffer-p)
(defvar ivy-completion-beg nil
"Completion bounds start.")
@@ -1241,6 +1267,7 @@ If the text hasn't changed as a result, forward to
`ivy-alt-done'."
(setq ivy-completion-beg ivy-completion-end)
(setq ivy-exit 'done)
(exit-minibuffer))
+(ivy--no-M-x #'ivy-immediate-done #'ivy--minibuffer-p)
(defun ivy--restore-session (&optional session)
"Resume a recorded completion SESSION, if any exists."
@@ -1314,23 +1341,27 @@ if one exists."
"Select the first completion candidate."
(interactive)
(ivy-set-index 0))
+(ivy--no-M-x #'ivy-beginning-of-buffer #'ivy--minibuffer-p)
(defun ivy-end-of-buffer ()
"Select the last completion candidate."
(interactive)
(ivy-set-index (1- ivy--length)))
+(ivy--no-M-x #'ivy-end-of-buffer #'ivy--minibuffer-p)
(defun ivy-scroll-up-command ()
"Scroll the candidates upward by the minibuffer height."
(interactive)
(ivy-set-index (min (1- (+ ivy--index ivy-height))
(1- ivy--length))))
+(ivy--no-M-x #'ivy-scroll-up-command #'ivy--minibuffer-p)
(defun ivy-scroll-down-command ()
"Scroll the candidates downward by the minibuffer height."
(interactive)
(ivy-set-index (max (1+ (- ivy--index ivy-height))
0)))
+(ivy--no-M-x #'ivy-scroll-down-command #'ivy--minibuffer-p)
(defun ivy-next-line (&optional arg)
"Move cursor vertically down ARG candidates."
@@ -1342,6 +1373,7 @@ if one exists."
(ivy-beginning-of-buffer)
(ivy-set-index (1- ivy--length)))
(ivy-set-index index))))
+(ivy--no-M-x #'ivy-next-line #'ivy--minibuffer-p)
(defun ivy-next-line-or-history (&optional arg)
"Move cursor vertically down ARG candidates.
@@ -1351,6 +1383,7 @@ If the input is empty, select the previous history
element instead."
(ivy-next-line arg)
(when (and (string= ivy-text "") (= ivy--index orig-index))
(ivy-previous-history-element 1))))
+(ivy--no-M-x #'ivy-next-line-or-history #'ivy--minibuffer-p)
(defun ivy-previous-line (&optional arg)
"Move cursor vertically up ARG candidates."
@@ -1363,6 +1396,7 @@ If the input is empty, select the previous history
element instead."
(ivy-end-of-buffer)
(ivy-set-index min-index))
(ivy-set-index index))))
+(ivy--no-M-x #'ivy-previous-line #'ivy--minibuffer-p)
(defun ivy-previous-line-or-history (arg)
"Move cursor vertically up ARG candidates.
@@ -1372,12 +1406,14 @@ If the input is empty, select the previous history
element instead."
(ivy-previous-line arg)
(when (and (string= ivy-text "") (= ivy--index orig-index))
(ivy-previous-history-element 1))))
+(ivy--no-M-x #'ivy-previous-line-or-history #'ivy--minibuffer-p)
(defun ivy-toggle-calling ()
"Flip `ivy-calling'."
(interactive)
(when (setq ivy-calling (not ivy-calling))
(ivy-call)))
+(ivy--no-M-x #'ivy-toggle-calling #'ivy--minibuffer-p)
(defun ivy-toggle-ignore ()
"Toggle user-configured candidate filtering."
@@ -1389,6 +1425,7 @@ If the input is empty, select the previous history
element instead."
(setf (ivy-state-ignore ivy-last) ivy-use-ignore)
;; invalidate cache
(setq ivy--old-cands nil))
+(ivy--no-M-x #'ivy-toggle-ignore #'ivy--minibuffer-p)
(defun ivy--get-action (state)
"Get the action function from STATE."
@@ -1438,6 +1475,7 @@ If the input is empty, select the previous history
element instead."
(when ivy-action-wrap
(setf (car action) 1))
(cl-incf (car action)))))))
+(ivy--no-M-x #'ivy-next-action #'ivy--minibuffer-p)
(defun ivy-prev-action ()
"When the current action is a list, scroll it backwards."
@@ -1448,6 +1486,7 @@ If the input is empty, select the previous history
element instead."
(when ivy-action-wrap
(setf (car action) (1- (length action))))
(cl-decf (car action))))))
+(ivy--no-M-x #'ivy-prev-action #'ivy--minibuffer-p)
(defun ivy-action-name ()
"Return the name associated with the current action."
@@ -1555,6 +1594,7 @@ See variable `ivy-recursive-restore' for further
information."
(if ivy-inhibit-action
res
current)))
+(ivy--no-M-x #'ivy-call #'ivy--minibuffer-p)
(defun ivy-call-and-recenter ()
"Call action and recenter window according to the selected candidate."
@@ -1562,6 +1602,7 @@ See variable `ivy-recursive-restore' for further
information."
(ivy-call)
(with-ivy-window
(recenter-top-bottom)))
+(ivy--no-M-x #'ivy-call-and-recenter #'ivy--minibuffer-p)
(defun ivy-next-line-and-call (&optional arg)
"Move cursor vertically down ARG candidates.
@@ -1570,6 +1611,7 @@ Call the permanent action if possible."
(ivy-next-line arg)
(ivy--exhibit)
(ivy-call))
+(ivy--no-M-x #'ivy-next-line-and-call #'ivy--minibuffer-p)
(defun ivy-previous-line-and-call (&optional arg)
"Move cursor vertically up ARG candidates.
@@ -1578,6 +1620,7 @@ Call the permanent action if possible."
(ivy-previous-line arg)
(ivy--exhibit)
(ivy-call))
+(ivy--no-M-x #'ivy-previous-line-and-call #'ivy--minibuffer-p)
(defun ivy-previous-history-element (arg)
"Forward to `previous-history-element' with ARG."
@@ -1586,6 +1629,7 @@ Call the permanent action if possible."
(ivy--cd-maybe)
(move-end-of-line 1)
(ivy--maybe-scroll-history))
+(ivy--no-M-x #'ivy-previous-history-element #'ivy--minibuffer-p)
(defun ivy--insert-symbol-boundaries ()
(undo-boundary)
@@ -1614,6 +1658,7 @@ Call the permanent action if possible."
(ivy--cd-maybe)
(move-end-of-line 1)
(ivy--maybe-scroll-history))
+(ivy--no-M-x #'ivy-next-history-element #'ivy--minibuffer-p)
(defvar ivy-ffap-url-functions nil
"List of functions that check if the point is on a URL.")
@@ -1699,24 +1744,28 @@ minibuffer."
(error
(when ivy-on-del-error-function
(funcall ivy-on-del-error-function))))))
+(ivy--no-M-x #'ivy-backward-delete-char #'ivy--minibuffer-p)
(defun ivy-delete-char (arg)
"Forward to `delete-char' ARG."
(interactive "p")
(unless (eolp)
(delete-char arg)))
+(ivy--no-M-x #'ivy-delete-char #'ivy--minibuffer-p)
(defun ivy-forward-char (arg)
"Forward to `forward-char' ARG."
(interactive "p")
(unless (eolp)
(forward-char arg)))
+(ivy--no-M-x #'ivy-forward-char #'ivy--minibuffer-p)
(defun ivy-kill-word (arg)
"Forward to `kill-word' ARG."
(interactive "p")
(unless (eolp)
(kill-word arg)))
+(ivy--no-M-x #'ivy-kill-word #'ivy--minibuffer-p)
(defun ivy-kill-line ()
"Forward to `kill-line'."
@@ -1726,11 +1775,21 @@ minibuffer."
(kill-region (minibuffer-prompt-end) (point))
(setq ivy--old-text (current-kill 0 t)))
(kill-line)))
+(ivy--no-M-x #'ivy-kill-line #'ivy--minibuffer-p)
+
+(defalias 'ivy--pos-eol
+ (if (fboundp 'pos-eol)
+ #'pos-eol
+ (lambda (&optional n)
+ (let ((inhibit-field-text-motion t))
+ (line-end-position n))))
+ "Compatibility shim for Emacs 29 `pos-eol'.")
(defun ivy-kill-whole-line ()
"Forward to `kill-whole-line'."
(interactive)
- (kill-region (minibuffer-prompt-end) (line-end-position)))
+ (kill-region (minibuffer-prompt-end) (ivy--pos-eol)))
+(ivy--no-M-x #'ivy-kill-whole-line #'ivy--minibuffer-p)
(defun ivy-backward-kill-word ()
"Forward to `backward-kill-word'."
@@ -1746,6 +1805,7 @@ minibuffer."
last-command)))
(forward-word -1)
(kill-region pt (point))))))
+(ivy--no-M-x #'ivy-backward-kill-word #'ivy--minibuffer-p)
(defvar ivy--regexp-quote #'regexp-quote
"Store the regexp quoting state.")
@@ -1757,6 +1817,7 @@ minibuffer."
(cl-rotatef ivy--regex-function ivy--regexp-quote)
(setq ivy--old-text "")
(setq ivy-regex (funcall ivy--regex-function ivy-text)))
+(ivy--no-M-x #'ivy-toggle-regexp-quote #'ivy--minibuffer-p)
(defcustom ivy-format-functions-alist
'((t . ivy-format-function-default))
@@ -1840,6 +1901,7 @@ specified for the current collection in
(when (consp (cdr cell))
(setcdr cell (nconc (cddr cell) (list (cadr cell))))
(ivy--reset-state ivy-last))))
+(ivy--no-M-x #'ivy-rotate-sort #'ivy--minibuffer-p)
(defcustom ivy-index-functions-alist
'((t . ivy-recompute-index-zero))
@@ -2284,10 +2346,6 @@ customizations apply to the current completion session."
hist (propertize item 'ivy-index ivy--index))))))))
(defun ivy--cleanup ()
- ;; Fixes a bug in ESS, #1660
- (put 'post-command-hook 'permanent-local nil)
- (remove-hook 'post-command-hook #'ivy--queue-exhibit)
- (remove-hook 'window-size-change-functions #'ivy--window-size-changed)
(let ((cleanup (ivy--display-function-prop :cleanup))
(unwind (ivy-state-unwind ivy-last)))
(when (functionp cleanup)
@@ -2529,6 +2587,13 @@ This is useful for recursive `ivy-read'."
"Make STR suitable for `format' with no extra arguments."
(ivy--string-replace "%" "%%" str))
+(defun ivy--crm-p (collection)
+ "Return non-nil if completing multiple strings from COLLECTION.
+That is, if we are called from `completing-read-multiple'."
+ ;; It would be nicer to check for `crm-completion-table',
+ ;; but that is local to the minibuffer which may be too late.
+ (eq collection 'crm--collection-fn))
+
;;;###autoload
(defun ivy-completing-read (prompt collection
&optional predicate require-match initial-input
@@ -2549,14 +2614,22 @@ INHERIT-INPUT-METHOD is currently ignored."
(let ((handler
(and (< ivy-completing-read-ignore-handlers-depth (minibuffer-depth))
(assq this-command ivy-completing-read-handlers-alist))))
- (if handler
- (let ((completion-in-region-function #'completion--in-region)
- (ivy-completing-read-ignore-handlers-depth (1+
(minibuffer-depth))))
- (funcall (cdr handler)
- prompt collection
- predicate require-match
- initial-input history
- def inherit-input-method))
+ (cond
+ (handler
+ (let (;; This could also be customizable.
+ (completion-in-region-function #'completion--in-region)
+ (ivy-completing-read-ignore-handlers-depth (1+
(minibuffer-depth))))
+ (funcall (cdr handler)
+ prompt collection predicate require-match
+ initial-input history def inherit-input-method)))
+ ((ivy--crm-p collection)
+ ;; Ivy is currently incompatible with `completing-read-multiple'.
+ ;; This was harmless while crm called `read-from-minibuffer'
+ ;; directly; but since Emacs 31 it uses `completing-read':
+ ;; `https://bugs.gnu.org/80296'.
+ (completing-read-default prompt collection predicate require-match
+ initial-input history def inherit-input-method))
+ (t
;; See the doc of `completing-read'.
(when (consp history)
(when (numberp (cdr history))
@@ -2589,7 +2662,7 @@ INHERIT-INPUT-METHOD is currently ignored."
;; For `completing-read' compat, return the first element of
;; DEFAULT, if it is a list; "", if DEFAULT is nil; or DEFAULT.
(or def "")
- str)))))
+ str))))))
(defun ivy-completing-read-with-empty-string-def
(prompt collection
@@ -2724,7 +2797,7 @@ See `completion-in-region' for further information."
(completion--done str 'finished "Sole match"))
t)
(t
- (when (eq collection 'crm--collection-fn)
+ (when (ivy--crm-p collection)
(setq comps (delete-dups comps)))
(let ((initial (substring str base-size))
(base-pos (+ start base-size)))
@@ -3107,8 +3180,11 @@ tries to ensure that it does not change depending on the
number of candidates."
"Minibuffer setting for `truncate-lines'."
:type 'boolean)
+(defvar-local ivy--minibuffer nil
+ "Whether the current buffer is an Ivy minibuffer.")
+
(defun ivy--minibuffer-setup ()
- "Setup ivy completion in the minibuffer."
+ "Set up Ivy completion in `minibuffer-setup-hook'."
;; Guard for --without-x builds where `mwheel' is not preloaded.
(when (boundp 'mwheel-scroll-up-function)
(setq-local mwheel-scroll-up-function 'ivy-next-line))
@@ -3129,27 +3205,32 @@ tries to ensure that it does not change depending on
the number of candidates."
(ivy-add-newline-after-prompt 2))))
(when height
(set-window-text-height nil height)))
+ (add-hook 'minibuffer-exit-hook #'ivy--minibuffer-exit nil t)
(add-hook 'post-command-hook #'ivy--queue-exhibit nil t)
(add-hook 'window-size-change-functions #'ivy--window-size-changed nil t)
+ (setq ivy--minibuffer t)
(let ((hook (ivy-alist-setting ivy-hooks-alist)))
(when (functionp hook)
(funcall hook))))
+(defun ivy--minibuffer-exit ()
+ "Clean up Ivy completion in `minibuffer-exit-hook'."
+ (remove-hook 'minibuffer-exit-hook #'ivy--minibuffer-exit t)
+ (remove-hook 'post-command-hook #'ivy--queue-exhibit t)
+ (remove-hook 'window-size-change-functions #'ivy--window-size-changed t))
+
(defun ivy--input ()
"Return the current minibuffer input."
- ;; assume one-line minibuffer input
+ ;; Assume one-line minibuffer input.
(save-excursion
(goto-char (minibuffer-prompt-end))
- (let ((inhibit-field-text-motion t))
- (buffer-substring-no-properties
- (point)
- (line-end-position)))))
+ (buffer-substring-no-properties (point) (ivy--pos-eol))))
(defun ivy--minibuffer-cleanup ()
"Delete the displayed completion candidates."
(save-excursion
(goto-char (minibuffer-prompt-end))
- (delete-region (line-end-position) (point-max))))
+ (delete-region (ivy--pos-eol) (point-max))))
(defun ivy-cleanup-string (str)
"Destructively remove unwanted text properties from STR."
@@ -3286,11 +3367,11 @@ Also handle `ivy-set-prompt-text-properties-function'."
;; option left. Since the user input stays put, we have to manually
;; remove the face as well.
(when ivy--use-selectable-prompt
- (if (= ivy--index -1)
- (add-face-text-property
- (minibuffer-prompt-end) (line-end-position) 'ivy-prompt-match)
- (remove-list-of-text-properties
- (minibuffer-prompt-end) (line-end-position) '(face))))
+ (let ((prompt (minibuffer-prompt-end))
+ (eol (ivy--pos-eol)))
+ (if (= ivy--index -1)
+ (add-face-text-property prompt eol 'ivy-prompt-match)
+ (remove-list-of-text-properties prompt eol '(face)))))
;; get out of the prompt area
(constrain-to-field nil (point-max))))))
@@ -3396,26 +3477,24 @@ Possible choices are
`ivy-magic-slash-non-match-cd-selected',
path))
(ivy--cd-maybe))
(insert last-input-event)))
+(ivy--no-M-x #'ivy-magic-read-file-env #'ivy--minibuffer-p)
(defun ivy-make-magic-action (caller key)
"Return a command that does the equivalent of `ivy-read-action' and KEY.
This happens only when the input is empty.
The intention is to bind the result to keys that are typically
bound to `self-insert-command'."
- (let* ((alist (assoc key
- (plist-get
- ivy--actions-list
- caller)))
- (doc (format "%s (`%S')"
- (nth 2 alist)
- (nth 1 alist))))
- `(lambda (&optional arg)
- ,doc
- (interactive "p")
- (if (string= "" ivy-text)
- (execute-kbd-macro
- (kbd ,(concat "M-o " key)))
- (self-insert-command arg)))))
+ (let* ((action (assoc key (plist-get ivy--actions-list caller)))
+ (fn (nth 1 action))
+ (desc (nth 2 action))
+ (keyseq (kbd (concat "M-o " key))))
+ (defalias (make-symbol (format "ivy--magic-%s" caller))
+ (lambda (&optional arg)
+ (interactive "p")
+ (if (string= "" ivy-text)
+ (execute-kbd-macro keyseq)
+ (self-insert-command arg)))
+ (and action (format "Action: %s (`%S')." desc fn)))))
(defcustom ivy-magic-tilde t
"When non-nil, ~ will move home when selecting files.
@@ -3471,10 +3550,22 @@ The function was added in Emacs 26.1.")
(ivy--format
(setq ivy--all-candidates cands))))
+;; Perhaps only one of `ivy--completing-p' or `ivy--minibuffer-p' is needed,
+;; but they are not equivalent: the former becomes nil after an error.
+
+(defun ivy--completing-p ()
+ "Return non-nil if Ivy is completing in the current buffer."
+ (memq #'ivy--queue-exhibit post-command-hook))
+
+(defun ivy--minibuffer-p (_cmd buf)
+ "Return non-nil if BUF is an Ivy minibuffer.
+Intended as a `completion-predicate'."
+ (buffer-local-value 'ivy--minibuffer buf))
+
(defun ivy--exhibit ()
"Insert Ivy completions display.
Should be run in the minibuffer."
- (when (memq #'ivy--queue-exhibit post-command-hook)
+ (when (ivy--completing-p)
(let ((inhibit-field-text-motion nil))
(constrain-to-field nil (point-max)))
(ivy-set-text (ivy--input))
@@ -3621,7 +3712,7 @@ height < `ivy-height', auto-shrink the minibuffer."
(defun ivy--window-size-changed (&rest _)
"Resize ivy window to fit with current frame's size."
- (when ivy-mode
+ (when (ivy--completing-p)
(ivy--resize-minibuffer-to-fit)))
(defun ivy--add-face (str face)
@@ -3663,6 +3754,7 @@ In any Ivy completion session, the case folding starts
with
(or ivy-case-fold-search-default 'auto)))
;; Reset cache so that the candidate list updates.
(setq ivy--old-re nil))
+(ivy--no-M-x #'ivy-toggle-case-fold #'ivy--minibuffer-p)
(defun ivy--re-filter (filter candidates &optional mkpred)
"Return all CANDIDATES matching FILTER, or nil on error.
@@ -3799,12 +3891,15 @@ 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-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))))
+(defvar ivy--features ()
+ "Alist mapping features to their `require' result.")
+
+(defun ivy--feature-p (feature)
+ "Try to load FEATURE once; return non-nil on success."
+ (cdr (or (assq feature ivy--features)
+ (let ((entry (cons feature (require feature nil t))))
+ (push entry ivy--features)
+ entry))))
(defun ivy--sort (name candidates)
"Re-sort candidates by NAME.
@@ -3813,7 +3908,7 @@ All CANDIDATES are assumed to match NAME."
(cond ((setq fun (ivy-alist-setting ivy-sort-matches-functions-alist))
(funcall fun name candidates))
((and (eq ivy--regex-function #'ivy--regex-fuzzy)
- (ivy--flx-available-p))
+ (ivy--feature-p 'flx))
(ivy--flx-sort name candidates))
(t
candidates))))
@@ -3913,7 +4008,7 @@ CANDS are the current candidates."
((and (not empty)
(not (eq caller 'swiper))
(not (and (eq ivy--regex-function
#'ivy--regex-fuzzy)
- (ivy--flx-available-p)
+ (ivy--feature-p 'flx)
;; Limit to configured number of
candidates
(null (nthcdr ivy-flx-limit cands))))
;; If there was a preselected candidate, don't try
to
@@ -4112,15 +4207,13 @@ N wraps around, but skips the first element of the
list."
SELECTED-FN is called for the selected candidate, OTHER-FN for the others.
Both functions take one string argument each. CANDS is a list of candidates
and SEPARATOR is used to join them."
- (let ((i -1))
- (mapconcat
- (lambda (str)
- (let ((curr (eq (cl-incf i) ivy--window-index)))
- (if curr
- (funcall selected-fn str)
- (funcall other-fn str))))
- cands
- separator)))
+ (mapconcat (let ((i -1))
+ (lambda (str)
+ (funcall (if (eql (cl-incf i) ivy--window-index)
+ selected-fn
+ other-fn)
+ str)))
+ cands separator))
(defun ivy-format-function-default (cands)
"Transform CANDS into a multiline string for the minibuffer.
@@ -4188,7 +4281,7 @@ with the extended highlighting of
`ivy-format-function-line'."
(defun ivy--highlight-fuzzy (str)
"Highlight STR, using the fuzzy method."
(if (and (eq (ivy-alist-setting ivy-re-builders-alist) #'ivy--regex-fuzzy)
- (ivy--flx-available-p))
+ (ivy--feature-p 'flx))
(let ((flx-name (string-remove-prefix "^" ivy-text)))
(ivy--flx-propertize
(cons (flx-score str flx-name ivy--flx-cache) str)))
@@ -4446,32 +4539,26 @@ TREE can be nested multiple times to have multiple
window splits.")
(defun ivy-default-view-name ()
"Return default name for new view."
- (let* ((default-view-name
- (concat "{} "
- (mapconcat #'identity
- (sort
- (mapcar (lambda (w)
- (let* ((b (window-buffer w))
- (f (buffer-file-name b)))
- (if f
- (file-name-nondirectory f)
- (buffer-name b))))
- (window-list))
- #'string-lessp)
- " ")))
+ (let* ((wins (mapcar (lambda (w)
+ (let* ((b (window-buffer w))
+ (f (buffer-file-name b)))
+ (if f
+ (file-name-nondirectory f)
+ (buffer-name b))))
+ (window-list)))
+ (default-view-name
+ (string-join (cons "{}" (sort wins #'string-lessp))
+ " "))
(view-name-re (concat "\\`"
(regexp-quote default-view-name)
- " \\([0-9]+\\)"))
- old-view)
- (cond ((setq old-view
- (cl-find-if
- (lambda (x)
- (string-match view-name-re (car x)))
- ivy-views))
- (format "%s %d"
- default-view-name
- (1+ (string-to-number
- (match-string 1 (car old-view))))))
+ " \\([0-9]+\\)")))
+ (cond ((let ((num (cl-some (lambda (view)
+ (let ((name (car view)))
+ (and (string-match view-name-re name)
+ (string-to-number
+ (match-string 1 name)))))
+ ivy-views)))
+ (and num (format "%s %d" default-view-name (1+ num)))))
((assoc default-view-name ivy-views)
(concat default-view-name " 1"))
(t
@@ -4679,7 +4766,7 @@ BUFFER may be a string or nil."
(defvar ivy-switch-buffer-map
(let ((map (make-sparse-keymap)))
- (ivy-define-key map (kbd "C-k") #'ivy-switch-buffer-kill)
+ (define-key map (kbd "C-k") #'ivy-switch-buffer-kill)
map))
(defun ivy-switch-buffer-kill ()
@@ -4690,6 +4777,7 @@ Otherwise, forward to `ivy-kill-line'."
(ivy-kill-line)
(ivy--kill-buffer-action
(ivy-state-current ivy-last))))
+(ivy--no-M-x #'ivy-switch-buffer-kill #'ivy--minibuffer-p)
(ivy-set-actions
'ivy-switch-buffer
@@ -4740,21 +4828,20 @@ Skip buffers that match `ivy-ignore-buffers'."
(and b (string-match-p
regexp (buffer-local-value 'default-directory b))))))
(copy-sequence candidates)))
- (let ((res (ivy--re-filter regexp candidates)))
- (if (or (null ivy-use-ignore)
- (null ivy-ignore-buffers))
- res
- (or (cl-remove-if
- (lambda (buf)
- (cl-find-if
- (lambda (f-or-r)
- (if (functionp f-or-r)
- (funcall f-or-r buf)
- (string-match-p f-or-r buf)))
- ivy-ignore-buffers))
+ (let ((res (ivy--re-filter regexp candidates))
+ (policy ivy-use-ignore)
+ (ignores ivy-ignore-buffers))
+ (cond ((null (and policy ignores))
res)
- (and (eq ivy-use-ignore t)
- res))))))
+ ((cl-remove-if (lambda (buf)
+ (cl-some (lambda (f-or-r)
+ (if (stringp f-or-r)
+ (string-match-p f-or-r buf)
+ (funcall f-or-r buf)))
+ ignores))
+ res))
+ ((eq policy t)
+ res)))))
(defun ivy-append-face (str face)
"Append to STR the property FACE."
@@ -4871,6 +4958,7 @@ If optional ARG is non-nil, pull in the next ARG
words (previous if ARG is negative)."
(interactive "p")
(ivy--yank-by #'forward-word arg))
+(ivy--no-M-x #'ivy-yank-word #'ivy--minibuffer-p)
(defun ivy-yank-symbol (&optional arg)
"Pull next symbol from buffer into search string.
@@ -4878,6 +4966,7 @@ If optional ARG is non-nil, pull in the next ARG
symbols (previous if ARG is negative)."
(interactive "p")
(ivy--yank-by #'forward-symbol (or arg 1)))
+(ivy--no-M-x #'ivy-yank-symbol #'ivy--minibuffer-p)
(defun ivy-yank-char (&optional arg)
"Pull next character from buffer into search string.
@@ -4885,6 +4974,7 @@ If optional ARG is non-nil, pull in the next ARG
characters (previous if ARG is negative)."
(interactive "p")
(ivy--yank-by #'forward-char arg))
+(ivy--no-M-x #'ivy-yank-char #'ivy--minibuffer-p)
(defvar ivy--pulse-overlay nil
"Overlay used to highlight yanked word.")
@@ -4899,6 +4989,11 @@ When nil, disable highlighting."
(number :tag "Delay in seconds")
(const :tag "Disable" nil)))
+;; TODO: Could use `pulse-momentary-highlight-region' but Emacs 24.5
+;; runs into `https://bugs.gnu.org/47437' since `ivy-yanked-word'
+;; lacks an explicit :background by default. So either Emacs 24
+;; support or `ivy-yanked-word' would need to be dropped.
+;; Also, the `pulse' library does not merge adjacent pulses.
(defun ivy--pulse-region (start end)
"Temporarily highlight text between START and END.
The \"pulse\" duration is determined by `ivy-pulse-delay'."
@@ -4936,6 +5031,7 @@ If the region is active, forward to `kill-ring-save'
instead."
(if (use-region-p)
(call-interactively #'kill-ring-save)
(kill-new (string-join ivy--old-cands "\n"))))
+(ivy--no-M-x #'ivy-kill-ring-save #'ivy--minibuffer-p)
(defun ivy-insert-current ()
"Make the current candidate into current input.
@@ -4947,11 +5043,13 @@ Don't finish completion."
-1)))
(insert (substring-no-properties
(ivy-state-current ivy-last) 0 end))))
+(ivy--no-M-x #'ivy-insert-current #'ivy--minibuffer-p)
(defun ivy-insert-current-full ()
"Insert the current directory into the minibuffer."
(interactive)
(insert ivy--directory))
+(ivy--no-M-x #'ivy-insert-current-full #'ivy--minibuffer-p)
(defcustom ivy-preferred-re-builders
'((ivy--regex-plus . "ivy")
@@ -4970,6 +5068,7 @@ This list can be rotated with
`ivy-rotate-preferred-builders'."
(let ((cell (assq ivy--regex-function ivy-preferred-re-builders)))
(car (or (cadr (memq cell ivy-preferred-re-builders))
(car ivy-preferred-re-builders)))))))
+(ivy--no-M-x #'ivy-rotate-preferred-builders #'ivy--minibuffer-p)
(defun ivy-toggle-fuzzy ()
"Toggle the re builder between `ivy--regex-fuzzy' and `ivy--regex-plus'."
@@ -4978,6 +5077,7 @@ This list can be rotated with
`ivy-rotate-preferred-builders'."
(if (eq ivy--regex-function 'ivy--regex-fuzzy)
(setq ivy--regex-function 'ivy--regex-plus)
(setq ivy--regex-function 'ivy--regex-fuzzy)))
+(ivy--no-M-x #'ivy-toggle-fuzzy #'ivy--minibuffer-p)
(defun ivy--label-and-delete-dups (entries)
"Label ENTRIES with history indices."
@@ -5011,10 +5111,11 @@ This list can be rotated with
`ivy-rotate-preferred-builders'."
(declare-function ring-remove "ring")
(ring-remove history (ring-member history current)))))
(ivy--kill-current-candidate)))
+(ivy--no-M-x #'ivy-reverse-i-search-kill #'ivy--minibuffer-p)
(defvar ivy-reverse-i-search-map
(let ((map (make-sparse-keymap)))
- (ivy-define-key map (kbd "C-k") #'ivy-reverse-i-search-kill)
+ (define-key map (kbd "C-k") #'ivy-reverse-i-search-kill)
map))
(defun ivy-history-contents (history)
@@ -5060,6 +5161,7 @@ You can also delete an element from history with
\\[ivy-reverse-i-search-kill]."
(insert (substring-no-properties (car x)))
(ivy--cd-maybe))
:caller 'ivy-reverse-i-search)))))
+(ivy--no-M-x #'ivy-reverse-i-search #'ivy--minibuffer-p)
(defun ivy-restrict-to-matches ()
"Restrict candidates to current input and erase input."
@@ -5079,31 +5181,39 @@ You can also delete an element from history with
\\[ivy-reverse-i-search-kill]."
(setf (ivy-state-dynamic-collection ivy-last) nil))
(setq ivy--all-candidates
(ivy--filter ivy-text ivy--all-candidates))))
+(ivy--no-M-x #'ivy-restrict-to-matches #'ivy--minibuffer-p)
;;; Occur
+;; Also used by `ivy--occur-p' to identify Ivy Occur buffers
+;; regardless of `major-mode'.
(defvar-local ivy-occur-last nil
- "Buffer-local value of `ivy-last'.
-Can't re-use `ivy-last' because using e.g. `swiper' in the same
+ "Buffer-local and Occur-specific value of `ivy-last'.
+Can't reuse `ivy-last' because using, e.g., `swiper' in the same
buffer would modify `ivy-last'.")
+(defun ivy--occur-p (_cmd buf)
+ "Return non-nil if BUF is an Ivy Occur buffer.
+Intended as a `completion-predicate'."
+ (buffer-local-value 'ivy-occur-last buf))
+
(defvar ivy-occur-mode-map
(let ((map (make-sparse-keymap)))
- (ivy-define-key map [mouse-1] #'ivy-occur-click)
- (ivy-define-key map (kbd "RET") #'ivy-occur-press-and-switch)
- (ivy-define-key map (kbd "j") #'ivy-occur-next-line)
- (ivy-define-key map (kbd "k") #'ivy-occur-previous-line)
+ (define-key map (kbd "<mouse-1>") #'ivy-occur-click)
+ (define-key map (kbd "RET") #'ivy-occur-press-and-switch)
+ (define-key map (kbd "j") #'ivy-occur-next-line)
+ (define-key map (kbd "k") #'ivy-occur-previous-line)
(define-key map (kbd "h") #'backward-char)
(define-key map (kbd "l") #'forward-char)
- (ivy-define-key map (kbd "f") #'ivy-occur-press)
- (ivy-define-key map (kbd "g") #'ivy-occur-revert-buffer)
- (ivy-define-key map (kbd "a") #'ivy-occur-read-action)
- (ivy-define-key map (kbd "o") #'ivy-occur-dispatch)
- (ivy-define-key map (kbd "c") #'ivy-occur-toggle-calling)
+ (define-key map (kbd "f") #'ivy-occur-press)
+ (define-key map (kbd "g") #'ivy-occur-revert-buffer)
+ (define-key map (kbd "a") #'ivy-occur-read-action)
+ (define-key map (kbd "o") #'ivy-occur-dispatch)
+ (define-key map (kbd "c") #'ivy-occur-toggle-calling)
(define-key map (kbd "q") #'quit-window)
(define-key map (kbd "R") #'read-only-mode)
- (ivy-define-key map (kbd "C-d") #'ivy-occur-delete-candidate)
- (ivy-define-key map (kbd "F") #'ivy-occur-flush-lines)
+ (define-key map (kbd "C-d") #'ivy-occur-delete-candidate)
+ (define-key map (kbd "F") #'ivy-occur-flush-lines)
map)
"Keymap for Ivy Occur mode.")
@@ -5116,6 +5226,7 @@ buffer would modify `ivy-last'.")
(ivy-occur-press))
(setq mode-name "Ivy-Occur"))
(force-mode-line-update))
+(ivy--no-M-x #'ivy-occur-toggle-calling #'ivy--occur-p)
(defun ivy--find-occur-buffer ()
(let ((cb (current-buffer)))
@@ -5128,8 +5239,7 @@ buffer would modify `ivy-last'.")
(defun ivy--select-occur-buffer ()
(let* ((ob (ivy--find-occur-buffer))
- (ow (cl-find-if (lambda (w) (equal ob (window-buffer w)))
- (window-list))))
+ (ow (get-buffer-window ob)))
(if ow
(select-window ow)
(pop-to-buffer ob))))
@@ -5154,6 +5264,7 @@ When `ivy-calling' isn't nil, call `ivy-occur-press'."
(ivy--select-occur-buffer)
(ivy-occur-next-line arg)
(ivy-occur-press-and-switch))))
+(ivy--no-M-x #'ivy-occur-next-line #'ivy--occur-p)
(defun ivy-occur-previous-line (&optional arg)
"Move the cursor up ARG lines.
@@ -5172,6 +5283,7 @@ When `ivy-calling' isn't nil, call `ivy-occur-press'."
(ivy--select-occur-buffer)
(ivy-occur-previous-line arg)
(ivy-occur-press-and-switch))))
+(ivy--no-M-x #'ivy-occur-previous-line #'ivy--occur-p)
(defun ivy-occur-next-error (n &optional reset)
"A `next-error-function' for `ivy-occur-mode'."
@@ -5185,6 +5297,7 @@ When `ivy-calling' isn't nil, call `ivy-occur-press'."
;; The window's point overrides the buffer's point every time it's
redisplayed
(dolist (window (get-buffer-window-list nil nil t))
(set-window-point window (point))))
+(ivy--no-M-x #'ivy-occur-next-error #'ivy--occur-p)
(define-derived-mode ivy-occur-mode fundamental-mode "Ivy-Occur"
"Major mode for output from \\[ivy-occur].
@@ -5193,9 +5306,10 @@ When `ivy-calling' isn't nil, call `ivy-occur-press'."
(setq-local view-read-only nil))
(defvar ivy-occur-grep-mode-map
- (let ((map (copy-keymap ivy-occur-mode-map)))
- (ivy-define-key map (kbd "C-x C-q") 'ivy-wgrep-change-to-wgrep-mode)
- (ivy-define-key map "w" 'ivy-wgrep-change-to-wgrep-mode)
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map ivy-occur-mode-map)
+ (define-key map (kbd "C-x C-q") #'ivy-wgrep-change-to-wgrep-mode)
+ (define-key map (kbd "w") #'ivy-wgrep-change-to-wgrep-mode)
map)
"Keymap for Ivy Occur Grep mode.")
@@ -5204,12 +5318,14 @@ When `ivy-calling' isn't nil, call `ivy-occur-press'."
(let ((inhibit-read-only t))
(delete-region (line-beginning-position)
(1+ (line-end-position)))))
+(ivy--no-M-x #'ivy-occur-delete-candidate #'ivy--occur-p)
(defun ivy-occur-flush-lines ()
"Delete lines matching regex."
(interactive)
(let ((inhibit-read-only t))
- (call-interactively 'flush-lines)))
+ (call-interactively #'flush-lines)))
+(ivy--no-M-x #'ivy-occur-flush-lines #'ivy--occur-p)
(define-derived-mode ivy-occur-grep-mode grep-mode "Ivy-Occur"
"Major mode for output from \\[ivy-occur].
@@ -5289,6 +5405,7 @@ There is no limit on the number of *ivy-occur* buffers."
(pop-to-buffer buffer)
(setq next-error-last-buffer buffer)
(setq-local next-error-function #'ivy-occur-next-error))))))
+(ivy--no-M-x #'ivy-occur #'ivy--minibuffer-p)
(defun ivy-occur-revert-buffer ()
"Refresh the buffer making it up-to date with the collection.
@@ -5315,6 +5432,7 @@ updated original buffer."
(goto-char (point-min))
(forward-line (1- line)))
(setq ivy-occur-last ivy-last)))
+(ivy--no-M-x #'ivy-occur-revert-buffer #'ivy--occur-p)
(declare-function wgrep-change-to-wgrep-mode "ext:wgrep")
@@ -5324,12 +5442,14 @@ updated original buffer."
(if (require 'wgrep nil 'noerror)
(wgrep-change-to-wgrep-mode)
(error "Package wgrep isn't installed")))
+(ivy--no-M-x #'ivy-wgrep-change-to-wgrep-mode #'ivy--occur-p)
(defun ivy-occur-read-action ()
"Select one of the available actions as the current one."
(interactive)
(let ((ivy-last ivy-occur-last))
(ivy-read-action)))
+(ivy--no-M-x #'ivy-occur-read-action #'ivy--occur-p)
(defun ivy-occur-dispatch ()
"Call one of the available actions on the current item."
@@ -5343,6 +5463,7 @@ updated original buffer."
(ivy-occur-read-action)
(ivy-occur-press))
(setf (ivy-state-action ivy-occur-last) actions))))
+(ivy--no-M-x #'ivy-occur-dispatch #'ivy--occur-p)
(defun ivy-occur-click (event)
"Execute action for the current candidate.
@@ -5353,6 +5474,7 @@ EVENT gives the mouse position."
(with-current-buffer (window-buffer window)
(goto-char pos)
(ivy-occur-press))))
+(ivy--no-M-x #'ivy-occur-click #'ivy--occur-p)
(declare-function swiper--cleanup "swiper")
(declare-function swiper--add-overlays "swiper")
@@ -5424,12 +5546,14 @@ EVENT gives the mouse position."
(cancel-timer ivy-occur-timer))
(setq ivy-occur-timer
(run-at-time 1.0 nil 'swiper--cleanup))))))))
+(ivy--no-M-x #'ivy-occur-press #'ivy--occur-p)
(defun ivy-occur-press-and-switch ()
"Execute action for the current candidate and switch window."
(interactive)
(ivy-occur-press)
(select-window (ivy--get-window ivy-occur-last)))
+(ivy--no-M-x #'ivy-occur-press-and-switch #'ivy--occur-p)
(defun ivy--marked-p ()
(member (ivy-state-current ivy-last) ivy-marked-candidates))
@@ -5466,6 +5590,7 @@ make decisions based on the whole marked list."
(unless (ivy--marked-p)
(ivy--mark (ivy-state-current ivy-last)))
(ivy-next-line))
+(ivy--no-M-x #'ivy-mark #'ivy--minibuffer-p)
(defun ivy-unmark ()
"Unmark the selected candidate and move to the next one."
@@ -5473,6 +5598,7 @@ make decisions based on the whole marked list."
(when (ivy--marked-p)
(ivy--unmark (ivy-state-current ivy-last)))
(ivy-next-line))
+(ivy--no-M-x #'ivy-unmark #'ivy--minibuffer-p)
(defun ivy-unmark-backward ()
"Move to the previous candidate and unmark it."
@@ -5481,6 +5607,7 @@ make decisions based on the whole marked list."
(ivy--exhibit)
(when (ivy--marked-p)
(ivy--unmark (ivy-state-current ivy-last))))
+(ivy--no-M-x #'ivy-unmark-backward #'ivy--minibuffer-p)
(defun ivy-toggle-marks ()
"Toggle mark for all narrowed candidates."
@@ -5489,6 +5616,7 @@ make decisions based on the whole marked list."
(if (member cand ivy-marked-candidates)
(ivy--unmark cand)
(ivy--mark cand))))
+(ivy--no-M-x #'ivy-toggle-marks #'ivy--minibuffer-p)
(defconst ivy-help-file (let ((default-directory
(if load-file-name