complete-computing-environment/ivy_and_counsel.org

130 lines
5.4 KiB
Org Mode

:PROPERTIES:
:ID: cce/ivy_and_counsel
:ROAM_ALIASES: Swiper Counsel Ivy "Ivy and Counsel"
:END:
#+TITLE: Emacs Control Via Ivy
#+ARCOLOGY_KEY: cce/ivy-config
#+filetags: :CCE:
#+PROPERTY: header-args :mkdirp yes :results none
#+PROPERTY: header-args:emacs-lisp :tangle ivy-config.el
,#+ARROYO_EMACS_MODULE: ivy-config
#+ARROYO_MODULE_WANTS: cce/diminish.org
#+begin_src emacs-lisp
(provide 'cce/ivy-config)
#+end_src
[[https://oremacs.com/swiper/][Ivy]] is a [[id:a7420bb9-395f-4afa-92fb-8eaa0b8a4cd8][Tool]] for interactive text completion in [[id:cce/emacs][Emacs]]. It's built for quick string matching within a list of completion candidates, such as commands to run, the auto-completion value for a function signature, et cetera. It's a replacement for a large swath of Emacs functionality, making it quicker and more intuitive to work with than it is with the default interface, and a bit more responsive than, in my experience, than [[https://github.com/emacs-helm/helm][Helm]].
Out of the box, Ivy does little more than replace =ido= functionality, but there are a wealth of connectors, both in the collection of Counsel commands in the package, and elsewhere within ELPA, GitHub and the rest of the Emacs ecosystem. Here I configure the base commands, and in sister documents I will configure specific functionalities past that.
In short:
- Install Ivy
- configure Magit and Projectile to use it.
- bind =C-x b= and =<NORMAL><SPC>b= to =ivy-switch-buffer=
- bind =M-u= to =ivy-resume= which will re-display any previous Ivy command and possibly re-start it (this works with Counsel commands at least)
#+begin_src emacs-lisp
(use-package ivy
:demand
:config
(ivy-mode 1)
(setq ivy-height 15
projectile-completion-system 'ivy
magit-completing-read-funciton 'ivy-completing-read)
:bind
("M-u" . ivy-resume)
("C-x b" . ivy-switch-buffer)
:bind (:map evil-leader--default-map
("b" . 'ivy-switch-buffer))
:diminish ivy-mode)
#+end_src
In short:
- =counsel-find-files= and related commands will auto-fill if there is a file under the cursor.
- Ignore files that end with a =~= or start with a =.=, or end or start with a =#=.
- Bind =/= and =?= to Swiper in Normal Mode
- Bind =<NORMAL><SPC><SPC>= and =M-x= to =counsel-M-x=, which is an interactive command launcher but with Ivy
- Bind =C-c C-q= to a tag selector in =org-mode= and =org-agenda=.
#+begin_src emacs-lisp
(use-package counsel
:demand
:after (org org-agenda ivy)
:commands (counsel-M-x swiper swiper-backward counsel-org-tag counsel-org-tag-agenda)
:config
(setq counsel-find-file-at-point t
counsel-find-file-ignore-regexp (concat "\\(?:\\`[#.]\\)" "\\|\\(?:[#~]\\'\\)"))
:bind (:map evil-leader--default-map ;; prefix to SPC
("<SPC>" . counsel-M-x))
(:map evil-normal-state-map ;; evil normal mode
("/" . swiper)
("?" . swiper-backward))
(:map org-mode-map ;; org-mode
("C-c C-q" . counsel-org-tag))
(:map org-agenda-mode-map ;; org-agenda
("C-c C-q" . counsel-org-tag-agenda))
:bind ;; global keys
("M-x" . counsel-M-x)
("C-x C-f" . counsel-find-file)
("C-x d" . counsel-dired)
("M-`" . counsel-tmm)
:diminish counsel-mode)
#+end_src
I have a special [[id:cce/hydra][Hydra]] interface, which exposes some common Ivy actions in a Hydra which I can access from within Ivy itself. I should source this code properly, it's not a thing I wrote, it may've been lifted from the Ivy documentation.
#+BEGIN_SRC emacs-lisp
(defun ivy--matcher-desc () ; used in `hydra-ivy'
(if (eq ivy--regex-function
'ivy--regex-fuzzy)
"fuzzy"
"ivy"))
(defhydra hydra-ivy (:hint nil :color pink)
"
^^_,_ _f_ollow occ_u_r _g_o ^^_c_alling %-7s(if ivy-calling \"on\" \"off\") _w_/_s_/_a_: %-14s(ivy-action-name)
_p_/_n_ _d_one ^^ _i_nsert ^^_m_atcher %-7s(ivy--matcher-desc)^^^^^^^^^^^^ _C_ase-fold: %-10`ivy-case-fold-search
^^_._ _D_o it! ^^ _q_uit _<_/_>_ shrink/grow^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _t_runcate: %-11`truncate-lines
"
;; arrows
("," ivy-beginning-of-buffer) ; default h
("p" ivy-previous-line) ; default j
("n" ivy-next-line) ; default k
("." ivy-end-of-buffer) ; default l
;; quit ivy
("q" keyboard-escape-quit :exit t) ; default o
("C-g" keyboard-escape-quit :exit t)
;; quit hydra
("i" nil)
("C-o" nil)
;; actions
("f" ivy-alt-done :exit nil)
;; Exchange the default bindings for C-j and C-m
("C-m" ivy-alt-done :exit nil) ; RET, default C-j
("C-j" ivy-done :exit t) ; default C-m
("d" ivy-done :exit t)
("g" ivy-call)
("D" ivy-immediate-done :exit t)
("c" ivy-toggle-calling)
("m" ivy-toggle-fuzzy)
(">" ivy-minibuffer-grow)
("<" ivy-minibuffer-shrink)
("w" ivy-prev-action)
("s" ivy-next-action)
("a" ivy-read-action)
("t" (setq truncate-lines (not truncate-lines)))
("C" ivy-toggle-case-fold)
("u" ivy-occur :exit t))
(with-eval-after-load 'ivy
(define-key ivy-minibuffer-map (kbd "C-m") 'ivy-alt-done) ; RET, default C-j
(define-key ivy-minibuffer-map (kbd "C-j") 'ivy-done) ; default C-m
(define-key ivy-minibuffer-map (kbd "C-S-m") 'ivy-immediate-done)
(define-key ivy-minibuffer-map (kbd "C-t") 'ivy-toggle-fuzzy)
(define-key ivy-minibuffer-map (kbd "C-o") 'hydra-ivy/body))
#+END_SRC