Emacsモダン化計画 -かわEmacs編-

[EmacsJP](https://emacs-jp.github.io/) Slackで話題に上がったEmacsモダン化計画という語感に触発され、[Emacsひなまつり](https://tokyo-emacs.connpass.com/event/121603/)でそれっぽい話をすることにした。本記事では、見た目中心の変更方法について紹介する。

ちなみに現在82パッケージ導入しているが、use-packageでフル遅延ロード、なにか遅ければデフォルトのプロファイラで原因を解析して修正しているのでEmacsでも起動も動作も早い(現在の起動時間は0.4秒)。

## コードが読みやすいテーマ -- [doom-emacs-themes(doom-dracula)](https://github.com/hlissner/emacs-doom-themes)

[Doom Emacs](https://github.com/hlissner/doom-emacs)という(Evilユーザ向け)Spacemacs系のプロジェクトがあり、このDoom Emacsのために開発されたテーマ。
目立たせるものと、そうでないもののバランスが良ため、非常に気に入っている。Dracula公式のEmacsThemeもあるが、Doomとは微妙に色味が異なる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/01db5aa7-3da5-5c4c-9158-525e4a404db4.png)

```emacs-lisp
  (use-package doom-themes
    :custom
    (doom-themes-enable-italic t)
    (doom-themes-enable-bold t)
    :custom-face
    (doom-modeline-bar ((t (:background "#6272a4"))))
    :config
    (load-theme 'doom-dracula t)
    (doom-themes-neotree-config)
    (doom-themes-org-config))
```

## 必要十分な状態を表示する -- [doom-modeline](https://github.com/seagle0128/doom-modeline)

モードラインもDoom系を使っている。これは、Doomの開発者ではなく、[Centaur](https://github.com/seagle0128/.emacs.d)[^1]の開発者によって開発されている。モードラインはシンプルなものが好みのため、色々と削っている

[^1]: Centaur Emacsは色々と参考になるので、この人のレポジトリはオススメ

```emacs-lisp
    (use-package doom-modeline
      :custom
      (doom-modeline-buffer-file-name-style 'truncate-with-project)
      (doom-modeline-icon t)
      (doom-modeline-major-mode-icon nil)
      (doom-modeline-minor-modes nil)
      :hook
      (after-init . doom-modeline-mode)
      :config
      (line-number-mode 0)
      (column-number-mode 0)
      (doom-modeline-def-modeline 'main
	'(bar workspace-number window-number evil-state god-state ryo-modal xah-fly-keys matches buffer-info remote-host buffer-position parrot selection-info)
	'(misc-info persp-name lsp github debug minor-modes input-method major-mode process vcs checker)))
```

**Active/Deactive**
コードを書いているとウィンドウを大量に分割するため、どのウィンドウがactive/deactiveであるかの分かりやすさは重要。また、Gitのブランチ名もミス防止のために表示しておきたい。
![modeline-activve-diactive.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/a090a8f9-81c5-fa59-60bf-c1626a7362cc.gif)

**Narrow/Widen**
org-modeにはnarrow/widenという一つのことに集中するのに便利な機能があるのだが、その状態もmodelineから把握することができる
![narrow-widen.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/0d157a5d-1a7f-4149-73b2-7804db6949b2.gif)

**Search/Replace**
検索や置換のmatch数などのステータスも見やすい。nyan-catは場所を取るが、コーディングの癒しには必要。ファイル内でのポジションを示してくれている。
![replace.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/4c102b03-c133-709d-427f-d45b45cdca50.gif)

**Edit/Save**
そのバッファに未保存の修正があるかどうかも把握しやすい。また、ファイル名はそのまま表示すると幅をとるが、Gitリポジトリの場合はそのプロジェクト名と、開いているファイル名、それまでのパスは一文字だけ表示している。`truncate-with-project`オプションでは、コンパクトに必要十分な情報が得られる。
![edit-save.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/461530c5-1cb8-c949-9842-a8da02151b7a.gif)

### 不要なモードラインを隠す -- [hide-mode-line](https://github.com/hlissner/emacs-hide-mode-line)

無駄なスペースで必要な情報が削れていくのはツライいのでモードラインが不要なneotree, imenu, minimapでは隠している。

```emacs-lisp
  (use-package hide-mode-line
    :hook
    ((neotree-mode imenu-list-minor-mode minimap-mode) . hide-mode-line-mode))
```

### タスクを時計する -- org-clock, [org-pomodoro](https://github.com/lolownia/org-pomodoro)

Emacsを使い続けている理由の一つにorg-modeがある。コードを汚さずにコードリーディングのメモをコードに対してつけたり、その日のメモをコードスニペットとともにとったり(もちろんその場で実行できる)、図を書いたり、タスクを管理したりと、まぁ何でもできる。

多くのタスクは見積もり時間を設定している。そうしておくと、org-agendaでその日の見積もり時間の合計と実際にかかった時間の差分などをリアルタイムに確認できる。

下の図はある一つのタスクを実施している時のモードラインの様子を示している。デフォルトだとタスク名とか色々表示されて煩わしいので、`取り組んだ時間/見積もり時間` のみを表示させている

![org-tomato.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/26599439-669d-6275-0164-313690cd30e9.gif)

```emacs-lisp
(defun ladicle/task-clocked-time ()
    	"Return a string with the clocked time and effort, if any"
    	(interactive)
    	(let* ((clocked-time (org-clock-get-clocked-time))
    	       (h (truncate clocked-time 60))
    	       (m (mod clocked-time 60))
    	       (work-done-str (format "%d:%02d" h m)))
    	  (if org-clock-effort
    	      (let* ((effort-in-minutes
    		      (org-duration-to-minutes org-clock-effort))
    		     (effort-h (truncate effort-in-minutes 60))
    		     (effort-m (truncate (mod effort-in-minutes 60)))
    		     (effort-str (format "%d:%02d" effort-h effort-m)))
    		(format "%s/%s" work-done-str effort-str))
    	    (format "%s" work-done-str))))
```

## ポモドーロテクニック

やる気が出ないときは、やる気を出すためにポモドーロテクニックを使っている。世にはさまざまなツールが出回っているが、Orgと連携して時間の集計もやってくれる`org-pomodoro`を使っている。

カスタムしやすい作りになっており、パッチを当てずにmodelineをおしゃれにできる。また起動と終了時にhookして、見逃し防止用のNotificationも飛ばしている。Notificatonはアイコンも設定できるので、開始は🍅、終了は🍺だ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/3c394298-c6cf-99e1-d54c-fa31d880944c.png)

```emacs-lisp
(use-package org-pomodoro
    :after org-agenda
    :custom
    (org-pomodoro-ask-upon-killing t)
    (org-pomodoro-format "%s")
    (org-pomodoro-short-break-format "%s")
    (org-pomodoro-long-break-format  "%s")
    :custom-face
    (org-pomodoro-mode-line ((t (:foreground "#ff5555"))))
    (org-pomodoro-mode-line-break   ((t (:foreground "#50fa7b"))))
    :hook
    (org-pomodoro-started . (lambda () (notifications-notify
                                               :title "org-pomodoro"
					       :body "Let's focus for 25 minutes!"
					       :app-icon "~/.emacs.d/img/001-food-and-restaurant.png")))
    (org-pomodoro-finished . (lambda () (notifications-notify
                                               :title "org-pomodoro"
					       :body "Well done! Take a break."
					       :app-icon "~/.emacs.d/img/004-beer.png")))
    :config
    :bind (:map org-agenda-mode-map
                ("p" . org-pomodoro)))
```

### lsp-mode サーバステータス/エラー数

lspサーバのステータスは起動時はプロセスIDと進行状況を表示し、起動し終わった後はlspサーバ名のみ表示させている。
![lsp-starting.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/f0291740-bf1c-20b1-3d55-eeb0fa1f6597.gif)

コード内にエラーが見つかるとモードラインからも確認することができる。
![flymake.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/0e835771-78bc-89bf-f79d-73ebe169c460.gif)

lspとは関係ないが、言語のバージョンも表示させておくとバージョン指定のある開発時に困らない。

```patch
diff --git common/emacs.d/elpa/lsp-mode-20190227.1647/lsp-mode.el common/emacs.d/elpa/lsp-mode-20190227.1647/lsp-mode.el
index 7ad6275..2a82d0f 100644
--- common/emacs.d/elpa/lsp-mode-20190227.1647/lsp-mode.el
+++ common/emacs.d/elpa/lsp-mode-20190227.1647/lsp-mode.el
@@ -1316,9 +1316,9 @@ CALLBACK - callback for the le
    (require 'alert)nses."
 (defun lsp-mode-line ()
   "Construct the mode line text."
   (if-let (workspaces (lsp-workspaces))
-      (concat " LSP" (string-join (--map (format "[%s]" (lsp--workspace-print it))
-                                         workspaces)))
-    (concat " LSP" (propertize "[Disconnected]" 'face 'warning))))
+      (string-join (--map (format "%s" (lsp--workspace-print it))
+                                         workspaces))
+    (propertize "" 'face 'warning)))
 
 (defalias 'make-lsp-client 'make-lsp--client)
 
@@ -3964,7 +3964,7 @@ SESSION is the active session."
          (pid (propertize (format "%s" (process-id proc)) 'face 'italic)))
 
     (if (eq 'initialized status)
-        (format "%s:%s" server-id pid)
+        (format "%s" server-id)
       (format "%s:%s status:%s" server-id pid status))))
 
 (defun lsp--map-tree-widget (m)
```

## 全てをプレーンテキストで管理するために -- org, [org-bullets](https://github.com/sabof/org-bullets), org-capture

doom-draculaはorg用のテーマも設定されているため、デフォルトでいいカンジにしてくれる(特にbulletのグラデーション)。独自に追加したTODOキーワードなど、一部の色だけ新たに定義している。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/33b33131-de2a-aab0-3d81-a729944f6e01.png)

```emacs-lisp
...
    :custom-face
    (org-link ((t (:foreground "#ebe087" :underline t))))
    (org-list-dt ((t (:foreground "#bd93f9"))))
    (org-special-keyword ((t (:foreground "#6272a4"))))
    (org-todo ((t (:background "#272934" :foreground "#51fa7b" :weight bold))))
    (org-document-title ((t (:foreground "#f1fa8c" :weight bold))))
    (org-done ((t (:background "#373844" :foreground "#216933" :strike-through nil :weight bold))))
    (org-footnote ((t (:foreground "#76e0f3"))))
...
    :config
    (setq org-todo-keyword-faces
	    '(("WAIT" . (:foreground "#6272a4":weight bold))
	      ("NEXT"   . (:foreground "#f1fa8c" :weight bold))
	      ("CARRY/O" . (:foreground "#6272a4" :background "#373844" :weight bold))))
...
```

**org-bullets**

org-bulletsを導入するだけで見やすくなるが、さらにアイコンをNerdFontの絵文字に変更している。数字が入っているため、Narrowしたときも何階層目にいるのかが分かりやすい。

```emacs-lisp
(use-package org-bullets
      :custom (org-bullets-bullet-list '("" "" "" "" "" "" "" "" "" ""))
      :hook (org-mode . org-bullets-mode))
```

**org-capture**

コードリーディングやメモを取るのに便利なorg-captureだが、テンプレートが増えてくると分かりにくくなる。そんな時は、カテゴリごとに同じアイコンを`templateタイトル`に追加すると可視性が高まる。(文字に比べて絵は情報量が多くてよい

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/5ed10ef7-7c2a-b66f-fa42-f595c02afe55.png)

**org-agenda**

org-agendaのtime-gridのデザインも変更できる。デフォルトでは現在時刻のインディケータや区切り線がasciiになっているため、かわいみの強いunicodeに変更している。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/f21e7637-1bf4-338f-746a-84033ff5f863.png)

```emacs-lisp
    (setq org-agenda-current-time-string "← now")
    (setq org-agenda-time-grid ;; Format is changed from 9.1
        '((daily today require-timed)
          (0900 01000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000 2100 2200 2300 2400)
          "-"
	  "────────────────"))
```


## キーバインドを覚えずに使いこなす -- [emacs-which-key](https://github.com/justbur/emacs-which-key), [amx](https://github.com/DarwinAwardWinner/amx)

Emacsは多機能すぎるので全てのキーバインドを覚えてられない。そんなときはwhich-keyでガイドを表示するのが良い。紙の辞書を引くと周辺の単語を覚えるように、キーバインドも記憶しやすくなる。空きバインドのチェックにも便利だ。一度Spacemacsを体験すると欲しくなる機能。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/0f59cebb-80eb-ff4e-9969-4357e9d4eef5.png)

```emacs-lisp
  (use-package which-key
    :diminish which-key-mode
    :hook (after-init . which-key-mode))
```

また、M-xをサポートしてくれるsemexから派生したAlternative interface for M-xというパッケージもおすすめだ。(Doomあたり？で便利さに気づいた気がする)通常通り`M-x`を実行すると、そのコマンドにキーバインドが割り当てられていた時にそのバインドを表示してくれる。(コマンドの説明はivy-richの機能)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/5cfacadf-c9df-9276-914c-f5ee52a1640c.png)

```emacs-lisp
(use-package amx)
```

## 小指を酷使せず、かつキーバインドのガイドを出す -- [hydra](https://github.com/abo-abo/hydra)

一度導入してから手放せなくなったパッケージ。hydraマップをoffにするまで連続実行できるので、修飾キーを押し続ける必要がない。また、連続実行するものとしないもので色分けもされており、非常に分かりやすい。見た目もunicodeを使えば可愛くなる。そのうちアイコンも表示させていきたい。

![multi-cursor.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/af26afa5-ce40-e81b-b6d5-23b353852283.gif)

Evilを使わず、Vimっぽい簡易なview modeも実現できる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/8a56da52-8a22-4c68-c97c-8c1714bb23c1.png)

最近はposframeに対応させたので画面中央に表示できたりする
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Hydra works well with posframe! Never miss Hydra even if I&#39;m using widescreen :) <a href="https://t.co/6EW2nmYSgH">pic.twitter.com/6EW2nmYSgH</a></p>&mdash; ladicle (@Ladicle) <a href="https://twitter.com/Ladicle/status/1109656276064067584?ref_src=twsrc%5Etfw">March 24, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 検索などの補完インタフェース -- [swiper/counsel](https://github.com/abo-abo/swiper), [ivy-rich](https://github.com/Yevgnen/ivy-rich)

anything, helmと色々な補完インタフェースを使ってきたが、軽量かつhelm-swoop likeな見やすい検索インタフェースに惹かれてswiperに落ち着いた。

counselの設定は少々(?)長すぎるので見た目の設定に絞ってのせていく。`ivy-format-function`では現在行の表示方法を変更できる。デフォルトでは見づらいため、現在行には`>` を表示するようにしている。[^2] また、コピーしたテキストのリスト検索ができる`counsel-yank-pop`では、helmに比べて区切りがわかりずらいのでseparatorを変更している。

[^2]: サンプルはM-x参照

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/b391ba57-2958-1b3e-6098-cb38f5432f39.png)

```emacs-lisp
    :custom
    (ivy-format-function 'ivy-format-function-arrow)
    (counsel-yank-pop-separator "\n-------\n")
....
```

カーソルも自由に変えられる。またivy-posframeを使えばこれも画面中央に表示することもできる。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ivyのcursorが可愛くなった <a href="https://t.co/43Qrvmx7RW">pic.twitter.com/43Qrvmx7RW</a></p>&mdash; ladicle (@Ladicle) <a href="https://twitter.com/Ladicle/status/1107860569149693952?ref_src=twsrc%5Etfw">March 19, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## よりリッチなUIを提供するivy-rich

ivyの見た目をよりモダンにしてくれるパッケージ。all-the-iconsと組み合わせて可視性を高めている。ちなみに、ファイルに応じたアイコンを変更したい場合はall-the-iconsの修正が必要。(例えば、デフォルトのGopherくんが可愛くないので、かわいいGopherくんに変更している。)

**recentf**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/af71daab-4238-901f-1ebf-a5c82fe4f5a5.png)

**switch-buffer**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/992eb057-24bc-e0db-3114-348c2d78861e.png)

**find-file**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/9511d4c9-3e03-d5fa-de72-12e41cd669ca.png)

## 気分が高まる起動画面 -- [emacs-dashbaord](https://github.com/emacs-dashboard/emacs-dashboard)

起動直後に開くダッシュボード画面。起動時にすぐに作業するファイルに飛んだり、予定を確認できるようにしている。デフォルトでアイコンPrefixを設定する機能が無かったため、emacs-dashboardにパッチを当てている。バーナーは画像も設定できるが、asciiアートが好きなのであえて画像は使わずasciiナバーナを設定している。asciiジェネレータは[TAAG](http://patorjk.com/software/taag/#p=display&f=ANSI%20Shadow&t=HELLO)をよく使う。

<img width="1721" alt="Screen Shot 2019-03-02 at 23.49.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/26683/86e6a8fc-b925-c70e-399b-6534f1deadaf.png">

```emacs-lisp
  (use-package dashboard
    :diminish
    (dashboard-mode page-break-lines-mode)
    :custom
    (dashboard-startup-banner 4)
    (dashboard-items '((recents . 15)
		       (projects . 5)
		       (bookmarks . 5)
		       (agenda . 5)))
    :hook
    (after-init . dashboard-setup-startup-hook)
    :config
    (add-to-list 'dashboard-items '(agenda) t))
```

## Tmuxっぽくウィンドウを移動する -- [ace-window](https://github.com/abo-abo/ace-window)

カーソルをピンポイントで移動させたい時に便利なace/avyシリーズ。avyは特にデフォルト設定で問題ないが、ace-windowはガイド文字が小さすぎて見づらいので大きく&色を変更している。画面の分割数が3を超えたあたりから欲しくなる機能。

![ace-window.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/784dfeb1-21ea-2b06-d19d-8a8036316d7a.gif)

```emacs-lisp
  (use-package ace-window
    :functions hydra-frame-window/body
    :bind
    ("C-M-o" . hydra-frame-window/body)
    :custom
    (aw-keys '(?j ?k ?l ?i ?o ?h ?y ?u ?p))
    :custom-face
    (aw-leading-char-face ((t (:height 4.0 :foreground "#f1fa8c"))))
... 
```

## LSPでよりモダンな開発環境を構築する -- [lsp-mode](https://github.com/emacs-lsp/lsp-mode)

[好みのエディタに快適な開発環境を提供するLSP](https://qiita.com/Ladicle/items/e666e3fb9fae9d807969) からまだ数ヶ月しか経過していないが、あれからlsp-modeに大幅な変更が入り、別物の設定になった。また、デバッグ版LSPというポジションのDAP(Debug Adapter Protocol)とも連携できるようになったようだ。~~(気になるもののGoやC++は未サポートの為まだ試していない~~

やる気が湧いたのでGo対応もした。IDEっぽくbreakpointをマウスでぽちぽちもできるし、Emacsっぽくキーのみで条件付きのbreakpoint設定したり、localsの値をテキストとしてマルッとコピーしたり、stack frameを移動したりデバッグが捗るようになった。(Remote Debugは未実装だったものの別の人が対応してくれました。ありがたい。OSS最高

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Emacs dap-modeのdelve対応、完全に勝利した💪 明日PRするぞ!!! <a href="https://t.co/QEPzfgsoK0">pic.twitter.com/QEPzfgsoK0</a></p>&mdash; ladicle (@Ladicle) <a href="https://twitter.com/Ladicle/status/1102979010487705600?ref_src=twsrc%5Etfw">March 5, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

また、以前はlsp-modeでKubernetesなどの大規模なプロジェクトを開くと使い物にならなかったが、重い原因であったflycheckをやめてflymakeへの移行、go-langserverからbingoへの移行、速さ優先で常時cacheやincremental同期の利用などを経て、使えるようになってきた。[^4]

[^4]: ただし、メモリも食っていくので良いPCが必要

```emacs-lisp
(use-package lsp-mode
  :custom
  ;; debug
  (lsp-print-io nil)
  (lsp-trace nil)
  (lsp-print-performance nil)
  ;; general
  (lsp-auto-guess-root t)
  (lsp-document-sync-method 'incremental) ;; always send incremental document
  (lsp-response-timeout 5)
  (lsp-prefer-flymake 'flymake)
  (lsp-enable-completion-at-point nil)
  :hook
  (go-mode . lsp)
  :bind
  (:map lsp-mode-map
  ("C-c r"   . lsp-rename))
  :config
  (require 'lsp-clients)
  ;; LSP UI tools
  (use-package lsp-ui
    :custom
    ;; lsp-ui-doc
    (lsp-ui-doc-enable t)
    (lsp-ui-doc-header t)
    (lsp-ui-doc-include-signature t)
    (lsp-ui-doc-position 'top) ;; top, bottom, or at-point
    (lsp-ui-doc-max-width 150)
    (lsp-ui-doc-max-height 30)
    (lsp-ui-doc-use-childframe t)
    (lsp-ui-doc-use-webkit t)
    ;; lsp-ui-flycheck
    (lsp-ui-flycheck-enable nil)
    ;; lsp-ui-sideline
    (lsp-ui-sideline-enable nil)
    (lsp-ui-sideline-ignore-duplicate t)
    (lsp-ui-sideline-show-symbol t)
    (lsp-ui-sideline-show-hover t)
    (lsp-ui-sideline-show-diagnostics nil)
    (lsp-ui-sideline-show-code-actions nil)
    ;; lsp-ui-imenu
    (lsp-ui-imenu-enable nil)
    (lsp-ui-imenu-kind-position 'top)
    ;; lsp-ui-peek
    (lsp-ui-peek-enable t)
    (lsp-ui-peek-peek-height 20)
    (lsp-ui-peek-list-width 50)
    (lsp-ui-peek-fontify 'on-demand) ;; never, on-demand, or always
    :preface
    (defun ladicle/toggle-lsp-ui-doc ()
      (interactive)
      (if lsp-ui-doc-mode
        (progn
          (lsp-ui-doc-mode -1)
          (lsp-ui-doc--hide-frame))
         (lsp-ui-doc-mode 1)))
    :bind
    (:map lsp-mode-map
    ("C-c C-r" . lsp-ui-peek-find-references)
    ("C-c C-j" . lsp-ui-peek-find-definitions)
    ("C-c i"   . lsp-ui-peek-find-implementation)
    ("C-c m"   . lsp-ui-imenu)
    ("C-c s"   . lsp-ui-sideline-mode)
    ("C-c d"   . ladicle/toggle-lsp-ui-doc))
    :hook
    (lsp-mode . lsp-ui-mode))
  ;; Lsp completion
  (use-package company-lsp
    :custom
    (company-lsp-cache-candidates t) ;; always using cache
    (company-lsp-async t)
    (company-lsp-enable-recompletion nil)))

;; cclsは別途hookする
(use-package ccls
  :custom (ccls-executable "/usr/local/bin/ccls")
  :hook ((c-mode c++-mode objc-mode) .
         (lambda () (require 'ccls) (lsp))))
```

### Emacs26の機能をフル活用したモダンなUI -- [lsp-ui](https://github.com/emacs-lsp/lsp-ui)

Emacsにはeglotというlsp-clientもあるが、lsp-uiが好みのためlsp-modeを愛用している。lsp-ui-peekは常時on、documentとsidelineはtoggle, imenuは昔ながらのimenu-listの方が機能が充実しているためoff, flycheckもflymakeを使っているためoffにしている。[^3]

[^3]: flymakeにも対応しようというissueはある

**lsp-ui-peek**
これが便利でlsp-uiを使っていると言ってもよい機能。関数や変数の定義場所や、呼び出し元へジャンプする時に利用する。1つしかマッチしなかった場合にはそのままジャンプするが、複数の候補があった場合はその周辺コードを確認しながら移動先を選択することができる。
![lsp-peek.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/123c7fe5-4aa9-6985-d082-d3f0008f2676.gif)

**lsp-ui-document**
Emacs26から追加されたchild-frameに対応しており、child-frameとwebkitを有効にすると綺麗なドキュメントが手軽に読める。(child-frameではEmacsからはみ出せる) hoverした要素の解説を表示してくれるが、常時onにしておくことはないと思うので、`ladicle/toggle-lsp-ui-doc` を定義して手軽にon/offできるようにしている。単純なmodeの切り替えだけだとframeが残ることに注意が必要だ。
<img width="755" alt="Screen Shot 2019-03-02 at 23.08.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/26683/3f1a5369-eac9-e174-bb48-9b7d7325c267.png">

**lsp-ui-sideline**
稀にonにしている。現在はOverlayな実装だが、こちらもchild-frameにしようというissueを見かけた。今後より使いやすくなっていくかもしれない。
![lsp-ui-sidebar.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/547f4562-7e7c-27fd-394a-657a077aabc0.gif)

### 要素がわかりやすい補完インタフェース -- [company](https://github.com/company-mode/company-mode), [company-lsp](https://github.com/tigersoldier/company-lsp), [company-box](https://github.com/sebastiencs/company-box), [company-quickhelp](https://github.com/expez/company-quickhelp)

lsp-modeにも補完インタフェースはあるが、company-lspを補完backendに登録するとcompanyと連携できる。モダンなエディタの補完では、候補にアイコンやその候補の要素の説明がついているが、Emacsでもcompany-boxで実現することができる。デフォルトのアイコンが好みではなかったため、各要素(snippet, varible, module, func...)のアイコンやカラーを変更している。

![company-box.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/a8fbe4f4-0837-c0ca-0ffc-de624652de76.gif)

company-quickhelpはその名の通り補完要素のhelp機能。候補のより詳細な情報を手軽に得ることができる。スクショの通りこれもまたEmacs26の恩恵を受けることができる。company周りの設定は長すぎるので割愛する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/b7bc56af-0b8d-d1fe-73be-fef0b7500b77.png)

### コード内の要素ジャンプと全体像の把握 -- [imenu-list](https://github.com/bmag/imenu-list)

lsp-uiのimenuは見た目がオシャレだが、現在カーソルが示している要素とのマッチングや、ファイル移動時の自動更新、検索など足りない機能も多い。それもあってimenuのインタフェースは安定しているimenu-listを利用している。デフォルトのimenu-listにはアイコン表示などはないため、entryの中身に応じてcompany-boxと同じアイコンを表示するパッチを当てた。また、色味はNeotreeに合わせて変更した。

![imenu-list.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/02a591c8-97c3-4001-70b5-eb46b10e6663.gif)

```diff
diff --git common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.el common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.el
index 7936a2c..69dc2f8 100644
--- common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.el
+++ common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.el
@@ -229,25 +229,12 @@ See `hs-minor-mode' for information on what is hide/show."
         (goto-char pos)
         (hs-toggle-hiding)))))
 
-(defun entry-icon (entry)
-   (pcase entry
-     ("Variable" "")
-     ("Variables" "")
-     ("Constant" "")
-     ("Types" "")
-     ("Function" "")
-     ("Method" "")
-     ("Field" "")
-     ("Class" "")
-     ("Interface" "")
-     (_ "")))
-
 (defun imenu-list--insert-entry (entry depth)
   "Insert a line for ENTRY with DEPTH."
   (if (imenu--subalist-p entry)
       (progn
         (insert (imenu-list--depth-string depth))
-        (insert-button (format "%s %s" (entry-icon (car entry)) (car entry))
+        (insert-button (format "%s" (car entry))
                        'face (imenu-list--get-face depth t)
                        'help-echo (format "Toggle: %s"
                                           (car entry))
diff --git common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.elc common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.elc
index 58ded97..ef1eceb 100644
Binary files common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.elc and common/emacs.d/elpa/imenu-list-20190115.2130/imenu-list.elc differ
```

```emacs-lisp
  (use-package imenu-list
    :bind
    ("<f10>" . imenu-list-smart-toggle)
    :custom-face
    (imenu-list-entry-face-1 ((t (:foreground "white"))))
    :custom
    (imenu-list-focus-after-activation t)
    (imenu-list-auto-resize nil))
```

### flymakeでもエラー内容をわかりやすく --- [flymake-posframe](https://github.com/Ladicle/flymake-posframe)

posframeでエラーを表示するパッケージ作りました

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Showing flymake diagnostics at point using posframe<a href="https://t.co/zwHcydDqaN">https://t.co/zwHcydDqaN</a> <a href="https://twitter.com/hashtag/emacs?src=hash&amp;ref_src=twsrc%5Etfw">#emacs</a> <a href="https://t.co/eprAopBnPl">pic.twitter.com/eprAopBnPl</a></p>&mdash; ladicle (@Ladicle) <a href="https://twitter.com/Ladicle/status/1105106282292244480?ref_src=twsrc%5Etfw">March 11, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## パッと見で把握できるディレクトリツリー -- [emacs-neotree](https://github.com/jaypei/emacs-neotree)

Vimのプラグインをインスパイアしたパッケージで、プロジェクト内のディレクトリ構造をツリー表示することができる。VSCodeのようなフルアイコン表示もできるが、あまりゴチャゴチャしたものは好みではない。アイコンの種類は最小限にとどめるnerd2テーマを利用している。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/829c953e-9491-f0bb-5425-fca8c9d1d9ed.png)

```emacs-lisp
  (use-package neotree
    :after
    projectile
    :commands
    (neotree-show neotree-hide neotree-dir neotree-find)
    :custom
    (neo-theme 'nerd2)
    :bind
    ("<f9>" . neotree-projectile-toggle)
    :preface
    (defun neotree-projectile-toggle ()
      (interactive)
      (let ((project-dir
	     (ignore-errors
	     ;;; Pick one: projectile or find-file-in-project
	       (projectile-project-root)
	       ))
	    (file-name (buffer-file-name))
	    (neo-smart-open t))
	(if (and (fboundp 'neo-global--window-exists-p)
		 (neo-global--window-exists-p))
	    (neotree-hide)
	  (progn
	    (neotree-show)
	    (if project-dir
		(neotree-dir project-dir))
	    (if file-name
		(neotree-find file-name)))))))
```

## YAMLの階層構造に負けない -- [highlight-indent-guides](https://github.com/DarthFennec/highlight-indent-guides)

Kubernetesなど、最近のインフラ周りの設定によくYAMLフォーマットが使われている。しかし、「画面に定規を当てて書く」というようなジョークがあるように、何もガイドがないと階層構造が把握しずらいという欠点がある。`responsive`オプションを有効にするとより分かりやすくなるのでオススメ。

![highlight-indent-column.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/7dd6686e-4715-d940-52a2-1d696fab6905.gif)

```emacs-lisp
  (use-package highlight-indent-guides
    :diminish
    :hook
    ((prog-mode yaml-mode) . highlight-indent-guides-mode)
    :custom
    (highlight-indent-guides-auto-enabled t)
    (highlight-indent-guides-responsive t)
    (highlight-indent-guides-method 'character)) ; column
```

## 操作に視覚的フィードバックを与える -- [volatile-hilights](https://github.com/k-talo/volatile-highlights.el)

ペースとした要素など、地味に見逃しやすい操作を実行した時にフィードバックを得られる。doom-draculaのデフォルト設定だと選択と同じ色合いになって余計混乱するため、目立つ色に変更している。

![volatile.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/327804f0-ed2f-5306-8c11-38e59f80c07e.gif)

```emacs-lisp
  (use-package volatile-highlights
    :diminish
    :hook
    (after-init . volatile-highlights-mode)
    :custom-face
    (vhl/default-face ((nil (:foreground "#FF3333" :background "#FFCDCD")))))
```

## 括弧が多いと虹がみえる -- [rainbow-delimiters](https://github.com/Fanael/rainbow-delimiters)

かっこの階層ごとにレインボーなカラーにしてくれるelisp等の括弧の多い言語には欠かせないパッケージ。機能的にも見た目的にも良いのでお気に入り。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/c61b94d7-6569-0d3b-ba05-06c80515ff3b.png)

```emacs-lisp
  (use-package rainbow-delimiters
    :hook
    (prog-mode . rainbow-delimiters-mode))
```

## 対応する括弧を分かりやすく -- paren

デフォルトの機能だが、オプションに応じて対応する括弧が画面外にある時のハイライト方法などを変更することができる。doom-draculaデフォルトの色味がみづらかったため、暗闇で光る感じの色味にした。

![paren.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/9f5e3bf3-7570-3b4c-29f5-e927011ce050.gif)

```emacs-lisp
  (use-package paren
    :ensure nil
    :hook
    (after-init . show-paren-mode)
    :custom-face
    (show-paren-match ((nil (:background "#44475a" :foreground "#f1fa8c"))))
    :custom
    (show-paren-style 'mixed)
    (show-paren-when-point-inside-paren t)
    (show-paren-when-point-in-periphery t))
```

## もうカーソルを見失わない -- [beacon](https://github.com/Malabarba/beacon)

画面を大量に分割しているとカーソルを見失いがちだが、`recenter`等を実行してBeaconで現在行を光らせれば迷子を防止できる。グラデーションカラーや発光時間など、細かく指定できる。

![beacon.gif](https://qiita-image-store.s3.amazonaws.com/0/26683/32146f74-31d8-e79e-11a2-185c17a057e7.gif)

```emacs-lisp
  (use-package beacon
    :custom
    (beacon-color "yellow")
    :config
    (beacon-mode 1))
```

## 変更範囲と操作を可視化 -- [git-gutter](https://github.com/syohex/emacs-git-gutter)

Sublimeからポートされたパッケージで、変更/追加/削除された行を視覚的に把握することができる。緑が追加、赤が削除、黄色が変更に対応している。初めは文字で見分けていたが、変更が多い時にきになるので背景色だけ変更する方向に落ち着いた。また、スクショのように変更ぶぶだけを表示することも可能。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/edf7eb7d-04aa-69d7-56ff-3721cc56ef53.png)

```emacs-lisp
(use-package git-gutter
    :custom
    (git-gutter:modified-sign "~")
    (git-gutter:added-sign    "+")
    (git-gutter:deleted-sign  "-")
    :custom-face
    (git-gutter:modified ((t (:background "#f1fa8c"))))
    (git-gutter:added    ((t (:background "#50fa7b"))))
    (git-gutter:deleted  ((t (:background "#ff79c6"))))
    :config
    (global-git-gutter-mode +1))
```

## 一行あたりの文字数制限を可視化 -- [fill-column-indicator](https://github.com/alpaker/fill-column-indicator)

Gitのコミットメッセージなど、文字数を制限して書きたい時はガイドを表示している。`fill-column`により指定した文字数になると自動改行されるが、視覚的にも把握できると安心感がある。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26683/71a9c3bb-fee3-1dc9-1244-700323a36fcf.png)

```emacs-lisp
(use-package fill-column-indicator
  :hook
  ((markdown-mode
    git-commit-mode) . fci-mode))
```

## コードの地図を表示する -- [minimap](https://github.com/dengste/minimap)

Atom? Sublime?あたりから発祥したコードの全体像を把握するのに便利なminimap。稀に使うくらいの機能のため、デフォルトoffでtoggle運用をしている。デフォルト色は激しいため落ち着きある色に変更した。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f32363638332f66343335303635362d363633312d393261642d653133312d6361303638366338313833612e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/26683/8d2802ef-8fa1-8926-d18f-db0d4349cfdd.png)

```emacs-lisp
  (use-package minimap
    :commands
    (minimap-bufname minimap-create minimap-kill)
    :custom
    (minimap-major-modes '(prog-mode))

    (minimap-window-location 'right)
    (minimap-update-delay 0.2)
    (minimap-minimum-width 20)
    :bind
    ("M-t m" . ladicle/toggle-minimap)
    :preface
    (defun ladicle/toggle-minimap ()
      "Toggle minimap for current buffer."
      (interactive)
      (if (null minimap-bufname)
	  (minimap-create)
	(minimap-kill)))
    :config
    (custom-set-faces
     '(minimap-active-region-background
      ((((background dark)) (:background "#555555555555"))
	(t (:background "#C847D8FEFFFF"))) :group 'minimap)))
```

## おわりに

気づいたら長くなってしまった...。
Emacsもモダンなエディタになる！(特にEmacs26以降のchild-frameよいのでアプデしよう)

> **余談**
> 普段ポモドーロテクニックをよく使っているが、25分集中して5 or 10分やすみでEmacsという名の盆栽を手入れをしている。心が落ち着き、次のタスクに取り掛かる集中力が得られる。