(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-q") 'ivy-toggle-regexp-quote)
+ (define-key map (kbd "M-j") 'ivy-yank-word)
+ (define-key map (kbd "C-o") 'hydra-ivy/body)
map)
"Keymap used in the minibuffer.")
+(autoload 'hydra-ivy/body "ivy-hydra" "" t)
(defvar ivy-mode-map
(let ((map (make-sparse-keymap)))
"Insert TEXT and exit minibuffer."
(if (and ivy--directory
(not (eq (ivy-state-history ivy-last) 'grep-files-history)))
- (insert (expand-file-name
- text ivy--directory))
- (insert text))
+ (insert (setq ivy--current (expand-file-name
+ text ivy--directory)))
+ (insert (setq ivy--current text)))
(setq ivy-exit 'done)
(exit-minibuffer))
domain)))
(declare-function tramp-get-completion-function "tramp")
+(declare-function Info-find-node "info")
(defun ivy-alt-done (&optional arg)
"Exit the minibuffer with the selected candidate.
(let* ((parts (or (split-string ivy-text " " t) (list "")))
(postfix (car (last parts)))
(completion-ignore-case t)
- (new (try-completion postfix
+ (startp (string-match "^\\^" postfix))
+ (new (try-completion (if startp
+ (substring postfix 1)
+ postfix)
(mapcar (lambda (str) (substring str (string-match postfix str)))
ivy--old-cands))))
(cond ((eq new t) nil)
((string= new ivy-text) nil)
(new
(delete-region (minibuffer-prompt-end) (point-max))
- (setcar (last parts) new)
+ (setcar (last parts)
+ (if startp
+ (concat "^" new)
+ new))
(insert (mapconcat #'identity parts " ")
(if ivy-tab-space " " ""))
t))))
:require-match (ivy-state-require-match ivy-last)
:initial-input ivy-text
:history (ivy-state-history ivy-last)
- :preselect (regexp-quote ivy--current)
+ :preselect (unless (eq (ivy-state-collection ivy-last)
+ 'read-file-name-internal)
+ (regexp-quote ivy--current))
:keymap (ivy-state-keymap ivy-last)
:update-fn (ivy-state-update-fn ivy-last)
:sort (ivy-state-sort ivy-last)
:matcher (ivy-state-matcher ivy-last)
:dynamic-collection (ivy-state-dynamic-collection ivy-last)))
+(defvar ivy-calling nil
+ "When non-nil, call the current action when `ivy--index' changes.")
+
+(defun ivy-set-index (index)
+ "Set `ivy--index' to INDEX."
+ (setq ivy--index index)
+ (when ivy-calling
+ (ivy--exhibit)
+ (ivy-call)))
+
(defun ivy-beginning-of-buffer ()
"Select the first completion candidate."
(interactive)
- (setq ivy--index 0))
+ (ivy-set-index 0))
(defun ivy-end-of-buffer ()
"Select the last completion candidate."
(interactive)
- (setq ivy--index (1- ivy--length)))
+ (ivy-set-index (1- ivy--length)))
(defun ivy-scroll-up-command ()
"Scroll the candidates upward by the minibuffer height."
(interactive)
- (setq ivy--index (min (+ ivy--index ivy-height)
- (1- ivy--length))))
+ (ivy-set-index (min (+ ivy--index ivy-height)
+ (1- ivy--length))))
(defun ivy-scroll-down-command ()
"Scroll the candidates downward by the minibuffer height."
(interactive)
- (setq ivy--index (max (- ivy--index ivy-height)
- 0)))
+ (ivy-set-index (max (- ivy--index ivy-height)
+ 0)))
(defun ivy-next-line (&optional arg)
"Move cursor vertically down ARG candidates."
(interactive "p")
(setq arg (or arg 1))
- (cl-incf ivy--index arg)
- (when (> ivy--index (1- ivy--length))
- (if ivy-wrap
- (ivy-beginning-of-buffer)
- (setq ivy--index (1- ivy--length)))))
+ (let ((index (+ ivy--index arg)))
+ (if (> index (1- ivy--length))
+ (if ivy-wrap
+ (ivy-beginning-of-buffer)
+ (ivy-set-index (1- ivy--length)))
+ (ivy-set-index index))))
(defun ivy-next-line-or-history (&optional arg)
"Move cursor vertically down ARG candidates.
"Move cursor vertically up ARG candidates."
(interactive "p")
(setq arg (or arg 1))
- (cl-decf ivy--index arg)
- (when (< ivy--index 0)
- (if ivy-wrap
- (ivy-end-of-buffer)
- (setq ivy--index 0))))
+ (let ((index (- ivy--index arg)))
+ (if (< index 0)
+ (if ivy-wrap
+ (ivy-end-of-buffer)
+ (ivy-set-index 0))
+ (ivy-set-index index))))
(defun ivy-previous-line-or-history (arg)
"Move cursor vertically up ARG candidates.
(ivy-previous-history-element 1))
(ivy-previous-line arg))
+(defun ivy-toggle-calling ()
+ "Flip `ivy-calling'"
+ (interactive)
+ (when (setq ivy-calling (not ivy-calling))
+ (ivy-call)))
+
+(defun ivy-call ()
+ "Call the current action without exiting completion."
+ (when (ivy-state-action ivy-last)
+ (with-selected-window (ivy-state-window ivy-last)
+ (funcall (ivy-state-action ivy-last) ivy--current))))
+
(defun ivy-next-line-and-call (&optional arg)
"Move cursor vertically down ARG candidates.
Call the permanent action if possible."
(interactive "p")
(ivy-next-line arg)
(ivy--exhibit)
- (when (ivy-state-action ivy-last)
- (with-selected-window (ivy-state-window ivy-last)
- (funcall (ivy-state-action ivy-last) ivy--current))))
+ (ivy-call))
(defun ivy-previous-line-and-call (&optional arg)
"Move cursor vertically down ARG candidates.
(interactive "p")
(ivy-previous-line arg)
(ivy--exhibit)
- (when (ivy-state-action ivy-last)
- (with-selected-window (ivy-state-window ivy-last)
- (funcall (ivy-state-action ivy-last) ivy--current))))
+ (ivy-call))
(defun ivy-previous-history-element (arg)
"Forward to `previous-history-element' with ARG."
regexps that should match and that should not match as you
like.")
+(defvar ivy-initial-inputs-alist
+ '((org-refile . "^")
+ (counsel-M-x . "^"))
+ "Command to initial input table.")
+
(defcustom ivy-sort-max-size 30000
"Sorting won't be done for collections larger than this."
:type 'integer)
DYNAMIC-COLLECTION is a function to call to update the list of
candidates with each input."
+ (unless initial-input
+ (setq initial-input (cdr (assoc this-command
+ ivy-initial-inputs-alist))))
(setq ivy-last
(make-ivy-state
:prompt prompt
(setq ivy--regexp-quote 'regexp-quote)
(setq ivy--old-text "")
(setq ivy-text "")
+ (setq ivy-calling nil)
(let (coll sort-fn)
(cond ((eq collection 'Info-read-node-name-1)
(if (equal Info-current-file "dir")
(ivy--sorted-files default-directory))
(when initial-input
(unless (or require-match
- (equal initial-input default-directory))
+ (equal initial-input default-directory)
+ (equal initial-input ""))
(setq coll (cons initial-input coll)))
(setq initial-input nil)))
((eq collection 'internal-complete-buffer)
(<= (length coll) ivy-sort-max-size))
(setq coll (cl-sort (copy-sequence coll) sort-fn))))))
(when preselect
- (unless (or require-match
- (let ((re (format "\\`%s" preselect)))
+ (unless (or (and require-match
+ (not (eq collection 'internal-complete-buffer)))
+ (let ((re (format "\\`%s" (regexp-quote preselect))))
(cl-find-if (lambda (x) (string-match re x))
coll)))
(setq coll (cons preselect coll))))
res)))
(t (error "Unexpected: use only one !")))))
+(defun ivy--regex-fuzzy (str)
+ "Build a regex sequence from STR.
+Insert .* between each char."
+ (if (string-match "\\`\\(\\^?\\)\\(.*?\\)\\(\\$?\\)\\'" str)
+ (concat (match-string 1 str)
+ (mapconcat #'string (string-to-list (match-string 2 str)) ".*")
+ (match-string 3 str))
+ str))
+
;;** Rest
(defun ivy--minibuffer-setup ()
"Setup ivy completion in the minibuffer."
"Update the prompt according to `ivy--prompt'."
(when ivy--prompt
(unless (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done
- counsel-find-symbol))
+ counsel-find-symbol))
(setq ivy--prompt-extra ""))
(let (head tail)
(if (string-match "\\(.*\\): \\'" ivy--prompt)
(std-props '(front-sticky t rear-nonsticky t field t read-only t))
(n-str
(format
- (concat head
- ivy--prompt-extra
- tail
- (if ivy--directory
- (abbreviate-file-name ivy--directory)
- ""))
+ (concat
+ (if (and (bound-and-true-p minibuffer-depth-indicate-mode)
+ (> (minibuffer-depth) 1))
+ (format "[%d] " (minibuffer-depth))
+ "")
+ head
+ ivy--prompt-extra
+ tail
+ (if ivy--directory
+ (abbreviate-file-name ivy--directory)
+ ""))
(or (and (ivy-state-dynamic-collection ivy-last)
ivy--full-length)
ivy--length))))
;; while-no-input would cause annoying
;; "Waiting for process to die...done" message interruptions
(let ((inhibit-message t))
- (while-no-input
- (unless (equal ivy--old-text ivy-text)
- (cl-letf ((store (ivy-state-dynamic-collection ivy-last))
- ((ivy-state-dynamic-collection ivy-last) nil))
- (setq ivy--all-candidates (funcall store ivy-text))))
- (ivy--insert-minibuffer (ivy--format ivy--all-candidates))))
+ (unless (equal ivy--old-text ivy-text)
+ (while-no-input
+ ;; dynamic collection should take care of everything
+ (funcall (ivy-state-dynamic-collection ivy-last) ivy-text)
+ (setq ivy--old-text ivy-text)))
+ (unless (eq ivy--full-length -1)
+ (ivy--insert-minibuffer
+ (ivy--format ivy--all-candidates))))
(cond (ivy--directory
(if (string-match "/\\'" ivy-text)
(if (member ivy-text ivy--all-candidates)
(setq ivy--old-re nil))))
(ivy--insert-minibuffer
(ivy--format
- (ivy--filter ivy-text ivy--all-candidates))))
- (setq ivy--old-text ivy-text))
+ (ivy--filter ivy-text ivy--all-candidates)))
+ (setq ivy--old-text ivy-text)))
(defun ivy--insert-minibuffer (text)
"Insert TEXT into minibuffer with appropriate cleanup."
(matcher (ivy-state-matcher ivy-last))
(cands (cond
(matcher
- (let ((ivy--old-re re))
- (cl-remove-if-not matcher candidates)))
+ (funcall matcher re candidates))
((and (equal re ivy--old-re)
ivy--old-cands)
ivy--old-cands)
"Store the virtual buffers alist.")
(defvar recentf-list)
-(defvar ido-use-faces)
+
+(defface ivy-virtual '((t :inherit font-lock-builtin-face))
+ "Face used by Ivy for matching virtual buffer names.")
(defun ivy--virtual-buffers ()
"Adapted from `ido-add-virtual-buffers-to-list'."
(not (assoc name virtual-buffers))
(push (cons name head) virtual-buffers)))
(when virtual-buffers
- (if ido-use-faces
- (dolist (comp virtual-buffers)
- (put-text-property 0 (length (car comp))
- 'face 'ido-virtual
- (car comp))))
+ (dolist (comp virtual-buffers)
+ (put-text-property 0 (length (car comp))
+ 'face 'ivy-virtual
+ (car comp)))
(setq ivy--virtual-buffers (nreverse virtual-buffers))
(mapcar #'car ivy--virtual-buffers))))
(switch-to-buffer
ivy-text nil 'force-same-window)
(let ((virtual (assoc buffer ivy--virtual-buffers)))
- (if virtual
+ (if (and virtual
+ (not (get-buffer buffer)))
(find-file (cdr virtual))
(switch-to-buffer
buffer nil 'force-same-window)))))
:preselect (buffer-name (other-buffer (current-buffer)))
:action #'ivy--switch-buffer-action)))
+(defun ivy-recentf ()
+ "Find a file on `recentf-list'."
+ (interactive)
+ (ivy-read "Recentf: " recentf-list
+ :action #'find-file))
+
+(defun ivy-yank-word ()
+ "Pull next word from buffer into search string."
+ (interactive)
+ (let (amend)
+ (with-selected-window (ivy-state-window ivy-last)
+ (let ((pt (point))
+ (le (line-end-position)))
+ (forward-word 1)
+ (if (> (point) le)
+ (goto-char pt)
+ (setq amend (buffer-substring-no-properties pt (point))))))
+ (when amend
+ (insert amend))))
+
(provide 'ivy)
;;; ivy.el ends here