A Hydra for ivy/swiper26 Mar 2015
Today I'll share a Hydra that I've been working on that's similar to Lit Wakefield's original idea for a helm hydra.
(defhydra hydra-ivy (:hint nil :color pink) " ^^^^^^ ^Actions^ ^Dired^ ^Quit^ ^^^^^^-------------------------------------------- ^ ^ _k_ ^ ^ _._ repeat _m_ark _i_: cancel _h_ ^✜^ _l_ _r_eplace _,_ unmark _o_: quit ^ ^ _j_ ^ ^ _u_ndo " ;; arrows ("h" ivy-beginning-of-buffer) ("j" ivy-next-line) ("k" ivy-previous-line) ("l" ivy-end-of-buffer) ;; actions ("." hydra-repeat) ("r" ivy-replace) ("u" ivy-undo) ;; dired ("m" ivy-dired-mark) ("," ivy-dired-unmark) ;; exit ("o" keyboard-escape-quit :exit t) ("i" nil))
Here's how I bind it:
(define-key ivy-minibuffer-map (kbd "C-o") 'hydra-ivy/body)
And here are the auxiliaries:
(defun ivy-dired-mark (arg) (interactive "p") (dotimes (_i arg) (with-ivy-window (dired-mark 1)) (ivy-next-line 1) (ivy--exhibit))) (defun ivy-dired-unmark (arg) (interactive "p") (dotimes (_i arg) (with-ivy-window (dired-unmark 1)) (ivy-next-line 1) (ivy--exhibit))) (defun ivy-replace () (interactive) (let ((from (with-ivy-window (move-beginning-of-line nil) (when (re-search-forward (ivy--regex ivy-text) (line-end-position) t) (match-string 0))))) (if (null from) (user-error "No match") (let ((rep (read-string (format "Replace [%s] with: " from)))) (with-selected-window swiper--window (undo-boundary) (replace-match rep t t)))))) (defun ivy-undo () (interactive) (with-ivy-window (undo)))
The dired operations
There's actually an outstanding issue to make the hydra
heads appear conditionally. This would be quite useful for the m and , bindings, since
they don't work outside a
dired buffer. Maybe I'll get to it on the weekend.
Meanwhile, here's a screenshot for marking files in
dired using swiper:
Since the input is
swiper transforms it into the regex
What I do next:
- C-o to get into the hydra state.
- 99m to mark everything. Normally, it would mark 99 candidates, but since there are only 17, that means all of them.
- h to go to the first candidate.
- j, to to skip one candidate and unmark, then unmark some more, using this method.
If I wanted to move two candidates down at once, I could press 2j...... The . will repeat the previous command with the previous argument. You can also set the argument later, e.g. j.2.3.. etc.
The exit points
There are two:
- i will bring you back to
ivy, so that you can edit the input.
- o will quit everything and bring you to the
So you could first mark
Mar 10, exit with i, edit the input to
Mar 17, press
C-o and mark some more. Then finally exit with o.
The replace and undo operations
These two I've added the latest, so they are still a bit off. The
ivy-replace option is similar
to vim's r (I did
vimtutor yesterday). It lets you replace the selected candidate. And
u simply calls undo. Strangely, at the moment it will undo several
operations at once, even though I call
ivy and the
hydra docstring blend in together quite nicely, like
old dogs and new tricks. I don't know which is which.