Emacsの補完と検索を超強化する

私が最初にEmacsを使ったときの感想は「IDEに比べて補完，検索が弱すぎる」でした
この記事ではそんな思いを抱いたEmacserを対象として，Emacsの補完・検索をどうやって強化していくか紹介していきます
（[helm](https://github.com/emacs-helm/helm)と[projectile](https://github.com/bbatsov/projectile)は今回の記事では参照しないので，気になる方は[「初心者〜初級者のためのEmacs-Helm事始め」](https://qiita.com/jabberwocky0139/items/86df1d3108e147c69e2c)などを参照ください）

注) 基本的に私が使っているpackageの紹介になります

# コマンド補完
## [counsel](https://github.com/abo-abo/swiper#counsel)
Emacsで重要になってくるのが`M-x`で起動する各種コマンドの扱いです
`counsel`は`ivy`というコマンド補完機能を用いて，いわゆる絞込検索を実現しています
うろ覚えのコマンドであっても，絞込んで`Ctrl+n`, `Ctrl+p`で選択できます

![out4.gif](https://qiita-image-store.s3.amazonaws.com/0/144707/75aac71a-f7bc-bc4f-dae1-bb2786f607cf.gif)

`ivy`自体の設計コンセプトが「より効率的で，より小さく，よりシンプルで，よりスムーズに」なので拡張性が非常に高く，以降紹介するpackageもこのフレームワークが使えます

```el
;; 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](https://github.com/abo-abo/swiper#swiper)
`ivy`を用いた`isearch`の拡張です
半角スペースを入れての複数単語による絞込みから，fuzzy検索も可能なので本当に便利
うわさでは[swiper-helm](https://github.com/abo-abo/swiper-helm)もあるらしい

![swiper.gif](https://qiita-image-store.s3.amazonaws.com/0/144707/2d9a4b1a-852b-50a3-c82c-08a924eef134.gif)

```el
(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](https://www.emacswiki.org/emacs/InteractivelyDoThings)や[anything](https://www.emacswiki.org/emacs/Anything)もありますが，そのあたりはぜひ [「君は誰とEmacsる？」](https://qiita.com/tadsan/items/33ebb8db2271897a462b)を参照してください

## [company](http://company-mode.github.io/)
いわずとしれたEmacsのインテリセンス用package！
[auto-complete](https://github.com/auto-complete/auto-complete)と双璧を成していますが，`auto-complete`に比べて気持ち高速で，開発も盛んです
（開発が盛んというのは正義で，3rd party性の拡張packageが出やすく，モダンな言語などに対応しやすいです）

![company.gif](https://qiita-image-store.s3.amazonaws.com/0/144707/595c73f4-3c40-f188-378c-57b1aca0ca60.gif)

```el
(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](https://github.com/auto-complete/auto-complete)
最近まではこちらを使っていましたが速度の問題で`company`に移行しました
開発者の方([@m2ym](https://github.com/m2ym)さん，[@syohex](https://github.com/syohex)さん)が日本人で，コンタクトをとりやすいというのは大きなメリットだと思います

```el
(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](https://github.com/zk-phi/git-complete)

`git grep`を用いた補完エンジンで，Git管理されたプロジェクトであるならば時に`company`などの補完よりも優れています．
特に単語レベルではなく行レベルでの補完もできる（なんなら連続して補完も可能）ので，ぶっちゃけ凄いです
詳しくは[@zk_phi](https://github.com/zk-phi)さんの[記事](https://qiita.com/zk_phi/items/642b1e7dd12b44ea83ce)を参照ください

![git-complete](https://raw.githubusercontent.com/zk-phi/git-complete/master/screencast.gif)

```el
(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](https://github.com/redguardtoo/eacl)

`git-complete`と同様にGit管理下にあるプロジェクトでの補完用エンジンです
私自身は[@zk_phi](https://github.com/zk-phi)さんのファンなので`git-complete`を使っていますが，こちらも良いかもしれません

# ファイル検索
## [find-file-in-project](https://github.com/technomancy/find-file-in-project)
project内のfileをfile名で検索してくれます
当然`ivy`が効いているので絞込検索が可能です！

```el
(require 'find-file-in-project)
(global-set-key [(super shift i)] 'find-file-in-project)
```

## [recentf](https://www.emacswiki.org/emacs/RecentFiles)
絶対に導入しなくてはならない，履歴によるファイル検索packageです
直近に開いたファイルをリスト化してminibufferに表示してくれます
`counsel`と組み合わせて使えば絞込によるファイル移動が可能になります
(cf. [「エコーエリアや *Messages* バッファにメッセージを表示させたくない」](https://qiita.com/itiut@github/items/d917eafd6ab255629346))

```lisp
;; 余分なメッセージを削除しておきましょう
(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](https://github.com/abo-abo/swiper#small-config-example)
`git-grep`の`counsel`による応用

<img width="532" alt="Screen Shot 2017-12-21 at 14.54.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/144707/ea34434f-d3c7-ca7f-5155-203d74750f9c.png">


## [counsel-rg](https://github.com/abo-abo/swiper#small-config-example)
`git-grep`を高速化した`rip-grep`を用いたgrep検索
`counsel-gitgrep`よりもこちらのほうがおすすめかも

## [dumb-jump](https://github.com/jacktasia/dumb-jump)
これはすごいです！
Emacsでは`tag`を使って関数の宣言まで移動するpackageはいくつかありますが，`tag`の生成や設定などが面倒でした．
`dumb-jump`はそれらを全くすることなく，どの言語でもいい感じに宣言箇所までコマンド１つで移動することが可能になります
（ただし，`ruby`のような言語では宣言以外の箇所も検索に引っかかってしまうので，そういった時はminibufferで`ivy`を使って絞込検索しましょう）

![dumbjump.gif](https://qiita-image-store.s3.amazonaws.com/0/144707/0d74e132-7b69-b710-c159-9843cd18f61f.gif)

```el
(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](https://github.com/jojojames/smart-jump)
ほんの最近melpaに登録されたpackageで，宣言移動系のpackageを順次実行して宣言まで移動させてくれます
（すいません．まだ使ってません）

# その他
## [neotree](https://github.com/jaypei/emacs-neotree)
ディレクトリツリーをサイドバーに表示してくれるpackageです
プロジェクトのディレクトリ構成が気になった時などに使いたいですね

![neotree](https://raw.githubusercontent.com/wiki/jaypei/emacs-neotree/imgs/neotree-1.png)

```el
(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](https://github.com/wolray/symbol-overlay)
あまり知られていないpackageですが，とても便利です！
カーソル位置の単語を，カーソルが離れてもハイライトしてくれます


![symbol-overlay](https://raw.githubusercontent.com/wolray/symbol-overlay/master/screenshot-black.png)

```el
(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](https://github.com/Malabarba/emacs-google-this)
Emacsから直接ググれます！
（cf. [「selected.el で「選択して右クリック」的な概念を」](https://qiita.com/takaxp/items/00245794d46c3a5fcaa8#%E8%A8%AD%E5%AE%9A)）

```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](https://github.com/joaotavora/yasnippet)
補完候補用のsnippet群です
とりあえず入れておいて間違いないでしょう！

```el
(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)
```

# まとめ
最終的に私の補完・検索系の主な設定やキーバインドは以下のようになりました！

```lisp

(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への移動

```