自動インデントなど C, C++ 系モード以外でも使えるようになった Emacs 機能の設定

Emacs では C, C++ を始め、 Java 、 JavaScript 、 C# などのモードは cc-mode を元に作られています。 これらの言語はよく使われるせいか cc-mode には自動改行など便利な機能がたくさんあります。
そういった機能を使うのに慣れていると他の言語の編集中にめんどくさいなと思うことがよくあります。 そう思う人は多いようで、 Emacs のバージョンがあがって、他の言語モードでも使えるように格上げ(?) された機能があります。
今回はそんな C 系モード以外でも使えるようになった機能のいくつかを設定方法を含めて紹介したいと思います。

紹介する機能はモード行で "/lah" 表示されている 3 つとタブを押した時の挙動の設定です。
機能 機能名
がっつり削除 hungry-delete
自動インデント electric-indent, c-elecric-state
自動改行 electric-layout, c-auto-newline
タブキーの挙動の変更 tab-always-indent


なお、これらの機能は基本的に C 系モードではそちらの設定が使われます。 そのため、設定方法については一般、 C 系モードの両方について説明しています。

変数設定の注意点

各機能の設定方法の前に注意点をいくつか説明しておきます。

バッファーローカル変数

変数には Emacs 全体で同じ値を使う通常の変数とバッファー毎に違った値を保持できる バッファーローカル変数があります。
バッファーローカルな変数は setq などでそのまま設定しても意味がありません。 ホックを使って、バッファーを開いた時に設定する必要があります。

C 系モードすべて
 (defun my-all-cc-mode-init ()
   ;; C 系(cc-mode を継承した)モード共通の設定を記述
 
   (setq tab-width 8)
   )
 (add-hook 'c-mode-common-hook 'my-all-cc-mode-init)
C, C++ モード
(defun my-c-c++-mode-init ()
  ;; C, C++ 用の設定を記述  

  (setq tab-width 4)
  )
(add-hook 'c-mode-hook 'my-c-c++-mode-init)
(add-hook 'c++-mode-hook 'my-c-c++-mode-init)
バッファーローカル変数に対して、 Emacs で共通した値を設定することもできます。 正確にいうとバッファーローカル変数のデフォルト値を指定する感じです。
それには次のカスタマイズで設定するか、 setq ではなく setq-default などで設定します。
(setq-default tab-width 8)

カスタマイズ

Emacs では GUI 風に設定が可能なカスタマイズという機能があります。
これを使用する場合、 M-x customize-option の後に設定したい変数名を指定して起動します。 なお、前節でも触れたようにカスタマイズで設定した値はバッファーローカルにならないということも注意する必要があります。

トグル系の有効/無効の指定

変数で機能の ON/OFF を設定する場合、通常 t, nil を使います。
これがモードの有効/ 無効など関数で指定する場合、 1, 0 を使って設定します。 1 と t はどちらでもよいのですが、 nil を指定すると、 ON/OFF の切り替えになるため、 OFF にするには 0 を指定します。
 (c-toggle-hungry-state 1) ;; 有効
 (c-toggle-hungry-state 0) ;; 無効

がっつり削除 (hungry-delete)

まずは分かりやすい機能から説明します。
コーディングの場合、インデントや空行などを大量に使います。 がっつり削除(hungry-delete) の機能を使うと [Back Space][Delete](C-d) で スペース、タブ、改行の空白文字をまとめて一気に削除します。

emacs_hungry_delete.png


この機能に慣れてしまうと、他の言語での削除がかなりタルく感じます。実際、私は我慢できず自分で削除用の関数を作って使っていました。
今ではそんなことをしなくても、一行設定を書くだけでどのモードでも使えるようになっています。

この機能を有効にする場合、バッファーローカルな機能なので、各モードのホックで (hungrry-delete-mode 1) の記述を行います。
ただ、できて困るものでもないですし、全モードで有効にした方が簡単です。そういった場合、 init.el に以下の記述を行います。
(global-hungry-delete-mode 1)
ただし、 C 系モードの場合、そちらの設定が使われるため、別途設定する必要があります。 こちらは C 系共通のホックなどに以下の記述を行います。
(c-toggle-hungry-state 1)
C 系モードではこの hungry-delete 機能が有効になっているとモード行に "/h" が表示されます。

C 系モードでの自動インデント、自動改行

C 系モードでの自動インデント、自動改行の機能について説明します。 この 2 つは設定変更時に連動することが多く、セットで使うと覚えておいた方が簡単です。

自動インデント(c-electric-state)は、改行や { などのキーを入力した時に インデントも自動で行う機能です。
有効時には "/l" が付きます。

自動改行(c-auto-newline)は、 {; などのキーを入力した時に 自動で改行を行う機能です。
有効時には "/a" が付きます。

emacs_electric_state.png


有効にする場合は C 系共通のホックなどで以下を記述します。
(c-toggle-auto-newline 1)
これらの機能は非常に便利です。 ただ、有効に利用するにはスタイル、インデント量などをちゃんと設定しておく必要があります。

自動インデント (electric-indent-mode)

C 系モードの自動インデントの機能は 24.4 のバージョンで Emacs 全体で使えるようになり、 しかもデフォルトで有効になっています。 ただ、これがかなりタチが悪いです。

機能は C 系と同じような感じで改行や特定の文字(electric-indent-chars で指定)で自動でインデントします。
問題なのは C-j[Return](C-m) が入れ替えられるということです。 もともと C-j に "改行してインデント" という機能が割り当てられたいるのですが、これを入れ替えることによって 改行時のインデントが実現されています。

C-j での改行に慣れている人間にとっては、これがめちゃくちゃ邪魔で、「何勝手なことしてるんだ」って気がします。 ということで、この機能を無効にします。
無効にする場合には以下の記述を init.el に追加します。 この機能はバッファーローカルではないので、ホックで記述する必要もありません。
(electric-indent-mode 0)
ただ、今まで "リターンで改行して、タブでインデント" とやっていた人にとっては 便利だと思うので、そのままでもいいかもしれません。

自動改行 (electric-layout-mode)

Emacs 全体での自動改行の機能は electric-layout-mode です。 こちらは特定の文字を入力すると自動で改行を行います。

これを有効にする場合は以下の記述をします。こちらもバッファーローカルではありません。
(electric-layout-mode 1)
しかし、これは設定してもそのままでは特に何もかわりません。 というのも改行を挿入する文字は electric-layout-rules で設定するのですが、 ここに何も設定されていないからです。
こういうは言語のモード作成者側で設定するようなものだと思うので、 これからの機能ではないかと思います。



とはいえ、一応、設定方法も紹介しておきます。

electric-layout-rules は (対象文字 . 改行位置) のコンスセルのリストで設定します。 改行位置は befor(前)、 after(後)、 around(前後) などで指定します。

C 系の言語以外だとあまりこの機能が役立つものを思いつかないのですが、 唯一使っている CMake モードの設定を例としてあげます。
以下の記述で ")" の文字を入力すると改行するようになります。
 (add-hook 'cmake-mode-hook '(lambda ()
                              (setq-local electric-layout-rules '((?\) . after)))
                              ))
ここで注意点ですが、 electric-layout-rules はバッファーローカルではありません。
そのため、ホックに書いたからといって普通に setq で設定すると、全モードで ")" で改行するようになります。 それだと問題なので、 setq-local を使って、バッファーローカルにして値を設定しています。


この手の変数は明らかにバッファーローカルにしておくべきです。 しかし、"モード毎に設定が必要な変数" に対する Emacs の方針が、"バッファーローカルな変数を必要な場合に setq-defalut などで設定する" から "通常の変数としておいて setq-local で設定する" というように変わってきたのかもしれません。
ただ、自動インデントのことも考えると electric.el を書いた人が「単にどうかしている」という可能性も捨てきれません。

[Tab] キーの挙動の変更 (tab-always-indent)

Emacs では基本 [Tab] キーはインデントで、 本当にタブを挿入したい場合、 C-q [Tab]M-i を使います。
これだとタブ挿入したい場合にめんどくさいのですが、 tab-always-indent の設定を変えると、 挙動を変えることができます。

動作
t 常にインデント (デフォルト)
nil 左端(文字の前)ではインデント、それ以外はタブの挿入
t, nil 以外 コメント、文字列などではタブ、それ以外はインデント

nil を設定しておくのが一番使いやすいのではないかと思います。

emacs_tab_always_indent.png


こちらも C 系モード用の両方を設定する必要があります。
 (setq tab-always-indent nil)
 (setq c-tab-always-indent nil)
これらの変数はバッファーローカルではないため、そのまま設定ファイルに記述できます。

設定の記述

最後に今までの項目をまとめた設定を記述しておきます。
自動改行はスタイルなどをちゃんと設定していないと逆に邪魔なのでコメントアウトしていますが、 設定をして、有効に変えた方がよいです。
 ;; がっつり削除
 (global-hungry-delete-mode 1)

 ;; 改行時などの自動インデント(C-j と C-m の入れ替え)を禁止
 (electric-indent-mode 0)
 
 ;; 特定の文字を入力すると自動で改行
 ;; (electric-layout-mode 1)
 
 ;; 左端(文字の前)ではインデント、それ以外はタブの挿入
 (setq tab-always-indent nil)
 (setq c-tab-always-indent nil)
 
 
 
 ;; C 系(cc-mode を継承した)モード共通の設定を記述
 (defun my-all-cc-mode-init ()
 
   ;; がっつり削除
   (c-toggle-hungry-state 1)
 
   ;; ";", "}" などを入力したときに自動改行
   ;; 自動インデントも一緒に ON になる
   ;; (c-toggle-auto-newline 1)
 
   )
 (add-hook 'c-mode-common-hook 'my-all-cc-mode-init)
 
 
 ;;  C, C++ モードのみで有効にしたい場合はこちらに記述
 (defun my-c-c++-mode-init ()
   ;; C, C++ 用の設定を記述  
 
   )
 (add-hook 'c-mode-hook 'my-c-c++-mode-init)
 (add-hook 'c++-mode-hook 'my-c-c++-mode-init)
関連記事
スポンサーサイト
Prev.    Category    Next 

Facebook コメント


コメント

コメントの投稿

Font & Icon
非公開コメント

このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
43位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
3位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

05月 | 2017年06月 | 07月
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。