4. 標準 Emacs Lisp ライブラリ
ここでは、Meadow に標準で導入されているライブラリの中で、 私が良く利用しているものを紹介します。 ただし、Meadow に標準で含まれていても、 site-lisp ディレクトリに格納されているものは、 次章の 非標準 Emacs Lisp ライブラリにて紹介します。
4.1 CC mode
CC mode とは?
- 構文解析エンジンによる、超強力な自動インデント付け。
- コンパイラの呼び出し、および、コンパイルエラー個所へのジャンプ。
- 関数単位のコピー、ジャンプ等、構文に応じたプログラムの編集。
- 自動改行、連続する空白文字の一括削除。
- 強力なカスタマイズ機能。
また、対応する言語は次のとおりです。
- C
- C++
- Objective-C
- Java
- IDL
自動インデント付けや自動改行は、とても便利なのですが、デフォルトの設定 のままだと、自分の思うとおりにならずに、いらいらすることもあります。気 持ち良く CC mode を利用するには、自分のコーディングスタイルに合わせたカ スタマイズが必須になります。
設定
;; C/C++ 用のカスタマイズ
(defconst my-c-style
'(
;; 基本オフセット量の設定
(c-basic-offset . 4)
;; tab キーでインデントを実行
(c-tab-always-indent . t)
;; コメント行のオフセット量の設定
(c-comment-only-line-offset . 0)
;; カッコ前後の自動改行処理の設定
(c-hanging-braces-alist
. (
(class-open before after) ; クラス宣言の'{'の前後
(class-close after) ; クラス宣言の'}'の後
(defun-open before after) ; 関数宣言の'{'の前後
(defun-close after) ; 関数宣言の'}'の後
(inline-open after) ; クラス内のインライン
; 関数宣言の'{'の後
(inline-close after) ; クラス内のインライン
; 関数宣言の'}'の後
(brace-list-open after) ; 列挙型、配列宣言の'{'の後
(brace-list-close before after) ; 列挙型、配列宣言の'}'の前後
(block-open after) ; ステートメントの'{'の後
(block-close after) ; ステートメントの'}'前後
(substatement-open after) ; サブステートメント
; (if 文等)の'{'の後
(statement-case-open after) ; case 文の'{'の後
(extern-lang-open before after) ; 他言語へのリンケージ宣言の
; '{'の前後
(extern-lang-close before) ; 他言語へのリンケージ宣言の
; '}'の前
))
;; コロン前後の自動改行処理の設定
(c-hanging-colons-alist
. (
(case-label after) ; case ラベルの':'の後
(label after) ; ラベルの':'の後
(access-label after) ; アクセスラベル(public等)の':'の後
(member-init-intro) ; コンストラクタでのメンバー初期化
; リストの先頭の':'では改行しない
(inher-intro before) ; クラス宣言での継承リストの先頭の
; ':'では改行しない
))
;; 挿入された余計な空白文字のキャンセル条件の設定
;; 下記の*を削除する
(c-cleanup-list
. (
brace-else-brace ; else の直前
; "} * else {" -> "} else {"
brace-elseif-brace ; else if の直前
; "} * else if (.*) {"
; -> } "else if (.*) {"
empty-defun-braces ; 空のクラス・関数定義の'}' の直前
;;"{ * }" -> "{}"
defun-close-semi ; クラス・関数定義後の';' の直前
; "} * ;" -> "};"
list-close-comma ; 配列初期化時の'},'の直前
; "} * ," -> "},"
scope-operator ; スコープ演算子'::' の間
; ": * :" -> "::"
))
;; オフセット量の設定
;; 必要部分のみ抜粋(他の設定に付いては info 参照)
;; オフセット量は下記で指定
;; + c-basic-offsetの 1倍, ++ c-basic-offsetの 2倍
;; - c-basic-offsetの-1倍, -- c-basic-offsetの-2倍
(c-offsets-alist
. (
(arglist-intro . ++) ; 引数リストの開始行
(arglist-close . c-lineup-arglist) ; 引数リストの終了行
(substatement-open . 0) ; サブステートメントの開始行
(statement-cont . ++) ; ステートメントの継続行
(case-label . 0) ; case 文のラベル行
(label . 0) ; ラベル行
(block-open . 0) ; ブロックの開始行
(member-init-intro . ++) ; メンバオブジェクトの初期化リスト
))
;; インデント時に構文解析情報を表示する
(c-echo-syntactic-information-p . t)
)
"My C Programming Style")
;; hook 用の関数の定義
(defun my-c-mode-common-hook ()
;; my-c-stye を登録して有効にする
(c-add-style "PERSONAL" my-c-style t)
;; 次のスタイルがデフォルトで用意されているので選択してもよい
; (c-set-style "gnu")
; (c-set-style "cc-mode")
; (c-set-style "stroustrup")
; (c-set-style "ellemtel")
;; 既存のスタイルを変更する場合は次のようにする
; (c-set-offset 'member-init-intro '++)
;; タブ長の設定
(setq tab-width 4)
;; タブの代わりにスペースを使う
; (setq indent-tabs-mode nil)
;; 自動改行(auto-newline)を有効にする
(c-toggle-auto-state t)
;; 連続する空白の一括削除(hungry-delete)を有効にする
(c-toggle-hungry-state t)
;; セミコロンで自動改行しない
(setq c-hanging-semi&comma-criteria nil)
;; キーバインドの追加
;; ------------------
;; C-m 改行+インデント
;; C-c c コンパイルコマンドの起動
;; C-h 空白の一括削除
(define-key c-mode-base-map "\C-m" 'newline-and-indent)
(define-key c-mode-base-map "\C-cc" 'compile)
(define-key c-mode-base-map "\C-h" 'c-electric-backspace)
;; コンパイルコマンドの設定
; (setq compile-command "make -k" ) ; Cygwin の make
(setq compile-command "nmake /NOLOGO /S") ; VC++ の nmake
)
;; モードに入るときに呼び出す hook の設定
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
;; ヘッダファイルもc++モードで開く
(setq auto-mode-alist (append
'(("\\.h$" . c++-mode))
auto-mode-alist))
使い方
プログラム編集後にコンパイルする時には、M-x compile と入力します。この コマンドは、compile-command で指定する外部コマンド(通常は make)を起動し ます。当然 make コマンドでコンパイルできるようにMakefile を作成しておく 必要があります。なお、このコマンドは頻繁に使うので、私は、C-c c にバイ ンドしています。コンパイルでエラーが発生した場合には、C-x ` (next-error)でエラー個所にジャンプすることができます。このキーは私にとっ て入力し難いので、C-x C-j キーにもバインドしています。
C や C++ 以外にも、Java, Objective-C, CORBA IDL 用の編集モードも提供さ れています。拡張子と起動されるモードの関係は、変数 auto-mode-alist を見 てください。また、CC Mode の詳しい使い方は Info を参照してください。
4.2 Allout outline mode
Allout outline mode とは?
私が Allout outline mode を使う理由を以下に示します。
- 見出しのレベルを自在に変更できる。特定の見出しと、その子孫全体の レベルを1キー操作で、深くしたり浅くしたりできる。
- 見出しを、レベルに応じてインデント表示できるので、見やすい。
- 見出し番号を自動的に生成できる。
- その他 outline-mode が提供する機能を備える。
反面、次のような欠点があります。
- 見出し記号の表現に柔軟性がないため、TeX や HTML の見出し記号をそ のまま利用できません(と思う)。そのため、通常の outline-mode が必 要な場合もあります。
- 上記にかかわらず、グローバルな関数・変数名が衝突するため、従来の outline-mode と、共存できません。この問題を回避するため、関数・変 数名を変更したパッケージを用意しました。必要ならば、Nallout outline mode の項を参 考にしてください。
設定
ここで、青色文字の部分は、Font Lock mode 用の設定です。これを利用しな い場合は、省略してください。
;;;
;;; outline-mode の設定
;;;
;; outline-mode の代わりに allout outline-mode を使用
;; 詳細は allout.el を参照のこと
(require 'allout)
(outline-init t)
;; 拡張子が .out のファイルをロードするときに自動的に outline-mode にする
(setq auto-mode-alist
(append '(("\\.out$" . outline-mode))
auto-mode-alist))
(add-hook
'outline-mode-hook
(function
(lambda ()
;; font-lock 用の設定
;; 見出しのレベルによってハイライト色を変える
;; outline.el と allout.el を参考にした
(make-local-variable 'font-lock-defaults)
(defvar outline-font-lock-keywords
(list
;; 最上位以外のの見出しの設定
;; ちょっと自信がないけど、とりあえずは動いている
'(eval .
(list
;; 見出しの正規表現
(concat "^\\("
(regexp-quote outline-header-prefix)
"\\)\\([ \t]*["
outline-bullets-string
"]\\)[^ \t]*[ \t]*\\([^\n\r]*\\)")
;; 見出しの文字列(3番目にマッチしたもの)の face を、見
;; 出しの深さに応じて変更する
'(3 (let ((len (- (match-end 2)
(match-beginning 2))))
(setq len (mod len 3))
(or (cdr
(assq len
'((0 . font-lock-function-name-face)
(1 . font-lock-keyword-face)
(2 . font-lock-comment-face))))
font-lock-variable-name-face))
nil t)))
;; 最上位の見出しの設定
'(eval .
(list
;; 見出しの正規表現
(concat "^\\("
(regexp-quote outline-primary-bullet)
"\\)[ \t]*\\([^\n\r]*\\)")
;; 見出しの文字列(2番目にマッチしたもの)の face を設定
;; する
'(2 font-lock-function-name-face))))
"Additional expressions to highlight in allout outline mode.")
(setq font-lock-defaults '(outline-font-lock-keywords t))
;; font-lock-mode の明示な起動
(turn-on-font-lock)
;; キーバインドの追加
;; ------------------
;; C-c C-r 見出し全体を右方向へシフト(C-c > と同じ)
;; C-c c-l 見出し全体を左方向へシフト(C-c < と同じ)
(define-key outline-mode-map "\C-c\C-r" 'allout-shift-in)
(define-key outline-mode-map "\C-c\C-l" 'allout-shift-out)
;; メニューバーへの登録
(require 'easymenu)
(easy-menu-define
outline-menu outline-mode-map
"Outline Mode Commands"
'("Outline"
["Next visible heading" outline-next-visible-heading t]
["Previous visible heading" outline-previous-visible-heading t]
"---"
["Hide current subtree" outline-hide-current-subtree t]
["Show current subtree" outline-show-current-subtree t]
"---"
["Open sibtopic" outline-open-sibtopic t]
["Open subtopic" outline-open-subtopic t]
["supertopic" outline-open-supertopic t]
"---"
["Shift in" outline-shift-in t]
["Shift out" outline-shift-out t]
["Number siblings" outline-number-siblings t]
"---"
["Kill topic" outline-kill-topic t]
["Yank" outline-yank t]
))
)))
使い方
以下に、簡単な使用例を示します。allout mode にした後で、C-c <SPC> (outline-open-sibtopic)と入力すると、見出しが作成されます。 C-c <SPC> で現在の見出しと同レベルの見出しを、新規作成します。見出 しが存在しない場合は、トップレベルの見出し"*"を作成します。
*
* 見出し1
本文1
* 見出し1
本文1
.*
* 見出し1
本文1
.* 見出し2
本文2
. + 見出し3
本文3
. - 見出し4
本文4
* 見出し1
本文1
.* 見出し2
本文2
. + 見出し3
本文3
. - 見出し4
本文4
. +
* 見出し1
本文1
.* 見出し2
本文2
. + 見出し3
本文3
. - 見出し4
本文4
. + 見出し5
本文5
* 見出し1
本文1
.* 見出し2...
* 見出し1
本文1
.* 見出し2
本文2
. + 見出し3
本文3
. - 見出し4
本文4
. + 見出し5
本文5
* 見出し1
本文1
.* 見出し2
本文2
.* 見出し3
本文3
. + 見出し4
本文4
. + 見出し5
本文5
このほかの詳しいキー操作は、allout mode の クイックリファレンスを参考にして下さい。
問題点
[原因] allout.el で、既存の関数 isearh-done 置き換える 所に不具合があるようです。置きかえる関数と、置きかえられる関数の引数が 一致していません。
[対策] 不具合を修正するパッチ を作成しました。このパッチを allout.el にあて、バイトコンパイルしてください。パッチの あて方は、パッチの項を参照してください。
4.3 Font Lock mode
Font Lock mode とは?
同じような機能を持つものに、hilit19 があります。デフォルトで私の嫌いな イタリック体を使っていたので、ほとんど使ったことがありません。 hilit19.el には、Emacs19 用であり、もはやメンテナンスされていないとも記 述してあります。Emacs20 (もちろん、Meadow も)で、hilit19 を使っている方 は、Font Lock mode を使うべきでしょう。
設定
(1) ~/.emacs の設定
;;;
;;; font-lock-mode の設定
;;;
;; font-lock-mode を常時利用する
(global-font-lock-mode t)
;; 表示の高速化のために fast-lock-mode を利用する
(setq font-lock-support-mode 'fast-lock-mode)
;; キャッシュファイルの格納先を指定する
(let* ((file-dir "~/.emacs-flc"))
(if (file-exists-p file-dir) ; ~/.emacs-flc の存在をチェック
;; 存在するならば、キャッシュファイルの格納先に指定
(setq fast-lock-cache-directories (list file-dir))))
(2) fast-lock.el の修正
[修正前]
(if (eq system-type 'emx)
[修正後]
(if (or (eq system-type 'emx)
(eq system-type 'windows-nt))
4.4 Abbrevs(略称)
Abbrevs とは?
例えば、下記に示す C++ のソースを、あなたならどのように入力しますか? aVariableOfVeryLongName を馬鹿正直に2回とも入力する人は、あまりいないと 思います。では、kill & yank を使いますか?実は、Abbrevs を使えばもっと 簡単に入力できるのです。
if (!aVariableOfVeryLongName) {
aVariableOfVeryLongName = true;
}
動的 Abbrevs は、編集中のバッファから展開する単語を選ぶものです。上記の ソース例では、
if (!aVariableOfVeryLongName) {
a
}
if (!aVariableOfVeryLongName) {
aVariableOfVeryLongName
}
これに対して、通常の Abbrevs は、事前に定義しておいた略称を基にして、正 式名へと展開するものです。上記のソースの例だと、aVariableOfVeryLongName の略称をvvln と定義しておけば、
if (!vvln
if (!aVariableOfVeryLongName
設定
(let ((file "~/.abbrev_defs"))
(if (file-exists-p file)
(quietly-read-abbrev-file file))) ; 定義ファイルの読込み
使い方
- 動的 Abbrevs
- M-/ (dabbrev-expand): 直前の略称を展開する。
- C-M-/ (dabbrev-completion): 直前の略称を補完形式で展開する。
- 通常の Abbrevs
- C-x a e (expand-abbrev): 直前の略称を展開する。
- C-x a g (add-global-abbrev): すべてのモードで有効な略称の定義。
- C-x a l (add-mode-abbrev): 現在のモードでのみ有効な略称の定義。
- M-x list-abbrevs: 定義済みの略称を表示する。
- M-x edit-abbrevs: 定義済みの略称を編集する。
4.5 jka-compr
jka-compr とは?
- compress 形式(拡張子は .Z)
- gzip 形式(拡張子は .gz)
- zip2 形式(拡張子は .bz2)
jka-compr を使うことのメリットは、ファイルのサイズを小さくできることで す。デメリットは、ファイルの入出力が遅くなることです。これは、入出力の たびにツールを呼び出して圧縮・展開するためです。頻繁に参照するファイル には使い難いかもしれませんが、めったに参照しないファイルには適用できる と思います。私は、nnml メールバックエンドを使って保存してある古いメール は、みんな圧縮してあります。
準備
設定
(require 'jka-compr)