プログラマーのためのMule (backup版)

このページは、本来はプログラマー天国にあったものですが、ページが消失し てしまったので、googleのキャッシュから拾っておきました。著作権的に問題 があることは承知していますので、苦情があれば管理人にご一報ください。

はじめに
表記法
変数 load-path の設定
略語展開機能を使おう(基本編)!
略語の登録
略語の展開
登録内容の保存
まとめ
略語展開機能を使おう!(応用編)
キー割り当ての変更
複数行の登録
C-modeでの登録例
Java-modeでの登録例
動的略語展開機能を使おう!
cc-mode を使おう!
cc-modeを使うための設定
cc-modeでのインデント
cc-modeの簡単な使い方
cc-modeのカスタマイズ例
キー割り当てを変更しよう!
キー割り当ての基本
デフォルトで空いているキー
2ストロークキーによる拡張
ホームポジションを離れないために
キー割り当ての方針
ソースコードに色をつけよう!
フォントを変えよう! (for Win32)
フォントを変更する
もっと簡単にフォントを変更する
もっともっと簡単にフォントを変更する
インフォでの斜体をやめる
テンプレートを使おう!
insert-templateの使い方
キーワードの展開
Hookによる拡張
headerline.elを使おう!
headerline.elのインストール
headerline.elの使い方:Java編
headerline.elの使い方:テキスト編
次/前の見出しに移動する
カスタマイズ:見出しのパターン
カスタマイズ:画面分割の方向と幅
類似機能との比較
コンパイルを楽にしよう!
コンパイルコマンドを変更する
コンパイルウィンドウを小さくする
そのほか
Rectangle機能を使おう!
一行入力を簡素化しよう!
その他、便利な機能
余分な空白を削除する
大文字を簡単に入力する
プログラムを整形する
中身を確認して貼り付ける
罫線を入力する
バッファ移動を便利にする
改行文字を置換する
日付を入力する
Muleに関するリンク集

はじめに

ここんとこ、Muleをやめて別のエディタを使っています。Muleによく似ている 上により便利になっています。

ホントいうと、UNIXにおいていつまでもMuleやViが主流ではアカンと思ってま す。それらを打ち負かすような特長をもった、それでいて初心者にも敷居が低 いエディタがどんどんでてこないと、UNIXはいつまでたってもマニアの道具で しかないです。

といっても、プログラマにとってMule(Emacs)が最強のエディタであることは 変わらないでしょう。ここではMuleの使い方がよくわからんという人に、実は Muleってこんなにすごいんだよということを紹介しています。内容は中級者向 けです。

表記法

C-x とは、Controlキーを押しながらキー x を押すことです。 CM-x とは、 Altキーを押しながらキー x を押す、あるいは Escキーを 押した後に キー x を押すことです。

例: C-q C-r C-k

Controlキーを押しながら q を押し、 次にControlキーを押しながら r を押し、 最後にControlキーを押しながら k を押します。

例: C-x a i l

Controlキーを押しながら x を押し、 次にControlキーを 離して a、i、l と押します。

例: M-C-s

ControlキーとAltキーを押しながら s を押す、 あるいは ESCキーを 押した後 にControlキーを押しながら s を押します。

変数 load-path の設定

あとで紹介する cc-mode.el や browse-yank.el を使うために、自分のホーム ディレクトリの下に lib/emacs というディレクトリを作ってください。

そして自分の .emacs に

  ;;; load-path の設定
  (setq load-path
        (append
         (list
          (expand-file-name "~/lib/emacs")  
          ) ; list end
         load-path))
と書いておいてください。

そして cc-mode.el や browse-yank.el を、この emacs というディレクトリ に入れておくと、これらのファイルが使えるようになります。

説明の中で、「xxxxxx.el をパスが通るところに入れてください」という表現 があったら、xxxxxx.el をこのフォルダに入れるようにしてください。

略語展開機能を使おう(基本編)!

Muleには、略語展開機能という非常に便利な機能があります。どういうものか というと、例えば "p" と入力して、あるキーを押すと、 "printf" と展 開してくれるというものです。これを使えば、例えば "al" という入力を "actionListener" に展開する、 "sop" という入力を "System.out.println(" に展開する、ということができます。

略語展開機能を用いることで、入力が軽減されるだけでなく、打ち間違いも少 なくなります。また、「えーと、Javaではmain関数の書き方はどうだったっ け?」と忘れてしまっても、略語として登録しておけば、簡単に "public static void main(String args[]) {" と展開できます。

どの単語(略語)をどういう文字列に展開するかは、ユーザが自由に登録でき ます。また、登録はメジャーモード毎に行いますので、例えば "main" という 単語を、C-mode では "int main(int argc, char *argv[])" に展開し、 Java-mode では "public static void main(String args[]) {" に展開すると いうことができます。

略語の登録

それでは実際に登録してみましょう。ここでは C-mode において、 "w""while (" と展開されるように登録します。

まずはMuleを起動し、適当なプログラム(xxx.c)を書いてみてください。す ると C-mode になりますね。ここで "w" と押してください。この状態では カーソルが "w" の右隣にあります。そして C-x a i l(Ctrlキーを押しな がら x を押し、そのあとCtrlキーを離して a、i、l) と打ちます。するとミ ニバッファに

        Mode expansion for "w":
と聞かれますので、ここで "while (" と入力します。
        Mode expansion for "w": while (
そしてリターンキーを押してみてください。先ほどの "w""while (" に展開されたと思います。これで "w""while (" に展開されるように 登録できました。

略語の展開

さて、今度は登録した単語(略語)を展開してみましょう。略語を展開するの は、C-x ' です。

まず、もう一度 "w" と入力してみてください。そして C-x ' (Ctrlキーを 押しながら x を押し、そのあとCtrlキーを離して ' (シングルクォート)) と入力します。すると "w""while (" に展開されたと思います。

また、お分かりとは思いますが、C-x ' で展開されるのは、あるいは C-x a i l で登録されるのは、カーソルの右にある単語です。よって、いくら "w" を略語として登録したといっても、 "now" と入力してC-x ' と打っても "nowhile (" とは展開されません。

また、略語(単語)とカーソルとの間に空白や記号が入っていてもきちんと展 開されますが、数字はだめです(数字は単語として認識されます)。他にも、 略語が大文字だったりキャピタライズ(先頭の文字だけ大文字になっているこ と)されていたりした場合の動作など、自分でいろいろ試してみてください。

登録内容の保存

最後に、この登録した略語を保存しましょう。どうやらMuleは、デフォルトで は登録した略語を保存してくれないようです(これについては後で説明しま す)。そこで、次回もこの略語展開を使いたいと思ったら、自分で明示的に保 存する必要があります。それには、M-x write-abbrev-file(ESCキーを押した 後に x を押し、write-abbrev-file と(ミニバッファに)入力してリターン) を実行します。するとミニバッファに

        Write abbrev file: ~/
と聞かれますので、登録した略語を書き出すファイル名を入力します。今回は ".abbrev_defs" と入力します(別にどんな名前でもいいのですが、ふつう はこの名前にするようです)。
        Write abbrev file: ~/.abbrev_defs
入力したらリターンキーを押してください。これで登録した略語がホームディ レクトリの下の ".abbrev_defs" というファイルに保存されました。次回の Mule起動時にもこの設定を読み込むようにするには、ホームディレクトリの下 の .emacs に
;;; abbrev(略語展開)のための設定
;;; デフォルトでは "~/.abbrev_defs" を読み込む
(read-abbrev-file)
と書いておきましょう。略語を保存するファイルの名前を他の名前にした人は、
(read-abbrev-file "some/where/file")
としてください(当然ながら、 "some/where/file" は適切に書き換えてく ださい)。

さて、Mule はデフォルトでは登録した略語を保存してくれないと先ほど書き ました。しかし、上の設定を行ってMuleの起動時に登録内容を読み込むように 設定すると、今度は自動的に略語を保存してくれるようになります(略語登録 の保存といっても、実際は "~/.abbrev_defs" ファイルを保存することで す)。Mule の終了時や C-x s を押したときに、ミニバッファに

        Save abbrevs in ~/.abbrev_defs? (y or n)
と聞かれますので、 y と打てば登録した内容が保存されます。

もう少し詳しく言うと、変数 save-abbrevs の値が nil だと保存してくれま せんが、それ以外だと保存してくれます。そして、デフォルトでは変数 save-abbrevs は nil ですが、read-abbrev-file すると nil 以外の値にな るということです。

まとめ

まとめると、

  1. 略語を入力
  2. C-x a i l
  3. ミニバッファに展開する語を登録
  1. 略語を入力
  2. C-x '
  1. M-x write-abbrev-file を実行
  2. ファイル名 ~/.abbrev_defs で保存
  3. ~/.emacs に (read-abbrev-file) と記述

となります。

略語展開機能を使おう!(応用編)

さて、略語展開機能については基本的なことを述べました。応用編として、略 語展開機能をさらに便利につかうためのカスタマイズを説明します。また、私 が C-mode と Java-mode でどのように略語展開機能を利用しているかを紹介 します。

キー割り当ての変更

略語展開は非常に便利なものですが、ひとつだけ欠点があります。それは、略 語を展開するためのキー C-x ' が とっても打ちにくい!! ことです。そこ でこれをもっと打ちやすいキーに割り当てましょう。

私の場合、C-l に割り当てています(元々このキーには recenter という機能 (関数)が割り当てられていますが、私はこれを C-q C-l に割り当てていま す)。この変更により略語展開機能が非常に使いやすくなり、とても幸せです。

プログラムを書いているときには、略語展開を使いまくるので、本当に自分が 打ちやすいと思うキーに割り当てるのがいいです。

C-mode においてキーの割り当てを変更するには、.emacs に

(define-key c-mode-map "<it>キー</it>" '<it>関数名</it>)
と書いておきます。例えば、私のように C-l に略語展開機能(関数名は expand-abbrev)を割り当てようと思ったら、.emacs に
(define-key c-mode-map "\C-l" 'expand-abbrev)
と書いておきます。

C-modeだけでなく、全てのモードでキーバインドを変更したいなら、

(define-key global-map "\C-l" 'expand-abbrev)
とします(私はこうしています)。

C-l のような、既にキー割り当てがあるものは変更したくないなー、というこ とでしたら、M-n や M-p などが空いてますので、これらに割り当てるといい でしょう。例えば C-mode で M-n に略語展開機能を割り当てようと思ったら、. emacs に

(define-key c-mode-map "\M-n" 'expand-abbrev)
と書いておきます。

キー割り当てについての詳しいことは、「キー割り当てを変更しよう!」を 参照してください。

複数行の登録

略語展開では、ひとつの略語を複数行に展開することができます。例えば、 "main"という単語(略語)を C-x ' で

#include <stdio.h>

int main(int argc, char *argv[])
{
と展開させたり、"comment"という単語(略語)を
/**********************************************************
 *
 ***********************************************************/
と展開させたりすることができます。

複数行を登録するには改行を入れなければいけませんが、登録する際にミニバッ ファで C-q C-j と打つと改行を入力できます(リターンキーを押しても改行 を登録することはできません)。

また、あらかじめ C-w や M-w で複数行をコピーしておき、ミニバッファで展 開する語を入力する場面で C-y として入力してもよいです。

さらに、直接 ~/.abbrev_defs をいじって登録することもできます(もちろん、 注意していじってください)。

私はこれを使って関数のコメントを略語として登録しており、"sfunc" を展開 することでstaticな関数のコメントを、"gfunc" を展開することでglobalな関 数のコメントを入力しています。みなさんもそれぞれ便利な使い方を考えてみ てください。

C-modeでの登録例

以下に、わたくしが C-mode で登録している内容を示します。

登録する際の方針としては、頻出度の高いものを中心に登録しています。だい たい1文字で登録しています。

個人的には、"q" で "exit(0);"と展開されるのが気に入っています("q" は "quit" のつもりです)。

また、"ture" と打ち間違えることの多い "true" を登録しています。これで、 「あ、打ち間違えた!」と思っても、キー操作一発で修正できてしまうので便 利です。略語展開機能には、入力ミスを防ぐだけでなく修正するチカラまであ るんです。

《C-modeの略語》

w	while ( 
while	while ( 
i	if ( 
if	if ( 
f	for (i = 0; i < 
for	for (i = 0; i < 
s	switch ( 
sw	switch ( 
sz	sizeof( 
st	struct 
d	default 
b	break; 
r	return 
n	NULL 
e	extern 
p	printf(" 
fp	fprintf(stderr," 
q	exit(0); 
ture	true 
in	#include 
def	#definle 
ifdef	#ifdef 
elif	#elif 
else	#else 
end	#end /* */ 
dont	/* do nothing */; 
sfunc	/*----------------------------------------
	.^----------------------------------------*/ 
gfunc	/*========================================
	.^========================================*/ 
main	#include <stdio.h> 
	.^int main(int argc,char *argv[])
	{ 
hasami	/* ----- 8< ------ 8< ------ 8< ------ 8< ------ */ 

Java-modeでの登録例

次は Java-mode での略語登録です。

Javaはキーワード(予約語)が多いうえに、クラス名やメソッド名が頻出する ので、登録することも多くなってしまいました。 Cならprintfですんだものが、 JavaではSystem.out.printlnですから、略語として登録すべきでしょう。

synchronized なんて略語登録でもしておかないと、打ちにくいわ綴りは分か らんわでストレスのもとになり、血圧も上がります。しかし、略語登録すれば ストレスはなくなり血圧も70以下まで下がるといわれています。健康のために も、ぜひ略語登録をしたいものです。

変わった使い方としては、exceptionの名前をいくつか登録しています。こう すると、"exception" と入力して C-x ' を何回か押していくと、目的の exceptionになります。こんな使い方もできるとは、恐るべし略語展開機能。

《Java-modeの略語》

w			while ( 
while			while ( 
i			if ( 
if			if ( 
f			for (int i = 0; i < 
for			for (int i = 0; i < 
s			switch ( 
sw			switch ( 
sz			sizeof( 
d			default 
b			break; 
r			return 
n			null 
ture			true 
pub			public 
st			static 
pro			protected 
sync			synchronized 
syc			synchronized 
v			void 
in			import 
int			interface 
ins			instanceof 
pri			private 
pub			public 
c			catch 
cat			catch 
catch			catch (Exception e) { 
l			length 
bool			boolean 
bl			boolean 
imp			implements 
pv			public void 
ex			extends 
sop			System.out.println(" 
sep			System.err.println(" 
q			System.exit(0); 
exit			System.exit(0); 
sg			String 
g			Graphics 
im			Image 
main			public static void main(String[] args) { 
jap			java.applet 
ja			java.awt.*; 
jawt			java.awt.*; 
ju			java.util.*; 
exception			MalFormedURLException 
malformedurlexception	NumberFormatException 
numberformatexception	InterruptedException 
ap			public void actionPerformed(ActionEvent ev) {
			    String command = ev.getActionCommand();
			} 
aal			addActionListener 
actionp			public void actionPerformed(ActionEvent ev) { 
			    String command = ev.getActionCommand(); 
			} 
addactionlistener		addActionListener(new ActionListener() { 
			    public void actionPerformed(ActionEvent ev) {
			        ev.getSource(); 
			    } 
			} 

動的略語展開機能を使おう!

先ほどの略語展開機能は、あらかじめ登録しておいたものだけしか展開できま せんでした。いまから紹介する動的略語展開機能(dynamic abbrev、略して dabbrev)は、あらかじめ登録していなくても展開してくれるというスグレモ ノです。

例えば、次のようなプログラムを入力していたとします。

String errorMessage = "segmentation fault!";
System.out.println(e
さて、最後の e ですが、これは errorMessage と入力するつもりです。カー ソルはこの e のすぐ後ろにあるとします。

ここで M-/ (関数dabbrev-expand)を押してください。すると、e が errorMessage となって、次のようになります。

String errorMessage = "segmentation fault!";
System.out.println(errorMessage
これは、M-/ を押すと「カーソルのすぐ右にある単語を取り出し、その単語と 先頭の文字列が一致する単語を探してきて置き換えてくれる」からです。探す のはカーソルより上の行からですが、なければ下の行から探してくれます。

もうひとつ例をだします。先の例と似ていますが、少し違います。

String systemErrorMessage = "segmentation fault!";
System.out.println(s
最後の s は、systemErrorMessage と入力するつもりです。カーソルは、最後 の s のすぐ後ろにあるとします。

ここで M-/ を押すと、s は system に展開されます。

String systemErrorMessage = "segmentation fault!";
System.out.println(system
もう一度 M-/ を押すと、s は segmentation に展開されます。
String systemErrorMessage = "segmentation fault!";
System.out.println(segmentation
もう一度 M-/ を押すと、s は systemErrorMessage に展開されます。
String systemErrorMessage = "segmentation fault!";
System.out.println(systemErrorMessage
もう一度 M-/ を押すと、s は string に展開されます。
String systemErrorMessage = "segmentation fault!";
System.out.println(string

このように、連続して M-/ を押すことで、次々と単語が展開されます。

これが動的略語展開機能です。先の略語展開機能と違い、まさに動的です。こ れも非常に便利な機能ですので、ぜひ使いこなしましょう。 Muleを使ってい るのに略語展開機能と動的略語展開機能を使わないのは非常にもったいないで すよ。

ちなみに、私にとって M-/ は押しにくいので、C-o にこの機能を割り当てて います。あまりによく使う機能のうえ、連続して押すことも多いので、押しや すいキーに割り当てました。

;;; C-o に動的略語展開機能を割り当てる
(define-key global-map "\C-o" 'dabbrev-expand)    

cc-mode を使おう!

cc-modeとは、従来のc-modeに替わるものであり、従来はバラバラに存在して いた c-mode, c++-mode, Objective-c-mode, Java-mode をまとめてサポート したものです。ここでは cc-mode について、簡単ではありますが説明します。 私の .emacs のうち、cc-modeに関する部分も載せておきましたので、参考に して下さい。

cc-modeを使うための設定

Emacs 19.?? からは、従来のc-modeに替わり、cc-mode が標準で使われるよう になりました。ただし、バージョンが古いので、新しいのを入れたほうがいい です。最新のバージョンは1996/7/15現在で 5.21 ですが、これは Mule for Win32 では動かないかもしれないので、ここでは Version 4.379 を使います。

cc-mode Version4.379はここからダウンロードできます。

ダウンロードしてきたら解凍し、cc-mode.elを取り出します。そしてこれを自 分のパスが通るところにコピーしてください(わからない方はこちらを参照し てください)。

次に、自分の .emacs を設定します。以下を付け加えてください。

;;;
;;; cc-mode.el の使用
;;;
(fmakunbound 'c-mode)
(makunbound 'c-mode-map)
(fmakunbound 'c++-mode)
(makunbound 'c++-mode-map)
(makunbound  'c-style-alist)
(autoload 'c-mode    "cc-mode" "C Editing Mode" t)
(autoload 'c++-mode  "cc-mode" "C++ Editing Mode" t)
(autoload 'objc-mode "cc-mode" "Objective-C Editing Mode" t)
(autoload 'java-mode "cc-mode" "Java Editing Mode" t)
(setq auto-mode-alist
      (append
       '(
         ("\\.c$"    . c-mode)
         ("\\.h$"    . c-mode)
         ("\\.java$" . java-mode)
         ("\\.m$"    . objc-mode)
         ("\\.c\\+\\+$" . c++-mode)
         ("\\.cpp$"  . c++-mode)
         ("\\.cc$"   . c++-mode)
         ("\\.hh$"   . c++-mode)
         )
       auto-mode-alist))
これでcc-modeが使えるようになりました。

試しに、何らかの C や Java のファイルを開いてみてください。そして、 M-x c-version を実行して見てください。ミニバッファに "Using CC Mode version 4.379" と表示されればOKです。なお、cc-modeを使っていてもミニバッ ファに "cc-mode" と出るわけではなく、"C" や "Java" と表示されますので 間違わないように。

cc-modeでのインデント

Cc-modeにおけるソースコードのインデントについてです。

インデントは各自それぞれのスタイルがあるかと思いますが、cc-modeにはあ らかじめ幾つかのスタイルが用意されています(これをビルトインモードとい います)。列挙すると、次のとおりです。

gnu
GNUが推奨するスタイル
k&r
「プログラミング言語C(通称K&R)」のスタイル
bsd
BSD Unix のスタイル
stroustrup
「プログラミング言語C++」のスタイル
whitesmith
B.J.プローガー氏のスタイル
ellemtel
C++ではポピュラーなスタイル(らしい)
java
Javaを書くのに適したスタイル。java-modeになると自動的に選択さ れる
CC-MODE
cc-modeで用意しているスタイル。大文字であることに注意

デフォルトでは、gnuスタイルが選択されています。これを他のスタイルにす るには、M-x c-set-style [Return] スタイル名 [Return] とするか、あるい は自分の .emacs に以下のように書き加えてください。

(add-hook 'c-mode-common-hook
          '(lambda ()
             (c-set-style "--スタイル名--")))

私がお勧めするスタイルは CC-MODE です。インデント量も4ですし、これが いちばん癖がなくていいでしょう。ちなみに、k&rスタイルはインデント量が 5です。前述したスタイルをいろいろ試してみて、気に入ったものを見つけて ください。

当然ですが、自分で新しいスタイルを作ったり、既存のスタイルをカスタマイ ズすることもできます。残念ながらここでは説明を割愛しますので、インフォ を参照してください。また、私のカスタマイズ例を最後に載せておきますので、 参考にしてください。

スタイルを変更すると、新しく書くコードは新しいスタイルに従ってインデン トされますが、既存のコードは(何もしなければ)自動的にインデントされる わけではありません。既存のコードを新しいスタイルに従って整形するには、

C-x h
バッファ全体にリージョンを設定する
M-C-\
リージョンをインデントする

を使うと便利です。また、関数indent-and-next-lineも便利ですので使ってみ てください。

cc-modeの簡単な使い方

cc-modeの使い方を簡単に説明します。

C-c C-d
BackSpaceを押したときに、カーソルの左側にある空白を全て消す /ひとつずつ消すを入れ替える
C-c C-a
"{" や ")" で自動的に改行をする/しないを入れ替える
C-c C-c
リージョンをコメントアウトする。引数として -1 を与えると、 コメントを外す
C-c C-q
関数をインデントする
C-c RET
関数にリージョンを設定する
C-c C-n
プリプロセッサの #if に対応する #endif に移動する
C-c C-p
プリプロセッサの #endif に対応する #if に移動する
C-c C-u
#if と #endif のあいだにカーソルがあるとき、#if に移動する
C-c C-e
プリプロセッサを使ってマクロを展開したものを表示する
C-c C-\
リージョンの行末に "\" をつける。複数行のマクロを書くときな どに便利

cc-modeのカスタマイズ例

参考までに、自分の .emacs のうち、cc-modeに関する部分を載せておきます。 新しく自分用のスタイルを定義していますが、新しいスタイルを定義するとき はCC-MODEスタイルとの差分を記述すればいいそうです。私の場合、caseラベ ル部分とコメント部分のインデントを除き、ほぼCC-MODEスタイルで済みまし た。

(defconst my-style
  '(
    ;; インデント幅を空白4コ分にする
    ;(c-basic-offset . 4)
    ;; コメントだけの行のインデント幅
    ;(c-comment-only-line-offset . 4)
    ;; インデント量の設定
    (c-offsets-alist . (
                        (comment-intro . 0)
                        (case-label . *)           ; or 2
                        (statement-case-intro . *) ; or 2
                        ;(access-label . 0)
                        ))
    ;; '{' や '}' での改行の制御
    ;(c-hanging-braces-alist . (
    ;                           ;; デフォルトは以下の4つ
    ;                           (brace-list-open)
    ;                           (substatement-open after)
    ;                           (block-close . c-snug-do-while)
    ;                           (extern-lang-open after)
    ;                           ;; 以下を追加
    ;                           (brace-list-close)
    ;                           ;(class-open after)
    ;                           (class-close before)
    ;                           (inline-open after)
    ;                           (arglist-cont-noempty after)
    ;                           (statement-cont after)
    ;                           ))
    ;; '}' で改行したのをもどす
    ;(c-cleanup-list . (
    ;                 ;brace-else-brace
    ;                 empty-defun-braces
    ;                 ;defun-close-semi
    ;                 list-close-comma
    ;                 scope-operator
    ;                 ))
    )
  "My Style")


;;;
;;;  cc-mode共通の設定
;;;
(add-hook 'c-mode-common-hook
        '(lambda ()
           ;; 自分用のスタイルを使う
           (c-add-style "my-style" my-style t)
           (c-set-style "my-style")

           ;; いつでも TAB でインデント
           (setq c-tab-always-indent t)

           ;; hungry-state にしない
           (c-toggle-hungry-state -1)

           ;;
           ;; 新規作成時だけ auto-indent にする
           (if (not (file-exists-p buffer-file-name))
               (c-toggle-auto-state 1))

           ;; C-c C-c でコンパイル, C-c c でコメントアウト
           (define-key c-mode-map "\C-c\C-c" 'compile)
           (define-key c-mode-map "\C-cc" 'comment-region)

           ;; コンパイルウインドウの大きさを制限する
           (setq compilation-window-height 8)

           ;; 日本語コードをEUCにする
           (if (not (eq system-type 'windows-nt))
               (set-default-file-coding-system *euc-japan

           ;; かんなで "、" を入力できるようにする
           (if (and (boundp 'CANNA) CANNA)
               (local-set-key "," 'canna-self-insert-command))

           ;; RET と C-j を入れ替える
           ;(local-set-key "\C-j" 'newline)
           ;(local-set-key "\C-m" 'newline-and-indent)

           )) ;; end c-mode-common-hook

キー割り当てを変更しよう!

キー割り当てこそカスタマイズの基本です。

エディタは、自分が使いやすいようにキー割り当てを変更してこそ、自分の道 具となります。

あなたもバリバリにキー割り当てをカスタマイズして、Muleなしでは生きてい けない体になってください。

キー割り当ての基本

キー割り当てを変更する方法を説明します。

あるキーに対して機能(関数)を割り当てるには、define-key または global-set-key という関数を使います。例えば C-h に delete-backward-char という関数を割り当てるには、以下のようにします。

(define-key global-map "\C-h" 'delete-backward-char)
; あるいは (global-set-key "\C-h" 'delete-backward-char)

あるモードだけキー割り当てを変更したいときには、 define-key の例に出て きた global-map の代わりに、モードごとのキーマップを指定します。例えば、 C-mode でだけ M-p に compile という関数を割り当てるには、次のようにし ます。

(define-key c-mode-map "\M-p" 'compile)

機能(関数)を2ストロークキーに割り当てることもできます。例えば C-x C-y に browse-yankを割り当てるなら、次のようにします。

(define-key global-map "\C-x\C-y" 'browse-yank)
; または (global-set-key "\C-x\C-y" 'browse-yank)

ファンクションキーに割り当てることもできます。例えば F4 に toroku-region を割り当てるなら、次のようにします。

(define-key global-map [F4] 'toroku-region)

デフォルトで空いているキー

Mule のデフォルト設定では、以下のキーには 機能(関数)を割り当てていま せんので、これらに好きな機能(関数)を割り当てましょう。

C-\,      M-g,      M-n,      M-o,      M-p,      M-s,
C-x c,    C-x p,    C-x t,    C-x w,    C-x y,    C-x z,
C-x C-a,  C-x C-h,  C-x C-j,  C-x C-m,  C-x C-y,
M-C-m,    M-C-q,    M-C-x,    M-C-y,    M-C-z

また、記号でもかまわなければ、以下のキーも空いています。

C-x 7,   C-x 8,   C-x 9,   C-x !,   C-x @,   C-x #,   C-x %,
C-x ~,   C-x &,   C-x *,   C-x _,   C-x |,   C-x {,   C-x },
C-x ",   C-x :,   C-x \,   C-x ?,   C-x ,,
M- `,    M- &,    M- *,    M- _,    M- +,    M- [,    M- ],
M- ",    M- :,    M- ?,

例えば、指定された行番号へ移動する goto-line という関数があります。こ の関数は筆者もよく使いますが、なぜか標準ではどのキーにも割り当てられて いません。そこで、これを M-g に割り当てることにします。以下を自分の .emacs に書いてください。

;; 指定した行に移動する
(global-set-key "\M-g" 'goto-line)

また、C-] は quail-mode という機能(関数)が割り当てられていますが、日 本ではめったに使わないでしょう。 C-q も非常に押しやすいキーなのに、 quoted-insertという使用頻度の低い機能(関数)が割り当てられています。 これらを、自分がよく使う機能(関数)を割り当てると幸せになれます。

ちなみに、現在のキー割り当てを一覧するには C-h b を使います。これで空 いているキーを捜してください。

2ストロークキーによる拡張

Mule では、デフォルトで空いているキーがいくつかありますが、これだけで は自由に割り当てられるキーが少ないですね。そんなときは、2ストロークキー で拡張しましょう。

私は C-q を使って拡張しています。 C-q には quoted-insert という関数が 割り当てられてますが、これを C-q C-q に割り当てます。

;;; C-q でキーバインドを拡張する
(global-unset-key "\C-q")	     ; default 'quoted-insert
(global-set-key "\C-q\C-q" 'quoted-insert)	; default C-q
これで準備はできました。あとは自分の好きなように拡張してください。以下 は私の例です。
;;; C-q を接頭辞として使うことができる。
(global-set-key "\C-q\C-q" 'quoted-insert)	; default C-q
(global-set-key "\C-q\C-]" 'quail-mode)		; default C-]
(global-set-key "\C-q\C-o" 'open-line)		; default C-o
(global-set-key "\C-q\C-u" 'universal-argument)	; default C-u
(global-set-key "\C-q\C-w" 'kill-region)	; default C-w
(global-set-key "\C-q\C-l" 'recenter)		; default C-l
;
(global-set-key "\C-q\C-p" 'beginning-of-buffer); default M-<
(global-set-key "\C-q\C-a" 'beginning-of-buffer); default M-<
(global-set-key "\C-q\C-n" 'end-of-buffer)	; default M->
(global-set-key "\C-q\C-e" 'end-of-buffer)	; default M->
(global-set-key "\C-q2" 'compare-windows)   ; default unbinded
(global-set-key "\C-q\C-y" 'browse-yank)    ; default unbinded
(global-set-key "\C-q\C-k" 'compile)	    ; default unbinded
(global-set-key "\C-q\C-c" 'comment-region)	; default <none>

また、3ストロークキーを設定することもできます。以下は、C-q C-mを3スト ロークキーの接頭辞にした私の例です。

;;; C-q C-m を用いた拡張
(global-unset-key "\C-q\C-m")
;;;
(global-set-key "\C-q\C-m\C-o" 'overwrite-mode)
;(global-set-key "\C-q\C-m\C-o" 'outline-minor-mode)
(global-set-key "\C-q\C-m\C-a" 'auto-fill-mode)
(global-set-key "\C-q\C-m\C-f" 'fundamental-mode)
(global-set-key "\C-q\C-m\C-t" 'text-mode)
(global-set-key "\C-q\C-m\C-i" 'indented-text-mode)
(global-set-key "\C-q\C-m\C-p" 'picture-mode)
(global-set-key "\C-q\C-m\C-l" 'japanese-latex-mode)
(global-set-key "\C-q\C-m\C-y" 'yatex-mode)
(global-set-key "\C-q\C-m\C-e" 'emacs-lisp-mode)
(global-set-key "\C-q\C-m\C-c" 'c-mode)
(global-set-key "\C-q\C-m\C-d" 'c++-mode)   ; 'c++' is 'd' (^-^)
(global-set-key "\C-q\C-m\C-m" 'objc-mode)
(global-set-key "\C-q\C-m\C-j" 'java-mode)
(global-set-key "\C-q\C-m\C-h" 'html-helper-mode)

ホームポジションを離れないために

Tabの入力は C-i で

タブを入力するのに、普通はTabキーを使います。しかし、C-i でもタブを入 力することができます。同じように、改行を入力するのに普通はEnterキーを 用いますが、C-m でも入力することができます。これらはホームポジションか らあまり指を動かすことなく入力できるので、便利です。ぜひ使ってみてくだ さい。

改行は C-m で、字下げもするなら C-j で

プログラムを書いているときは、EnterキーあるいはC-mで改行し、Tabキーあ るいはC-iで字下げするということを頻繁に行います。しかし、C-jを使えばこ れがいっぺんにできます。つまり、C-jを押せば、改行と字下げとを一度にやっ てくれるのです。まさに一石二鳥、一挙両得、両手に花(意味不明)。とにか く便利ですのでこれも使いましょう。

ESC は C-[ で

ESCキーは、キーボードによって位置がまちまちだったりするうえに、ホーム ポジションから遠い位置にあります。そんなあなたに耳寄りな話があります。 実は、C-[ が ESCキーと同じ役目を果たしてくれます。つまり、C-[ を押せば エスケープシーケンスが発生するのです。M-x と入力するときも、C-[ x と入 力すればOK。ホームポジションから手を離さないですみます。これで、ESCキー を押すために、画面から目を離してキーボードを見るということがなくなるで しょう。

BackSpaceキーの代わりに C-h を

ESCキーと同じくらいホームポジションから遠いのが BackSpaceキー(BSキー) です。頻繁に使うキーなのに、なぜあんな遠いところにあるんや!もっと打ち やすいところにないんかい!そんなあなたに、term/keyswap.el をオススメし ます。これは、BackSpaceキーと C-h とを入れ替えてしまうEmacsLispです。

もともとUNIXではC-hで一文字消去が行えることが多いですし、MS-DOSプロン プトでもC-hで一文字消去が行えます。このように、C-hをBackSpaceキーのか わりにすることはよく行われることなので、Emacs(Mule)ではBackSpaceキーと C-hとを入れ替えるEmacsLispがあらかじめ用意されているのです。

これを用いると、C-hが一文字消去、BackSpaceキーがヘルプになります。使い 方は、以下の通りです。

;; C-h と BS を入れ替える
(load "term/keyswap" nil t)  ;; "term/bobcat" でもOK
ちなみに筆者は C-h もBackSpaceキーも一文字消去にしています。どっちも一 文字消去として使うのです。

そしてヘルプは C-q C-h に割り当てています。これには C-q を接頭辞として 使うための設定が必要となりちょっと面倒ですので、通常は C-x C-h に割り 当てるほうが面倒がなくていいでしょう。

;;; C-h でカーソルの左にある文字を消す
(define-key global-map "\C-h" 'delete-backward-char)

;;; C-h に割り当てられている関数 help-command を C-x C-h に割り当てる
(define-key global-map "\C-x\C-h" 'help-command)

Deleteキーのかわりに C-d を

BackSpaceキーと似た働きをするものに、Deleteキー(Delキー)があります。 Windowsのアプリケーションでは普通、BackSpaceでカーソルの左にある文字を 消し、Deleteキーで右にある文字を消します。

ところが、Mule for Win32 ではDeleteキーがBackSpaceキーと同じ働きをする ようです。つまり、Deleteキーでもカーソルの左にある文字が消えます。なぜ こうなっているかはわかりませんが、もしカーソルの右にある文字を消したい のなら、C-d が使えます。ホームポジションから遠い位置にあるDeleteキーを 使うより、C-d を使いましょう。

キー割り当ての方針

キー割り当ての大原則は、

です。これは誰もが考えつくことです。

しかし、もうひとつ大事なことがあります。

例えば、一行を消す機能は連続して使うことが多いので C-k という1ストロー クキーが便利です。連続して使いたいときは C-k を押しっぱなしにすればい いわけです。それに対し、ファイルを開くという機能も非常によく使いますが、 連続して使うことはないので C-x C-f という2ストロークキーでいいわけです。

この観点からいうと、あまり使わない機能でも、連続してつかいたいことがあ るなら1ストロークキーに割り当てるべきです。

例えば私の場合ですと、キーボードマクロを実行する機能(標準で C-x e)は、 普段使わないけど使うときは連続して使うので、2ストロークキーでは都合が わるく、自分で C-] に割り当てています。

また私の作った、インデントして次の行に移動するという機能は、連続して使っ てこそ意味があるものなので、やはり1ストロークキーの M-n に割り当ててい ます。

また逆に、よく使う機能でも連続して使わないのなら、1ストロークキーに割 り当てなくても構わないということですから、 C-q や C-l や C-w や C-z や C-u や C-h などは2ストロークキーにしてもよく、他に1ストロークキーで割 り当てたほうがよい機能があれば、そちらにキーを譲るべきだと思います。

もうひとつ、キー割り当てで考慮すべきことがあります。それは、

ということです。

例えば、指定した範囲を削除する機能は C-w に割り当てられていますが、こ れはよくない。C-q や C-e を押そうとして、間違って C-w を押してしまう可 能性が高いです。

もちろん、間違って押したときは C-_ を押せばもとに戻せますし、C-y を押 して削除したのを同じ場所に貼り付けることもできます。しかし、問題は「間 違って押したことに気づかないことがある」ということです。

私は結構このミスを繰り返しました。プログラムが完成した!と思ってコンパ イルすると、全然通らない。あれ〜?と思ってみると、できたはずのプログラ ムのうち、上半分が全てなくなっているではないか!そう、気づかぬうちに C-w を押していたのです。

通常、Muleは削除したものを20個まで覚えてくれるのですが、それ以上は覚え ていませんので復活できません。このときも、復活できませんでした。おかげ で、もう一度プログラムを書く羽目に・・・

これに懲りて、指定した範囲を削除する機能は C-q C-w に割り当て、 C-w に はスクロールダウンする機能を割り当てました。 C-w なら、間違って押して も害はないですから。

ソースコードに色をつけよう!

Mule FAQにも載っていますが、ソースコードを編集するときに、コメントや予 約語に色をつけて表示させることができます。色をつけるには、

  1. hilit9.elをロードする
  2. font-lock.elをロードする

と2つのやり方があります。

しかし、hilit9では入力した文章に自動的に色がつきません。色をつけるため には C-l でバッファを表示しなおす必要があります。

もうひとつのfont-lock.elなら、入力するはしから色がついていきます。(た だし、ときどき間違えるので、そのときは関数 font-lock-fontify-buffer を 実行する必要があります)。そこで、ここではfont-lock.elの使い方を説明し ます。

font-lock.el を使うには、M-x font-lock-mode とします(font-lock-mode はマイナーモードですので、c-modeやjava-modeと併用できます)。いつも font-lock-mode で色をつけたいのなら、色をつけたいモード毎に

(add-hook 'c-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'c++-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'objc-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'java-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'emacs-lisp-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'html-helper-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'dired-mode-hook '(lambda () (font-lock-mode 1)))
        ・・・・・・
と、自分の .emacs に書いてください。

また、デフォルトでは色がつくのではなく、かわりに太字や斜体になります。 自分の好きな色をつけるには、以下を自分の .emacs に書いてください。

ここで、 "tomato" とか "darkolivegreen" と書かれてある部分に、自分の好 きな色を入れてください。どのような色が使えるかは、こちらを参考にしてく ださい。

(add-hook 'font-lock-mode-hook
          '(lambda ()
             (my-font-lock-set-face)))
(defun my-font-lock-set-face ()
  ;;
  ;; 'if' や 'while' といった予約語
  (make-face 'my-keyword-face)
  (set-face-foreground 'my-keyword-face "tomato")
  (setq font-lock-keyword-face 'my-keyword-face)
  ;(setq font-lock-keyword-face 'bold)
  ;;
  ;; コメント
  (make-face 'my-comment-face)
  (set-face-foreground 'my-comment-face "violetred4")
  (setq font-lock-comment-face 'my-comment-face)
  ;;
  ;; 文字列
  (make-face 'my-string-face)
  (set-face-foreground 'my-string-face "darkgreen")
  (setq font-lock-string-face 'my-string-face)
  ;;
  ;; 関数名
  (make-face 'my-function-face)
  (set-face-foreground 'my-function-face "blueviolet")
  (setq font-lock-function-name-face 'my-function-face)
  ;(setq font-lock-function-name-face 'default)
  ;;
  ;; 'typedef' や 'class'
  (make-face 'my-type-face)
  (set-face-foreground 'my-type-face "darkolivegreen")
  (setq font-lock-type-face 'my-type-face)
  ;(setq font-lock-type-face 'default)
  ;;
  ;; document
  ;;(make-face 'my-doc-string-face)
  ;;(set-face-foreground 'my-doc-string-face "lightgrey")
  ;;(setq font-lock-doc-string-face 'my-doc-string-face)
  )

これで、コメントや文字列や関数名に色がつくようになるはずです。どの部分 がコメントでどの部分が文字列かといったことは、主モードごとに違います。 例えば、c-mode では '/*' から '*/' までがコメントなので色がつきますが、 emacs-lisp-mode では '#' から行末までがコメントなので色がつきます。

c-modeやc++-modeでは、コメントや文字列や関数名には色がつきますが、 'if' や 'for' や 'while' といった予約語(キーワード)には色がつきませ ん。つけたい人は、自分の .emacs に以下を加えてください。

;;;
;;; c-mode, c++-modeの設定
;;;
(add-hook 'c-mode-hook
          '(lambda ()
             (font-lock-mode 1)
             (setq font-lock-keywords c-font-lock-keywords-2)
             ))
(add-hook 'c++-mode-hook
          '(lambda ()
             (font-lock-mode 1)
             (setq font-lock-keywords c++-font-lock-keywords-2)
             ))

デフォルトでは、java-mode ではコメントと文字列にしか色がつきません。ク ラス名やメソッド名や予約語に色をつけるには、こちらから font-lock-java.el をとってきて、パスの通っているディレクトリにおいてく ださい。そして自分の .emacs に以下を加えてください。色を設定している部 分は、自由に変更してください。

(add-hook
 'java-mode-hook
 '(lambda ()
    ;;
    ;; font-lock-mode にする
    (font-lock-mode 1)
    ;;
    ;; font-lock-java をロードする
    (require 'font-lock-java)
    ;;
    ;; java-mode用の face を設定する
    ;; -- 予約語は色をつけず、太字にする。
    (setq font-lock-java-keyword-face 'bold)
    ;; -- 新たに darkolivegreen の face をつくり、クラス名に使う
    (make-face 'my-java-class-face)
    (set-face-foreground 'my-java-class-face "darkolivegreen")
    (setq font-lock-java-class-face 'my-java-class-face)
    ;; -- コンストラクタもクラス名と同色にする
    (setq font-lock-java-constructor-face 'my-java-class-face)
    ;; -- メソッド名は色をつけない。
    (setq font-lock-java-method-face 'default)
    ;;
    ;; 設定を反映させる
    (set-font-lock-keywords-for-java)
    ;
    ))
この font-lock-java.el は、font-lock.el を参考にして私が書いたものです。 しかし、私は Emacs Lisp をあまり詳しくは知らないので、 font-lock-java.el は不完全なうえに稚拙です。とりあえず Java のソースに 色がつく、という程度ですが、それでもよければお使いください。

andersl-java-font-lock.el というものがあるそうです。使ったことがない ので解説はできませんが、参考までに。

最後に、参考になるか混乱のタネになるかわかりませんが、私の .emacs のう ち font-lock に関係する部分を載せておきます。

;;;
;;; どんな face があるかは M-x list-faces-display で分かる。
;;; また、どんな色が指定できるかは
;;; http://www.geocities.co.jp/SiliconValley-PaloAlto/5236/rgb.html
;;; を参照のこと。


;;;
;;; faces の設定
;;;
(add-hook 'font-lock-mode-hook
          '(lambda ()
             (my-font-lock-set-face)
             ;;
             ))
(defun my-font-lock-set-face ()
  ;;
  ;; 'if' や 'while' といった予約語
  (make-face 'my-keyword-face)
  (set-face-foreground 'my-keyword-face "midnightblue")
  (setq font-lock-keyword-face 'my-keyword-face)
  ;(setq font-lock-keyword-face 'bold)
  ;;
  ;; コメント
  (make-face 'my-comment-face)
  ;(set-face-foreground 'my-comment-face "darkkhaki")
  ;(set-face-foreground 'my-comment-face "darkgoldenrod4")
  ;(set-face-foreground 'my-comment-face "dimgray")
  (set-face-foreground 'my-comment-face "slategray")
  (setq font-lock-comment-face 'my-comment-face)
  ;;
  ;; 文字列
  (make-face 'my-string-face)
  (set-face-foreground 'my-string-face "darkgreen")
  (setq font-lock-string-face 'my-string-face)
  ;;
  ;; 関数名
  (make-face 'my-function-face)
  (set-face-foreground 'my-function-face "violetred4")
  (setq font-lock-function-name-face 'my-function-face)
  ;(setq font-lock-function-name-face 'default)
  ;;
  ;; 'typedef' や 'class'
  (make-face 'my-type-face)
  (set-face-foreground 'my-type-face "royalblue")
  (setq font-lock-type-face 'my-type-face)
  ;(setq font-lock-type-face 'default)
  ;;
  ;; ドキュメント
  ;;(make-face 'my-doc-string-face)
  ;;(set-face-foreground 'my-doc-string-face "lightgrey")
  ;;(setq font-lock-doc-string-face 'my-doc-string-face)
  )


;;;
;;; diredモードのカスタマイズ
;;;     diredモードでは、ヘッダの表示に font-lock-type-face,
;;;     シンボリックリンクの表示に font-lock-function-name-face,
;;;     マーク(印)とディレクトリの表示に font-lock-keyword-face
;;;     が使われている。これを変更するための emacs lisp。
(add-hook
 'dired-mode-hook
 '(lambda ()
    ;;
    ;; font-lock-mode にする
    (font-lock-mode 1)
    ;;
    ;; dired-mode 用の face
    (setq font-lock-path-face 'bold)
    (copy-face 'bold 'my-dir-face)
    (set-face-foreground 'my-dir-face "navyblue")
    (setq font-lock-dir-face 'my-dir-face)
    (setq font-lock-symlink-face 'bold)
    (setq font-lock-mark-face 'bold)
    ;;
    ;; dired-mode 用の font-lock-keywords
    (setq font-lock-keywords-for-dired
          '(;; ヘッダ
            ("^  \\(\\([a-z]:\\)?/.+\\)$" 1 font-lock-path-face)
            ;; シンボリックリンク
            ("\\([^ ]+\\) -> [^ ]+$" . font-lock-symlink-face)
            ;; マーク(印)
            ("^\\([^ ]\\).*$" 1 font-lock-mark-face)
            ;; ディレクトリ
            ("^..d.* \\([^ ]+\\)$" 1 font-lock-dir-face)
            ))
    (setq font-lock-keywords font-lock-keywords-for-dired)
    ))


;;;
;;; infoモード
;;;
(add-hook
 'Info-mode-hook
 '(lambda ()
    ;;
    ;; メニューやクロスリファレンスの face を変更する
    (copy-face 'default 'info-node)
    (copy-face 'bold 'info-menu-5)
    (copy-face 'default 'info-xref)
    (set-face-foreground 'info-node "darkslateblue")
    (set-face-foreground 'info-menu-5 "dimgray")
    (set-face-foreground 'info-xref "darkgreen")
    ;;
    ;; あるいはこちらのやり方
    ;(make-face 'my-info-face)
    ;(set-face-foreground 'my-info-face "tomato")
    ;(copy-face 'my-info-face 'info-node)
    ;(copy-face 'my-info-face 'info-menu-5)
    ;(copy-face 'my-info-face 'info-xref)
    ))


;;;
;;; モードラインの色を変える
;;;
(set-face-background 'modeline "skyblue2")
(set-face-foreground 'modeline "skyblue4")


;;;
;;; c-mode, c++-modeの設定
;;;
(add-hook
 'c-mode-hook
 '(lambda ()
    ;;
    ;; font-lock-mode にする
    (font-lock-mode 1)
    ;;
    ;; デフォルトでは 'if' や 'for' といった予約語に
    ;; 色がつかないので、色をつけるようにする
    ;(setq font-lock-keywords c-font-lock-keywords-2)
    ))
(add-hook
 'c++-mode-hook
 '(lambda ()
    (font-lock-mode 1)
    ;(setq font-lock-keywords c++-font-lock-keywords-2)
    ))


;;;
;;; java-mode 用の face を設定
;;;
(add-hook
 'java-mode-hook
 '(lambda ()
    ;;
    ;; font-lock-mode にする
    (font-lock-mode 1)
    ;;
    ;; font-lock-java をロードする
    (require 'font-lock-java)
    ;;
    ;; java-mode用の face を設定する
    ;(setq font-lock-java-keyword-face font-lock-keyword-face)
    (setq font-lock-java-keyword-face 'default)
    ;(setq font-lock-java-class-face font-lock-type-face)
    ;(setq font-lock-java-constructor-face font-lock-type-face)
    ;(setq font-lock-java-method-face font-lock-funtion-face)
    ;;
    ;; 設定を反映させる
    (set-font-lock-keywords-for-java)
    ;
    ))


;;;
;;; html-helper-mode 用の設定
;;;
(add-hook
 'html-helper-mode-hook
 '(lambda ()
    (font-lock-mode 1)
    (setq font-lock-html-tag-face font-lock-keyword-face)
    (setq font-lock-html-anchor-face font-lock-string-face)
    (setq font-lock-html-bold-face 'bold)
    (setq font-lock-keywords-for-html
          '(("\\(<a[ \t][^>]*>\\)" 1 font-lock-html-anchor-face)
            ("</a>" . font-lock-html-anchor-face)
            ("\\(<.[^>]*>\\)" 1 font-lock-html-tag-face)
            ("<b>\\(.*\\)</b>" 1 font-lock-html-bold-face)))
    (setq font-lock-keywords font-lock-keywords-for-html)
    (font-lock-fontify-buffer)
    ))


;;;
;;; font-lock-mode を使用するその他の主モードの設定
;;;
(add-hook 'emacs-lisp-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'html-helper-mode-hook '(lambda () (font-lock-mode 1)))
;(add-hook 'dired-mode-hook '(lambda () (font-lock-mode 1)))
;(add-hook 'c-mode-hook '(lambda () (font-lock-mode 1)))
;(add-hook 'c++-mode-hook '(lambda () (font-lock-mode 1)))
(add-hook 'objc-mode-hook '(lambda () (font-lock-mode 1)))
;(add-hook 'java-mode-hook '(lambda () (font-lock-mode 1)))


;;;
;;; フォントの色を付け直す関数 font-lock-fontify-buffer を
;;; F6 に割り当てる
;;;
(define-key global-map [f6] 'font-lock-fontify-buffer)


;;;
;;; C-l (recenter) に、色を付け直す機能を付け加える
;;;
(defun my-recenter-and-fontify-buffer ()
  (interactive)
  (recenter)
  (font-lock-fontify-buffer))

(add-hook
 'font-lock-mode-hook
 '(lambda ()
    ;; 普通の人は、recenter が C-l に割り当てられている
    ;(local-set-key "\C-l" 'my-recenter-and-fontify-buffer)
    ;; 私は recenter を C-q C-l に割り当てているので、こうなる
    (local-set-key "\C-q\C-l" 'my-recenter-and-fontify-buffer)
    ))

フォントを変えよう! (for Win32)

Mule for Win32 は、デフォルトでは字間(文字と文字の間隔)が広すぎるよ うに感じます。これを狭めるには、フォントを変更する必要があります。しか し、そのやり方がよく分かりません。

フォントについて説明した Readme.fontset というファイルが Mule for Win32 についてますが、これを読んでも私はよく分かりませんでした。そこで、 私が試行錯誤した範囲でわかったことをここでは書いてみます。

とりあえず、手っ取り早く字間を狭めたいという人は、次の Emacs-Lisp を自 分の .emacs に書いてください。

;;; Mule for Win32 で文字と文字の間隔を狭める
(if (eq system-type 'windows-nt)
    (progn
      (apply 'win32-change-fontset-attribute
             (win32-get-font-metric "default" 0))
      ;; 画面を再描写する
      (win32-refresh-fontset (selected-frame))
      ))

フォントを変更する

フォントを設定するには、本当なら fontset やら font やら logfont やらの 知識が必要となります。が、ここでは説明をしません(私もよくわかってな い)。こうすればフォントを変更できる、というやり方だけを説明します。

まず Mule for Win32 を起動すると、初めに「*scratch*」という名前のつい たバッファが開かれます。これを「*scratch*バッファ」といいます。特別な 設定をしていなければ、*scrach*バッファは lisp-interaction-mode になっ ているはずです。もしなっていなければ、M-x lisp-interaction-mode を実行 してください。

この *scrach*バッファで、

(win32-query-get-logfont)
と書きます。カーソルは最後の閉じカッコの後ろにあるとします。そして、 C-j を押してください。すると、フォントを選択するダイアログが出てきます。 このダイアログでは、フォントのフォント名・スタイル・サイズが選べます。

ここで、スタイルを 'Regular' にし、好きなフォント名・好きなサイズを選 びます。例としてフォント名に 'Terminal'、サイズに 14 を選んでみます。

選んだら、OKボタンを押します。すると、*scratch*バッファに

("Terminal" 0 -19 400 0 nil nil 128 1 1 49)
という行が挿入されました。これが、フォント 'Terminal' の、スタイルが 'Regular' でサイズが 14 のときの属性です。

属性は、11個の要素からなるリストです(ここでは、属性についての詳しい説 明はしません)。

同じようにして、スタイルが 'Bold'、'Italic'、'Bold Italic' のときの属 性を調べます。

このようにして調べた属性が、例えば次のようだとします。

;;; フォント名:Terminal、サイズ:14
("Terminal" 0 -19 400 0 nil nil 128 1 1 49) ; regular
("Terminal" 0 -19 700 0 nil nil 128 1 1 49) ; bold
("Terminal" 0 -19 400 0 t nil 128 1 1 49) ; italic
("Terminal" 0 -19 700 0 t nil 128 1 1 49) ; bold italic
ここまで調べたら、あとは自分の .emacs に以下を加えてください。ここで、 フォントの属性部分は各自で調べた値を使用してください。
(if (eq system-type 'windows-nt)
    (progn
      ;; regular
      (win32-change-font-property
       "default" 0 '("Terminal" 0 -19 400 0 nil nil 128 1 1 49))
      ;; bold
      (win32-change-font-property
       "default" 1 '("Terminal" 0 -19 700 0 nil nil 128 1 1 49))
      ;; italic
      (win32-change-font-property
       "default" 2 '("Terminal" 0 -19 400 0 t nil 128 1 1 49))
      ;; bold italic
      (win32-change-font-property
       "default" 3 '("Terminal" 0 -19 700 0 t nil 128 1 1 49))
      ;; 設定したフォントの属性を適用する
      (apply 'win32-change-fontset-attribute
             (win32-get-font-metric "default" 0))
      ;; 画面を再描写する
      (win32-refresh-fontset (selected-frame))
      ))

これでもう一度 Mule for Win32 を起動すると、フォントが変更されているは ずです。

参考までに、代表的なフォントの属性をこちらに 書いておきます。ちなみに、 個人的には Terminalフォントが見やすくてよろしいかと思います。

もっと簡単にフォントを変更する

先の方法よりも、フォントをいろいろと変更しやすい方法を紹介します。

まず、フォントの属性について説明し、そのあとに変更方法を紹介します。フォ ントセットやフォントについての詳しい説明はしません(私がよくわかってい ないため)。

先の代表的なフォントの属性を見れば分かりますが、フォントの属性は11個の 要素から構成されています。

最初の要素は、フォント名です。

2番目の要素は、フォントの幅を表しますが、気にしないで下さい。通常は 0 になるようです。

3番目の要素は、フォントの高さを表します。高さを表す数字はフォントの大 きさと対応しています。例えば、フォントの大きさが 10pt なら高さは -13、 12pt なら -16、 14pt なら -19、・・・です。マイナスであることに注意し てください。

4番目の要素は、太字(bold)かそうでないかを表します。 700なら太字、400な ら普通の文字です。

5番目の要素は、気にしないで下さい。ここも 0 になるようです。

6番目の要素は、斜体(italic)かそうでないかを表します。 t なら斜体、nil なら普通の文字です。

7番目の要素は、気にしないで下さい。必ず nil になるようです。

8番目の要素は、文字コードを表しますが、気にしないで下さい。 128であれ ばOKです。

9番目の要素は、フォントの品質を表します。1 になるようですが、 0 にして いても問題ないようです。

10番目の要素は、フォントの出力精度を表します。1 や 3 になるようですが、 0 にしていても問題ないようです。

11番目の要素は、Pitchとフォントファミリを表します。フォントごとに違い ますが、1 にしていても問題はないようです。

つまり、全てのフォントで 2・4・5・6・7・8番目は同じ値を使用できること が分かります。

これらのことから、以下のような関数を作りました。こちらのほうが、フォン トを選択しやすいでしょう。

;;;
;;; フォントを選択する関数
;;;
(defun my-set-font (font h q o p)
  (let (;; regular
        (logfont0 (list font 0 h 400 0 nil nil 128 q o p))
        ;; bold
        (logfont1 (list font 0 h 700 0 nil nil 128 q o p))
        ;; italic
        (logfont2 (list font 0 h 400 0 t   nil 128 q o p))
        ;; bold italic
        (logfont3 (list font 0 h 700 0 t   nil 128 q o p)))
    ;; フォントの属性を設定する
    (win32-change-font-property "default" 0 logfont0)
    (win32-change-font-property "default" 1 logfont1)
    (win32-change-font-property "default" 2 logfont2)
    (win32-change-font-property "default" 3 logfont3)
    ;; 設定した属性を適用する
    (apply 'win32-change-fontset-attribute
            (win32-get-font-metric "default" 0))
    ;; 画面を再描写する
    (win32-refresh-fontset (selected-frame))
    ))

;;;
;;; フォントを選択する。
;;; この中のどれかひとつのコメントをはずす
;;;
;(my-set-font "Terminal" -13 1 1 49)     ; Terminal 10pt
(my-set-font "Terminal" -19 1 1 49)      ; Terminal 14pt
;(my-set-font "Terminal" -23 1 1 49)     ; Terminal 17pt
;(my-set-font "MS ゴシック" -11 1 3 49) ; MSゴシック 8pt
;(my-set-font "MS ゴシック" -12 1 3 49) ; MSゴシック 9pt
;(my-set-font "MS ゴシック" -13 1 3 49) ; MSゴシック 10pt
;(my-set-font "MS ゴシック" -15 1 3 49) ; MSゴシック 11pt
;(my-set-font "MS ゴシック" -16 1 3 49) ; MSゴシック 12pt
;(my-set-font "MS ゴシック" -19 1 3 49) ; MSゴシック 14pt
;(my-set-font "MS ゴシック" -21 1 3 49) ; MSゴシック 16pt
;(my-set-font "MS ゴシック" -24 1 3 49) ; MSゴシック 18pt
;(my-set-font "MS 明朝" -11 1 3 17)     ; MS明朝 8pt
;(my-set-font "MS 明朝" -12 1 3 17)     ; MS明朝 9pt
;(my-set-font "MS 明朝" -13 1 3 17)     ; MS明朝 10pt
;(my-set-font "MS 明朝" -15 1 3 17)     ; MS明朝 11pt
;(my-set-font "MS 明朝" -16 1 3 17)     ; MS明朝 12pt
;(my-set-font "MS 明朝" -19 1 3 17)     ; MS明朝 14pt
;(my-set-font "MS 明朝" -21 1 3 17)     ; MS明朝 16pt
;(my-set-font "MS 明朝" -24 1 3 17)     ; MS明朝 18pt

あるいは、フォントの属性において 9・10・11番目の要素をそれぞれ 0・0・1 にしても問題ないことと、全てのフォントでサイズと高さが一対一に対応する ことを利用して、次のようにしてもよいでしょう。先の関数 my-set-font を 書いた後ろに、以下を加えてください。

;;;
;;; my-set-font を使いやすくした my-set-font-2
;;;
(defun my-set-font-2 (font size)
  (let (h)
    (cond ((= size 8) (setq h -11))
          ((= size 9) (setq h -12))
          ((= size 10) (setq h -13))
          ((= size 11) (setq h -15))
          ((= size 12) (setq h -16))
          ((= size 14) (setq h -19))
          ((= size 16) (setq h -21))
          ((= size 17) (setq h -23))
          ((= size 18) (setq h -24))
          )
    (my-set-font font h 0 0 1)))

;;;
;;; フォントの選択。
;;; どれか一つのコメントをはずして選択する。
;;;
;(my-set-font-2 "Terminal" 10)      ; Terminal    10pt
(my-set-font-2 "Terminal" 14)      ;             14pt
;(my-set-font-2 "Terminal" 17)      ;             17pt
;(my-set-font-2 "MS ゴシック" 8)  ; MSゴシック 8pt
;(my-set-font-2 "MS ゴシック" 9)  ;              9pt
;(my-set-font-2 "MS ゴシック" 10) ;             10pt
;(my-set-font-2 "MS ゴシック" 11) ;             11pt
;(my-set-font-2 "MS ゴシック" 12) ;             12pt
;(my-set-font-2 "MS ゴシック" 14) ;             14pt
;(my-set-font-2 "MS ゴシック" 16) ;             16pt
;(my-set-font-2 "MS ゴシック" 18) ;             18pt
;(my-set-font-2 "MS 明朝" 8)      ; MS 明朝    8pt
;(my-set-font-2 "MS 明朝" 9)      ;              9pt
;(my-set-font-2 "MS 明朝" 10)     ;             10pt
;(my-set-font-2 "MS 明朝" 11)     ;             11pt
;(my-set-font-2 "MS 明朝" 12)     ;             12pt
;(my-set-font-2 "MS 明朝" 14)     ;             14pt
;(my-set-font-2 "MS 明朝" 16)     ;             16pt
;(my-set-font-2 "MS 明朝" 18)     ;             18pt

もっともっと簡単にフォントを変更する

今までに紹介した方法は、.emacs を編集して再起動することでフォントを変 更しました。しかし、いちいち再起動するのは面倒です。これから紹介する方 法は、再起動することなしにフォントを変更する方法です。

以下のEmacs Lispを自分の .emacs に書いて Mule for Win32 を起動し直して ください。そして、Controlキーを押しながらマウスの右ボタンをクリックし て下さい。フォントを選ぶポップアップウィンドウが出てくるので、好きなフォ ントを選んでください。

;;;
;;; フォントセットを作り出す関数
;;;     引数:   fontset ... フォントセット名、
;;;              winfont ... Windowsのフォント名
;;;              size    ... Windowsのフォントサイズ
;;;                          (8,9,10,11,12,14,16,17,18)
;;;
(defun my-create-fontset (fontset winfont size)
  (let* ((h (cond ((= size 8)  -11)
                  ((= size 9)  -12)
                  ((= size 10) -13)
                  ((= size 11) -15)
                  ((= size 12) -16)
                  ((= size 14) -19)
                  ((= size 16) -21)
                  ((= size 17) -23)
                  ((= size 18) -24)))
         (logfont0
          (list winfont 0 h 400 0 nil nil 128 0 0 1)) ; regular
         (logfont1
          (list winfont 0 h 700 0 nil nil 128 0 0 1)) ; bold
         (logfont2
          (list winfont 0 h 400 0 t   nil 128 0 0 1)) ; italic
         (logfont3
          (list winfont 0 h 700 0 t   nil 128 0 0 1)) ; bold italic
         )
    ;; フォントセットをつくる
    (win32-add-fontset fontset 0 0 0 0)
    ;; 'default'フォントをつくって、フォントセットに加える
    (win32-add-font "default" '*sjis* fontset)
    ;; 'default'フォントの属性(ログフォント)を設定する
    (win32-change-font-property "default" 0 logfont0 fontset)
    (win32-change-font-property "default" 1 logfont1 fontset)
    (win32-change-font-property "default" 2 logfont2 fontset)
    (win32-change-font-property "default" 3 logfont3 fontset)
    ;; 設定を反映させる
    (apply 'win32-change-fontset-attribute
            (append (win32-get-font-metric "default" 0 fontset)
                    (list fontset)))
    ))


;;;
;;; フォントセットの登録
;;;
(my-create-fontset "Terminal10" "Terminal" 10)
(my-create-fontset "Terminal14" "Terminal" 14)
(my-create-fontset "Terminal17" "Terminal" 17)
(my-create-fontset "MS-Gothic8"  "MS ゴシック" 8)
(my-create-fontset "MS-Gothic9"  "MS ゴシック" 9)
(my-create-fontset "MS-Gothic10" "MS ゴシック" 10)
(my-create-fontset "MS-Gothic11" "MS ゴシック" 11)
(my-create-fontset "MS-Gothic12" "MS ゴシック" 12)
(my-create-fontset "MS-Gothic14" "MS ゴシック" 14)
(my-create-fontset "MS-Gothic16" "MS ゴシック" 16)
(my-create-fontset "MS-Gothic18" "MS ゴシック" 18)
(my-create-fontset "MS-Mincho8"  "MS 明朝" 8)
(my-create-fontset "MS-Mincho9"  "MS 明朝" 9)
(my-create-fontset "MS-Mincho10" "MS 明朝" 10)
(my-create-fontset "MS-Mincho11" "MS 明朝" 11)
(my-create-fontset "MS-Mincho12" "MS 明朝" 12)
(my-create-fontset "MS-Mincho14" "MS 明朝" 14)
(my-create-fontset "MS-Mincho16" "MS 明朝" 16)
(my-create-fontset "MS-Mincho18" "MS 明朝" 18)


;;;
;;; 起動時のフォントセットを指定する
;;;
(defun my-select-fontset (fsetname)
  (setq default-frame-alist
        (append (list (cons 'fontset fsetname))
                default-frame-alist)))
(my-select-fontset "Terminal14") ; Terminalフォント 14pt

以上で、Mule for Win32を再起動することなしに、フォントを選ぶことができ るようになりました。しかし、なんとまあ面倒くさいことでしょうかね。ここ らへんが、 Mule for Win32 の弱いところではあります。

インフォでの斜体をやめる

Mule for Win32 ではインフォを表示させると、メニューやクロスリファレン スなど、リンクを表示する部分が太字斜体になっています。太字であることは いいのですが、斜体になっているので、文字が一部欠けて表示されます。これ を止めるには、自分の .emacs に次のように書いてください。

(add-hook 'Info-mode-hook
           '(lambda ()
              ;;
              ;; メニューやクロスリファレンスの face を太字にする
              (copy-face 'bold 'info-node)
              (copy-face 'bold 'info-menu-5)
              (copy-face 'bold 'info-xref)
              ))

また、太字で表示する替わりに色を変えたいのなら、次のようにするといいで しょう。

(add-hook 'Info-mode-hook
          '(lambda ()
             ;;
             ;; メニューやクロスリファレンスの face を変更する
             (copy-face 'default 'info-node)
             (copy-face 'bold 'info-menu-5)
             (copy-face 'default 'info-xref)
             (set-face-foreground 'info-node "darkslateblue")
             (set-face-foreground 'info-menu-5 "dimgray")
             (set-face-foreground 'info-xref "darkgreen")
             ;;
             ;; あるいはこちらのやり方
             ;(make-face 'my-info-face)
             ;(set-face-foreground 'my-info-face "tomato")
             ;(copy-face 'my-info-face 'info-node)
             ;(copy-face 'my-info-face 'info-menu-5)
             ;(copy-face 'my-info-face 'info-xref)
             ))

テンプレートを使おう!

新しいプログラムを作成するときに、テンプレートが利用できると便利です。 例えば、Cプログラムを書くのにいつも #include int main ... と 書くのは面倒ですので、これをテンプレートとして必要なときに挿入できると 便利です。

またJavaプログラムでしたら、Applet用と通常のClass用とでテンプレートを 分けて利用できると便利ですし、ファイル名からクラス名を推測してテンプレー トを挿入してくれるともっと便利です。

ここではそのための方法として insert-template.el を紹介します。

insert-templateの使い方

例えばCのプログラムを書くときは、いつも次のような形から始めるとします。

/*
 *
 * $Id$
 */

#include <stdio.h>

int main(int argc, char *argv[])
{
    
}
しかし、これを毎回手で入力しているのも面倒です。

そこで、これをテンプレートとし、新しくプログラムを作るときはこのテンプ レートを呼び出すことにしましょう。

まず、先のプログラムをテンプレートとしてファイルに保存します。保存先は $HOME/lib/template/template.c とします(保存するディレクトリはどこでも いいですが、ファイル名は必ずtemplate.cとしてください)。

次に、以下のEmacs Lispを自分の .emacs に加えるか、または insert-template.elをダウンロードしてパスが通っているところに置いてくだ さい。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;  insert-template.el -- insert template file
;;;	author: kwatch <kwatch@lycos.jp>
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;
;;; insert-template-directory
;;;
(defvar insert-template-directory
  (expand-file-name "~/lib/template")
  ;"~/lib/template" ; xyzzy
 "* Template Directory which contains template files (\"template.xxx\").")


;;;
;;; insert-template
;;;
(defun insert-template (&optional arg)
  (interactive "P")
  "* Insert template file and call hook according to file suffix.
  Example: If you are editing `hogehoge.java', insert-template inserts
template file `template.java' and calls 'insert-template-java-hook'.
  If you would like to insert another template file, call this function
with argument, and you'll be prompted in mini-buffer to enter another
template file name.
  Variable `insert-template-directory' indicates the location of template
files.
  When inserting template files, inset-template replaces the default
keywords: __FILE__, __CLASS__, __USER__, __EMAIL__
See function `insert-template-replace-default-keywords'.
"
  (let* ((file (file-name-nondirectory buffer-file-name))
	 ;(file (file-namestring (get-buffer-file-name))) ; xyzzy
	 (index (string-match "\\.\\w+$" file))
	 (suffix (if index (substring file (1+ index)) file))
	 template
	 hook
	)
    ;;
    (setq template
	  (concat insert-template-directory "/template." suffix))
    (setq hook
	  (concat "insert-template-" suffix "-hook"))

    ; read strings from mini-buffer
    (setq template (read-string "Template File: " template))
    (if arg (setq hook (read-string "Hook Name: " hook)))

    ;;
    (if (not
	 (file-exists-p template)
	 ;(file-exist-p template) ; xyzzy
	 )
	(message "ERROR: File not found: %s" template)
      (progn
	(insert-file template)
	(run-hooks (intern hook))
	(insert-template-replace-default-keywords) ; replace keywords
	(message "Inset Template ... done.")
      ))
  ))


;;;
;;; insert-template-replace-default-keywords
;;;
(defun insert-template-replace-default-keywords ()
  (interactive)
  "* Replace default keywords: __FILE__, __CLASS___, __USER__, __EMAIL__
   __FILE__  -- file name (not include path name)
   __CLASS__ -- class name (== file name without suffix)
   __USER__  -- user name (== variable `user-name' or `user-login-name')
   __EMAIL__ -- user e-mail address (== variable `user-mail-address')
"
  (let* ((file (file-name-nondirectory buffer-file-name))
	 ;(file (file-namestring (get-buffer-file-name))) ; xyzzy
	 (index (string-match "\\.[A-Za-z0-9]*$" file))
	 (class (substring file 0 index))
	 (user (if (boundp 'user-name) user-name (user-login-name)))
	 (email user-mail-address)
	 )
    ;;
    (goto-char (point-min))
    (replace-string "__FILE__" file)
    ;(replace-string "__FILE__" file t) ; xyzzy
    (goto-char (point-min))
    (replace-string "__CLASS__" class)
    ;(replace-string "__CLASS__" class t) ; xyzzy
    (goto-char (point-min))
    (replace-string "__USER__" user)
    ;(replace-string "__USER__" user t) ; xyzzy
    (goto-char (point-min))
    (replace-string "__EMAIL__" email)
    ;(replace-string "__EMAIL__" email t) ; xyzzy
    ;;
    (goto-char (point-min))
    ))

;;;
;;; keybind
;;;
(global-set-key "\C-xt" 'insert-template)
;(global-set-key '(#\C-x #\t) 'insert-template) ; xyzzy

これで準備完了です。

使い方を説明します。

  1. まず新しいCプログラムを作成します。
  2. そして C-x t を押します。
  3. ミニバッファに
    Template File: /home/kwatch/lib/template/template.c
    
    と聞かれますので、Enterキーを押します。
  4. すると、template.c が挿入されます。ワォ、これは便利。

テンプレート名を聞かれるところで、他のテンプレート名を入力することがで きます。例えば同じJavaプログラムでも、AppletとServletとでは異なるテン プレートを使いたいと思うでしょう。このとき、それぞれのテンプレート Applet.javaとServlet.javaを用意しておき、テンプレート名を聞かれたとき にそれらの名前を答えれば、テンプレートを使いわけることができます。

どのテンプレートがデフォルトとなるかは、拡張子によって決まります。例え ばCプログラムの拡張子は .c なので、template.cがデフォルトで表示されま す。Javaならtemplate.javaが表示されます。

ただし、拡張子がないときはそのファイル名が拡張子として使われます。どう いうことかというと、例えばファイル名が "Makefile" のときは template.Makefile がデフォルトのテンプレート名として表示されます。

キーワードの展開

insert-template では、次のようなキーワードを自動的に展開してくれます。

__FILE__
ファイル名に展開されます。パスは含みません。
__CLASS__
ファイル名から拡張子を取り除いた名前に展開されます。
__USER__
変数user-nameが設定してあればその値に、なければ関数 user-login-nameの値に展開されます。
__EMAIL__
変数user-mail-addressの値に展開されます。

例えば、Java用のテンプレート template.java を次のような内容で作ったと します。

import java.lang.*;
import java.util.*;

/**
 *
 * @author     __USER__ <__EMAIL__>
 * @version    $Revision$, $Date$
 */
public class __CLASS__ {
    /**
     */
    public __CLASS__() {
        super();
    }

そしてC-x t と入力して、ミニバッファに「template.java」とでてからEnter キーを押せば、キーワードが例えば次のように展開されて挿入されます。

import java.lang.*;
import java.util.*;

/**
 *
 * @author     kwatch <kwatch@lycos.jp>
 * @version    $Revision$, $Date$
 */
public class Sample {
    /**
     */
    public Sample() {
        super();
    }

ワォ、なんて便利。

Hookによる拡張

insert-templateでは、「insert-template-拡張子-hook」というHook関数が定 義されてあれば、それを実行するようになっています。これを利用して、 insert-templateの機能を拡張することができます。

例えば、HTML用のテンプレートtemplate.htmlを次のような内容で作ります。 「__TITLE__」という独自のキーワードを指定しているのがポイントです。

<html>
<head>
  <title> __TITLE__  </title>
</head>
<body>

<div align="center">
  <h1> __TITLE__ </h1>
</div>


</body>
</html>

そして、この独自キーワードを展開するために、.emacsに次のように記述しま す。

;; hook for template.html
(add-hook
 'insert-template-html-hook
 '(lambda ()
   (let (title)
     (setq title (read-string "Enter Title: "))
     (goto-char (point-min))
     (replace-string "__TITLE__" title)
     ;(replace-string "__TITLE__" title t) ; xyzzy
   )))

こうして、HTMLファイルを作成するときに C-x t を押してEnterキーを押すと、 template.cが挿入されたあとに、ミニバッファにタイトルを聞かれます。

Enter Title: プログラマーのためのMule

タイトルを適当に入力すると、それが「__TITLE__」の部分に展開されます。

<html>
<head>
  <title> プログラマーのためのMule </title>
</head>
<body>

<div align="center">
  <h1> プログラマーのためのMule </h1>
</div>


</body>
</html>

ワォ、すげー便利。

headerline.elを使おう!

headerline.elは、見出し(章や節のタイトル)を一覧で表示してくれる、自作 EmacsLispです。一覧から見出しを選んでEnterキーを押すと、該当するタイト ルにジャンプする機能もあります。

見出しのパターンは正規表現で指定するようになっています。この正規表現は メジャーモードごとに変更できますので、例えばc-modeであれば関数の一覧を、 またJavaであればメソッド名やインスタンス変数の一覧を表示することができ ます。ジャンプ機能と組み合わせれば、好きな関数やメソッドに簡単にジャン プできて、とても便利です。

タグジャンプなどの類似機能との違いについては「類似機能との比較」をご覧 ください。

headerline.elのインストール

  1. headerline_1.7.zipをダウンロードして解凍します。
  2. headerline.elを、パスの通ったディレクトリに置きます。
  3. .emacsに、次のように書きます。
    ;; headerline.elのロード
    (load-library "headerline")
    ;; キー割り当て(例:F10やControl+F10に割り当てる)
    (global-set-key [f10] 'headerline)     ; F10
    ;(global-set-key [C-F10] 'headerline)  ; Control+ F10
    
  4. Muleを再起動します。

以上でインストールは完了です。

注意:headerline 1.7から、デフォルトではキー割り当てをしなくなりました。 ユーザーのほうで、明示的にキー割り当てを行うようにしてください。なお以 降の説明では、F10に割り当てたものとして説明しています。

headerline.elの使い方:Java編

Javaプログラムを例にして、headerline.elの使い方を説明します。

まず、次のようなサンプルプログラム「Sample.java」をMuleで作成します。

/* Sample.java */
import java.util.*;

public class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public Point() {
        this(0, 0);
    }

    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

そして、モードがjava-modeであることを確認したうえで、F10キーを押します。 すると、画面が上下に分かれ、画面下に

の一覧が表示され、カーソルがそこに移動します。

ここで画面下の一覧において、適当な行にカーソルを移動しEnterキーを押し ます。すると、メソッドやインスタンス変数にジャンプします。

またEnterキーのかわりにC-jを押すと、ジャンプしたあとに一覧画面を消して くれます。

画面イメージ(イメージといっても画像じゃなくてホンマにイメージね。):

 +--------------------------------------+
 | /* Sample.java */                    |
 |                                      |
 | import java.util.*;                  |
 |                                      |
 | public class Point {                 |
 |     private int x;                   |
 |     private int y;                   |
 |                                      |
 |     public Point(int x, int y) {     | ←(2) ここにジャンプ
 |         this.x = x;                  |       してくれる。
 |         this.y = y;                  |       またC-jのときは
 |     }                                |       ジャンプしたあとに
 |     public Point() {                 |       下の一覧画面が消える。
 |         this(0, 0);                  |
 |     }                                |
 |======================================|
 | public class Point {                 |
 |     private int x;                   |
 |     private int y;                   |
 |     public Point(int x, int y) {     | ←(1) 例えばこの行に
 |     public Point() {                 |       カーソルを置いて
 |     public int getX() {              |       Enterキーを押すと…
 |     public int getY() {              |
 |======================================|
 +--------------------------------------+

headerline.elでは、他に以下のメジャーモード用のパターンを用意しています。

headerline.elの使い方:テキスト編

headerline.elはもともと、テキスト文章で見出しを一覧するために作成しま した。ここでは、テキスト文章での使い方を説明します。

テキスト文章でも使い方はJavaのときと同じですが、以下の点が異なります。

例えば、次のようなサンプル「sample.txt」があるとします。

●headerline.elを使おう
headerline.elは、見出し(章や節のタイトル)を
一覧で表示してくれる、自作EmacsLispです。
      ‥‥‥‥

◎headerline.elのインストール
headerline_1.2.zipをダウンロードして解凍し、
headerline.elをパスの通ったディレクトリに
置きます。
      ‥‥‥‥

◎headerline.elの使い方:Java編
Javaプログラムを例にして、headerline.elの
使い方を説明します。
      ‥‥‥‥

これをMuleで開きます。メジャーモードがtext-modeまたはfundamental-mode であることを確認してください。

そして、F10キーを押します。すると画面が左右に分割され、右の画面に見出 しの一覧が表示されます。

また見出しにカーソルを合わせてEnterキーを押すと、対応する見出しにジャ ンプするのも同じです。

画面イメージ:

+-----------------------------------------------------------------------+
| ●headerline.elを使おう            |●headerline.elを使お→|
| headerline.elは、見出し(章や節のタイトル)を |◎headerline.elのイン→|
| 一覧で表示してくれる、自作EmacsLispです。   |◎headerline.elの使い→|
|    ‥‥‥‥                |                  |
|                        |                  |
| ◎headerline.elのインストール         |                  |
| headerline_1.2.zipをダウンロードして解凍し、 |                  |
| headerline.elをパスの通ったディレクトリに   |                  |
| 置きます。                  |                  |
|    ‥‥‥‥                |                  |
|                        |                  |
| ◎headerline.elの使い方:Java編        |                  |
| Javaプログラムを例にして、headerline.elの   |                  |
| 使い方を説明します。             |                  |
|    ‥‥‥‥                |                  |
|=======================================================================|
+-----------------------------------------------------------------------+

次/前の見出しに移動する

headerline.elをロードすると、次のような関数が使えるようになります。

headerline-goto-next
カーソルの現在位置から、次の見出しに移動します。
headerline-goto-previous
カーソルの現在位置から、前の見出しに移動し ます。

画面イメージ:

+------------------------------------+
| ●headerline.elを使おう       |
| headerline.elは、見出し(章や節の  |←(1)ここにカーソルを置いて
| タイトル)を一覧で表示してくれる、 |     headerline-goto-nextを
|    ‥‥‥‥           |     実行すると…
|                   |
| ◎headerline.elのインストール    |←(2)ここに移動する。
| headerline_1.2.zipをダウンロード  |     もう一度実行すると…
| して解凍し、headerline.elをパスの  |
|    ‥‥‥‥           |
|                   |
| ◎headerline.elの使い方:Java編   |←(3)ここに移動する。
| Javaプログラムを例にして、     |     headerline-goto-previous
| headerline.elの使い方を説明します。|     を実行すると、前に戻る。
|    ‥‥‥‥           |
|====================================|
+------------------------------------+

デフォルトでは、両方ともキー割り当てがされていませんので、使用する場合 は.emacsに例えば次のように書いてください。

;; headerline.elのロード
(load-library "headerline")
;; キー割り当て(デフォルトではF10に割り当てられている)
;(global-set-key [C-F10] 'headerline)  ; Controll + F10


;; 次/前の見出しにジャンプする
(global-set-key "\M-n" 'headerline-goto-next)
(global-set-key "\M-p" 'headerline-goto-previous)

この例ではM-pとM-nに割り当てました。理由は、Muleのデフォルトではこの2 つにはキー割り当てがされていないからです。 M-pとM-pにすでに他の関数を 割り当てている場合は、別のキーに割り当ててください。

ちなみに筆者の場合は、M->とM-<に割り当てています。そして、もともとの M->とM-<に割り当てられていた関数(end-of-bufferとbeginning-of-buffer) はそれぞれC-q C-eとC-q C-aに割り当てています。

(global-set-key "\M->" 'headerline-goto-next)
(global-set-key "\M-<" 'headerline-goto-previous)

カスタマイズ:見出しのパターン

見出しのパターンは正規表現で指定します。またその正規表現は、メジャーモー ドごとに設定します。

見出しのパターンは、連想配列 headerline-pattern-alist に格納されていま す。デフォルトでは、次のような設定になっています。

(defvar *headerline-pattern-alist*
       '(
	 (text-mode . "^[=●◎○■□◆◇▼▽▲△★☆].*$\\|^\\.\\$.*$")
         (ruby-mode . "^[ \t]*\\(class\\|module\\|def\\)[ \t].*$")
         (java-mode . "^[ \t]*\\(class\\|abstract\\|public\\|protected\\|
private\\)[ \t].*$")
         (c-mode    . "^[a-zA-Z].*$")
         (c++-mode  . "^\\[a-zA-Z].*")
         (html-helper-mode . "<[hH][1-4].*</[hH][1-4]>")
         (yahtml-mode      . "<[hH][1-4].*</[hH][1-4]>")
         (emacs-lisp-mode  . "^(defun .*$\\|^(defvar .*$")
         (latex-mode       . "^\\\\\\(sub\\)*section.*\\|\\\\chapter.*")
         (yatex-mode       . "^\\\\\\(sub\\)*section.*\\|\\\\chapter.*")
         ))
この設定に追加したり上書きしたりするには、次のようにしてください。
(setq *headerline-pattern-alist*
      (append
       '(
	 (java-mode . "^\\(    \\)?[a-zA-Z].*")
	 (text-mode . "^[=●◎○].*")
	 )
       *headerline-pattern-alist*))

また現在のメジャーモードで見出しパターンが設定去れていない場合は、デフォ ルトの見出しパターンが使用されます。これは変数 headerline-default-pattern に格納されており、デフォルトでは次のように なっています1

(defvar *headerline-default-pattern*
        "^[=●◎○■□◆◇▼▽▲△★☆].*$\\|^\\.\\$.*$")

これを変更するには、例えば次のような記述を.emacsに追加してください。

(setq *headerline-default-pattern* "^=.*")

1 「.$」で始まる行がパターンに入っているのは、kwaterのためです。

カスタマイズ:画面分割の方向と幅

画面の分割を、上下に分割するか左右に分割するかをメジャーモードごとに設 定できます。また分割したときの幅も設定できます。

これは、連想配列 headerline-split-window-params-alist で行います。デフォ ルトでは次のようになっています。「25」や「10」が幅を、「t」や「nil」が 分割の方向を表しています(tなら左右、nilなら上下)。

(defvar *headerline-split-window-params-alist*
  '(
    (text-mode        25 t)
    (ruby-mode        25 t)
    (java-mode        10 nil)
    (c-mode           10 nil)
    (c++-mode         10 nil)
    (html-helper-mode 25 t)
    (yahtml-mode      25 t)
    (emacs-lisp-mode  10 nil)
    (latex-mode       10 nil)
    (yatex-mode       10 nil)
    ))
例えばJavaではメソッド名やパラメータ名が長くなるので、デフォルトでは上 下に分割し、画面の幅を広く使えるようにしています。またRubyならメソッド 名もパラメータ名も短く、表示幅が狭くても問題ないので、左右に分割してい ます。

この設定に変更や追加をするには、例えば次のようにします。

(setq *headerline-split-window-params-alist*
      (append
       '(
         (java-mode 35 t)    ; t は縦に分割
         (text-mode 12 nil)  ; nil は横に分割
         )
       *headerline-split-window-params-alist*))
また現在のメジャーモードでの設定がない場合は、デフォルトの設定が使用さ れます。これは変数 headerline-split-window-default-params で設定されて おり、デフォルトでは次のようになっています。
(defvar *headerline-split-window-default-params* '(25 t))
この設定を変更するには、次のような記述を.emacsに追加します。
(setq *headerline-split-window-default-params* '(30 nil))

類似機能との比較

headerline.elと似た機能を提供するものとして、次のようなものがあります。

tags-search
いわゆるタグジャンプ機能です。etagsというコマンドを使っ て関数名とファイル名と行番号のリストを作っておき、任意の関数にジャンプ する機能です。Emacs標準機能です。headerline.elと違って、異なるファイル へのジャンプもできます。

ただしetagsというコマンドが対応している言語(C言語など)でしか使用でき ませんので、テキスト文章の見出しなどでは使用できません。もっというと、 etagsが作成するタグファイルの形式であれば他の言語でも対応可能ですが、 headerline.elほど簡単には対応できません。

navi.el
http://www.ne.jp/asahi/love/suna/pub/soft/navi.el/ で公開さ れているEmacsLispスクリプトです。headerline.elとかなり似ています。

ただし、こちらも対応している言語は限られているようで、headerline.elほ ど柔軟には設定できないようです。また関数へのジャンプは文字列で検索して いるため、例えばC言語のプロトタイプ宣言がある場合では正しくジャンプで きません。

そのほか、headerline.elでは次/前の見出しや関数に移動するコマンドが用意 されていますが、上の2つにはありません。

どちらにしても、これらを置き換える目的でheaderline.elを作ったわけでは ありませんので、気に入ったものを使えばいいと思います。

コンパイルを楽にしよう!

コンパイルコマンドを変更する

Muleでは M-x compile を実行することで、Muleからコンパイルを実行するこ とができます。しかしコンパイルコマンドはいつも "make -k" となっていて 不便です。これを変更してもっと便利にしましょう。

コンパイルを行うときのコマンドは、変数 compile-command に格納されてい ます。そこで、これを次のような方針で変更します。

以下を自分の .emacs に加えてください。

(add-hook
 'java-mode-hook
 '(lambda ()
    ;; コンパイルコマンドの設定
    (make-local-variable 'compile-command)
    (setq compile-command
          (concat "javac "
                  (file-name-nondirectory buffer-file-name)))
    ))

(add-hook
 'c-mode-hook
 '(lambda ()
    ;; コンパイルコマンドの設定
    (make-local-variable 'compile-command)
    (set-compile-command-for-c)
    ))

(defun set-compile-command-for-c ()
  (interactive)
  (let* ((filename (file-name-nondirectory buffer-file-name))
         (index (string-match "\\.c$" filename))
         (filename-no-suffix (substring filename 0 index)))
    (cond
     ;; make用のファイルがあれば "make -k"
     ((or (file-exists-p "Makefile")
          (file-exists-p "makefile"))
      (setq compile-command "make -k"))
     ;; ヘッダファイルがあれば、オブジェクトファイルをつくる
     ((file-exists-p (concat filename-no-suffix ".h"))
      (setq compile-command
            (concat "gcc -ansi -Wall -g -c " filename)))
     ;; それ以外
     (t
      (setq compile-command
            (concat "gcc -ansi -Wall -g -o "
                    filename-no-suffix " " filename))))))

コンパイルウィンドウを小さくする

M-x compile でコンパイルを行うと、画面が2つに分割され、上にプログラム コードが、下にコンパイルウィンドウが表示されます。しかし、コンパイルウィ ンドウは画面の半分を占めなくても、もっと小さい大きさのウィンドウで十分 なことも多いです。そんなときは、次のEmacs Lispを自分の .emacs に書いて 下さい。

;; コンパイルウインドウの大きさを制限する
(setq compilation-window-height 8)	;; 高さ8行
これで、コンパイルするたびに C-x 1 を実行しなくてすみます。

もしコンパイルエラーがたくさん出て、コンパイルウィンドウを大きくしたい 場合は、モード行(白黒反転している行のことです)をマウスでドラッグし、 上下に動かしてみてください。コンパイルウィンドウの大きさを大きくするこ とができます。

そのほか

コンパイルを行う関数 compile は、標準ではキーに割り当てられていません。 しょっちゅう使う関数ですので、「キー割り当てを変更しよう!」を参考にし てどこかのキーに割り当てておきましょう。例えば M-p に割り当てるのでし たら、以下のようにでもしてください。

;; M-p でコンパイル
(global-set-key "\M-p" 'compile)

また、関数compileでコンパイルしたら、C-x ` でエラー箇所にジャンプし ましょう。いちいち行番号を探す必要がなくなります。

この、エラー箇所へのジャンプ機能は非常に便利です。作業効率がグンと上が りますので、ぜひ使ってみてください。

Rectangle機能を使おう!

Muleでは、矩形編集ができます(矩形「くけい」とは、長方形のこと)。

例えば、次のようなファイルがあったとします。

	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
ここで、一行目の f にカーソルを持っていき、 C-SPC(Ctrlキーを押しなが らSpaceキー)を押します。次に最後の行の q にカーソルを持っていき、 C-x r k (Ctrlキーを押しながら x を押し、Ctrlキーを離して r k )と押します。 すると、以下のように f から p までが切り取られます。 C-x r k は、矩形 領域を切り取る機能なのです。
	abcdeqrstuvwxyz
	abcdeqrstuvwxyz
	abcdeqrstuvwxyz
	abcdeqrstuvwxyz
次に、一行目の v にカーソルを移動し、C-x r y を押します。すると、先ほ ど切り取った矩形が貼り付けられました。 C-x r y は、切り取った矩形を貼 り付ける機能なのです。
	abcdeqrstufghijklmnopvwxyz
	abcdeqrstufghijklmnopvwxyz
	abcdeqrstufghijklmnopvwxyz
	abcdeqrstufghijklmnopvwxyz
このほかにも、Muleには様々な矩形編集機能があります。簡単に紹介しますの で、自分で動作を確かめて下さい。
C-x r k	kill-rectangle	(矩形を切り取る。C-x r y で貼り付けられる) 
C-x r c	clear-rectangle	(矩形領域を空白に変換する) 
C-x r o	open-rectangle	(矩形領域ぶんの場所をあける) 
C-x r y	yank-rectangle	(C-x r kで切り取った矩形を貼り付ける) 
C-x r d	delete-rectangle	(矩形を削除する。C-x r y で貼り付けられない) 
C-x r t	string-rectangle	(矩形領域に文字列を埋め込む) 

特に、最後の string-rectangle は便利ですので紹介しておきます。

例えば、先ほどのファイルで、

	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
	abcdefghijklmnopqrstuvwxyz
一行目の k で C-SPC を押し、最後の行の k にカーソルを移動したとします。 ここで C-x r t と押すと、ミニバッファに String rectangle: と聞かれます ので、例えば FOOBAR と入力してリターンキーを押します。すると、
	abcdefghijFOOBARklmnopqrstuvwxyz
	abcdefghijFOOBARklmnopqrstuvwxyz
	abcdefghijFOOBARklmnopqrstuvwxyz
	abcdefghijFOOBARklmnopqrstuvwxyz
のように、指定した文字列が縦に連なって挿入されます。

この機能は、プログラムやスクリプトをコメントアウトするときに便利です。 例えばシェルスクリプトを書いていて、ある範囲をコメントアウトしたいとき は、範囲を指定して C-x r t を押し、ミニバッファに # を入力すればコメン トアウトできます。コメントを外したいときは、C-x r d または C-x r k を 使ってください。

ところで、矩形領域の編集機能として、切り取りや削除の機能はあってもコピー の機能がない、つまり copy-rectangle という関数がないことに気がつかれた でしょうか。

そうです、ないんです。しかし、

  1. C-x r k で矩形領域を切り取る
  2. C-_ でもとに戻す
  3. C-x r y で貼り付ける

でコピーと同じようなことができますので、問題ないでしょう。私はいつもこ うしています。

実は copy-rectangle-to-register という関数があるのですが、使ったこと ないです。すみません。

一行入力を簡素化しよう!

会社におくるメールにはいつも「拝啓 時下ますますご清栄のこととお喜び申 し上げます。」と入力しなければならず面倒だ、

あるいは、Javaの例外は名前が長ったらしくて、入力が面倒なうえに覚えられ ない、

そんな方のために、EZ-insert-mode なるものを作ってみました。 EZ-insert-modeを使うことにより、

という効果があり、あなたのストレスを70%削減します(期待値)。

EZ-insert-modeを使うためにはまず、この文章のいちばん最後にのせてある Emacs-Lisp を自分の .emacs にコピーしてください。そして自分のホームディ レクトリに lib/emacs/ez-insert というディレクトリを作り、その中に EZ-insert用のファイル(入力したい行を記述したファイル)を、メジャーモー ドごとに用意します。ファイルの拡張子は ".ez" にしてください。

例えば、Fundamentalモード用のファイル Fundamental.ez を用意し、以下の ような内容を書いたとします。

拝啓 時下ますますご清栄のこととお喜び申し上げます。
拝啓 貴社におかれましてはますますご清栄のこととお喜び申し上げます。
前略 この度は大変お世話になりました。
	・・・・・・・・・・

そして、Fundamentalモードでメールの原稿を書いているときに、 M-x ez-insert とします。すると、別のウィンドウに先ほどの内容が表示されます ので、ここで入力したい行にカーソルをあわせ、 i または C-i を押すと、も との原稿にその行が挿入されます。

また、このときに q または C-q を押せば、何も入力しないでもとの原稿に戻 りますし、 C-x C-q を押せば登録内容を変更できます(変更したら、C-x C-q を押してください)。

ほかにも、例えば「JavaのExceptionは入力するのも面倒だが、どんなのがあ るのか調べるのも面倒だ」という方なら、 Javaモード用に Java.ez というファ イルを用意し、

URLNotFoundException
FileNotFoundException
	・・・・・
と記述しておけば、これらの入力が、一覧表示された中から選ぶだけというと ても簡単な作業になってくれます。

頻繁に入力するものを支援するのが EZ-insert ですので、ぜひキーに割り当 てて使いましょう。私は F8 に割り当てています。

(global-set-key [f8] 'ez-insert)

それでは EZ-insert.el をお使いください。

;;;
;;; EZ-insert  --- よく入力する一行をあらかじめ登録しておき、
;;;                入力を支援する
;;;

;;
;; モードごとに行を登録するためのファイルを用意する。
;; そのファイルが置かれてあるディレクトリを指定する。
(defvar ez-insert-directory
  (expand-file-name "~/lib/emacs/ez-insert/")
  "must be ended with \"/\"."
  )

;;; -------------

(defvar ez-insert-mode-map (make-sparse-keymap)
  "the keymap in used in ez-insert-mode.")
(define-key ez-insert-mode-map "\C-i"    'ez-insert-insert)
(define-key ez-insert-mode-map "i"    'ez-insert-insert)
(define-key ez-insert-mode-map "\C-q"    'ez-insert-quit)
(define-key ez-insert-mode-map "q"    'ez-insert-quit)

(defun ez-insert-mode ()
  (kill-all-local-variables)
  (make-local-variable 'mode-line-process)
  (make-local-variable 'minor-mode-alist)
  (mapcar '(lambda (minmode)
	     (set (car minmode) nil))
	  minor-mode-alist)
  (use-local-map ez-insert-mode-map)
  (setq mode-name "EZinst")
  ;;(setq mode-line-process (concat ": "
  ;;				   ez-insert-cur-txt
  ;;				   "/"
  ;;				   ez-insert-max-txt))
  (setq buffer-read-only t)
  (setq major-mode 'ez-insert-mode)
  (goto-char (point-min))
  ;(run-hooks 'ez-insert-hook)
  ;(setq buffer-read-only nil)
  )

(defun ez-insert ()
  (interactive)
  (let ((filename
	 (concat ez-insert-directory mode-name ".ez")))
    (find-file-other-window filename)
    (rename-buffer (concat "EZ-insert (" mode-name ")"))
    (ez-insert-mode)
    ;(shrink-window (- (window-height) 5))
    ;(goto-char (point-min))
    ))

(defun ez-insert-insert ()
  (interactive)
  (let (pos)
    (beginning-of-line)
    (setq pos (point))
    (end-of-line)
    (copy-region-as-kill pos (point))
    )
  (kill-buffer (buffer-name))
  (delete-window)
  (yank)
  )

(defun ez-insert-quit ()
  (interactive)
  (kill-buffer (buffer-name))
  (delete-window)
  )

その他、便利な機能

その他の、細かいが便利な機能やカスタマイズについて書きます。

余分な空白を削除する

次に紹介するEmacs Lispは、プログラマーにとってうれしい、次のような機能 を提供します。

自分の .emacs に以下のEmacs Lispを記述します。空白を削除したいファイル を開き、M-x trim-buffer として実行してください。

;;; 余分な空白を削除する
(defun trim-buffer ()
  "Delete excess white space."
  (interactive)
  (save-excursion
    ;; 行末の空白を削除する
    (goto-char (point-min))
    (while (re-search-forward "[ \t]+$" nil t)
      (replace-match "" nil nil))
    ;; ファイルの終わりにある空白行を削除する
    (goto-char (point-max))
    (delete-blank-lines)
    ;; タブに変換できる空白は変換する
    (mark-whole-buffer)
    (tabify (region-beginning) (region-end))
    ))

いちいち呼び出すのが面倒くさいときは、ファイルをセーブしたときに自動的 に実行させることができます。

(add-hook 'write-file-hooks
	  '(lambda ()
	     (trim-buffer)))

問題がひとつあります。プログラムを書いているときには、タブに変換して欲 しくない空白などもあります。しかし、このEmacs Lispはそういった空白もタ ブに変換してしまいます。その場合は、空白をタブに変換する部分をコメント アウトしてください。

参考:「プログラマに捧げる GNU Emacs ガイドブック」

        亀井 信義、舘野 信行 著、技術評論社発行、1993

大文字を簡単に入力する

Cのマクロ定数、あるいはJavaのfinal変数のように、大文字を連続して入力す ることがよくあると思います。それを支援してくれるのが、次の関数です。

(defun changecase-word (cnt)
  "カーソルのすぐ左にある単語を大文字→先頭だけ大文字→小文字にする。"
  (interactive "p")
  (if (not (eq last-command 'changecase-word))
	 (setq changecase-word-type 0))
  (cond ((= changecase-word-type 0)
	  (upcase-word (- cnt))
	  (setq changecase-word-type 1))
	 ((= changecase-word-type 1)
	  (capitalize-word (- cnt))
	  (setq changecase-word-type 2))
	 (t
	  (downcase-word (- cnt))
	  (setq changecase-word-type 0))))
;; C-u に割り当てる
(global-set-key "\C-u" 'changecase-word)

C-u を押すと、カーソルのすぐ左にある単語がすべて大文字になります。

もう一度 C-u を押すと、最初の文字だけ大文字になります。

もう一度 C-u を押すと、すべて小文字になります。

C-u を押すたびに、これが繰り返されます。

(注:デフォルトでは C-u には関数 universal-argument が割り当てられて います。これを使いたい人は、別のキーに割り当て直してください。)

プログラムを整形する

プログラムを整形する(インデントする)のに、M-C-\(関数indent-region) が使えます。リージョンを指定しておき、M-C-\ を押すと、指定した範囲がイ ンデントされます。

しかし、いちいちリージョンを指定して M-C-\ を押す、というのは(少なく とも私にとっては)面倒くさい。もっと簡単にする方法がないか…ということ で作ったのが次の関数です。

;;; インデントして、次の行に移動する
(defun indent-and-next-line ()
  (interactive)
  (indent-according-to-mode)
  (next-line 1))

;;; M-n に割り当てる
(define-key global-map "\en" 'indent-and-next-line)
関数indent-and-next-lineは、カーソルのある行をインデントして次の行に移 動するというものです。ここではこの関数を M-n に割り当てています。

使い方は、インデントしたい範囲の先頭行にカーソルを持っていき、M-nを押 し続けます。すると次々と行がインデントされていきます。

はっきりいって、これはかなり便利です。なんでこの関数が標準でないんや! といいたくなるくらい便利です。ぜひ使ってみてください。

中身を確認して貼り付ける

Muleでは、C-k や C-w や M-w で切り取ったテキストを C-y で貼り付けます。 C-y で貼り付けた直後に M-y を押すと、以前に切り取ったテキストを替わり に貼り付ける(ペーストする)ことができます。もう一度 M-y を押すと、そ の前に切り取ったテキストを貼り付けます。M-y を次々と押すことで、今まで 切り取ったテキストをさかのぼって貼り付けられます。

しかし、切り取ったテキストをさかのぼって貼り付けるなら、もっと便利なも のがあります。それがbrowse-yank.elです。これをここから、あるいはここから 取ってきて、解凍し、自分のロードパスが通っているところにおいてくださ い。そして、以下を自分の .emacs に加えてください。

;;; yank が便利になる browse-yank.el
(autoload 'browse-yank "browse-yank" nil t)
(global-set-key "\C-x\C-y" 'browse-yank)	; C-x C-y に割り当てる
使い方は、以前切り取ったテキストを貼り付けたくなったら、C-x C-y を押し ます。すると、新しいバッファ(*Browse Yank* バッファ)が開かれ、そこに カーソルが移動します。このバッファには、最も最近に切り取ったテキストが 表示されます。

ここで p を押すと、その前に切り取ったテキストが表示されます。

もう一度 p を押すと、またその前に切り取ったテキストが表示されます。

このように p を押すことで、今まで切り取ったテキストの内容をみることが できます。

ちなみに n を押すと、さかのぼるのではなく、新しいほうのテキストが表示 されます。

さて、 p と n で貼り付けたいテキストを見つけたら、 i を押します。する と、そのテキストが元の文章に貼り付けられます。 Browse Yank バッファは 自動的に閉じられます。

i の替わりに q (または C-g)を押すと、貼り付けるのを取り消します。

e を押すと、貼り付ける内容を編集することができます。

h を押すと、クイックヘルプが表示されます。

? を押すと、詳しいヘルプが表示されます。詳しいことはこのヘルプを参照し てください。

browse-yank は、貼り付けるテキストを確認してから貼り付けられるので、安 心できます。使い方を文章で説明すると分かりにくいですが、使ってみれば分 かると思います。

罫線を入力する

keisen-mule.el というありがたいシロモノがあります。使用するには、 keisen-mule.elをとってきて、パスの通っているディレクトリに入れてくださ い。そして、.emacs に以下のように書き加えます。

;;; 罫線の入力支援
(autoload 'keisen-mule "keisen-mule" nil t)

使い方を簡単に紹介します。

これ以上のことは、C-h m を押してヘルプをご覧ください。

ただし、まだバグがあるようで、ときどき動作がおかしくなることがあります。 特に Mule for Win32 で使用した場合、日本語の入力がおかしくなります。そ んな時はいったん終了して、もう一度起動しましょう。面倒ですけどね。

バッファ移動を便利にする

Muleで C-x C-b を押すと、画面が2分割されてバッファの一覧が表示されます。 この一覧を表示しているウィンドウは Buffer Menu モードになっています。 C-x o を押してその一覧ウィンドウに移動し、任意のバッファにカーソルを合 わせて f を押すと、そのバッファを開くことができます。他にも以下のよう なコマンドが使用できます。

f	そのバッファを開く。画面は分割されたまま。 
o	そのバッファを別のウィンドウで開く。画面は分割されたまま。 
C-o	o と同じだが、カーソルがバッファ一覧から移動しない。 
1	そのバッファを開く。画面はひとつになる。 
2	f と同じだがバッファ一覧は消える。 
C-k	削除マークをつけて下に一行移動 
C-d	削除マークをつけて上に一行移動 
x	削除マークをつけたバッファを削除 

Buffer Menuモードで使えるマンドは他にもありますので、 C-h m でモードの ヘルプをご覧ください。

ところで、 C-x C-b を押してバッファの一覧を表示させたあと、 C-x o を押 さないとその一覧に移動しないというのは不便です。できれば C-x C-b を押 したらカーソルもバッファの一覧に移動してくれたほうが便利です。そこで、 以下のようなカスタマイズをしてみました。

;;; C-x C-b で表示した *Buffer List* に移動する
(defun my-list-buffers ()
  (interactive)
  (list-buffers)
  (pop-to-buffer "*Buffer List*")
  (goto-line 4)		; これはお好みでどうぞ。
  )
;;; C-x C-b に割り当てる
(global-set-key "\C-x\C-b" 'my-list-buffers)
;;; Buffer Menu モードで C-m つまり Return に 1 と同じ機能を
;;; 割り当てる。お好みでどうぞ。
(define-key Buffer-menu-mode-map "\C-m" 'Buffer-menu-1-window)

これで、バッファの一覧を表示すると同時にその一覧に移動するようになりま した。おまけに、ひとつ前のバッファにカーソルが移動するようにしましたの で、このまま 1 あるいは Retrun を押せばバッファを「入れ替える」ことが できます( C-x b と同じ機能ですね)。文章で説明しにくいので、実際に使っ て試してください。

改行文字を置換する

M-% で、文字列の置換ができることは知っている人も多いでしょう。しかし、 改行文字も置換できることはあまり知られてないのではないでしょうか。

例えば、以下のような名前のリストがあったとします。

   鈴木 洋
   佐藤 ひろし
   渡辺 広志
   タナカ ヒロシ
この名前のリストに、敬称として「様」をつけたいとします。こんなとき、あ なたならどうしますか?正規表現を使った文字列置換(M-x replace-regexp) を使うのが普通かもしれませんが、実は通常の文字列置換でもできます。それ は、C-q C-j とすれば改行文字が入力できるからです。

先ほどの名前リストで試してみましょう。カーソルをバッファの先頭にもって いき、以下の通りにやってみてください。

  1. M-% を押す
  2. ミニバッファで Query replace: と聞かれるので C-q C-j と押して リター ンキーを押す
  3. ミニバッファに with: と出てきたら、「様」と入力し、 C-q C-j を押し、 リターンキーを押す。

あとは通常の文字列置換と同じです。 y またはスペースでひとつずつ置換す る、n または BackSpace で置換しない、 ! で全部を置換する、ができます。

3番目の手順で、C-q C-j を押さなかったら改行文字がなくなってしまい、全 部一行になってしまいます。注意してください。逆にいえば、一行にまとめた いときは押さなければいいわけです。

また、3番目を少し変えて、「様」と入力して C-q C-j を押し、「当選 」と 入力してリターンキーを押せば、

   当選 鈴木 洋様
   当選 佐藤 ひろし様
   ・・・・・
となります。

日付を入力する

今日の日付を簡単に入力する関数を書いてみました。 '8/29(Wed)'のような形 式で日付をカーソル位置に挿入します。引数 N を渡すと、N日前の日付まで挿 入してくれます。うるう年には対応していませんが、日記を書いたりするぶん には充分でしょう。

これをつかうには、M-x my-insert-date と呼び出すか、あるいはどれかのキー に割り当てて呼び出して下さい。引数を渡すには、呼び出す前に M-n を押し てください。

;; F5キーに割り当てる
;(define-key global-map [f5] 'my-insert-date)

;;;
;;; 日付入力関数
;;;
(defun my-insert-date (arg)
  "'8/29(Wed)'のような形式で日付を挿入する。
引数 N を渡すと、N日前の日付まで挿入する。"
  (interactive "p")
  (if (not arg) (setq arg 1))
  (let* ((time (current-time-string))
	 (weekday (substring time 0 3))
	 (monthname (substring time 4 7))
	 (index (string-match
		 monthname "JanFebMarAprMayJunJulAugSepOctNovDec"))
	 (month (+ 1 (/ index 3)))
	 (day (string-to-number (substring time 8 10)))
	 )
    (my-insert-date-body arg month day weekday)
    ))


(defun my-insert-date-body (arg month day weekday)
  ;; 日付を挿入する
  (insert
   ;; *** この行を変えれば、書式が変えられます! *******
   (concat month "/" day "(" weekday ")\n\n")
   )
  ;; arg > 1 なら、前日の日付も挿入する
  (if (> arg 1)
      (progn
	;; 前日の日にちを求める
	(setq day (- day 1))
	(if (= day 0)
	    (progn
	      (setq month (- month 1))  ;; 前の月
	      (if (= month 0) (setq month 12))
	      (setq day	 	        ;; 日にち
		    (nth month
			 '(0 31 28 31 30 31 30 31 31 30 31 30 31)))
	      ))
	;; 前日の曜日を求める
	(let* (
	       ;; "Sat" から始まって "Sat" で終わっているのがミソ
	       (weekdays "SatSunMonTueWedThuFriSat")
	       ;; 検索するのは先頭からではなく3文字目から
	       (index1 (string-match weekday weekdays 3))
	       ;; 前日の曜日
	       (index2 (- index1 3))
	       )
	  (setq weekday
		(substring weekdays index2 (+ 3 index2)))
	  ) ; let end
	;; 前日の日付を挿入する
	(my-insert-date-body (- arg 1) month day weekday)
	))
  ) ; defun end

Muleに関するリンク集

リンク切れが多かったので、更新しました。

プログラマに捧げる GNU Emacs ガイドブック
主に亀井信義さんが書かれ た、Emacsのガイドブックです。私もこの本を買って勉強しました。この本な しではこのページも生まれなかったでしょう。亀井さん、ありがとうございま した。
GNU Emacs Manual 日本語版
Emacs の日本語マニュアルです。 バージョン が18ですのでちと古いですが、十分参考になります。
GNU Emacs Lisp Reference Manual
GNU Emacs Lisp の、日本語マニュアル です。これに限らず、http://flex.ee.uec.ac.jp/texi には役に立つドキュメ ントが数多くあります。
GNU Emacs Lisp 入門
Robert J. Chassell 氏が書かれた入門書を日本語に 訳したものです。 マニュアルを読んでも何のことやら分からない人はこちら をどうぞ。
「便利に使おう Mule for Windows 活用入門」
Mule for Win の作者、宮 下 尚さんによる解説書の紹介です。
HIROSE Yuuji
TeX/LaTeX入力支援環境「YaTeX(野鳥、やてふ)」の 作者、広瀬さんのページです。
Gnus Japanese Texinfo (based on 5.0.12)
Mule で使うニュースリーダ Gnus のマニュアルを日本語訳したものが、下のほうにあります。
Emacs活用法
中級者向けのページです。狙いはこのページと同じですね。
CC MODE Version 4 Documentation
cc-mode ver.5 のマニュアルです。た だし、全部英語。
CC Mode Version 5
cc-mode の(おそらく公式の)ホームページです。
Muleの基本操作
よくあるオンライン入門書です。
Emacs Beginner's HOWTO
初心者に向けた、Emacsの簡単な紹介です。