114
100

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

helm を背に ivy の門を叩く

Last updated at Posted at 2019-08-03

はじめに

ivy は, helm と双璧を成す Emacs の補完システムです.リスト表示された多くの選択肢から,自分が使いたいものを高速に絞り込んで,効率良く選び出す.このシンプル,かつ極めて重要なタスクを, ivyhelm が手助けしてくれます.

過去を振り返れば,特に理由もなく私は anything.el から(強いて言えばメンテナス状況が良かった) helm.el に移行し,そして今回, helm.el から ivy.el に移行することにしました. ivy への移行の理由はいくつかありますが,シンプル軽量であり,ミニバッファで完結するインターフェイスに安定感があり,なにより all-the-icons.el との相性が良いことです.

特に普段からモードラインを表示しない派の方は,全体的にスッキリ・シャープな Emacs に生まれ変わりますので,移行をオススメします.

よければEmacs勉強会の講演資料設定集もご参照ください.また, ivy 以外の設定集も公開しています.

Untitled.gif
↑GUI

Untitled.gif
↑ターミナル

インストール

いくつかのインストール方法がありますが,パッケージ管理ツールを使うのが楽です. ivy.el をインストールする時は,プリセット関数を集めている counsel.el と, helm-swoop 相当の機能を提供する swiper.el も同時に入れるのが一般的です.

counsel.elswiper.el に, swiper.elivy.el に依存しているので,パッケージ管理ツールを使う場合は, counsel.el をインストールすれば,3つのパッケージを同時にインストールできます.うまくいかない場合は,3つとも指定すれば良いです…

なお当方の環境は macOS で,それ以外の環境では動作未確認ですが,大きな違いは無いと思います.

MELPA

counsel をインストールします.Cask使いの場合は,一行追加で.

(depends-on "counsel")

el-get

swiper のリポジトリを指定します.

(el-get-bundle "abo-abo/swiper")

基本設定

ここでは基本的な設定と配色, ivy の流儀と選択候補のソーティング変数を紹介します.

設定例

個別の設定や細かなハックに移る前に,まずは,これさえあればとりあえず動くという設定を施します.

ivy.el

まずは ivy を使えるようにします.ほぼ素のままで良いです.

(when (require 'ivy nil t)

  ;; M-o を ivy-dispatching-done-hydra に割り当てる.
  (require 'ivy-hydra)

  ;; `ivy-switch-buffer' (C-x b) のリストに recent files と bookmark を含める.
  (setq ivy-use-virtual-buffers t)

  ;; ミニバッファでコマンド発行を認める
  (when (setq enable-recursive-minibuffers t)
    (minibuffer-depth-indicate-mode 1)) ;; 何回層入ったかプロンプトに表示.

  ;; ESC連打でミニバッファを閉じる
  (define-key ivy-minibuffer-map (kbd "<escape>") 'minibuffer-keyboard-quit)

  ;; アクティベート
  (ivy-mode 1))

counsel.el

counsel.el は, ivy の骨格関数である ivy-read を様々なコマンドに拡張し,それらをプリセットとして収録しています.全文探索の counsel-ag など,よく使うコマンドを別途インストールする必要がありません.

(when (require 'counsel nil t)

  ;; キーバインドは一例です.好みに変えましょう.
  (global-set-key (kbd "M-x") 'counsel-M-x)
  (global-set-key (kbd "M-y") 'counsel-yank-pop)
  (global-set-key (kbd "C-M-z") 'counsel-fzf)
  (global-set-key (kbd "C-M-r") 'counsel-recentf)
  (global-set-key (kbd "C-x C-b") 'counsel-ibuffer)
  (global-set-key (kbd "C-M-f") 'counsel-ag)

  ;; アクティベート
  (counsel-mode 1))

swiper

swiper は, helm-swoop のような文字列探索機能を提供します.カーソル位置の単語をキーに,バッファ内を探索.絞り込まれた選択候補を C-n/C-p で変えると,それに合わせてバッファの表示も変わり,連続してプレビューできます.なお, swiper-all-thing-at-point も実装されていて,これは開いているすべてのバッファを探索します.

Untitled.gif

(when (require 'swiper nil t)

  ;; キーバインドは一例です.好みに変えましょう.
  (global-set-key (kbd "M-s M-s") 'swiper-thing-at-point))

検索語のハイライト

デフォルトの配色は,なかなかに個性的なので自分の好みに書き換えましょう.中途半端に書き換えると,デフォルトの配色が表に出てくるので,次にリストしたフェイスはすべて書き換える方が安全です.なお, (setq ivy-display-style t) とすると,配色を無効にできます.

Screen Shot 2019-08-03 at 13.07.34.png

  • ivy-current-match

    • ミニバッファ内カーソル行の配色. :background を使うと,絞り込み中のカーソル行の文字色にも反映されてしまう. :distant-foreground を使うと反映されない.ただし,指定する色の明るさに依存して期待通りにならないこともある.微調整が必要.
  • ivy-minibuffer-match-face-1

    • 単語間を埋めるために使われる.ただし, ivy-re-builders-alist で指定するフィルタの種別に依存して使われたり,使われなかったりする.デフォルトの ivy--regex-plus の場合は,使われる.

      Screen Shot 2019-08-03 at 12.57.10.png

  • ivy-minibuffer-match-face-{2,3,4}

    • 検索語のハイライトに使われる.検索語が3つを超える時は,ループして使う.

      Screen Shot 2019-08-03 at 13.02.04.png

(custom-set-faces
 '(ivy-current-match
   ((((class color) (background light))
     :background "#FFF3F3" :distant-foreground "#000000")
    (((class color) (background dark))
     :background "#404040" :distant-foreground "#abb2bf")))
 '(ivy-minibuffer-match-face-1
   ((((class color) (background light)) :foreground "#666666")
    (((class color) (background dark)) :foreground "#999999")))
 '(ivy-minibuffer-match-face-2
   ((((class color) (background light)) :foreground "#c03333" :underline t)
    (((class color) (background dark)) :foreground "#e04444" :underline t)))
 '(ivy-minibuffer-match-face-3
   ((((class color) (background light)) :foreground "#8585ff" :underline t)
    (((class color) (background dark)) :foreground "#7777ff" :underline t)))
 '(ivy-minibuffer-match-face-4
   ((((class color) (background light)) :foreground "#439943" :underline t)
    (((class color) (background dark)) :foreground "#33bb33" :underline t))))

最初に知っておくべき機能

ivy への移行に際して,知っておくべきデフォルト機能・コマンドがあります.それらは helm とは流儀が異なるので,少々戸惑うかもしれませんが,すぐ慣れます.

counsel-M-x 等で ivy インターフェイスで選択候補リストを表示した状況では,次のコマンドを使えるようになります.

コマンド 効果
M-o 選択項目に対するアクションを選択できる
C-o ミニバッファを表示したままコマンドを発行.jk移動.gプレビュー.
C-M-n 候補を切り替えるとバッファも切り替わりプレビューできる(順方向)
C-M-p 候補を切り替えるとバッファも切り替わりプレビューできる(逆方向)
C-M-m 候補リストの表示を維持したまま,選択候補をプレビューする
C-M-j 選択候補を無視して,入力中の値を使う

C-M-m, C-M-n, C-M-p は,helm-file-preview の機能をデフォルト実装した印象です. swiper もそうですが, QuickLook 的にファイルの内容を確認できるのがとても便利です.

その他, M-x ivy-resume すれば,いつでも前回のセッションに戻れます.頻繁にリジュームする人は,キーバインドを設定するべきかもしれません.また,プロンプトでユーザが入力する検索語は,一部の正規表現に対応しているので, ^ を付ければ先頭マッチ, $ 末尾マッチというように制御できます.

ソーティング設定

少し細かい話になりますが, ivy には絞り込み時の振る舞いに影響する重要な変数がいくつか定義されています.基本的に「すべてのコマンドに対する設定(全体設定)」と「個別のコマンドに対する設定」の双方を定義できます.

後述の prescient.el を導入する時は,「すべてのコマンドに対する設定」を上書きするため,導入することで振る舞いが変化し,それが気に入らないこともありえます.その場合には,各設定を上書きしないようにするフラグがありますので,とりあえずフラグをOFFの状態で使い始めるのも良さそうです.

変数 全体設定
ivy-sort-functions-alist ivy-string<
ivy-sort-matches-functions-alist nil
ivy-re-builders-alist ivy–regex-plus
  • ivy-sort-functions-alist

    • 絞り込み開始前のリストの並び方を設定します
    • まだ何もしていない時の選択候補の並びが気になる時は,この変数を設定します.
    • prescient.el を導入し, ivy-prescient-enable-sorting などを正しく設定すれば,使用頻度の高い項目を上位に上げるなど,良きに計らってくれます.
  • ivy-sort-matches-functions-alist

    • 絞り込み開始後のリストの並び方を設定します
  • ivy-re-builders-alist

    • ivy--regex, regexp-quote, ivy--regex-plus, ivy--regex-fuzzy, ivy--regex-ignore-order から選べます.独自実装した関数を設定することも可能です.

    • ivy--regex-ignore-orderhelm の振る舞いに一番近そうです.

    • prescient.el は,「すべてのコマンド」に対して ivy-prescient-re-builder を設定します.

      • ivy-prescient-enable-filteringnil ならば,設定されません.
    • 絞り込み時の face に影響を与えます.デフォルトの振る舞いが気に入っている場合は, ivy--regex-plus を「すべてのコマンド」に対して設定しましょう.

      • ivy–regex-ignore-order は,enc org と org enc で結果が同じ.ivy-minibuffer-match-face-1不使用
      • ivy–regex-plus は,enc org と org enc で結果が異なる.ivy-minibuffer-match-face-1使用

デフォルト機能を便利に使う

まず counsel.el にプリセットされているデフォルト機能のうち,いくつかをピックアップして紹介します.それらをカスタマイズすれば,さらに便利に使えるようになります.

counsel.el にプリセットされているコマンド

counsel.el (0.12.0) には,82個のコマンドが実装されています.頻繁に使うであろうコマンドと,注目のコマンドを抜粋します.完全なリストは,記事の下に示します.

コマンド 機能
counsel-minor マイナーモードの一覧
counsel-unicode-char ユニコード文字の入力補助
counsel-yank-pop ペーストした文字列の選択
counsel-mark-ring マーク位置の選択
counsel-fzf fzf インターフェイス
counsel-ag ag インターフェイス
counsel-locate locate インターフェイス
counsel-recentf recentf インターフェイス
counsel-find-library Emacs Lisp ライブラリの選択
counsel-faces フェイスの一覧
counsel-colors-emacs カラーリスト
counsel-colors-web カラーリスト(Webカラー)
counsel-M-x コマンド一覧
counsel-set-variable 変数の一覧と書き換え
counsel-bookmark ブックマーク選択
counsel-switch-buffer バッファリスト(プレビュー付)
counsel-ibuffer iBuffer インターフェイス

counsel-minor はマイナーモードを表示して有効・無効化ができるので地味に便利です.ただ見やすさの点では,manage-minor-mode.elがオススメです.

org.el と共に使う時

counsel.el には,org mode ユーザ向けのコマンドとして, counsel-org-tag, counsel-org-tag-agenda, counsel-org-goto, counsel-org-goto-all, counsel-org-file, counsel-org-entity, counsel-org-capture, counsel-org-agenda-headlines が実装されています.

counsel-org-tag は,タグの書き換え時に ivy を使いますが,どうやってタグを削除するのかがよくわからないと思います.私も戸惑いましたが,そんな時は, C-M-j (ivy-immediate-done) を呼び出せばよいです.

もし, org-capture にも ivy を使いたい場合は,次の設定を使います.ただ, org-capture については,多くのユーザがキーバインドを記憶して呼び出していると思うので,それほど役立たない気もします.

(define-key counsel-mode-map [remap org-capture]  'counsel-org-capture)

以下は, swiper を使う時に,カーソル位置の単語を自動選択から org mode の見出しを除外するためのハックです.

(when (require 'swiper nil t)
  (defun ad:swiper-thing-at-point ()
    "`swiper' with `ivy-thing-at-point'."
    (interactive)
    (let ((thing (if (thing-at-point-looking-at "^\\*+")
                     nil
                   (ivy-thing-at-point))))
      (when (use-region-p)
        (deactivate-mark))
      (swiper thing)))

  (advice-add 'swiper-thing-at-point :override #'ad:swiper-thing-at-point))

dired.el と共に使う時

ivy-dired-history を導入すると, dired (C-x d) で訪問した場所を記録してソート表示してくれます.さらに,diredにコピー(C)と移動(R)機能を与えてくれます.ただし,コピーや移動先の表示順位を上げる機能ではないので要注意です.履歴の保存は, session.el で明示的に管理しています.一般には savehist を使うことが推奨されているようです.

(when (require 'ivy-dired-history nil t)
  (define-key dired-mode-map "," 'dired)
  (with-eval-after-load "session"
    (add-to-list 'session-globals-include 'ivy-dired-history-variable)))

なお,最近 dired で開いたディレクトリを M-x dired-recent-open で一覧できる dired-recentivy 対応しています.こちらは規定の dired-recent-directories-file に履歴が記録されます.

magit.el と共に使う時

magit の branch の選択などが ivy インターフェイスになります.後述の prescient.el を導入すれば,選択項目を上に上げたり,履歴を保存できます.

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

eldoc.el と共に使う時

eldoceldoc-idle-delay の値を用いて一定時間が経過したらミニバッファに情報を出します. helm は別ウィンドウに情報を出すため衝突しませんが, ivy はミニバッファを使うため,高頻度で衝突します.これを回避するために eldoc-print-after-edit を有効にしましょう.

(setq eldoc-print-after-edit t) でも同様の効果がありますが,いろいろ試した結果,不十分とわかりました(例:Org を開き,counsel-recentf して,org に戻り,treeを移動した時に, org-eldoc が反応する)

(with-eval-after-load "eldoc"
  (defun ad:eldoc-message (f &optional string)
    (unless (active-minibuffer-window)
      (funcall f string)))
  (advice-add 'eldoc-message :around #'ad:eldoc-message))

mic-paren.el と共に使う時

eldoc と同様に,ミニバッファで衝突します.以下のコードで回避できます.

(with-eval-after-load "mic-paren"
  (defun ad:mic-paren-highlight (f)
    (if (active-minibuffer-window)
        (let ((paren-display-message 'never))
          (funcall f))
      (funcall f)))
  (advice-add 'mic-paren-highlight :around #'ad:mic-paren-highlight))

counsel-find-file を使わない

counsel-find-filefind-file を置き換えますが,私は素の find-file を気に入っているので, counsel-find-file を無効化します.

;; completion-in-region-function も一時的にデフォに戻さないと,TAB補完時に
;; ivy が有効化されてしまう.
(defun my-disable-counsel-find-file (&rest args)
  "Disable `counsel-find-file' and use the original `find-file' with ARGS."
  (let ((completing-read-function #'completing-read-default)
        (completion-in-region-function #'completion--in-region))
    (apply #'read-file-name-default args)))
(setq read-file-name-function #'my-disable-counsel-find-file)
;; (counsel-mode 1) を設定しても counsel-find-file が呼ばれないようにする.
(define-key counsel-mode-map [remap find-file]  nil)

see https://emacs.stackexchange.com/questions/45929/disable-ivy-for-find-file

find-library のバグを回避

厳密に言えばバグではないのですが,最初に find-library を使うと,大量の ./ を表示する問題があります.これは find-library ではなく counsel-find-library を直接呼べば回避できます.しかし, M-x した時のコマンド候補には依然として find-library が出てきますので,誤選択の原因になります.

この問題は, find-library から interactive を取ることで解決します.advice では無意味で,再定義が必要です.

(when (require 'find-func nil t)
  (defun find-library (library)
    "Override the original `find-library' to hide in command list."
    (prog1
        (switch-to-buffer (find-file-noselect (find-library-name library)))
      (run-hooks 'find-function-after-hook))))

counsel-M-x

helmivy を使う大きな目的として,コマンドの絞り込みがあります. helm から ivy に移行すると, M-x の印象がかなり違うので,必要に応じて helm 流に合わせて設定して使います.4点ほど設定・カスタマイズします.

まず, smex 或いは amx を導入して,コマンドの使用履歴を保存・利用します. amx がインストールされていると, smex よりも優先的に使われます.なお残念ながら helm-M-x で培った履歴をそのまま使うのは難しいようです.

(when (require 'smex nil t)
  (setq smex-history-length 35)
  (setq smex-completion-method 'ivy))

次に, M-x ^ とデフォルトで入力される ^ 前方マッチ記号を非表示にします. ivy-initial-inputs-alist を設定します.

(setq ivy-initial-inputs-alist
      '((org-agenda-refile . "^")
        (org-capture-refile . "^")
        ;; (counsel-M-x . "^") ;; 削除.必要に応じて他のコマンドも除外する.
        (counsel-describe-function . "^")
        (counsel-describe-variable . "^")
        (Man-completion-table . "^")
        (woman . "^")))

さらに, ivy-re-builders-alist でスタイルを選びます.私は ivy--regex-ignore-order を選択.デフォルトは ivy--regex-plus です.

(setf (alist-get 'counsel-M-x ivy-re-builders-alist) #'ivy--regex-ignore-order)

最後に,絞り込み開始後のソーティング方法をカスタマイズします.

;; see https://github.com/abo-abo/swiper/issues/1294
(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 #'length
                   (lambda (a b)
                     (< (abs (- name-len a))
                        (abs (- name-len b))))
                   candidates))))

(setf (alist-get 'counsel-M-x ivy-sort-matches-functions-alist)
      #'ivy--sort-by-len)

counsel-ag

counsel-ag は, grep と同様に全文検索する ag コマンドのインターフェイスを提供します.私はカーソル位置の単語を使って全文検索する頻度が高いので,そのようにハックします.

(defun ad:counsel-ag (f &optional initial-input initial-directory extra-ag-args ag-prompt caller)
  (apply f (or initial-input (ivy-thing-at-point))
         (unless current-prefix-arg
           (or initial-directory default-directory))
         extra-ag-args ag-prompt caller))

(advice-add 'counsel-ag :around #'ad:counsel-ag)

さらに,デフォルトではカレントディレクトリ以下の範囲で全文検索しますが,ディレクトリを変えて再検索したいこともあります.検索語を再入力せずディレクトリを変えるために,次の関数を実装して, M-o r で呼び出せるようにします.

;; directory を指定して ag やり直し.クエリは再利用する
(defun my-counsel-ag-in-dir (_arg)
  "Search again with new root directory."
  (let ((current-prefix-arg '(4)))
    (counsel-ag ivy-text nil ""))) ;; also disable extra-ag-args

(ivy-add-actions
 'counsel-ag
 '(("r" my-counsel-ag-in-dir "search in directory")))

counsel-cd が上記の機能を意図しているようですが,想像と少々異なる振る舞いをするので,私は使っていません.

(define-key counsel-ag-map (kbd "C-x C-d") 'counsel-cd)

と設定しておけば, counsel-ag 使用中に M-o せず直接 C-x C-d すれば counsel-cd を呼べます.

counsel-fzf

counsel-ag の場合と同様に,カーソル位置の単語を使って counsel-fzf を起動するようにハックします.

(2022-08-19) default-directory ではなく, (funcall counsel-fzf-dir-function) が使われるように変更.projectile のルートディレクトリから探索されるようになります.

(defun ad:counsel-fzf (f &optional initial-input initial-directory fzf-prompt)
  (apply f (or initial-input
               (if (thing-at-point-looking-at "^\\*+") ;; org heading を除外
                   nil
                 (ivy-thing-at-point)))
         (or initial-directory (funcall counsel-fzf-dir-function))
         fzf-prompt))

(advice-add 'counsel-fzf :around #'ad:counsel-fzf)

さらに,検索語を維持したまま探索範囲を変えるための関数を登録します. counsel-fzf を利用中に, M-o r で発動します.

(defun my-counsel-fzf-in-dir (_arg)
  "Search again with new root directory."
  (counsel-fzf ivy-text
               (read-directory-name
                (concat (car (split-string counsel-fzf-cmd))
                        " in directory: "))))

(ivy-add-actions
 'counsel-fzf
 '(("r" my-counsel-fzf-in-dir "search in directory")))

検索語を入力してもヒットしないとき counsel-fzf に誘導する(半自動)

ivy で検索語を入力すると,ヒットしないことも多いです.入力ミス等なら再入力で済みますが,実は探索範囲を広げたいだけという場合もあります.以下の設定では,検索がヒットしない時に,一定時間が過ぎたら counsel-fzf に接続するかを [y/n] で問うように設定しています.常に問われると煩雑なので,一つの ivy セッションで1回だけ問うようにしています.

counsel-fzf に誘導する機能を追加したい場合は, my-nocand-then-fzf-commands にコマンドを追加して下さい.

選択候補が無いと確定してから my-nocand-then-fzf-idle-time 秒後に [y/n] を問うようにカスタマイズできます.

(defcustom my-nocand-then-fzf-commands '(counsel-find-flie
                                         counsel-recentf
                                         counsel-projectile-find-file
                                         counsel-projectile-switch-project)
  "List of commands for applying extension no candidates then `counsel-fzf'."
  :group 'ivy
  :type '(list symbol))

(defcustom my-nocand-then-fzf-idle-time 0.8
  "Idle time for showing prompt."
  :group 'ivy
  :type 'float) ;; 1[s] 無応答の時[y/n]を出す.

(defvar my--nocand-then-fzf t)
(defun my-nocand-then-fzf-reset ()
  (setq my--nocand-then-fzf t))
(defun my-nocand-then-fzf (prompt)
  (when (= ivy--length 0)
    (if (eq (read-char prompt) ?y) ;; y-or-n-p is not applicable
        (ivy-exit-with-action
         (lambda (x)
           (counsel-fzf ivy-text default-directory)))
      (setq my--nocand-then-fzf nil))))
(defun ad:fzf:ivy--insert-prompt ()
  (when (and my--nocand-then-fzf
             (memq (ivy-state-caller ivy-last) my-nocand-then-fzf-commands)
             (= ivy--length 0))
    (let* ((std-props '(front-sticky t rear-nonsticky t field t read-only t))
           (prompt (concat (my-ivy-prompt-prefix) "Switch to Counsel-fzf? [y/n] ")))
      (set-text-properties 0 (length prompt)
                           `(face minibuffer-prompt ,@std-props) prompt)
      (run-with-idle-timer my-nocand-then-fzf-idle-time
                           nil #'my-nocand-then-fzf prompt))))
(advice-add 'ivy--insert-prompt :before #'ad:fzf:ivy--insert-prompt)
(add-hook 'minibuffer-setup-hook #'my-nocand-then-fzf-reset)
(add-hook 'minibuffer-exit-hook #'my-nocand-then-fzf-reset)

counsel-recentf

デフォルトでは "/" からファイルの表示が始まりますが, "~" から始める方が好みなので counsel-recentf を上書き設定します.

(defun ad:counsel-recentf ()
  "Find a file on `recentf-list'."
  (interactive)
  (require 'recentf)
  (recentf-mode)
  (ivy-read "Recentf: "
            (progn
              (mapcar #'substring-no-properties recentf-list) ;; no need?
              (mapcar #'abbreviate-file-name recentf-list)) ;; ~/
            :action (lambda (f)
                      (with-ivy-window
                        (find-file f)))
            :require-match t
            :caller 'counsel-recentf))
(advice-add 'counsel-recentf :override #'ad:counsel-recentf)

さらに,所望のファイルがヒットしない時に, M-o zcounsel-fzf に移れるようにします.検索語は引き継がれるので,再入力する手間を省けます.

;; 以下の関数は,counsel-projectile-* と counsel-recentf にぶら下げる.
(defun my-counsel-fzf-in-default-dir (_arg)
  "Search the current directory with fzf."
  (counsel-fzf ivy-text default-directory))

;; add an action for counsel-recentf (M-o z)
(ivy-add-actions
 'counsel-recentf
 '(("z" my-counsel-fzf-in-default-dir "switch to fzf")))

なお, recentf のリストには,頻繁に自動更新されるが,自分が見ることはほとんどないファイルも含まれます.例えば bookmarks です.それらは,使用しないにも関わらずリストの上部に上がってきますので,除外しておくべきです. ivy 側の設定で counsel-find-file-ignore-regexp(regexp-opt '("~/.emacs.d/bookmarks")) などとすれば回避できますが,それよりも, recentf の設定で除外しておくのがよいでしょう.

(custom-set-variables
 '(recentf-exclude
   '(".recentf" "bookmarks" "org-recent-headings.dat" "^/tmp\\.*"
     "^/private\\.*" "^/var/folders\\.*" "/TAGS$")))

パッケージの移行

helm で便利に使っていたパッケージを ivy のパッケージ,または,フラグメントとして公開されているコードを集めて紹介します.

helm と ivy-counsel のコマンド対応表

個人的に helm で依存していたコマンドの対応表です.現在メインで使用しているコマンドは概ねカバーしています.表中の「X」は,デフォルト実装されているコマンドを表します.

機能 Helm Ivy/Counsel
コマンド選択 X helm-M-x X counsel-M-x
bookmark.el I/F X helm-bookmark X counsel-bookmark
locate I/F X helm-locate X counsel-locate (1)
バッファ切り替え X helm-buffers-list X counsel-ibuffer
recentf.el I/F X helm-recentf X counsel-recentf
キーバインド表示 helm-descbinds X counsel-descbinds
ag I/F helm-ag X counsel-ag
複数単語検索 helm-swoop X swiper
bm.el I/F helm-bm counsel-bm (2)
projectile.el I/F helm-projectile counsel-projectile (3)
単語の辞書記録 flyspell-correct-helm flyspell-correct-ivy (4)
heading の選択 org-recent-headings-helm org-recent-headings-ivy (5)
global I/F helm-gtags counsel-gtags (6)
dired 履歴 helm-dired-history ivy-dired-history (7)
selected.el I/F helm-selected counsel-selected (8)
flycheck.el I/F helm-flycheck counsel-flycheck (9)
pass I/F helm-pass ivy-pass (10)
emms.el I/F helm-emms nil
emmet I/F helm-emmet nil

(1) counsel-locate
(2) counsel-bm (fragment)
(3) counsel-projectile
(4) flyspell-correct-ivy
(5) org-recent-headings-ivy
(6) counsel-gtags
(7) ivy-dired-history
(8) counsel-selected
(9) counsel-flycheck (fragment)
(10) ivy-pass

counsel-flycheck (fragment)

https://github.com/nathankot/dotemacs/blob/master/init.el#L709 にありますので.拝借しました.関数名を変更して, caller を追加しています.

(defvar counsel-flycheck-history nil
  "History for `counsel-flycheck'")

(defun counsel-flycheck ()
  (interactive)
  (if (not (bound-and-true-p flycheck-mode))
      (message "Flycheck mode is not available or enabled")
    (ivy-read "Error: "
              (let ((source-buffer (current-buffer)))
                (with-current-buffer
                    (or (get-buffer flycheck-error-list-buffer)
                        (progn
                          (with-current-buffer
                              (get-buffer-create flycheck-error-list-buffer)
                            (flycheck-error-list-mode)
                            (current-buffer))))
                  (flycheck-error-list-set-source source-buffer)
                  (flycheck-error-list-reset-filter)
                  (revert-buffer t t t)
                  (split-string (buffer-string) "\n" t " *")))
              :action (lambda (s &rest _)
                        (-when-let* ( (error (get-text-property 0 'tabulated-list-id s))
                                      (pos (flycheck-error-pos error)) )
                          (goto-char (flycheck-error-pos error))))
              :history 'counsel-flycheck-history
              :caller 'counsel-flycheck)))

counsel-bm (fragment)

https://www.reddit.com/r/emacs/comments/700xck/ivy_with_bmel_bookmark_manager/ に公開されているコードをアレンジしました. ivy とは無関係ですが, <f10>bm.elbm-toggle を呼び出し, C-<f10> で次のブックマークに移動するように設定しています.詳細は, Configurations for GNU Emacs::4.9 [bm.el] カーソル位置をブックマークして追う を参照ください.

(with-eval-after-load "bm"
  (defun counsel-bm-get-list (bookmark-overlays)
    (-map (lambda (bm)
            (with-current-buffer (overlay-buffer bm)
              (let* ((line (replace-regexp-in-string
                            "\n$" ""
                            (buffer-substring (overlay-start bm)
                                              (overlay-end bm))))
                     ;; line numbers start on 1
                     (line-num
                      (+ 1 (count-lines (point-min) (overlay-start bm))))
                     (name (format "%s:%d - %s" (buffer-name) line-num line)))
                `(,name . ,bm))))
          bookmark-overlays))

  (defun counsel-bm ()
    (interactive)
    (let* ((bm-list (counsel-bm-get-list (bm-overlays-lifo-order t)))
           (bm-hash-table (make-hash-table :test 'equal))
           (search-list (-map (lambda (bm) (car bm)) bm-list)))
      (-each bm-list (lambda (bm)
                       (puthash (car bm) (cdr bm) bm-hash-table)
                       ))
      (ivy-read "Find bookmark(bm.el): "
                search-list
                :require-match t
                :keymap counsel-describe-map
                :action (lambda (chosen)
                          (let ((bookmark (gethash chosen bm-hash-table)))
                            (switch-to-buffer (overlay-buffer bookmark))
                            (bm-goto bookmark)
                            ))
                :sort t)))

  (global-set-key (kbd "<S-f10>") 'counsel-bm))

counsel-world-clock.el

counsel-world-clock は,タイムゾーンから時刻と時差を調べるツールです.ビルトインの display-time-world でも似たことができますが, ivy でタイムゾーンを絞り込めるので圧倒的に便利です.

デフォルトではソートされないので,prescient.el を導入して,直近の選択を上位に移すソーティングと履歴保存を有効にしましょう.

(with-eval-after-load "ivy"
  ;; package 経由のインストールなら,M-x counsel-world-clock ですぐ使える.
  (require 'counsel-world-clock nil t))

counsel-selected.el

拙作の helm-selectedivy に移植しました.どちらかといえば,絞り込みしたいと言うより,領域選択から l 押下で,メニューを表示し,設定項目を思い出すために使います.

(when (require 'counsel-selected nil t)
  (define-key selected-keymap (kbd "l") 'counsel-selected))

counsel-osx-app.el

counse.el には Linuxのアプリケーションを呼び出すためのインターフェイスである counsel-linux-app が実装されています. macOS用のコマンドは counsel-osx-app に公開されています.以前はOS側のランチャーを呼び出して使っていましたが,このコマンドのおかげで,Emacs から直接アプリケーションを呼び出せるので,かなり重宝しています.

counsel-osx-app-location を正しく設定すれば,サブディレクトリに含まれるアプリケーションもリストに入れてくれます.

(global-set-key (kbd "C-M-1") 'counsel-osx-app)
(with-eval-after-load "counsel-osx-app"
  (custom-set-variables
   '(counsel-osx-app-location
     '("/Applications" "/Applications/Utilities"
       "/Applications/Microsoft Remote Desktop.localized"))))

counsel-projectile.el

project.elivy インターフェイスを提供するパッケージです. projectile-find-filecounsel-git に近い気もします.下記の my-counsel-fzf-in-default-dir は, counsel-recentf に紐付けたアクションと同じです.

;; 以下の関数は,counsel-projectile-* と counsel-recentf にぶら下げる.
(defun my-counsel-fzf-in-default-dir (_arg)
  "Search the current directory with fzf."
  (counsel-fzf ivy-text default-directory))

(with-eval-after-load "projectile"
  (when (require 'counsel-projectile nil t)
    ;; M-o z で fzf を呼び出せる.
    ;; https://twitter.com/takaxp/status/1134481340458360832
    ;; あれ,これなんで動いてるの?関数に add-to-list できるの?
    ;; 以下の2つの関数は,動的に生成される defcustom で規定される.すごい.
    (add-to-list 'counsel-projectile-switch-project-action
                 '("z" my-counsel-fzf-in-default-dir
                   "switch to fzf") t)
    (add-to-list 'counsel-projectile-find-file-action
                 '("z" my-counsel-fzf-in-default-dir
                   "switch to fzf") t)

    (setq projectile-completion-system 'ivy)
    (setq counsel-projectile-sort-files t) ;; 当該プロジェクト内リストをソート
    (setq counsel-projectile-sort-projects t) ;; プロジェクトリストをソート
    (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
    (counsel-projectile-mode 1)))

counsel-gtags.el

安全安心の @syohexhttps://github.com/syohex/emacs-counsel-gtags

(when (require 'counsel-gtags nil t)
  (setq counsel-gtags-update-interval-second 10)
  (dolist (hook '(c-mode-hook c++-mode-hook))
    (add-hook hook 'counsel-gtags-mode)))

flyspell-correct-ivy.el

意外と使用頻度が高い flyspellivy インターフェイスです.当初,新しい単語を追加する save を helm のように,選択リストに含める方法を選択しましたが, ivy を使い込んでいくうちに, M-o で追加メニューを表示する ivy のお作法になれる方が生産的と気づきました.

(when (require 'flyspell-correct-ivy nil t)
  (setq flyspell-correct-interface '#'flyspell-correct-ivy)
  (global-set-key (kbd "<f7>") 'flyspell-correct-word-generic))

ivy-pass.el

特に設定はしていませんが,基本的にバグっている気がします.私の環境だけかもしれません…

see https://github.com/ecraven/ivy-pass

org-recent-headings-ivy (in org-recent-headings.el)

最近使用した org mode の見出しを 正確に 記録してくれる org-recent-headings.elivy インターフェイスです.とても便利でオススメなのですが,残念ながら,org の HEAD では壊れて使えないため,少し前の version で使ってください.動作確認ができたら,記事を後日更新します.

なお,現状では履歴のcleanup機能が無いので, ~/.emacs.d/org-recent-headings.dat は端末間で共有しない方がよいと思います.

(with-eval-after-load "ivy"
  ;; デフォルトだと `ivy-string<' が使われてしまい,使用履歴が反映されない.
  ;; つまり, recent-headings.dat に記録された順が反映されない.
  (add-to-list 'ivy-sort-functions-alist
               '(org-recent-headings-ivy . nil))

  ;; Originally located in org-recent-headings.el.
  (defun org-recent-headings-ivy ()
    "Choose from recent Org headings with Ivy."
    (interactive)
    (org-recent-headings :completing-read-fn #'ivy-completing-read)))

;; for Ivy interface
(global-set-key (kbd "C-c f r") 'org-recent-headings-ivy)

(with-eval-after-load "org-recent-headings"
  (custom-set-variables
   '(org-recent-headings-save-file "~/.emacs.d/org-recent-headings.dat")
   '(org-recent-headings-show-entry-function
     'org-recent-headings--show-entry-direct)
   '(org-recent-headings-advise-functions
     '(org-agenda-goto
       org-agenda-show
       org-agenda-show-mouse
       org-show-entry ;; having a bug, so just disabled
       org-reveal
       org-refile
       org-tree-to-indirect-buffer
       org-bookmark-jump))))

(defun ad:org-recent-headings-activate ()
  (interactive)
  (when (and (require 'dash-functional nil t) ;; FIXME
             (require 'org-recent-headings nil t))
    (org-recent-headings-mode)
    (advice-remove 'org-recent-headings-ivy
                   #'ad:org-recent-headings-activate)))
(advice-add 'org-recent-headings-ivy :before
            #'ad:org-recent-headings-activate)

prescient.el

ivy-prescient.el を導入すると,各 ivy インターフェイスの使用履歴が記録され,最近選択した項目を上位に出してくれるようになります.ただし,すべてのコマンドが影響下に入るわけではなく, ivy-read に正しく :caller が設定されている場合に限られます.また, :sort nil または :sort 設定が存在しない ivy-read の場合は, ivy-prescient-sort-commands に対象コマンドを追加することで, ivy-prescient.el の影響下に置くことができます.

もう一つの機能として,イニシャル入力が可能になります.例えば counsel-M-xM-x fap と入力すると, find-file-at-point が最上位で表示されます. counsel-recentf などでは,サブディレクトリの先頭の頭文字を入力すると,当該の情報が上位にきます.慣れれば極めて高速に絞り込みできるようになります.ただ,すべてのコマンドについてイニシャル入力を有効にすると,現状では face を思うように制御できないので, ivy-re-builders-alist を設定して,イニシャル入力を有効化するコマンドを限定することをオススメします.

イニシャル入力の設定周りがややこしいと感じる場合は,下記設定の2箇所の ivy-re-builders-alist に関わる設定を使わず,代わりに (setq ivy-prescient-enable-filtering nil) を設定すればうまく行きます.このように設定しても,使用履歴の保存には影響がありません.

なお, prescient.el の内部アルゴリズムは ivy 以外にも company-mode でも使えるようです.

(when (require 'prescient nil t)

  ;; ivy インターフェイスでコマンドを実行するたびに,キャッシュをファイル保存
  (setq prescient-aggressive-file-save t)
  ;; ファイルの保存先
  (setq prescient-save-file
        (expand-file-name "~/.emacs.d/prescient-save.el"))
  ;; アクティベート
  (prescient-persist-mode 1))

(when (require 'ivy-prescient nil t)
  ;; =ivy= の face 情報を引き継ぐ(ただし,完全ではない印象)
  (setq ivy-prescient-retain-classic-highlighting t)
  ;; コマンドを追加
  (dolist (command '(counsel-world-clock ;; Merged!
                     counsel-app)) ;; add :caller
    (add-to-list 'ivy-prescient-sort-commands command))

  ;; フィルタの影響範囲を限定する.以下の3つは順番が重要.
  ;; (1) マイナーモードの有効化
  (ivy-prescient-mode 1)
  ;; (2) =counsel-M-x= をイニシャル入力対応にする
  (setf (alist-get 'counsel-M-x ivy-re-builders-alist)
        #'ivy-prescient-re-builder)
  ;; (3) デフォルトのイニシャル入力を上書きする
  (setf (alist-get t ivy-re-builders-alist) #'ivy--regex-ignore-order))

視覚化

ivy の良いところは,アイコンを導入して視覚的な見やすさを簡単に向上できるところです.プロンプト,候補リストにアイコンを導入すると,選択対象がどのカテゴリのファイルなのかをファイル名や拡張子ではなく,アイコンで視覚的に把握できるようになります.

プロンプトを改良

プロンプトは,選択候補の数とコマンド名の組み合わせで構成されます. ivy-count-format をカスタマイズすれば,現在のカーソル位置が,候補リストの何番目に位置するかも表示できます.

(setq ivy-count-format "(%d/%d) ")

さらに,以下のようなハックを施すと,プロンプトの前に任意の情報を書き込む事ができます.例えば,プロンプトの上部に一行空行を入れて,さらに,プロンプトの直前にアイコンを入れることも可能です.モードラインを使わない派にオススメの設定です.

ただハックの方法としては ivy--insert-prompt を advice で override する必要があるので,公式にPR出そうと考えています.

(with-eval-after-load "ivy"
  (defvar my-ivy-prompt-prefix t)
  (defun my-toggle-ivy-prompt-prefix ()
    "Toggle showing a header line before the ivy prompt."
    (interactive)
    (setq my-ivy-prompt-prefix (not my-ivy-prompt-prefix)))

  (defun my-ivy-prompt-prefix ()
    "Return a header line for the ivy prompt."
    (when my-ivy-prompt-prefix
      (if window-system
          (format "%s\n%s "
                  (make-string (frame-width) ?\x5F) ;; "__"
                  (all-the-icons-faicon "sort-amount-asc")) ;; ""
        (format "%s\n" (make-string (1- (frame-width)) ?\x2D))))) ;; "--"

  (defun ivy--insert-prompt ()
    "Update the prompt according to `ivy--prompt'."
    (when (setq ivy--prompt (ivy-prompt))
      (unless (memq this-command '(ivy-done ivy-alt-done ivy-partial-or-done
                                            counsel-find-symbol))
        (setq ivy--prompt-extra ""))
      (let (head tail)
        (if (string-match "\\(.*?\\)\\(:? ?\\)\\'" ivy--prompt)
            (progn
              (setq head (match-string 1 ivy--prompt))
              (setq tail (match-string 2 ivy--prompt)))
          (setq head ivy--prompt)
          (setq tail ""))
        (let ((inhibit-read-only t)
              (std-props '(front-sticky t rear-nonsticky t field t read-only t))
              (n-str
               (concat
                (if (and (bound-and-true-p minibuffer-depth-indicate-mode)
                         (> (minibuffer-depth) 1))
                    (format "[%d] " (minibuffer-depth))
                  "")
                (concat
                 (if (string-match "%d.*%d" ivy-count-format)
                     (format head
                             (1+ ivy--index)
                             (or (and (ivy-state-dynamic-collection ivy-last)
                                      ivy--full-length)
                                 ivy--length))
                   (format head
                           (or (and (ivy-state-dynamic-collection ivy-last)
                                    ivy--full-length)
                               ivy--length)))
                 ivy--prompt-extra
                 tail)))
              (d-str (if ivy--directory
                         (abbreviate-file-name ivy--directory)
                       "")))
          (save-excursion
            (goto-char (point-min))
            (delete-region (point-min) (minibuffer-prompt-end))
            (let ((len-n (length n-str))
                  (len-d (length d-str))
                  (ww (window-width)))
              (setq n-str
                    (cond ((> (+ len-n len-d) ww)
                           (concat n-str "\n" d-str "\n"))
                          ((> (+ len-n len-d (length ivy-text)) ww)
                           (concat n-str d-str "\n"))
                          (t
                           (concat n-str d-str)))))
            ;; ADDED
            (when my-ivy-prompt-prefix
              (setq n-str (concat (my-ivy-prompt-prefix) n-str)))
            ;;
            (when ivy-add-newline-after-prompt
              (setq n-str (concat n-str "\n")))
            (let ((regex (format "\\([^\n]\\{%d\\}\\)[^\n]" (window-width))))
              (while (string-match regex n-str)
                (setq n-str (replace-match
                             (concat (match-string 1 n-str) "\n")
                             nil t n-str 1))))
            (set-text-properties 0 (length n-str)
                                 `(face minibuffer-prompt ,@std-props)
                                 n-str)
            (setq n-str (funcall ivy-set-prompt-text-properties-function
                                 n-str std-props))
            (insert n-str))
          ;; Mark prompt as selected if the user moves there or it is the only
          ;; option left.  Since the user input stays put, we have to manually
          ;; remove the face as well.
          (when ivy--use-selectable-prompt
            (if (= ivy--index -1)
                (ivy-add-face-text-property
                 (minibuffer-prompt-end) (line-end-position) 'ivy-prompt-match)
              (remove-list-of-text-properties
               (minibuffer-prompt-end) (line-end-position) '(face))))
          ;; get out of the prompt area
          (constrain-to-field nil (point-max))))))
  (advice-add 'ivy--insert-prompt :override #'ad:ivy--insert-prompt))

現在の選択候補をわかりやすくする

ivy-format-functions-alist にカスタマイズした関数を追加すれば,プロンプトの下部に位置するカーソル行の表示を変更できます. all-the-icons を導入して,好みのアイコンでカーソル行のある選択候補を目立たせましょう.

(defface my-ivy-arrow-visible
  '((((class color) (background light)) :foreground "orange")
    (((class color) (background dark)) :foreground "#EE6363"))
  "Face used by Ivy for highlighting the arrow.")

(defface my-ivy-arrow-invisible
  '((((class color) (background light)) :foreground "#FFFFFF")
    (((class color) (background dark)) :foreground "#31343F"))
  "Face used by Ivy for highlighting the invisible arrow.")

;; デフォルトを削除
(when (require 'counsel nil t)
  (delete '(t . ivy-format-function-default) ivy-format-functions-alist))

(if window-system
    (when (require 'all-the-icons nil t)
      (defun my-ivy-format-function-arrow (cands)
        "Transform CANDS into a string for minibuffer."
        (ivy--format-function-generic
         (lambda (str)
           (concat (all-the-icons-faicon
                    "hand-o-right"
                    :v-adjust -0.2 :face 'my-ivy-arrow-visible)
                   " " (ivy--add-face str 'ivy-current-match)))
         (lambda (str)
           (concat (all-the-icons-faicon
                    "hand-o-right" :face 'my-ivy-arrow-invisible) " " str))
         cands
         "\n"))
      (add-to-list 'ivy-format-functions-alist
                   '(t . my-ivy-format-function-arrow) t))
  (add-to-list 'ivy-format-functions-alist
               '(t . my-ivy-format-function-arrow-line) t))

(2022-08-27) ivy-format-functions-alistsetq で設定すると, counsel.el が先に読み込まれている場合に,そこで設定された値を破壊してしまうので,デフォルトの設定を削除して(delete),新しい設定をリストの最後に追加する(add-to-list)方法に変えました. add-to-list は,第3引数に t を与えることで append になります. append にしないと,上記のコードで指定した関数が常に呼ばれてしまいます.

ivy-rich.el

ミニバッファに候補リストを表示する ivy は,大きな画面で横方向に複数のウィンドウを表示する状況で,画面上に無駄なスペースが多く生じます. ivy-rich を導入すると,アイコンが追加され,さらに追加の情報が空きスペースに記述されるようになります.

私のように普段は80桁縛りで Emacs を使う人には相性が悪いかもしれません.

(when (require 'ivy-rich nil t)
  (ivy-rich-mode 1))

all-the-icons-ivy.el

ivy インターフェイスにアイコンを追加するパッケージです. all-the-icons.el が少々導入の難しいパッケージなのですが,一度設定がうまくいけば,殺伐とした Emacs バッファに安らぎがもたらされます.

いくつかのコマンドは,すでにアイコンを出すように設定されています.アイコンが表示されないコマンドを見つけたら, all-the-icons-ivy-buffer-commandsall-the-icons-ivy-file-commands にコマンドを追加すれば,アイコンが表示されるようになります.

なお,試した感じでは, all-the-icons-ivyivy-rich を併用するのは厳しそうです.

(when (require 'all-the-icons-ivy nil t)
  (dolist (command '(counsel-projectile-switch-project
                     counsel-ibuffer))
    (add-to-list 'all-the-icons-ivy-buffer-commands command))
  (all-the-icons-ivy-setup))

all-the-icons を導入した結果,候補リストの行頭が揃わない場合には,次の設定が効果を発揮するかもしれません.このあたりは難しく,まだ制御しきれていません.

(with-eval-after-load "all-the-icons-ivy"
      (defvar my-tab-width tab-width)
      (defun my-tab-width-2 () (setq tab-width 2))
      (defun my-tab-width-1 () (setq tab-width 1))
      (defun my-tab-width-8 () (setq tab-width 8))
      (defun my-tab-width-original ()
        (setq tab-width my-tab-width))
      (add-hook 'minibuffer-setup-hook #'my-tab-width-2)
      (add-hook 'minibuffer-exit-hook #'my-tab-width-original))

ivy-posframe.el

ivy-posframe を使うと,通常はミニバッファに表示されるリストを任意の位置に出すことができます.私自身,まだ使いこなせていないので今後の課題です.以下は, counsel-M-x でコマンドリストを表示するときだけカーソル位置にフレームを出す設定です.なお,当初 ivy-posframe はマイナーモード化されておらず不便でしたが, @conao3 氏の尽力で現在は (ivy-posframe-mode 1), (ivy-posframe-mode -1) で ON/OFFできます.

(with-eval-after-load "ivy-posframe"
  (setq ivy-posframe-display-functions-alist
        '((counsel-M-x . ivy-posframe-display-at-point)
          (t           . ivy-posframe-display)))
  (ivy-posframe-mode 1))

分析

読み込みコスト

ivy.elhelm.el の読み込み時間の計測を比較しました.それぞれ依存関係のパッケージの読み込みを含みます.計測は私の貧弱環境です.3回平均の単位は[ms]です.

思った以上に ivy.el の読み込みに時間を要しています. ivy.el 自体は約140[ms] ですが,さらに ffap.el の読み込みで約120[ms]程度消費します.

1 2 3 Ave.
helm.el 201 207 175 194
ivy.el 430 412 403 415
counsel.el 101 102 121 108
ivy+counsel 531 514 524 523

パッケージサイズ

ivyhelm でMALPA経由でインストールする場合のパッケージサイズを比較します.バイトコンパイル済みです.単位は[MB]です.

結果, ivy (1.36[MB]) と helm (3.27[MB]) で ivy が軽量のようです.ただし, ivy は,いくつかのコマンドが init.el 側に記述されています.フラグメントなのでサイズ増加のインパクトは小さいです.

helm size
flyspell-correct-helm-20181205.1932/ 0.016
helm-20190726.943/ 1.9
helm-ag-20170209.1545/ 0.1
helm-bm-20160321.1331/ 0.024
helm-core-20190726.1001/ 0.766
helm-descbinds-20190501.935/ 0.032
helm-dired-history-20170524.1046/ 0.020
helm-flycheck-20160710.829/ 0.024
helm-gtags-20170116.529/ 0.116
helm-pass-20190315.1335/ 0.020
helm-projectile-20190721.842/ 0.112
helm-swoop-20180215.1154/ 0.136
SUM 3.26
ivy size
flyspell-correct-ivy-20181205.1932 0.016
all-the-icons-ivy-20190508.1803/ 0.024
ivy-20190726.2134/ 0.492
ivy-dired-history-20170626.556/ 0.028
ivy-pass-20170812.1955/ 0.016
ivy-rich-20190707.107/ 0.052
counsel-20190726.1745/ 0.440
counsel-projectile-20190724.1903/ 0.144
counsel-world-clock-20190709.2211/ 0.036
swiper-20190726.1746/ 0.116
SUM 1.37

helm と共存の可能性

いくつかのコマンドを試しましたが,基本的に共存できる印象です.ただ基本的には同一のインターフェイスを使う方が効率が上がると思いますので,どうしても移行困難なコマンドに限定して併用するのが良さそうです.例えば, org-trellohelm に依存しているので,私はしばらく helm 環境を残すことになりそうです.

なお, org-recent-headings をインストールしていると共存が厳しくなります.これはバイトコンパイルせずに使うことで回避できます.

counsel.el にプリセットされている ivy-read 一覧

実装されているコマンド一覧です.

Command DOC STRING
counsel-el Elisp completion at point.
counsel-cl Common Lisp completion at point.
counsel-jedi Python completion at point.
counsel-clj Clojure completion at point.
counsel-company Complete using `company-candidates'.
counsel-irony Inline C/C++ completion using Irony.
counsel-describe-variable Forward to `describe-variable'.
counsel-describe-function Forward to `describe-function'.
counsel-set-variable Set a variable SYM, with completion.
counsel-apropos Show all matching symbols.
counsel-info-lookup-symbol Forward SYMBOL to `info-lookup-symbol'
counsel-M-x Ivy version of `execute-extended-command'.
counsel-command-history Show the history of commands.
counsel-load-library Load a selected the Emacs Lisp library.
counsel-find-library Visit a selected the Emacs Lisp library.
counsel-load-theme Forward to `load-theme'.
counsel-descbinds Show a list of all defined keys and their definitions.
counsel-describe-face Completion for `describe-face'.
counsel-faces Complete faces with preview.
counsel-git Find file in the current Git repository.
counsel-git-grep Grep for a string in the current Git repository.
counsel-git-stash Search through all available git stashes.
counsel-git-change-worktree Find the file corresponding to the current buffer
counsel-git-checkout Call the \"git checkout\" command.
counsel-git-log Call the \"git log –grep\" shell command.
counsel-find-file Forward to `find-file'.
counsel-dired Forward to `dired'.
counsel-recentf Find a file on `recentf-list'.
counsel-bookmark Forward to `bookmark-jump'
counsel-bookmarked-directory Ivy interface for bookmarked directories.
counsel-file-register Search file in register.
counsel-locate-action-extern Pass X to `xdg-open'
counsel-locate Call the \"locate\" shell command.
counsel-fzf Open a file using the fzf shell command.
counsel-dpkg Call the \"dpkg\" shell command.
counsel-rpm Call the \"rpm\" shell command.
counsel-file-jump Jump to a file below the current directory.
counsel-dired-jump Jump to a directory (see `dired-jump')
counsel-ag Grep for a string in the current directory using ag.
counsel-pt Grep for a string in the current directory using pt.
counsel-ack Grep for a string in the current directory using ack.
counsel-rg Grep for a string in the current directory using rg.
counsel-grep Grep for a string in the file visited by the current buffer
counsel-grep-backward Grep for a string similar to `swiper-backward'
counsel-grep-or-swiper Call `swiper' for small buffers and `counsel-grep'
counsel-grep-or-swiper-backward Call `swiper-backward' and `counsel-grep-backward'
counsel-recoll Search for a string in the recoll database.
counsel-org-tag Add or remove tags in `org-mode'.
counsel-org-tag-agenda Set tags for the current agenda item.
counsel-org-goto "Jump to an outline heading with completion."
counsel-org-goto-all Go to a different location in any org file.
counsel-org-file Browse all attachments for current Org file.
counsel-org-entity Complete Org entities using Ivy.
counsel-org-capture Capture something.
counsel-org-agenda-headlines Choose from headers of `org-mode' files in the agenda.
counsel-mark-ring Browse `mark-ring' interactively.
counsel-package Install or delete packages.
counsel-tmm Text-mode emulation of looking and choosing from a menubar.
counsel-yank-pop Ivy replacement for `yank-pop'.
counsel-register Interactively choose a register.
counsel-evil-registers Ivy replacement for `evil-show-registers'.
counsel-imenu Jump to a buffer position indexed by imenu.
counsel-list-processes Offer completion for `process-list'.
counsel-minibuffer-history "Browse minibuffer history."
counsel-esh-history "Browse Eshell history."
counsel-shell-history "Browse shell history."
counsel-hydra-heads Call a head of the current/last hydra.
counsel-semantic "Jump to a semantic tag in the current buffer."
counsel-semantic-or-imenu
counsel-ibuffer Use ibuffer to switch to another buffer.
counsel-switch-to-shell-buffer Switch to a shell buffer, or create one.
counsel-unicode-char Insert COUNT copies of a Unicode character at point.
counsel-colors-emacs "Show a list of all supported colors for a particular frame.
counsel-colors-web Show a list of all W3C web colors for use in CSS.
counsel-rhythmbox Choose a song from the Rhythmbox library to play or enqueue.
counsel-linux-app "Launch a Linux desktop application, similar to Alt-.
counsel-wmctrl "Select a desktop window using wmctrl."
counsel-switch-buffer Switch to another buffer.
counsel-switch-buffer-other-window Switch to another buffer in another window.
counsel-compile Call `compile' completing with smart suggestions
counsel-compile-env Update `counsel-compile-env' interactively.
counsel-minor Enable or disable minor mode.

82個/85個.

  • counsel–org-get-tags
  • counsel-outline (counsel-org-goto)
  • counsel-mode (minor-mode)

まとめ

この記事では(長々と) helm から ivy に移行した時に得られた知見と設定について解説しました.幸いながら,私の helm 利用レベルはそれほど高くなく,移行して全く後悔はないですが, helm への依存度がより高い人の場合は,色々と気に入らない点があるかもしれません.また, org-trello.el 等, helm 依存で ivy が使えないパッケージもまだあるので,移行に慎重な人は,一度自分が依存するパッケージの ivy インターフェイスが存在するかを確認してみるのをオススメします.それ以外の人は,もう「えいや!」で移行しても公開しないと思います.

いかがでしたか?

References

114
100
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
114
100

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?