Emacsの補完機能をHelmからIvyへ移行
バズってたQiitaの記事を参考に、HelmからIvyに移行してみた。
自分が加えた変更は次のとおり。
counsel-M-x
の絞り込み開始後のソーティング方法を辞書順に
長さでソートした後、さらに辞書順でソートするようにした。
(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) (if (not (= (cdr a) (cdr b))) (< (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))
helm-ls-gitパッケージの代替コマンドを定義
helm-ls-gitに相当するcounselのパッケージが見つからなかったので、 Find file in a Git repo with ivy · (or emacsを参考に代替コマンドを定義した。
追記: あとで見直したらcounsel-git
というコマンドが定義済みだった。なんで見逃したんだろ。
"other window"
アクションをどうしても追加したくて方法がわからず苦労したが、ソースコードやヘルプを色々と探したらどうやらivy-set-actions
で設定することが分かった。
ivy-read
のcaller
は何のために設定するのかと思ったらivy-set-actions
に登録するコマンド名と対応するようだ。
;; replaced from helm-ls-git (ivy-set-actions 'counsel-git-ls '(("j" find-file-other-window "other window") ("f" find-file-other-frame "other frame"))) (defun counsel-git-ls (&optional initial-input) "Find file in the current Git repository. When INITIAL-INPUT is non-nil, use it in the minibuffer during completion." (interactive) (let* ((default-directory (locate-dominating-file default-directory ".git")) (candidate-git-files (split-string (shell-command-to-string "git ls-files --full-name --") "\n"))) (ivy-read "Git files: " candidate-git-files :initial-input initial-input :action #'find-file :caller 'counsel-git-ls)))