selectrum/consult/marginaliaの設定

ivy/counsel系の代替として、selectrumやconsultが最近来ている。

特徴をまとめた方がいる:

  • selectrum … ivyに対応。ivyよりも実装はシンプル。
  • consult ... counselに対応。counselにはないユニーク機能を持つコマンドを提供したり。consult-bufferはその例。
  • marginalia ... ivy-richに対応。

最近使っているので設定を残す。
まずはseletrumとmarginalia-mode。

(eval-when-compile (require 'selectrum))
(eval-when-compile (require 'selectrum-prescient))
(declare-function selectrum-mode "selectrum")
(declare-function selectrum-prescient-mode "selectrum-prescient")

(require 'selectrum)
(selectrum-mode +1)
(define-key selectrum-minibuffer-map (kbd "C-l") #'selectrum-backward-kill-sexp)
(setq selectrum-max-window-height 20)

;; to make sorting and filtering more intelligent
(require 'selectrum-prescient)
(selectrum-prescient-mode +1)
(require 'prescient)
(prescient-persist-mode 1)
(setq prescient-aggressive-file-save t)
;; selectrum-prescient-enable-filtering : t
;; selectrum-prescient-enable-sorting : t

;; selectrumのivy-rich
;; https://github.com/minad/marginalia
(require 'marginalia)
(marginalia-mode +1)
(setq marginalia-align-offset 25) ; 右端にどれだけスペースを詰めるか
;; (setq marginalia-truncate-width 80)
;; (setq marginalia-margin-threshold 200)
;; (setq marginalia-separator-threshold 120)

;; marginalia-annotators 初期値およびサイクル順を指定する
(setq marginalia-annotators
      '(marginalia-annotators-light marginalia-annotators-heavy nil))

;; marginalia-annotatorsをサイクルする
(define-key minibuffer-local-map (kbd "C-M-a") #'marginalia-cycle)

;; When using Selectrum, ensure that Selectrum is refreshed
;; when cycling annotations.
(advice-add #'marginalia-cycle :after
            (lambda () (when (bound-and-true-p selectrum-mode)
                         (selectrum-exhibit 'keep-selected))))

次はconsult。

追記
consultについては設定を見直した。
tam5917.hatenablog.com

以下の設定は古いものになる。

(require 'consult)

;; consult-line ... swiper の代替
;; consult-isearch ... isearch中にconsultインタフェースでクエリを再入力し、isearch再実行
;; consult-multi-occur ... multi-occurの代替
;; consult-focus-line ... クエリにヒットする部分のみを抽出して「表示」する(他が隠れる, narrowing)。
;; その後、C-uつきで呼び出すと、隠れていた部分が表示される(もとに戻る, widen)
;; consult-recent-file ... 最近開いたファイルを選択

(setq consult-async-refresh-delay 0.2)

(global-set-key (kbd "C-z C-n") 'consult-recent-file)

;; consult-buffer時などにおけるpreview機能の調整
;; (setq consult-preview-key nil) ; 常にプレビューOFF
;; (setq consult-preview-key 'any) ; 常にプレビューON
;; (setq consult-preview-key (kbd "C-M-p")) ; これを押したときだけプレビューON

;; 以下のコマンド群については、M-.でプレビューする。それ以外はON
(consult-customize
 consult-ripgrep consult-git-grep consult-grep
 consult-bookmark consult-recent-file consult-xref
 consult--source-file consult--source-project-file consult--source-bookmark
 :preview-key (kbd "M-."))

;; カーソル下のシンボルを拾ってconsult-line発動
(defun consult-line-symbol-at-point (&optional at-point)
  (interactive)
  (if at-point
      (consult-line (thing-at-point 'symbol))
    (consult-line)))

(defun my-isearch-or-consult (use-consult)
  (interactive "p")
  (cond ((eq use-consult 1)
         (call-interactively 'isearch-forward))
        ((eq use-consult 4)
         (call-interactively 'consult-line-symbol-at-point))
        ((eq use-consult 16)
         (call-interactively 'consult-line))))

(global-set-key (kbd "C-s") #'my-isearch-or-consult)
(define-key isearch-mode-map (kbd "C-:") #'consult-isearch) ; 実質的な絞り込み
(define-key isearch-mode-map (kbd "C-;") #'consult-line) ; swiperに対応

;; 絞り込み対象をバッファに限定 : b SPC
;; 絞り込み対象をファイル(recentf)に限定 : f SPC
;; 絞り込み対象をブックマークに限定 : m SPC
(global-set-key (kbd "C-x b") #'consult-buffer)

;; consult--source-fileの公式実装では「現在バッファとして保持しているファイル」が
;; ファイル(recentf)の検索対象から除外されるので、
;; それをやめるため単純にitemsにrecentf-listだけを持ってくる。
;; この設定の影響範囲はconsult-bufferのみ。consult-recent-fileは影響を受けない。
(setq consult--source-recent-file
  `(:name     "File"
    :narrow   ?f
    :category file
    :face     consult-file
    :history  file-name-history
    :action   ,#'consult--file-action
    :enabled   ,(lambda () recentf-mode)
    :items ,recentf-list))

;; consult-grepがデフォルトで複数ファイルを対象にした串刺し検索なので、
;; 検索対象をカレントバッファ(単一ファイル)に限定
(defun consult-grep-one-file ()
  "Call `consult-grep' for the current buffer (a single file)."
  (interactive)
  (let ((consult-grep-args
         (concat "grep "
                 "--line-buffered "
                 "--color=never "
                 "--line-number "
                 "--with-filename "
                 (shell-quote-argument buffer-file-name))))
    (consult-grep)))

;; consult-ripgrepがデフォルトで複数ファイルを対象にした串刺し検索なので、
;; 検索対象をカレントバッファ(単一ファイル)に限定
(defun consult-ripgrep-one-file ()
  "Call `consult-ripgrep' for the current buffer (a single file)."
  (interactive)
  (let ((consult-ripgrep-args
         (concat "rg "
                 "--line-buffered "
                 "--color=never "
                 "--line-number "
                 "--no-heading "
                 "--max-columns=250 "
                 "--smart-case "
                 "--max-columns-preview "
                 "--with-filename "
                 (shell-quote-argument buffer-file-name))))
    (consult-ripgrep)))

(global-set-key (kbd "M-g e") 'consult-compile-error)
(global-set-key (kbd "M-g f") 'consult-flymake)
(global-set-key (kbd "M-g g") 'consult-goto-line)
(global-set-key (kbd "M-g M-g") 'consult-goto-line)
(global-set-key (kbd "M-g o") 'consult-outline)
(global-set-key (kbd "M-g m") 'consult-mark)
(global-set-key (kbd "M-g k") 'consult-global-mark)
(global-set-key (kbd "M-g i") 'consult-imenu)
(global-set-key (kbd "M-g I") 'consult-imenu-multi)
(global-set-key (kbd "M-y") 'consult-yank-pop)
(global-set-key (kbd "M-s f") 'consult-find)
(global-set-key (kbd "M-s F") 'consult-locate)
(global-set-key (kbd "M-s g") 'consult-grep)
(global-set-key (kbd "M-s G") 'consult-git-grep)
(global-set-key (kbd "M-s r") 'consult-ripgrep)
(global-set-key (kbd "M-s l") 'consult-line)
(global-set-key (kbd "M-s L") 'consult-line-multi)
(global-set-key (kbd "M-s m") 'consult-multi-occur)
(global-set-key (kbd "M-s k") 'consult-keep-lines)
(global-set-key (kbd "M-s u") 'consult-focus-lines)

;; linum表示中の行番号表示は邪魔なので消す
(setq consult-goto-line-numbers nil)

(declare-function persp-get-buffer-names "perspective")
;; Use consult-buffer with perspective-el.
;; This would hide the default consult--source-buffer,
;; and show the list of perspective buffers on the top
(with-eval-after-load "perspective"
  (consult-customize consult--source-buffer :hidden t :default nil)
  (defvar consult--source-perspective
    (list :name     "Perspective"
          :narrow   ?s
          :category 'buffer
          :state    #'consult--buffer-state
          :default  t
          :items    #'persp-get-buffer-names))

  (push consult--source-perspective consult-buffer-sources))