Skip to content

Commit

Permalink
Add swiper-query-replace
Browse files Browse the repository at this point in the history
* ivy.el (ivy-read): Update signature - a keymap is also accepted and
  the argument order has changed.
  The keymap is composed with `ivy-minibuffer-map'.
  Update for `ivy--action'.
(ivy--action): New defvar. If a function sets it, `ivy-read' will call it.

* swiper.el (swiper-map): New defvar.
(swiper-query-replace): New defun.
(swiper--ivy): Use swiper-map in the call to `ivy-read'.

* counsel.el (couns-git): Fix one empty candidate.
  • Loading branch information
abo-abo committed Mar 25, 2015
1 parent 2ae5b9c commit fdb0c45
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 22 deletions.
3 changes: 2 additions & 1 deletion counsel.el
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
(cands (split-string
(shell-command-to-string
"git ls-files --full-name --")
"\n"))
"\n"
t))
(file (ivy-read "Find file: " cands)))
(when file
(find-file file))))
Expand Down
46 changes: 28 additions & 18 deletions ivy.el
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

;; Author: Oleh Krehel <[email protected]>
;; URL: https://github.com/abo-abo/swiper
;; Version: 0.1.0
;; Version: 0.2.0
;; Package-Requires: ((emacs "24.1"))
;; Keywords: matching

Expand Down Expand Up @@ -165,7 +165,8 @@ On error (read-only), quit without selecting."
(minibuffer-keyboard-quit))))

;;** Entry Point
(defun ivy-read (prompt collection &optional initial-input update-fn preselect)
(defun ivy-read (prompt collection
&optional initial-input keymap preselect update-fn)
"Read a string in the minibuffer, with completion.
PROMPT is a string to prompt with; normally it ends in a colon
Expand All @@ -179,7 +180,9 @@ If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
UPDATE-FN is called each time the current candidate(s) is changed.
If PRESELECT is non-nil select the corresponding candidate out of
the ones that match INITIAL-INPUT."
the ones that match INITIAL-INPUT.
KEYMAP is composed together with `ivy-minibuffer-map'."
(cl-case (length collection)
(0 nil)
(1 (car collection))
Expand All @@ -203,21 +206,28 @@ the ones that match INITIAL-INPUT."
(concat ivy-count-format prompt))
(t
nil)))
(unwind-protect
(minibuffer-with-setup-hook
#'ivy--minibuffer-setup
(let ((res (read-from-minibuffer
prompt
initial-input
ivy-minibuffer-map
nil
'ivy-history)))
(when (eq ivy-exit 'done)
(pop ivy-history)
(setq ivy-history
(cons ivy-text (delete ivy-text ivy-history)))
res)))
(remove-hook 'post-command-hook #'ivy--exhibit)))))
(setq ivy--action nil)
(prog1
(unwind-protect
(minibuffer-with-setup-hook
#'ivy--minibuffer-setup
(let ((res (read-from-minibuffer
prompt
initial-input
(make-composed-keymap keymap ivy-minibuffer-map)
nil
'ivy-history)))
(when (eq ivy-exit 'done)
(pop ivy-history)
(setq ivy-history
(cons ivy-text (delete ivy-text ivy-history)))
res)))
(remove-hook 'post-command-hook #'ivy--exhibit))
(when ivy--action
(funcall ivy--action))))))

(defvar ivy--action nil
"Store a function to call at the end of `ivy--read'.")

(defun ivy--preselect-index (candidates initial-input preselect)
"Return the index in CANDIDATES filtered by INITIAL-INPUT for PRESELECT."
Expand Down
27 changes: 24 additions & 3 deletions swiper.el
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

;; Author: Oleh Krehel <[email protected]>
;; URL: https://github.com/abo-abo/swiper
;; Version: 0.1.0
;; Version: 0.2.0
;; Package-Requires: ((emacs "24.1") (ivy "0.1.0"))
;; Keywords: matching

Expand Down Expand Up @@ -72,6 +72,26 @@
"Only highlight matches for regexps at least this long."
:type 'integer)

(defvar swiper-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "M-q") 'swiper-query-replace)
map)
"Keymap for swiper.")

(defun swiper-query-replace ()
"Start `query-replace' with string to replace from last search string."
(interactive)
(delete-minibuffer-contents)
(setq ivy--action
(lambda ()
(let ((from (ivy--regex ivy-text)))
(perform-replace
from
(query-replace-read-to from "Query replace" t)
t t t))))
(swiper--cleanup)
(exit-minibuffer))

(defvar swiper--window nil
"Store the current window.")

Expand Down Expand Up @@ -150,8 +170,9 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
"%s" "pattern: " swiper--format-spec)
candidates
initial-input
#'swiper--update-input-ivy
preselect))
swiper-map
preselect
#'swiper--update-input-ivy))
(ido-mode 1)
(swiper--cleanup)
(if (null ivy-exit)
Expand Down

5 comments on commit fdb0c45

@kaushalmodi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

swiper replace deletes the current buffer contents:

From the doc string of delete-minibuffer-contents:

If the current buffer is not a minibuffer, erase its entire contents.

Also the (exit-minibuffer) call throws an error as the point isn't yet in the minibuffer

exit-minibuffer: No catch for tag: exit, nil

@kaushalmodi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it needs a fail safe so that a user doesn't try calling directly using M-x but only executes it using the swiper-map binding M-q after activating swiper

@abo-abo
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noticing, fixed.

@zhaojiangbin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abo-abo: Weird, I am getting this error when pressing M-q:

query-replace-read-to: Command attempted to use minibuffer while in minibuffer.

Any idea?

@abo-abo
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea?

No idea. Can you try to reliably reproduce it, then raise an issue with a recipe?

Please sign in to comment.