complete-computing-environment/ivy_and_counsel.org

5.4 KiB

Emacs Control Via Ivy

,#+ARROYO_EMACS_MODULE: ivy-config

(provide 'cce/ivy-config)

Ivy is a Tool for interactive text completion in 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 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)
(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)

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.
(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)

I have a special 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.

(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))