備忘録（init.el）- Emacs

# はじめに

最近Emacsを使い始めた初心者です。
これまでVSCodeやVimを使用しておりましたが、SpacemacsをきっかけにEmacsを始めました。
少しずつ理解を深めていきたいと思い、備忘録を作成していきます。

# early-init.el

画面が表示される前に読み込まれるファイルです。
Emacs27以降で利用できます。

ここでは`package.el`に関する設定と画面のUIに関する設定をしています。

```init.el
;;; package --- Summary
;;; Commentary:
;;; Code:

(setq package-enable-at-startup nil) ;; package.elを使用しない

(push '(fullscreen . maximized) default-frame-alist) ;; 画面を最大化
(push '(vertical-scroll-bars) default-frame-alist) ;; スクロールバー非表示
(push '(menu-bar-lines . 0) default-frame-alist) ;; メニューバー非表示
(push '(tool-bar-lines . 0) default-frame-alist) ;; ツールバー非表示

(provide 'early-init)
;;; early-init.el ends here
```

# init.el

初回起動時に自動生成される`.emacs.d`ディレクトリ内に`init.el`を作成します。

## パッケージ管理
パッケージの管理に[straight](https://github.com/raxod502/straight.el)を使用します。

[straight](https://github.com/raxod502/straight.el)は基本的に下記のコマンドを利用しています。

- `straight-use-package` - パッケージのインストール
- `straight-pull-all` - 全てのパッケージを最新の状態に更新
- `straight-freeze-versions` - ロックファイルを作成
- `straight-thaw-versions` - ロックファイルのバージョンでインストール

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #straight

(defvar bootstrap-version)
(let ((bootstrap-file
	   (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
	  (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
	(with-current-buffer
		(url-retrieve-synchronously
		 "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
		 'silent 'inhibit-cookies)
	  (goto-char (point-max))
	  (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))
```

## Emacs標準機能の設定
Emacs標準パッケージの設定を行います。

- `electric-pair-mode` 以外に[smartparens](https://github.com/Fuco1/smartparens)という括弧補完パッケージがありますが、[lsp-mode](https://github.com/emacs-lsp/lsp-mode) と相性が良くないため、`electric-pair-mode` を採用しました。
- 行番号の表示には `linum-mode` がありますが、[こちら](https://garaemon.hatenadiary.jp/entry/2018/07/08/181003)の記事を参考に `display-line-numbers` に変更しました。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #emacs

(setq backup-directory-alist '(("." . "~/.emacs.d/backup")) ;; バックアップファイルの作成場所を指定
      completion-ignore-case t ;; 補完時に大文字小文字を区別しない
      read-process-output-max (* 1024 1024) ;; 外部プロセスから読み取るデータ量の指定（LSP Modeのチューニング）
      use-short-answers t ;; 入力確認を「y or n」にする。Emacs27以下は (defalias 'yes-or-no-p 'y-or-n-p)
      recentf-max-saved-items 200 ;; 保存するファイルの履歴数を変更
      )

(server-mode +1) ;; デーモン起動
(savehist-mode +1) ;; コマンド履歴を保存
(save-place-mode +1) ;; 最後のカーソル位置を記録
(recentf-mode +1) ;; ファイルの閲覧履歴を保存
(show-paren-mode +1) ;; 対応括弧を強調表示（Emacs28から標準でON）
(global-auto-revert-mode +1) ;; 他プロセスの変更を常に反映する
(global-hl-line-mode +1) ;; 現在行を強調
(global-display-line-numbers-mode +1) ;; 左側に行番号を表示する
(which-function-mode +1) ;; モードラインにカーソル上の関数名等を表示する
(electric-pair-mode +1) ;; 括弧を補完する
(pixel-scroll-mode +1) ;; マウスホイールのスクロール幅を一般的なものに変更
(menu-bar-mode -1) ;; メニューバーを無効
(tool-bar-mode -1) ;; ツールバーを無効
(scroll-bar-mode -1) ;; スクロールバーを無効
```

## 文字コードの設定

文字コードの設定をOSに合わせて行います。

- [Emacs における日本語文字コードの設定](http://yohshiy.blog.fc2.com/blog-entry-273.html)
- [CP932で書かれたファイルの文字化けについて](https://ja.osdn.net/projects/gnupack/forums/22824/36798/)

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #character-code

(set-language-environment "Japanese")
(prefer-coding-system 'utf-8)

;; Windows向けに細かく設定
(when (eq system-type 'windows-nt)
  ;; shift-jis より cp932 を優先させる
  (set-coding-system-priority 'utf-8
                              'euc-jp
                              'iso-2022-jp
                              'cp932))
```

## フォントの設定

- [Emacsのフォントを設定する](https://qiita.com/j8takagi/items/01aecdd28f87cdd3cd2c)
- [Emacs のフォントを変更する](https://myn.hatenablog.jp/entry/change-emacs-font)

【2022/07/09 追記】フォント設定用に[fontaine](https://github.com/protesilaos/fontaine)を導入しました。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #font

(straight-use-package 'fontaine)

(cond ((eq system-type 'gnu/linux)
       (setq fontaine-presets
             '((regular
                :default-family "VLゴシック"
                :default-height 90
                :fixed-pitch-family "VLゴシック"
                :variable-pitch-family "VLPゴシック"
                :italic-family "VLゴシック"
                :line-spacing 1)
               (large
                :default-family "VLゴシック"
                :default-height 150
                :variable-pitch-family "VLPゴシック"
                :line-spacing 1))))

      ((eq system-type 'windows-nt)
       (setq fontaine-presets
             '((regular
                :default-family "BIZ UDゴシック"
                :default-height 90
                :fixed-pitch-family "BIZ UDゴシック"
                :variable-pitch-family "BIZ UDPゴシック"
                :italic-family "BIZ UDゴシック"
                :line-spacing 1)
               (large
                :default-family "BIZ UDゴシック"
                :default-height 150
                :variable-pitch-family "BIZ UDPゴシック"
                :line-spacing 1)))setq fontaine-presets))

;; Recover last preset or fall back to desired style from
;; `fontaine-presets'.
(fontaine-set-preset (or (fontaine-restore-latest-preset) 'regular))

;; The other side of `fontaine-restore-latest-preset'.
(add-hook 'kill-emacs-hook #'fontaine-store-latest-preset)
```

## 末尾のスペースを可視化

[Emacs: whitespace で余分な空白/タブに色づけ](https://yanqirenshi.hatenablog.com/entry/2016/07/03/Emacs%3A_whitespace_%E3%81%A7%E4%BD%99%E5%88%86%E3%81%AA%E7%A9%BA%E7%99%BD/%E3%82%BF%E3%83%96%E3%81%AB%E8%89%B2%E3%81%A5%E3%81%91)を参考に設定しました。
タブを可視化すると[highlight-indent-guides](https://github.com/DarthFennec/highlight-indent-guides)がうまく表示されないことがあったため、末尾スペースのみの可視化にしました。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #whitespace

(setq whitespace-style '(face trailing))

(global-whitespace-mode +1)
```

## IME
IMEに関するパッケージです。
Windowsでは[tr-ime]([tr-emmacs-ime-module](https://github.com/trueroad/tr-emacs-ime-module))、Ubuntuでは[mozc](https://wiki.debian.org/JapaneseEnvironment/Mozc)を使用します。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #ime

(straight-use-package 'tr-ime)
(straight-use-package 'mozc)

(cond ((eq system-type 'windows-nt)
       (setq default-input-method "W32-IME")
       (tr-ime-standard-install)
       (w32-ime-initialize))

      ((eq system-type 'gnu/linux)
       (setq default-input-method "japanese-mozc")))
```

## テーマの設定

[A GNU Emacs Themes Gallery](https://emacsthemes.com/)に様々なテーマが載っていて参考になります。
[modus-themes](https://protesilaos.com/emacs/modus-themes)は[こちら](https://zenn.dev/lambdagonbei/articles/1b2bce27673078)の記事で紹介されていますが、見やすくて気に入っています。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #theme

(straight-use-package 'modus-themes)

(defun disable-all-themes ()
  "Disable all active themes."
  (dolist (theme custom-enabled-themes)
    (disable-theme theme)))

;; load-theme 実行時に他のテーマを無効にします
(defadvice load-theme (before disable-themes-first activate)
  (disable-all-themes))

(modus-themes-load-operandi)
;; (modus-themes-load-vivendi)
```

## モードライン

[Emacsモダン化計画 -かわEmacs編-](https://qiita.com/Ladicle/items/feb5f9dce9adf89652cf)で紹介されている[doom-modeline](https://github.com/seagle0128/doom-modeline)と[nyan-mode](https://github.com/TeMPOraL/nyan-mode)を導入しました。

[【Emacs入門】③モードラインについて考える（Moody / Minions）](https://zenn.dev/lambdagonbei/articles/0bf693abee6e71)で紹介されている[moody](https://github.com/tarsius/moody)や[minions](https://github.com/tarsius/minions)等もあります。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #modeline

(straight-use-package 'doom-modeline)
(straight-use-package 'nyan-mode)

(setq nyan-animate-nyancat t
      nyan-bar-length 24)

(doom-modeline-mode +1)
(nyan-mode +1)
```

## git用のパッケージ

`C-x g`で[magit](https://magit.vc/)が起動します。
[[Emacs] magitチュートリアル](https://qiita.com/maueki/items/70dbf62d8bd2ee348274)がとても参考になります。
[git-gutter](https://github.com/emacsorphanage/git-gutter)は変更箇所を表示してくれるパッケージです。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #git

(straight-use-package 'magit)
(straight-use-package 'git-gutter)

(global-git-gutter-mode +1)
```

## ショートカットキーの可視化

[which-key](https://github.com/justbur/emacs-which-key)を導入すると、登録しているキーバインドが表示されるようになります。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #which-key

(straight-use-package 'which-key)

(which-key-mode +1)
```

## Vimキーバインド

Emacsキーバインドでしばらく入力していたら指が痛くなってきたので、Vimキーバインドを導入しました。
- [evil](https://github.com/emacs-evil/evil)
- [evil-collection](https://github.com/emacs-evil/evil-collection) - 各モードへいい感じにVim用のキーバインドを設定
- [evil-commentary](https://github.com/linktohack/evil-commentary) - `gc`でコメントアウト
- [evil-surround](https://github.com/emacs-evil/evil-surround) - Visualモード中に`S(`または`S)`で括弧を追加
- [evil-matchit](https://github.com/redguardtoo/evil-matchit) - `<div>...</div>`のタグ間を`%`キーでジャンプ
- [evil-org-mode](https://github.com/Somelauw/evil-org-mode) - org-modeでもVim用のキーバインドを設定
- 
```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #my-keymap

;; Spacemacsのようにスペースキーを起点にコマンド実行を行うためのキーマップ
(defvar my-intercept-mode-map (make-sparse-keymap)
  "High precedence keymap.")

;; Spacemacsのようにスペースキーを起点にコマンド実行を行うためのモード
(define-minor-mode my-intercept-mode
  "Global minor mode for higher precedence evil keybindings."
  :global t)

(my-intercept-mode)

(defvar my-quit-map (make-sparse-keymap)
  "My quit keymap.")

(defvar my-file-map (make-sparse-keymap)
  "My file keymap.")

(defvar my-buffer-map (make-sparse-keymap)
  "My buffer keymap.")

(defvar my-error-map (make-sparse-keymap)
  "My error keymap.")

(defvar my-toggle-map (make-sparse-keymap)
  "My toggle keymap.")

(defvar my-org-map (make-sparse-keymap)
  "My error keymap.")

(define-key my-quit-map (kbd "q") 'save-buffers-kill-terminal)
(define-key my-file-map (kbd "f") 'find-file)
(define-key my-file-map (kbd "b") 'bookmark-jump)
(define-key my-buffer-map (kbd "b") 'switch-to-buffer)
(define-key my-buffer-map (kbd "p") 'project-switch-to-buffer)

(my-intercept-mode)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #evil

(straight-use-package 'evil)
(straight-use-package 'evil-collection)
(straight-use-package 'evil-commentary)
(straight-use-package 'evil-surround)
(straight-use-package 'evil-matchit)
(straight-use-package 'evil-org)

(setq evil-want-keybinding nil
      evil-symbol-word-search t     ; `*` で検索する際、 `_` や `-` を含める
      evil-kill-on-visual-paste nil ; Visualモードで貼り付けた場合、コピー内容を上書きしない
      )

(define-key my-buffer-map (kbd "d") 'kill-this-buffer)

(with-eval-after-load 'evil
  (evil-collection-init)
  (evil-commentary-mode +1)
  (global-evil-surround-mode +1)
  (global-evil-matchit-mode +1)

  ;; 定義したキーマップをEvilで使用できるようにします
  (dolist (state '(normal visual insert))
    (evil-make-intercept-map
     ;; NOTE: This requires an evil version from 2018-03-20 or later
     (evil-get-auxiliary-keymap my-intercept-mode-map state t t)
     state))

  ;; 上で定義したモード・キーマップにキーを設定しています
  ;; <leader>キーは上手くいかなかったので、直接SPCを指定しています
  (evil-define-key '(normal visual) my-intercept-mode-map
    (kbd "SPC SPC") 'execute-extended-command
    (kbd "SPC s") `("search" . ,search-map)
    (kbd "SPC g") `("goto" . ,goto-map)
    (kbd "SPC q") `("quit" . ,my-quit-map)
    (kbd "SPC f") `("file" . ,my-file-map)
    (kbd "SPC b") `("buffer" . ,my-buffer-map)
    (kbd "SPC e") `("error" . ,my-error-map)
    (kbd "SPC t") `("toggle" . ,my-toggle-map)
    (kbd "SPC o") `("org" . ,my-org-map)
    (kbd "SPC 0") #'delete-window
    (kbd "SPC 1") #'delete-other-windows
    (kbd "SPC 2") #'split-window-below
    (kbd "SPC 3") #'split-window-right
    (kbd "SPC 4") #'switch-to-buffer-other-window
    (kbd "SPC 5") #'switch-to-buffer-other-frame
    (kbd "SPC w") #'evil-window-next
    (kbd "SPC W") #'other-window))

(with-eval-after-load 'evil-org
  (require 'evil-org-agenda)
  (evil-org-set-key-theme '(navigation insert textobjects additional calendar))
  (evil-org-agenda-set-keys))

(add-hook 'org-mode-hook 'evil-org-mode)

(evil-mode +1)
```

## 入力補完

入力補完は[company](https://company-mode.github.io/)と[auto-complete](https://github.com/auto-complete/auto-complete)が有名です。

またEmacs26以降で使用できる[company-box](https://github.com/sebastiencs/company-box)を導入して、UIも強化しました。

【2022/01/27 追記】[company-tabnine](https://github.com/TommyX12/company-tabnine)を追加しました。
【2022/02/10 追記】corfuの設定は[こちら](https://qiita.com/nobuyuki86/items/7c65456ad07b555dd67d)。
【2022/06/09 追記】[auto-complete から company に移行した](https://qiita.com/zk_phi/items/9dc373e734d20cd31641)を参考に`company-dwim`、`company-anywhere`を追加しました。

基本的にはTABでワチャワチャ補完しますが、確定を明示的にするときは`C-j`を押下して確定します。
`RET`はそのまま改行として使用します。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #company

(straight-use-package 'company)
(straight-use-package 'company-box)
(straight-use-package 'company-tabnine)
(straight-use-package '(company-dwim :type git :host github :repo "zk-phi/company-dwim"))
(straight-use-package '(company-anywhere :type git :host github :repo "zk-phi/company-anywhere"))

(setq company-minimum-prefix-length 1
      company-dabbrev-other-buffers nil ; パフォーマンスの向上
      company-dabbrev-ignore-case nil   ; パフォーマンスの向上
      company-dabbrev-downcase nil      ; パフォーマンスの向上
      company-require-match 'never      ; 補完候補に存在しない単語でも入力できるようにする
      company-auto-complete nil         ; スペースの挙動を一般的なものにする
      )

;; Tab で補完候補を表示する
(global-set-key [remap indent-for-tab-command] #'company-indent-or-complete-common)
(global-set-key [remap c-indent-line-or-region] #'company-indent-or-complete-common)

;; company-box を起動させる
(add-hook 'company-mode-hook 'company-box-mode)

(with-eval-after-load 'company
  (require 'company-dwim)
  (require 'company-anywhere)

  ;; TabNine を補完候補に追加
  (add-to-list 'company-backends '(company-capf company-yasnippet company-tabnine :separate))
  ;; company-dwim 用のフロントエンドを追加
  (add-to-list 'company-frontends 'company-dwim-frontend t)
  ;; 余分なフロントエンドを削除
  (delq 'company-preview-if-just-one-frontend company-frontends)

  ;; キーバインドの設定
  (define-key company-active-map (kbd "RET") nil)
  (define-key company-active-map (kbd "<return>") nil)
  (define-key company-active-map (kbd "TAB") #'company-dwim)
  (define-key company-active-map (kbd "<tab>") #'company-dwim)
  (define-key company-active-map (kbd "S-TAB") #'company-dwim-select-previous)
  (define-key company-active-map (kbd "<backtab>") #'company-dwim-select-previous)
  (define-key company-active-map (kbd "C-j") #'company-complete-selection))

(global-company-mode +1)
```

## 補完インターフェース

補完に関する記事では[Emacsの次世代ミニバッファ補完UI](https://blog.tomoya.dev/posts/a-new-wave-has-arrived-at-emacs/)がとても参考になります。

[prescient](https://github.com/raxod502/prescient.el)がいい感じだったので、[selectrum](https://github.com/raxod502/selectrum)を選択しました。

`company-prescient`のソート機能は便利ですが、LSPのソートも消してしまうので、`lsp-mode`ではソート機能を無効にしています。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #selectrum

(straight-use-package 'selectrum)

(global-set-key (kbd "C-x C-z") #'selectrum-repeat)

(with-eval-after-load 'selectrum
  (with-eval-after-load 'evil
    (evil-define-key '(normal visual) my-intercept-mode-map
      (kbd "SPC z") 'selectrum-repeat)))

(selectrum-mode +1)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #prescient

(straight-use-package 'prescient)
(straight-use-package 'selectrum-prescient)
(straight-use-package 'company-prescient)

(setq company-prescient-sort-length-enable nil)

(with-eval-after-load 'prescient
  (prescient-persist-mode +1))

(selectrum-prescient-mode +1)
(company-prescient-mode +1)
```

## 検索パッケージ

`isearch` より使いやすく設計された[ctrlf](https://github.com/radian-software/ctrlf)を導入します。
検索スタイルを `fuzzy` に設定することで、スペース区切りで検索することができます。
[swiper](https://github.com/abo-abo/swiper)系と違い、同じ行内で複数の一致があった場合でも移動できます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #ctrlf

(straight-use-package 'ctrlf)

(setq ctrlf-default-search-style 'fuzzy)

(define-key search-map (kbd "s") #'ctrlf-forward-default)

(ctrlf-mode +1)
```

## 詳細情報の表示

[marginalia](https://github.com/minad/marginalia)はミニバッファの補完に傍注（追加情報）をつけてくれます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #marginalia

(straight-use-package 'marginalia)

(marginalia-mode +1)
```

## 便利コマンド

[consult](https://github.com/minad/consult)と[embark](https://github.com/oantolin/embark)は[vertico](https://github.com/minad/vertico)、[selectrum](https://github.com/raxod502/selectrum)で利用できる便利コマンド集です。
ここで設定しているコマンド以外にも数多くの便利コマンドがあります。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #consutl

(straight-use-package 'consult)

(require 'consult)

;; C-c bindings (mode-specific-map)
(global-set-key (kbd "C-c h") #'consult-history)
(global-set-key (kbd "C-c m") #'consult-mode-command)
(global-set-key (kbd "C-c k") #'consult-kmacro)
;; C-x bindings (ctl-x-map)
(global-set-key (kbd "C-x M-:") #'consult-complex-command) ;; orig. repeat-complex-command
(global-set-key [remap switch-to-buffer] #'consult-buffer) ;; orig. switch-to-buffer
(global-set-key [remap switch-to-buffer-other-window] #'consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
(global-set-key [remap switch-to-buffer-other-frame] #'consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
(global-set-key [remap bookmark-jump] #'consult-bookmark) ;; orig. bookmark-jump
(global-set-key [remap project-switch-to-buffer] #'consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
(global-set-key (kbd "M-#") #'consult-register-load)
(global-set-key (kbd "M-'") #'consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
(global-set-key (kbd "C-M-#") #'consult-register)
;; Other custom bindings
(global-set-key (kbd "M-y") #'consult-yank-pop) ;; orig. yank-pop
(global-set-key (kbd "<help> a") #'consult-apropos) ;; orig. apropos-command
(define-key my-buffer-map (kbd "4") #'consult-buffer-other-window)
(define-key my-buffer-map (kbd "5") #'consult-buffer-other-frame)
;; M-g bindings (goto-map)
(define-key goto-map (kbd "e") #'consult-compile-error)
(define-key goto-map (kbd "g") #'consult-goto-line) ;; orig. goto-line
(define-key goto-map (kbd "o") #'consult-outline) ;; Alternative: consult-org-heading
(define-key goto-map (kbd "m") #'consult-mark)
(define-key goto-map (kbd "k") #'consult-global-mark)
(define-key goto-map (kbd "i") #'consult-imenu)
(define-key goto-map (kbd "I") #'consult-imenu-multi)
;; M-s bindings (search-map)
(define-key search-map (kbd "d") #'consult-find)
(define-key search-map (kbd "D") #'consult-locate)
(define-key search-map (kbd "g") #'consult-grep)
(define-key search-map (kbd "G") #'consult-git-grep)
(define-key search-map (kbd "r") #'consult-ripgrep)
(define-key search-map (kbd "l") #'consult-line)
(define-key search-map (kbd "L") #'consult-line-multi)
(define-key search-map (kbd "m") #'consult-multi-occur)
(define-key search-map (kbd "k") #'consult-keep-lines)
(define-key search-map (kbd "u") #'consult-focus-lines)
;; Minibuffer history
(define-key minibuffer-local-map (kbd "M-s") #'consult-history) ;; orig. next-matching-history-element
(define-key minibuffer-local-map (kbd "M-r") #'consult-history) ;; orig. previous-matching-history-element

;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
(add-hook 'completion-list-mode 'consult-preview-at-point-mode)

;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
      register-preview-function #'consult-register-format)

;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)

;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
      xref-show-definitions-function #'consult-xref)

;; Configure other variables and modes in the :config section,
;; after lazily loading the package.
(with-eval-after-load 'consult
  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key (kbd "M-."))
  ;; (setq consult-preview-key (list (kbd "<S-down>") (kbd "<S-up>")))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme
   :preview-key '(:debounce 0.5 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-recent-file
   consult--source-project-recent-file
   :preview-key (kbd "M-."))

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<") ;; (kbd "C-+")

  ;; Optionally make narrowing help available in the minibuffer.
  ;; You may want to use `embark-prefix-help-command' or which-key instead.
  ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)

  ;; By default `consult-project-function' uses `project-root' from project.el.
  ;; Optionally configure a different project root function.
  ;; There are multiple reasonable alternatives to chose from.
  ;;;; 1. project.el (the default)
  ;; (setq consult-project-function #'consult--default-project--function)
  ;;;; 2. projectile.el (projectile-project-root)
  (autoload 'projectile-project-root "projectile")
  (setq consult-project-function (lambda (_) (projectile-project-root)))
  ;;;; 3. vc.el (vc-root-dir)
  ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
  ;;;; 4. locate-dominating-file
  ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
  )


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #emabrk

(straight-use-package 'embark)
(straight-use-package 'embark-consult)

(global-set-key (kbd "C-.") #'embark-act) ;; pick some comfortable binding
(global-set-key (kbd "C-;") #'embark-dwim) ;; good alternative: M-.
(global-set-key (kbd "C-h B") #'embark-bindings) ;; alternative for `describe-bindings'

(setq prefix-help-command #'embark-prefix-help-command)

(with-eval-after-load 'embark
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none))))

  (with-eval-after-load 'consult
    (add-hook 'embark-collect-mode-hook 'consult-preview-at-point-mode)))
```

## 補完スタイル
~~補完スタイルにカスタマイズ性の高い[orderless](https://github.com/oantolin/orderless)を導入しています。`selectrum`は前述の`selectrum-prescient`を利用しているので、違いはほとんどありません。
`company`では`orderless-flex`で曖昧に絞り込み、`company-prescient`で並び替えるようにしています。~~

~~現在は `(add-to-list 'completion-styles 'flex t)` で `(basic partial-completion emacs22 flex)` になっています。~~

[fussy](https://github.com/jojojames/fussy)というパッケージがとても良かったので変更しました。
[Emacsで新しいFuzzy補完 - fussy -](https://qiita.com/nobuyuki86/items/7a08a8b22ff64e4cc60b)

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #fussy

(straight-use-package '(fussy :type git :host github :repo "jojojames/fussy"))

(setq completion-styles '(fussy)
      completion-category-defaults nil
      compleiton-category-overrides nil)
```

## カッコの補完

~~カッコの補完には[smartparens](https://github.com/Fuco1/smartparens)を使用しています。~~

【追記】現在はEmacs標準の `electric-pair-mode` を使用しています。下記はSmartparensを利用する場合の備忘録として残しています。

そのままだと`xxx {|}`で改行すると

```
xxx {
|}
```

となってしまうので関数を追加して、

```
xxx {
  |
}
```

となるようにしています。

```init.el
(straight-use-package 'smartparens)

(with-eval-after-load 'smartparens
  (require 'smartparens-config)

  (defun indent-between-pair (&rest _ignored)
	(newline)
	(indent-according-to-mode)
	(forward-line -1)
	(indent-according-to-mode))

  (sp-local-pair 'prog-mode "{" nil :post-handlers '((indent-between-pair "RET")))
  (sp-local-pair 'prog-mode "[" nil :post-handlers '((indent-between-pair "RET")))
  (sp-local-pair 'prog-mode "(" nil :post-handlers '((indent-between-pair "RET"))))

;; (smartparens-global-mode +1)
```

## スニペット

スニペットには[yasnippet](https://github.com/joaotavora/yasnippet)と[yasnippet-snippets](https://github.com/AndreaCrotti/yasnippet-snippets)を使用します。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #yasnippet

(straight-use-package 'yasnippet)
(straight-use-package 'yasnippet-snippets)

(with-eval-after-load 'yasnippet
  (require 'yasnippet-snippets)
  (define-key yas-minor-mode-map (kbd "TAB") nil)
  (define-key yas-minor-mode-map (kbd "<tab>") nil)
  (define-key yas-keymap (kbd "C-TAB") 'yas-next-field-or-maybe-expand)
  (define-key yas-keymap (kbd "C-<tab>") 'yas-next-field-or-maybe-expand))

(yas-global-mode +1)
```

## 変更履歴のツリー表示

[UndoTree](https://www.emacswiki.org/emacs/UndoTree)は変更履歴をツリー表示してくれるパッケージです。
[こちら](https://khiker.hatenablog.jp/entry/20100123/undo_tree)の記事では使い方などを簡単にまとめてくれています。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #undo-tree

(straight-use-package 'undo-tree)

(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo-history")))

(with-eval-after-load 'evil
  (evil-set-undo-system 'undo-tree)
  (evil-define-key 'normal my-intercept-mode-map
    (kbd "SPC u") 'undo-tree-visualize))

(global-undo-tree-mode +1)
```

## プロジェクトに関するパッケージ

あまり使いこなせていませんが、[projectile](https://github.com/bbatsov/projectile)プロジェクトレベルで動作する様々なコマンドを提供するパッケージです。
外部コマンドに依存せず利用できます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #projectile

(straight-use-package 'projectile)

(with-eval-after-load 'projectile
  (define-key projectile-mode-map (kbd "C-c p") #'projectile-command-map))

(with-eval-after-load 'evil
  (evil-define-key 'normal my-intercept-mode-map
    (kbd "SPC p") `("projectile" . projectile-command-map)))

(projectile-mode +1)
```

## 構文チェック

[flycheck](https://www.flycheck.org/en/latest/)はプログラムのエラーや警告をわかりやすく表示してくれるパッケージです。
この他にEmacs標準で搭載されている`flymake`などもあります。

下記では`Doom emacs`を参考にパフォーマンスが上がるように調整しています。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #flycheck

(straight-use-package 'flycheck)
(straight-use-package 'consult-flycheck)
(straight-use-package 'flycheck-posframe)

(define-key my-error-map (kbd "l") #'flycheck-list-errors)
(define-key my-error-map (kbd "n") #'flycheck-next-error)
(define-key my-error-map (kbd "p") #'flycheck-previous-error)
(define-key my-error-map (kbd "e") #'consult-flycheck)

(with-eval-after-load 'flycheck
  ;; Rerunning checks on every newline is a mote excessive.
  (delq 'new-line flycheck-check-syntax-automatically)
  ;; And don't recheck on idle as often
  (setq flycheck-idle-change-delay 1.0)
  ;; For the above functionality, check syntax in a buffer that you switched to
  ;; only briefly. This allows "refreshing" the syntax check state for several
  ;; buffers quickly after e.g. changing a config file.
  (setq flycheck-buffer-switch-check-intermediate-buffers t)
  ;; Display errors a little quicker (default is 0.9s)
  (setq flycheck-display-errors-delay 0.25)

  (require 'flycheck-posframe)
  (add-hook 'flycheck-mode-hook #'flycheck-posframe-mode)

  (with-eval-after-load 'company
    (add-hook 'flycheck-posframe-inhibit-functions #'company--active-p)))

(global-flycheck-mode +1)
```

## カッコをわかりやすく色付け

[rainbow-delimiters](https://github.com/Fanael/rainbow-delimiters)は括弧の階層によって色をつけてくれるパッケージです。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #rainbow-delimiters

(straight-use-package 'rainbow-delimiters)

(define-key my-toggle-map (kbd "r") #'rainbow-delimiters-mode)

(add-hook 'prog-mode-hook 'rainbow-delimiters-mode)
```

## インデントの色付け

[highlight-indent-guides](https://github.com/DarthFennec/highlight-indent-guides)はインデントに色や線を引いてくれるパッケージです。
他にもパッケージが存在しますが、見た目が綺麗で動作も軽量なこのパッケージを選択しました。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #highlight-indent-guides

(straight-use-package 'highlight-indent-guides)

(setq highlight-indent-guides-method 'character
      highlight-indent-guides-character 124
      highlight-indent-guides-responsive 'top)

(define-key my-toggle-map (kbd "h") 'highlight-indent-guides-mode)

(add-hook 'prog-mode-hook 'highlight-indent-guides-mode)
```

## 範囲選択パッケージ

[expand-region.el](https://github.com/magnars/expand-region.el)はコマンド押下毎に選択範囲を拡張してくれるパッケージです。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #expand-region

(straight-use-package 'expand-region)

(global-set-key (kbd "C-=") #'er/expand-region)

(with-eval-after-load 'evil
  (evil-define-key '(normal visual) my-intercept-mode-map
    (kbd "SPC v") 'er/expand-region))
```

## カーソル位置をわかりやすくする

~~[beacon](https://github.com/Malabarba/beacon)はカーソル移動箇所をわかりやすくしてくれるパッケージです。~~
もっとシンプルな[pulsar](https://protesilaos.com/emacs/pulsar)に変更しました。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #pulsar

(straight-use-package 'pulsar)

(pulsar-global-mode +1)
```

## ガベージコレクション

[gcmh](https://github.com/emacsmirror/gcmh)はEmacsがアクティブじゃない時や、しばらく操作されていない時にガベージコレクションを実行してくれるパッケージです。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #gcmh

(straight-use-package 'gcmh)

(setq gcmh-verbose t
      gcmh-idle-delay 'auto
      gcmh-auto-idle-delay-factor 10
      gcmh-high-cons-threshold (* 128 1024 1024))

(gcmh-mode +1)
```

## 起動画面を変更

[emacs-dashboard](https://github.com/emacs-dashboard/emacs-dashboard)は起動画面にファイルの閲覧履歴、ブックマーク、アジェンダを表示して使いやすくしてくれます。
また、このパッケージを使用しなくても[こちら](https://qiita.com/kiwanami/items/d10fac42d30a14c6c28d)のようにカスタマイズできます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #dashboard

(straight-use-package 'dashboard)

(setq dashboard-center-content t
      dashboard-set-heading-icons t
      dashboard-set-file-icons t
      dashboard-set-navigator t
      dashboard-set-init-info t)

(dashboard-setup-startup-hook)
```

## 操作をわかりやすくする

ペーストやUndo、Redo等の操作をわかりやすく色付けしてくれます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #volatile-highlights

(straight-use-package 'volatile-highlights)

(volatile-highlights-mode +1)
```

## Org

最近 `org-mode` を活用したいと思い、色々勉強中です。
[org-pomodoro](https://github.com/marcinkoziej/org-pomodoro)でEmacsでポモドーロを利用します。
[alert](https://github.com/jwiegley/alert)を適切に設定すれば、ポップアップで通知してくれます。


```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #org

(straight-use-package 'org-pomodoro)

(setq org-tag-alist '(("@Sample1" . nil)
                      ("@Test" . nil))
      org-directory "~/org/"
      org-default-notes-file (concat org-directory "/notes.org")
      org-capture-templates '(("t" "Todo" entry (file+headline "~/org/notes.org" "Tasks")
                               "* TODO %?\n  %i\n  %a")
                              ("j" "Journal" entry (file+datetree "~/org/journal.org")
                               "* %?\nEntered on %U\n  %i\n  %a"))
      org-agenda-files '("~/org/notes.org"
                         "~/org/journal.org"))

(global-set-key (kbd "C-c c") #'org-capture)
(global-set-key (kbd "C-c a") #'org-agenda)
(define-key my-org-map (kbd "c") #'org-capture)
(define-key my-org-map (kbd "a") #'org-agenda)
(define-key my-org-map (kbd "o") #'org-open-at-point)
(define-key my-org-map (kbd "l") #'org-link)
(define-key my-org-map (kbd "p") #'org-pomodoro)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #alert

(straight-use-package 'alert)
(straight-use-package 'alert-toast)

(cond ((eq system-type 'gnu/linux)
       (setq alert-default-style 'libnotify))

      ((eq system-type 'windows-nt)
       (setq alert-default-style 'toast)))
```

## valign

`org-mode` のテーブルを利用すると幅がずれてしまうことがあります。
このパッケージを導入すると幅を揃えてくれます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #valign

(straight-use-package 'valign)

(add-hook 'org-mode-hook 'valign-mode)
(add-hook 'markdown-mode-hook 'valign-mode)
```

## ripgrepパッケージ

`ripgrep`を利用するパッケージは色々ありますが、私は[rg](https://github.com/dajva/rg.el)を利用しています。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #rg

(straight-use-package 'rg)
```

## アイコンの表示

[lsp-mode](https://github.com/emacs-lsp/lsp-mode)等で使用するアイコンなどを[all-the-icons](https://github.com/domtronn/all-the-icons.el)の`M-x all-the-icons-install-fonts`で取得します。

[all-the-icons-dired](https://github.com/jtbm37/all-the-icons-dired)は`dired`上でアイコンを表示するパッケージです。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #all-the-icons

(straight-use-package 'all-the-icons)
(straight-use-package 'all-the-icons-dired)

(when (display-graphic-p)
  (require 'all-the-icons)
  (add-hook 'dired-mode-hook 'all-the-icons-dired-mode))
```

## 再起動用コマンド

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #restart-emacs

(straight-use-package 'restart-emacs)

(define-key my-quit-map (kbd "r") #'restart-emacs)
```

## プログラミング

### LSP
LSPに関する設定を行います。
[lsp-mode](https://github.com/emacs-lsp/lsp-mode)と[eglot](https://github.com/joaotavora/eglot)がありますが、[lsp-mode](https://github.com/emacs-lsp/lsp-mode)を導入しました。

[lsp-ui](https://github.com/emacs-lsp/lsp-ui)は画面のUI
[consult-lsp](https://github.com/gagbo/consult-lsp)はLSP用のコマンド
[dap-mode](https://github.com/emacs-lsp/dap-mode)はデバッグ機能
[lsp-java](https://github.com/emacs-lsp/lsp-java)はJava用の設定
[lsp-pyright](https://github.com/emacs-lsp/lsp-pyright)はPython(pyright)用の設定
を提供します。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #lsp-mode

(straight-use-package 'lsp-mode)
(straight-use-package 'lsp-ui)
(straight-use-package 'lsp-java)
(straight-use-package 'lsp-pyright)

(setq lsp-keymap-prefix "M-l"
      lsp-eldoc-enable-hover nil
      lsp-enable-folding nil
      lsp-headerline-breadcrumb-enable nil
      lsp-headerline-breadcrumb-enable-diagnostics nil
      lsp-java-vmargs '("-XX:+UseParallelGC" "-XX:GCTimeRatio=4" "-XX:AdaptiveSizePolicyWeight=90" "-Dsun.zip.disableMemoryMapping=true" "-Xmx2G" "-Xms100m"))

(add-hook 'lsp-mode-hook (lambda ()
                           (with-eval-after-load 'evil
                             (evil-local-set-key 'normal (kbd "SPC m") `("lsp" . ,lsp-command-map)))))

(add-hook 'web-mode-hook #'lsp)
(add-hook 'css-mode-hook #'lsp)
(add-hook 'rust-mode-hook #'lsp)
(add-hook 'java-mode-hook (lambda ()
                            (require 'lsp-java)
                            (lsp)))
(add-hook 'python-mode-hook (lambda ()
                              (require 'lsp-pyright)
                              (lsp)))
```

### Java

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #java

(add-hook 'java-mode-hook (lambda ()
                            (setq-local tab-width 2
                                        c-basic-offset 2
                                        indent-tabs-mode t)))
```

### Html/CSS

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #web

(straight-use-package 'web-mode)
(straight-use-package 'emmet-mode)
(straight-use-package 'web-beautify)

(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.jsp\\'" . web-mode))

(add-hook 'web-mode-hook (lambda ()
                           (setq-local tab-width 2)
                           (emmet-mode +1)))

(add-hook 'css-mode-hook (lambda ()
                           (setq-local tab-width 2)
                           (emmet-mode +1)))
```


### Rust言語
`lsp-mode`起動後に`lsp-install-server`コマンドを実行し、`rust-analyzer`を選択することで、自動的にLanguage Serverがダウンロードされます。

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #rust

(straight-use-package 'rust-mode)
(straight-use-package 'cargo)

(add-hook 'rust-mode-hook (lambda ()
                            (setq-local tab-width 4
                                        indent-tabs-mode nil)
                            (cargo-minor-mode +1)))
```

### Python

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #python

(straight-use-package 'pyvenv)
```

### Common Lisp

```
$ sudo apt sbcl
または
$ sudo apt clisp
```

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #common-lisp

(straight-use-package 'slime)
(straight-use-package 'slime-company)

(setq inferior-lisp-program "sbcl")

(with-eval-after-load 'slime
  (slime-setup '(slime-fancy slime-company slime-banner)))
```

### SQL

```init.el

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; #sql

(straight-use-package 'sql-indent)
(straight-use-package 'sqlformat)

(add-hook 'sql-mode-hook 'sqlind-minor-mode)
```

# 参考

[Emacsモダン化計画 -かわEmacs編-](https://qiita.com/Ladicle/items/feb5f9dce9adf89652cf)
[2020年代のEmacs入門](https://emacs-jp.github.io/tips/emacs-in-2020)