私が最初にEmacsを使ったときの感想は「IDEに比べて補完,検索が弱すぎる」でした
この記事ではそんな思いを抱いたEmacserを対象として,Emacsの補完・検索をどうやって強化していくか紹介していきます
(helmとprojectileは今回の記事では参照しないので,気になる方は「初心者〜初級者のためのEmacs-Helm事始め」などを参照ください)
注) 基本的に私が使っているpackageの紹介になります
コマンド補完
counsel
Emacsで重要になってくるのがM-x
で起動する各種コマンドの扱いです
counsel
はivy
というコマンド補完機能を用いて,いわゆる絞込検索を実現しています
うろ覚えのコマンドであっても,絞込んでCtrl+n
, Ctrl+p
で選択できます
ivy
自体の設計コンセプトが「より効率的で,より小さく,よりシンプルで,よりスムーズに」なので拡張性が非常に高く,以降紹介するpackageもこのフレームワークが使えます
;; ivy設定
(require 'ivy)
(ivy-mode 1)
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(setq ivy-height 30) ;; minibufferのサイズを拡大!(重要)
(setq ivy-extra-directories nil)
(setq ivy-re-builders-alist
'((t . ivy--regex-plus)))
;; counsel設定
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-x C-f") 'counsel-find-file) ;; find-fileもcounsel任せ!
(setq counsel-find-file-ignore-regexp (regexp-opt '("./" "../")))
候補補完•検索
swiper
ivy
を用いたisearch
の拡張です
半角スペースを入れての複数単語による絞込みから,fuzzy検索も可能なので本当に便利
うわさではswiper-helmもあるらしい
(global-set-key "\C-s" 'swiper)
(setq swiper-include-line-number-in-search t) ;; line-numberでも検索可能
;; migemo + swiper(日本語をローマ字検索できるようになる)
(require 'avy-migemo)
(avy-migemo-mode 1)
(require 'avy-migemo-e.g.swiper)
似たようなpackageにidoやanythingもありますが,そのあたりはぜひ 「君は誰とEmacsる?」を参照してください
company
いわずとしれたEmacsのインテリセンス用package!
auto-completeと双璧を成していますが,auto-complete
に比べて気持ち高速で,開発も盛んです
(開発が盛んというのは正義で,3rd party性の拡張packageが出やすく,モダンな言語などに対応しやすいです)
(require 'company)
(global-company-mode) ; 全バッファで有効にする
(setq company-transformers '(company-sort-by-backend-importance)) ;; ソート順
(setq company-idle-delay 0) ; デフォルトは0.5
(setq company-minimum-prefix-length 3) ; デフォルトは4
(setq company-selection-wrap-around t) ; 候補の一番下でさらに下に行こうとすると一番上に戻る
(setq completion-ignore-case t)
(setq company-dabbrev-downcase nil)
(global-set-key (kbd "C-M-i") 'company-complete)
(define-key company-active-map (kbd "C-n") 'company-select-next) ;; C-n, C-pで補完候補を次/前の候補を選択
(define-key company-active-map (kbd "C-p") 'company-select-previous)
(define-key company-search-map (kbd "C-n") 'company-select-next)
(define-key company-search-map (kbd "C-p") 'company-select-previous)
(define-key company-active-map (kbd "C-s") 'company-filter-candidates) ;; C-sで絞り込む
(define-key company-active-map (kbd "C-i") 'company-complete-selection) ;; TABで候補を設定
(define-key company-active-map [tab] 'company-complete-selection) ;; TABで候補を設定
(define-key company-active-map (kbd "C-f") 'company-complete-selection) ;; C-fで候補を設定
(define-key emacs-lisp-mode-map (kbd "C-M-i") 'company-complete) ;; 各種メジャーモードでも C-M-iで company-modeの補完を使う
;; yasnippetとの連携
(defvar company-mode/enable-yas t
"Enable yasnippet for all backends.")
(defun company-mode/backend-with-yas (backend)
(if (or (not company-mode/enable-yas) (and (listp backend) (member 'company-yasnippet backend)))
backend
(append (if (consp backend) backend (list backend))
'(:with company-yasnippet))))
(setq company-backends (mapcar #'company-mode/backend-with-yas company-backends))
auto-complete
最近まではこちらを使っていましたが速度の問題でcompany
に移行しました
開発者の方(@m2ymさん,@syohexさん)が日本人で,コンタクトをとりやすいというのは大きなメリットだと思います
(require 'auto-complete)
(require 'auto-complete-config)
(require 'fuzzy) ;; fuzzy search (heaby)
(setq ac-use-fuzzy t)
(global-auto-complete-mode t)
(ac-config-default)
(setq ac-delay 0) ;; 補完候補表示までの時間
(setq ac-auto-show-menu 0.05) ;; ヒント表示までの時間
(ac-set-trigger-key "TAB")
(setq ac-use-menu-map t)
(setq ac-menu-height 25) ;; ちょっと大きめにとりましょう!
(setq ac-auto-start 2) ;; 個人的には3でもいいかも
(setq ac-ignore-case t)
(define-key ac-completing-map (kbd "<tab>") 'ac-complete)
;; ac-source(要するにどうやって補完候補を選ぶか)
(setq-default ac-sources 'ac-source-words-in-same-mode-buffers)
(setq-default ac-sources (push 'ac-source-yasnippet ac-sources))
git-complete
git grep
を用いた補完エンジンで,Git管理されたプロジェクトであるならば時にcompany
などの補完よりも優れています.
特に単語レベルではなく行レベルでの補完もできる(なんなら連続して補完も可能)ので,ぶっちゃけ凄いです
詳しくは@zk_phiさんの記事を参照ください
(global-unset-key (kbd "C-c C-c")) ;; 一応unbindしておきましょう
(global-set-key (kbd "C-c C-c") 'git-complete)
(add-to-list 'load-path "~/.emacs.d/git-complete") ;; お好きなように
(setq git-complete-enable-autopair t)
eacl
git-complete
と同様にGit管理下にあるプロジェクトでの補完用エンジンです
私自身は@zk_phiさんのファンなのでgit-complete
を使っていますが,こちらも良いかもしれません
ファイル検索
find-file-in-project
project内のfileをfile名で検索してくれます
当然ivy
が効いているので絞込検索が可能です!
(require 'find-file-in-project)
(global-set-key [(super shift i)] 'find-file-in-project)
recentf
絶対に導入しなくてはならない,履歴によるファイル検索packageです
直近に開いたファイルをリスト化してminibufferに表示してくれます
counsel
と組み合わせて使えば絞込によるファイル移動が可能になります
(cf. 「エコーエリアや Messages バッファにメッセージを表示させたくない」)
;; 余分なメッセージを削除しておきましょう
(defmacro with-suppressed-message (&rest body)
"Suppress new messages temporarily in the echo area and the `*Messages*' buffer while BODY is evaluated."
(declare (indent 0))
(let ((message-log-max nil))
`(with-temp-message (or (current-message) "") ,@body)))
(require 'recentf)
(setq recentf-save-file "~/.emacs.d/.recentf")
(setq recentf-max-saved-items 200) ;; recentf に保存するファイルの数
(setq recentf-exclude '(".recentf")) ;; .recentf自体は含まない
(setq recentf-auto-cleanup 'never) ;; 保存する内容を整理
(run-with-idle-timer 30 t '(lambda () (with-suppressed-message (recentf-save-list))))
(require 'recentf-ext) ;; ちょっとした拡張
(define-key global-map [(super r)] 'counsel-recentf) ;; counselにおまかせ!
宣言・参照移動
counsel-gitgrep
git-grep
のcounsel
による応用
counsel-rg
git-grep
を高速化したrip-grep
を用いたgrep検索
counsel-gitgrep
よりもこちらのほうがおすすめかも
dumb-jump
これはすごいです!
Emacsではtag
を使って関数の宣言まで移動するpackageはいくつかありますが,tag
の生成や設定などが面倒でした.
dumb-jump
はそれらを全くすることなく,どの言語でもいい感じに宣言箇所までコマンド1つで移動することが可能になります
(ただし,ruby
のような言語では宣言以外の箇所も検索に引っかかってしまうので,そういった時はminibufferでivy
を使って絞込検索しましょう)
(setq dumb-jump-mode t)
(setq dumb-jump-selector 'ivy) ;; 候補選択をivyに任せます
(setq dumb-jump-use-visible-window nil)
(define-key global-map [(super d)] 'dumb-jump-go) ;; go-to-definition!
(define-key global-map [(super shift d)] 'dumb-jump-back)
smart-jump
ほんの最近melpaに登録されたpackageで,宣言移動系のpackageを順次実行して宣言まで移動させてくれます
(すいません.まだ使ってません)
その他
neotree
ディレクトリツリーをサイドバーに表示してくれるpackageです
プロジェクトのディレクトリ構成が気になった時などに使いたいですね
(setq neo-theme 'ascii) ;; icon, classic等もあるよ!
(setq neo-persist-show t) ;; delete-other-window で neotree ウィンドウを消さない
(setq neo-smart-open t) ;; neotree ウィンドウを表示する毎に current file のあるディレクトリを表示する
(setq neo-smart-open t)
(global-set-key "\C-o" 'neotree-toggle)
symbol-overlay
あまり知られていないpackageですが,とても便利です!
カーソル位置の単語を,カーソルが離れてもハイライトしてくれます
(require 'symbol-overlay)
(add-hook 'prog-mode-hook #'symbol-overlay-mode)
(add-hook 'markdown-mode-hook #'symbol-overlay-mode)
(global-set-key (kbd "M-i") 'symbol-overlay-put)
(define-key symbol-overlay-map (kbd "p") 'symbol-overlay-jump-prev) ;; 次のシンボルへ
(define-key symbol-overlay-map (kbd "n") 'symbol-overlay-jump-next) ;; 前のシンボルへ
(define-key symbol-overlay-map (kbd "C-g") 'symbol-overlay-remove-all) ;; ハイライトキャンセル
google-this
Emacsから直接ググれます!
(cf. 「selected.el で「選択して右クリック」的な概念を」)
(require 'google-this)
(with-eval-after-load "google-this"
(defun my:google-this ()
"検索確認をスキップして直接検索実行"
(interactive)
(google-this (current-word) t)))
(require 'selected)
(selected-global-mode 1)
(define-key selected-keymap (kbd "g") #'my:google-this)
yasnippet
補完候補用のsnippet群です
とりあえず入れておいて間違いないでしょう!
(require 'yasnippet)
(add-to-list 'load-path "~/.emacs.d/plugins/yasnippet")
(setq yas-snippet-dirs
'("~/.emacs.d/yasnippets" ;; お好みで!!
"~/.emacs.d/mysnippets"))
(yas-global-mode 1)
まとめ
最終的に私の補完・検索系の主な設定やキーバインドは以下のようになりました!
(company-mode t) ;; 自動補完
(global-set-key (kbd "M-x") 'counsel) ;; コマンド補完
(global-set-key (kbd "C-s") 'swiper) ;; buffer内検索
(global-set-key (kbd "C-c C-c") 'git-complete) ;; gitによる補完
(global-set-key (kbd "super-shift-i") 'find-file-in-project) ;; ファイル検索
(global-set-key (kbd "C-r") 'counsel-recentf) ;; 履歴によるファイル検索
(global-set-key (kbd "super-f") 'counsel-rg) ;; find-usage
(global-set-key (kbd "C-d") 'dumb-jump) ;; go-to-definition
(global-set-key (kbd "C-o") 'neotree) ;; ディレクトリツリー展開
(add-hook 'prog-mode-hook #'symbol-overlay-mode) ;; symbolへの移動