Emacs 基本環境設定 / キーバインド

emacsの基本設定したら予想以上に情報散乱してて面倒だったので．備忘録ついでにまとめ．

- emacs使用はするが、わざわざ調べてまで設定する程ではないのでしてなかった、みたいな人向け．


## 0.1 Emacs関連サイト
困ったら調べるのに使うサイトたち．

- Emacs公式:https://www.gnu.org/software/emacs/manual
    - 特にエディタに関しては [【ここ】](https://www.gnu.org/software/emacs/manual/html_node/emacs/index.html)
- 日本語マニュアル(ayatakesiさんによる和訳): https://ayatakesi.github.io/
- EmacsWiki: https://www.emacswiki.org/emacs/
- GNU Emacs Lispリファレンスマニュアル: http://www.fan.gr.jp/~ring/doc/elisp_20/elisp.html#Top


## 0.2 Emacs バージョン確認方法

たまにバージョンに依存するものが有るので。

```
emacs --version
```

か、emacs内で、

```
M-x version
```

- Macデフォルト: `GNU Emacs 22.1.1 (mac-apple-darwin)`
- 自分はbrew installしたemacsを使用．`GNU Emacs 26.2 (build 1, x86_64-apple-darwin18.5.0)`


## 1. Emacs 環境設定

Emacsの環境設定の基本は2つ。

1. 環境設定ファイル
2. package 管理：必要に応じて package をインストールして使用する。



## 1.1 環境設定ファイル名

下のいずれかのファイル名として環境設定ファイルを作成し、設定を記述していくことで、設定が反映される。
言語は **Emacs Lisp** を用いて記述する。（Lispプログラミング言語の方言みたいなもの。）

`~/.emacs.el`

`~/.emacs`

`~/.emacs.d/init.el`

- 上から優先にemacs起動時に読み込み．読み込まれるのは一つだけ。
- 推奨・非推奨は公式マニュアル/ソースコードのどこにも書かれてないが、`.emacs.d/init.el`を使用する人が多めの模様。
- `.el` = **Emacs Lisp** の拡張子
 
#### Emacs Lisp: 編集のための基本文法
環境設定ファイル見るのにある程度困らないためなので必要なければスルー．

- コメント

```lisp
;セミコロンでコメントに．文末まで．
(以下，慣習)
;;;; プログラム主要部分のヘッダ． 左端に揃える．
;;;関数グループへのコメント. 関数外側で左端に揃える．
;;後続の行の目的等を記述． 該当部分の字下げに揃える．
;その行のコードの動作を説明． 右側同じコラム位置に揃える
```

- 文字列

```lisp
"hoge"		; ダブルクォーテーションで挟む．

"hoge
fuga hoge"	; 改行も含められる． "hoge<RET>fuga hoge" っていう文字列．

"hoge\    
fuga hoge"	; 改行をエスケープ． (改行は見栄えだけで文字列に含まない．) "hogefuga hoge"っていう文字列．
```


- 実行文，評価
    - (operation, 引数)の順番に記述するポーランド記法(前置記法)．

```lisp
(+ 1 2) 		; 1+2のこと．3となる．丸括弧で挟む．
(setq x 2) 		; xに2を代入． setqは変数に値を代入するfunction.
```

- シンボル：本来データとして評価されてしまうものを評価されないようにしたデータタイプ．
    - シングルクォーテーションを最初につけて表す．
    - シングルクォーテーションが，一つの引数を取り何もしないで返す特殊operator `quote`の省略形. (変数に値を代入する`setq`は set quoteの略．なのでsetqの第1引数はシングルクォーテーションはつかない．)


```lisp
> hoge 			; hogeに5が代入されてるとき． 5として評価される.
5
> 'hoge			; hogeというそのもので保持．
HOGE
> (quote hoge)	;同じ意味
HOGE

> (1 2 3)		; リストが評価されてしまいエラー． (評価されると第1要素はfunction扱いされてしまう．)
EVAL: 1 is not a function name; try using a symbol instead
> '(1 2 3)		; リストとしてそのまま保持
(1 2 3)
```



## 1.2 package 管理 (`package.el`)
環境設定ファイルに設定を記述していくが、種類によっては package のインストールが必要となる。
`package.el` はemacs24から標準装備になった package 管理ツールで、基本的にこれを使用してインストール等を行うこととなっている。

package は基本的に何かしらのレポジトリに登録されているので、package install 手順としては、

1. レポジトリの登録：使用したい package が登録されているレポジトリを環境設定ファイルに記述し、登録。
2. パッケージインストール：レポジトリが登録されている状態で、登録レポジトリの package をインストール。

となる。

#### レポジトリの登録
環境設定ファイルに以下を記述する。（レポジトリは例。使用したいレポジトリを登録する。）

```lisp
(require 'package)

;; MELPAを追加
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)

;; MELPA-stableを追加
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)

;; Marmaladeを追加
(add-to-list 'package-archives  '("marmalade" . "http://marmalade-repo.org/packages/") t)

;; Orgを追加
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)

;; 初期化
(package-initialize)
```

- `package-archives`変数にレポジトリ情報が格納されているのでこの変数に追加．
- MELPAのpackageの使用が多かったりする。

#### レポジトリの種類

- GNU ELPA: 公式のリポジトリ．**デフォルトではこのレポジトリのみ利用可能となっている．**
- Marmalade
- MELPA: このレポジトリに登録されている package が結構多い．
- MELPA-stable
- Org

#### package install

基本的に emacs 内で、以下のコマンドを用いてインストールや更新などを行う。

`M-x package-install`

- enter後にpackage nameを聞かれるので入力してenterしてインストール．

`M-x package-refresh-contents`

- パッケージ情報の更新．

`M-x package-list-packages`

- （登録されているリポジトリの）パッケージ一覧表示．インストール済みかの状態とかも表示．
- `C-s`の検索も合わせて使うと使いやすい．

#### link
- [package.el | Emacs JP](https://emacs-jp.github.io/packages/package-management/package-el)


## 1.3 基本的な環境設定

具体的に基本的な設定を、環境設定ファイルに記述していく。必要に応じて package のインストールを行う。

### 日本語設定
    

```lisp
;; language
(set-language-environment 'Japanese)
(set-language-environment 'utf-8)
(prefer-coding-system 'utf-8)
```
- 文字コードも変更されるため言語環境の設定後に文字コードの設定を記述する必要あり．
- 日本語設定がないと日本語のコピペとかで文字化けしたり．

### [C-h] backspace

```lisp
;; key bind
(global-set-key (kbd "C-h") 'delete-backward-char)
(global-set-key (kbd "C-c C-h") 'help-command)    ; help呼び出しは別キーに
```
- デフォルトはhelpの呼び出しに割り当てられている．




### ハイライト

```lisp
(global-hl-line-mode t)                   ; 現在行をハイライト
(custom-set-faces
'(hl-line ((t (:background "color-236"))))
)                                         ; 色のカスタマイズ
(show-paren-mode t)                       ; 対応する括弧をハイライト
(setq show-paren-style 'mixed)            ; 括弧のハイライトの設定 (parenthesis/expression/mixed)
(transient-mark-mode t)                   ; 選択範囲をハイライト
```

- 現在行のハイライトはデフォルトの色が見にくいので色は多分変えたほうがいい．
- link: http://keisanbutsuriya.hateblo.jp/entry/2015/02/01/162035

### 行番号表示


```lisp
;; line number
(global-linum-mode t)
(setq linum-format "%d ")    ;行番号後ろにスペース
```
- Macデフォルトの古いバージョンのemacsではエラーが起こる．(インストールの必要あり)
- 行番号の表示の後ろにスペース入れたほうが見やすい．
- 行番号邪魔なとき(コピーとか)，`M-x linum-mode`でOn/Offできる．

### 改行時インデント

```lisp
;; indent when entering
(electric-indent-mode t)
```

- デフォルトだと改行で左端にカーソルが行ってしまう．

### スクロール1行ずつ
```lisp
;; scroll
(setq scroll-step 1)
```

- デフォルトだと下に到達すると25行分まとまって上にスクロールしてしまう

### 括弧自動補完

```lisp
(require 'smartparens)
(smartparens-global-mode t)
(setq-default sp-highlight-pair-overlay nil)    ;ハイライト機能削除
```
- `smartparens`パッケージインストール
- 括弧補完時のハイライトが邪魔なので多分消したほうがいい．
- link: [smartparens - github](https://github.com/Fuco1/smartparens)


### オートコンプリート (company-mode package)

```lisp
;; オートコンプリートの有効化
(require 'company)
(global-company-mode) ; 全バッファで有効にする
(setq company-idle-delay 0) ; デフォルト0.5
(setq company-minimum-prefix-length 2) ; デフォルト4
(setq company-selection-wrap-around t) ; 候補の一番下でさらに下に行こうとすると一番上に戻る
(define-key company-active-map (kbd "M-n") nil)
(define-key company-active-map (kbd "M-p") nil)
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous)
(define-key company-active-map (kbd "C-h") nil)
```

- `company`パッケージインストール
- 補完の次候補を選ぶキーバインドが`M-n`なので変更したほうが使いやすい．
- link: [emacsの補完用パッケージcompany-mode -qiita](https://qiita.com/sune2/items/b73037f9e85962f5afb7)


### Markdown, Yaml, Dockerfile

デフォルトだとMarkdownやYaml, Dockerfileに対応してないので．

- MELPAから`markdown-mode` package, `yaml-mode` package, `dockerfile-mode`をインストールするのみ． (環境設定が必要という記事が散見されるが必要なし)

>`M-x package-install <RET> markdown-mode <RET>`. When installed this way, the major modes markdown-mode and gfm-mode will be autoloaded and markdown-mode will be used for file names ending in either .md or .markdown.
>

- 初期では対応してないファイル形式，大体調べたら `***-mode` で出てくる

- link: [Markdown Mode for Emacs](https://jblevins.org/projects/markdown-mode/)， [yaml-mode - MELPA](https://melpa.org/#/yaml-mode), [dockerfile-mode - MELPA](https://melpa.org/#/dockerfile-mode)


###  emacs theme `monokai`

```lisp
(load-theme 'monokai t)
```

- `monokai-theme`パッケージインストール．
- `monokai`いい．
- [Emacs Themes](https://emacsthemes.com/) にだいたいそろってる．しっくり来なかったがatom風のものとかも．
  

## 1.4 最終的に
1.3での設定を全部行った場合、最終的に。
まずpackageについては、以下の packageがインストールされている状態。

- `smartparens`
- `company`
- `markdown-mode`, `yaml-mode`, `dockerfile-mode`
- `monokai-theme`

環境設定ファイル`.emacs` 全体は以下のよう。

```lisp
;; language
(set-language-environment 'Japanese)
(set-language-environment 'utf-8)
(prefer-coding-system 'utf-8)

;; add package repository
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

;; color themes
(load-theme 'monokai t)

;; highlight
(global-hl-line-mode t)
(custom-set-faces
 '(hl-line ((t (:background "color-236")))))
(show-paren-mode t)
(setq show-paren-style 'mixed)
(transient-mark-mode t)

;; line number
(global-linum-mode t)
(setq linum-format "%d ")

;; indent when entering
(electric-indent-mode t)

;; scroll
(setq scroll-step 1)

;; auto bracket complete
(require 'smartparens)
(smartparens-global-mode t)
(setq-default sp-highlight-pair-overlay nil)

;; auto-complete
(require 'company)
(global-company-mode)
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 2)
(setq company-selection-wrap-around t)
(define-key company-active-map (kbd "M-n") nil)
(define-key company-active-map (kbd "M-p") nil)
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous)
(define-key company-active-map (kbd "C-h") nil)

;; key bind
(global-set-key (kbd "C-h") 'delete-backward-char)
(global-set-key (kbd "C-c C-h") 'help-command)
 ```
## 2. キーバインド

emacs、自分はキーバインドでよく困ることが多いので。。

## 2.1 よく使用するキーバインド一覧

- `C-p/n/f/b` : 移動
- `C-v`: 1ページ下に移動
- `C-a/e` : 文頭/文末移動
- `C-d/h` : delete/backspace(`C-h`は上記のカスタマイズ)
- `C-@` : マーキング
- `C-w` : 選択範囲カット
- `M-w` : 選択範囲コピー
- `C-y` : 貼り付け
- `C-s` : 検索
- `M-%` : 置換 (対話的に変更前後の単語を聞かれる)
    - `y` : ハイライトされたキーワードを置換し次へ
    - `n` : ハイライトされたキーワードを置換せず次へ
    - `!` : すべて置換
    - `q` : 終了
- `C-z` : emacsをbackgroundに退避させる． (`fg`コマンドで戻る．)
- `C-x, 0` : (画面分割後)現在画面削除
- `C-x, 1` : (画面分割後)現在画面以外削除
- `C-x, 2` : 画面縦分割
- `C-x, 3` : 画面横分割
- `C-x, o` : 画面分割移動
- `C-x, C-f` : ファイルを開く(新規名をつければ新規ファイル作成)
- `M-;` : 範囲選択してからやれば(1行 or)複数行コメントアウト．何も選択せずで行末コメント．

## 2.2 キーバインド設定方法

1.3 でも一部設定したが自分のしたいことでカスタマイズできるように．

```lisp
(global-set-key [key] '[function-name])
(global-set-key "\C-h" 'delete-backward-char)
```

#### function nameの見つけ方

`F1-c`, `M-x describe-key-briefly`

- 調べたいキーを入力するとfunction nameが返る．
    - (`F1-c`も `describe-key-briefly`というfunction nameに割り当てられている．)

`F1-k`, `M-x describe-key`

- 調べたいキーを入力すると(function nameを含む)functionの説明文が返る．

`F1-f`, `M-x describe-function`

- function nameを入力するとfunctionの説明文が返る．

emacsはデフォルトで1353のキーバインドが有るらしい．なんとなく調べたい場合は以下のリンク参照．

- emacsキーバインド一覧：[A Curious Look at Emacs's One Thousand Keybindings](http://ergoemacs.org/emacs/gnu_emacs_keybinding.html)
- ベーシックなもの一覧：[Emacs Keys Basics](http://ergoemacs.org/emacs/emacs_keys_basics.html)