エディタの効率的な操作

初回のトラブルによるタイムロスへの対処として, このページの内容については省略します.

テキストエディタはC言語プログラミングに不可欠な道具です. 世の中には様々なエディタが存在しますが, この授業では,Unix の伝統的なエディタ「 vi 」の改良版「 Vim 」(Vi IMproved)を推奨します. Vim の操作方法を修得し,プログラミングの作業効率を高めましょう.

一般人向けのエディタ (Linux の gedit や nano とか Windows の notepad(メモ帳)等) では,特別な訓練を必要とせず,誰でもすぐに使い始められるが, 作業を効率的に進めるための機能は貧弱であることが多い. 一方,Vim や vi では,操作方法に多少のクセはあるものの, 慣れてしまえば,異常に高速な編集作業が可能になるだろう.
今回は Vim を使うが,どうしても馴染めない場合, 次回からは gedit や nano でもOK.
使うエディタは何であれ,必ず, 作業効率を高めるよう意識・工夫・努力してください.

準備

ディレクトリの準備

前回と同様に, 端末を開き,作業用ディレクトリを準備しよう:

$ cd		# ホームディレクトリへ移動
$ mkdir  p-1106	# 本日の作業用ディレクトリを作成
$ cd  p-1106	# 作業用ディレクトリへ移動
# または
$ cd  !$	# !$ は直前のコマンドの引数 p-1106 に置き換わる
エディタ nano の試用

まず今日は,反省文「I'm sorry」を 100回書け!! 一般人向けのエディタ nano では:

$ nano  sorry.txt
I'm sorry.
I'm sorry.
I'm sorry.
...

「パワハラかよ?」と叱られそうなので, これは100回まで書かなくても構いません.

「面倒くさい」と思う気持ちが大切. 楽にできる方法でやろう.
もちろん「面倒なのでやらない」は NG.

nano でもカット・アンド・ペースト すれば多少は楽に実行できますが...

nano のキー操作: カットは [Ctrl]+[K],ペーストは [Ctrl]+[U], 保存は [Ctrl]+[O],終了は [Ctrl]+[X].
エディタ Vim の試用

より,効率的な作業方法として,Vim を使ってみよう:

$ vim  sorry.txt

まず,1行だけ入力しよう. 最初に [i] キーを押して挿入モードへ移ってから...:

I'm sorry.		# 末尾で改行([Enter] or [Return] キー)

次に,カーソルキー(矢印キー)を使って,第1行へカーソルを移動し, 続けて [Esc][y][y][9][9][p] キーを操作しよう:

Esc でノーマルモードへ戻り, yy が1行コピー, 99p が 99回ペースト, ってこと.
困った時は,[Esc](エスケープ)キー.

こうなるハズ:

I'm sorry.
I'm sorry.
I'm sorry.
...
I'm sorry.

これで1行が 100行に簡単に増えた. 素晴らしい. もし,1,000行とか 1,000,000行にしたくても, 労力はほとんど変わらない.

そして最後に [:][w][q][Enter] キーで保存・終了となる.


本日の作業

Vim の操作方法の修得
自習用プログラム

Vim の操作方法について,自習用プログラム vimtutor を利用して学習しよう:

$ vimtutor		# 日本語版
# または
$ LANG=C  vimtutor	# English version

最低限,レッスン3までは終わらせよう.

最低限のキー操作

次のコマンドは是非ともおぼえよう:

また,コマンドによっては,回数を指定して繰り返せたりもする. 例:[1][0][x] で 10文字削除.

vi や Vim での編集作業を効率化するということは, 編集作業の手順をプログラミングするということだ. プログラマに愛されて約 50 年も存続している理由だろう.
「ゲームっぽいプログラム」の開発

端末内でキャラクタを上下左右に操作できるようなプログラムを開発しよう. C言語のソースファイルを Vim で効率的に編集しましょう.

Step 0. 基本プログラムを作ってみる.

ソースを編集:

$ vim  game.c
#include <ncurses.h>	// 端末制御に必要
	// 制御対象は文字端末内の入出力装置(画面とキーボード)

int main(void)
{
	int	x = 10, y = 10;	// キャラの位置(xは右方向,yは下方向)

	initscr();		// 端末制御を開始
	while (1) {		// ひたすら繰り返す
		move(y, x);		// カーソル(表示位置)を移動
		printw("(^o^)");	// キャラを表示
		getch();		// キー入力を待つ
		x++; y--;		// キャラの位置を変更
	}
	endwin();		// 端末制御を終了
	return (0);
}
この段階では,特別な技は必要ないハズ. [i] と [Esc] と [x] とカーソル移動,そして,「:wq」.
顔文字の内容は自分好みに変えてOK. Vim の置換コマンド「cw」を使うとよい.
今回のソースコードについては, 本科目の目的から脱線しているので, 理解しなくても OK. 操作方法の練習に集中しよう.

コンパイルと実行:

$ cc  game.c  -lncurses  -o  game
$ ./game
端末制御機能を利用するために, コンパイルの際,ncurses ライブラリをリンクしている.

何かキーを押すと,キャラが移動するよ.

しかし,移動方向は固定(右上だけ)だし, 画面からハミ出すと異常動作におちいる. また,画面にゴミ(キャラの跡,キーの文字)を残してしまうし, カーソルも目障りだ. 正常終了もできないので,[Ctrl]+[C] で強制終了しよう.


Step 1. キャラの移動方向をコントロールしてみる.

ソースを改造:

#include <ncurses.h>

int main(void)
{
	int	x = 10, y = 10;
	int	key;			// 入力キーの文字が入る

	initscr();
	noecho();			// 入力キーは表示するなよ
	curs_set(0);			// カーソルは表示するなよ
	while (1) {
		erase();		// 画面全体をクリア(跡を残さない)
		move(y, x);
		printw("(^o^)");
		key = getch();		// キー入力を待ち,文字も調べる
		if (key == 'h') { x--; }	// キーの文字に応じた方向へ移動
		if (key == 'j') { y++; }
		if (key == 'k') { y--; }
		if (key == 'l') { x++; }
		if (key == 'q') break;	// [Q]キーで繰り返しを終了
		// これら5個のほぼ同じ行を Vim で効率的に編集せよ.
		// 1個は手動入力,他はコピペ(yy,4p)と置換(r や cw)等で
	}
	endwin();
	return (0);
}
行の追加は [o].

コンパイルして実行...

キャラを [h],[j],[k],[l] キーで上下左右に移動できるようになったね.

Vim のカーソル移動コマンドの練習にもなるよね.

画面からゴミは消えたし,[q] キーで正常終了も可能になりました. しかしまだ,ハミ出すとダメです.


Step 2. キャラがハミ出さないようにしてみる.
#include <ncurses.h>

int main(void)
{
	int	x = 10, y = 10;
	int	key;
	int	w, h;			// 画面の幅と高さ(width,height)
	char	*face = "(^o^)";	// キャラの顔文字
	int	size = 5;		// 顔文字の文字数

	initscr();
	noecho();
	curs_set(0);
	getmaxyx(stdscr, h, w);		// 画面サイズを調べ,h と w に代入
	while (1) {
		erase();
		move(y, x);
		printw(face);		// 顔文字は変数化したよ
		key = getch();
		if (key == 'h') { x--; }
		if (key == 'j') { y++; }
		if (key == 'k') { y--; }
		if (key == 'l') { x++; }
		if (key == 'q') break;

		if (x < 0) x = 0;	// ハミ出したら画面内に戻す
		if (x + size >= w) x = w - size;	// 「>=」は数学の不等号「≧」と同意
		if (y < 0) y = 0;
		if (y >= h) y = h - 1;
		// これら4行も Vim で効率的に編集せよ
	}
	endwin();
	return (0);
}

画面上の位置はゼロから数えることに注意しよう. 画面の幅が w なら,x = 0 〜 w-1 が画面内, x < 0 や x ≧ w は画面外ですよ.


Step 3. キャラの表示を変化させてみる.
#include <ncurses.h>

int main(void)
{
	int	x = 10, y = 10;
	int	key;
	int	w, h;
	char	*lt="d^ ))";	// 左向き顔(left)
	char	*rt="(( ^b";	// 右向き顔(right)
	char	*dn="(^o^)";	// 正面顔(下方向 down)
	char	*up="((*))";	// 後ろ頭(上方向 up)
	// これら類似の4行も Vim で効率的に編集せよ
	char	*face = dn;	// 最初は正面顔にしておく
	int	size = 5;

	initscr();
	noecho();
	curs_set(0);
	getmaxyx(stdscr, h, w);
	while (1) {
		erase();
		move(y, x);
		printw(face);
		key = getch();
		if (key == 'h') { x--; face = lt; }	// 方向に応じて顔を変更
		if (key == 'j') { y++; face = dn; }
		if (key == 'k') { y--; face = up; }
		if (key == 'l') { x++; face = rt; }
		// これら類似の4行も Vim で...
		if (key == 'q') break;

		if (x < 0) x = 0;
		if (x + size > w) x = w - size;
		if (y < 0) y = 0;
		if (y > h) y = h - 1;
	}
	endwin();
	return (0);
}

ちょっとだけ面白くなった?


Step 4. 目標地点(旗)を出現させてみる.

#include <ncurses.h>
#include <stdlib.h>	// 乱数 rand() に必要

int main(void)
{
	int	x = 10, y = 10;
	int	key;
	int	w, h;
	char	*lt="d^ ))";
	char	*rt="(( ^b";
	char	*dn="(^o^)";
	char	*up="((*))";
	char	*face = dn;
	int	size = 5;

	char	*flag="__P__";	// 旗の絵文字
	int	f = 0;		// 旗の有無
	int	fx, fy;		// 旗の位置

	initscr();
	noecho();
	curs_set(0);
	getmaxyx(stdscr, h, w);
	while (1) {
		erase();
		if (f == 0) {	// 旗が無い場合...
			fx = rand()%20;		// ランダムな位置に...
			fy = rand()%20;
			f = 1;			// 旗を立てる
		}
		move(fy, fx); printw(flag);	// 旗を表示
		move(y, x); printw(face);
		key = getch();
		switch (key) {		// 処理の効率化,コードの適切化
		case  'h': x--; face = lt; break;
		case  'j': y++; face = dn; break;
		case  'k': y--; face = up; break;
		case  'l': x++; face = rt; break;
			// これら4行も Vim で効率的に編集せよ
		}
		if (key == 'q') break;

		if (x < 0) x = 0;
		else if (x + size > w) x = w - size;	// 処理の効率化
		if (y < 0) y = 0;
		else if (y > h) y = h - 1;		//   同上

		if ((x == fx) && (y == fy)) f = 0;	// 旗をゲットしたら消す
	}
	endwin();
	return (0);
}

さらにゲームっぽくなった?

この流れで,追いかけっこ系のゲームとか アルゴロジック的なものを開発できそうでは?
自学自習

vimtutor を再度実行し,より効率的な編集方法を身に付けよう.

練習を重ねれば,意識的に頭で考えなくても自然と手が動くようになります.

さらに,Vim の特徴や技について,ネット上でも調べて実践してみよう.

ふつうに「Vim」でも良いし, 「エディタ戦争」とかも 文化人類学(プログラマの生態・習性)的に興味深い.

今回,Vim を使ってみて,嫌悪感しかないという人は, 次回以降,自分好みのエディタを使っても構いません. ただし,どのエディタを使うにしても,編集作業を効率的に進められるよう努力すべき.