ivy/counselの設定

いろいろ試行錯誤して次の設定に落ち着いた。

ivy

基本設定

(require 'ivy)
(ivy-mode 1)
(setq ivy-height 30)
(setq ivy-use-virtual-buffers t)

helmのように正規表現を順不同にする

(setq ivy-re-builders-alist '((t . ivy--regex-ignore-order)))

デフォルトで入力済みの^を消す

鬱陶しいのでデフォルト値から消した。

(setq ivy-initial-inputs-alist
      (seq-remove
       (lambda (initial-input-pair)
         (let ((initial-input-name (car initial-input-pair)))
           (or (string-prefix-p "counsel-" (symbol-name initial-input-name))
               (seq-contains '(Man-completion-table woman) initial-input-name))))
       ivy-initial-inputs-alist))

検索候補を語長順かつ辞書順にする

Emacs-Lispのコマンド・関数・変数の検索が対象。

(defun ivy--sort-by-len (name candidates)
  "Sort CANDIDATES based on similarity of their length with NAME."
  (let ((name-len (length name))
        (candidates-count (length candidates)))
    (if (< 500 candidates-count)
        candidates
      (seq-sort-by (lambda (candidate-string)
                     (cons candidate-string
                           (abs (- name-len (length candidate-string)))))
                   (lambda (a b)
                     (or (< (cdr a) (cdr b))
                         (and (= (cdr a) (cdr b))
                              (string< (car a) (car b)))))
                   candidates))))
(dolist (i '(counsel-M-x
             counsel-apropos
             counsel-describe-function
             counsel-describe-variable
             counsel-describe-face))
  (setf (alist-get i ivy-sort-matches-functions-alist) 'ivy--sort-by-len))

swiper

呼び出すだけ。

(require 'swiper)

counsel

基本設定

(require 'counsel)
(counsel-mode 1)
(global-set-key (kbd "M-x") 'counsel-M-x)                  ; replace to counsel command
(global-set-key (kbd "C-x C-b") 'ivy-switch-buffer)        ; replace to counsel command
(global-set-key (kbd "ESC M-x") 'execute-extended-command) ; backup original command

counsel-gitにUntracked Filesを追加

helm-ls-gitに動作を近づける。

(setq counsel-git-cmd
      (string-join '("git status --short --untracked-files=all | awk '$1~/?/{print $2}'" ; additional untracked files
                     "git ls-files --full-name --")                                      ; default git command
                   "; "))

counsel-gitのエイリアス

counsel-git-grepと被るので、区別がつくようにエイリアスを定義。

(defalias 'counsel-git-ls 'counsel-git)

counsel-git-grepに別ウィンドウのアクションを追加

標準だとなぜか未定義なので追加した。

(defun counsel-git-grep-other-window (&rest args)
  "Go to occurrence X in current Git repository other window.
ARGS is passed through to `counsel-git-grep-action'."
  (switch-to-buffer-other-window (current-buffer))
  (apply #'counsel-git-grep-action args))
(ivy-add-actions
 'counsel-git-grep
 '(("j" counsel-git-grep-other-window "other window")))

magitの設定

(with-eval-after-load "magit"
  (setq magit-completing-read-function 'ivy-completing-read))

prescient

基本設定

(require 'prescient)
(setq prescient-aggressive-file-save t)
(prescient-persist-mode 1)
(require 'ivy-prescient)
(ivy-prescient-mode 1)

検索候補を辞書順に並べる

デフォルトだと同じ語長のワードがランダムに並んで 気持ち悪いので、adviceを使って無理やり辞書順に並べ替えた。

(defun my-advice/ivy-prescient-sort-function-by-dictionary-order (adviced-sort-function c1 c2)
  "Around advice function for `ivy-prescient-sort-function'.
This advice sorts candidates by dictionary order.
ADVICED-SORT-FUNCTION is original function.
C1 and C2 is original arguments."
  (or (funcall adviced-sort-function c1 c2)
      (progn
        (when (listp c1)
          (setq c1 (car c1)))
        (when (listp c2)
          (setq c2 (car c2)))
        (and (= (length c1) (length c2))
             (string< c1 c2)))))
(advice-add 'ivy-prescient-sort-function :around #'my-advice/ivy-prescient-sort-function-by-dictionary-order)