まず「骨格」だけを見る
最初からファイルの1行目へは行きません。入口である main() から、起動・準備・反復という大きな形を取り出します。
このプログラムは、起動してから終了するまで何を繰り返しているのか?
端末設定
1つ処理
!左側の準備は起動時に一度だけ。右側の2処理は、終了命令が来るまで何度も往復します。まずはこの「一度だけ」と「繰り返す」の境界を見つけることが重要です。
main() を4つに分けて読む
構文を一語ずつ追う前に、処理を「入口の確認」「起動準備」「案内表示」「反復」の4ブロックに分けます。右のカードを選ぶと対応行が明るくなります。
int main(int argc, char **argv) {
2 if (argc != 2) {
3 fprintf(stderr, "Usage: kilo <filename>\n");
4 exit(1);
5 }
6
7 initEditor();
8 editorSelectSyntaxHighlight(argv[1]);
9 editorOpen(argv[1]);
10 enableRawMode(STDIN_FILENO);
11
12 editorSetStatusMessage(
13 "HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find");
14
15 while (1) {
16 editorRefreshScreen();
17 editorProcessKeypress(STDIN_FILENO);
18 }
19
20 return 0;
21}
読解のコツ: 関数名は、作者が残した小さな見出しです。init、open、refresh、process という動詞だけを先に読むと、Cの細部が分からなくても処理の向きはつかめます。
a を押した瞬間を追う
イベントループは抽象語のままだと掴みにくいため、文字を1つ入力したときの時間の流れへ変換します。
- refresh 現在の編集状態を描く。 起動直後なら、読み込んだファイルとカーソルが初めて画面に現れます。
- process キー入力を待つ。 ここでプログラムは、次の1キーが来るまで入力処理の中にいます。
-
a
ユーザーが文字キーを押す。 端末からKiloへ、入力データとして
aが届きます。 - state ← “a” 内部の編集状態が変わる。 カーソル位置の行データへ文字が入り、カーソル位置も進みます。
- loop ↩ 入力処理が終わり、ループ先頭へ戻る。 この時点でデータは変わりましたが、次の描画はまだです。
-
refresh
更新後の状態を描き直す。 ここで初めて、画面上にも
aが見えます。
キーを押したから、直接画面に文字が現れるのではない。
なぜ「描画 → 入力」の順なのか
短い2行にも順序の理由があります。関数名だけでなく、どこで待ち、いつ次の周回へ戻るかを想像します。
待つ前に、最新状態を見せる
editorProcessKeypress() は入力待ちを含みます。その前に描画することで、Kiloは現在の編集内容とカーソルを表示した状態でユーザーを待てます。
変更後は、次の周回で見せる
キー処理が状態を変えると関数から戻り、ループ先頭の描画へ進みます。「変更したら次の周回で描く」という一定のリズムになります。
while (1) は、画面を無制限に高速描画する命令ではありません。 入力処理の内側に待機があるため、概念的には「描く → 待つ → 変える → 描く」です。また、通常の終了は末尾の return 0 へ到達するのではなく、Ctrl + Q を扱う入力処理側から行われます。末尾の return は形として残っていますが、通常経路では到達しません。
この4行が示す設計上の意味
Deep Readingでは「何をしているか」で止まりません。実装から、責務の分け方・背景概念・変更時の確認点まで視野を広げます。
What / 何を
画面を更新し、キー入力を1つ処理する。それを終了まで繰り返します。
How / どうやって
入力処理が内部状態を変更し、次の editorRefreshScreen() がその状態を端末表示へ変換します。
Why / なぜ
入力・状態・表示を一つの直線的な周期に揃えると、「今どの状態が画面に出るか」を追いやすくなります。
CS / 背景概念
イベントループ、状態管理、レンダリング、ブロッキング入力というGUIやゲームにも通じる基礎概念が見えます。
Review / 変更確認
新しいキー操作を加えるなら、「状態が正しく変わるか」「次の描画に反映されるか」「終了や保存を壊さないか」を確認します。
この設計の強み
- 処理順が直線的で追いやすい
- 画面を状態から再構成できる
- 小さなプログラムでは全体像が明快
規模が大きくなると考えること
- 一つの共有状態への依存が増えないか
- 重い処理が入力待ちを妨げないか
- 毎回の再描画コストが高くないか
English / Naming 補足
英語は本文の途中に割り込ませず、必要なときだけ開ける層に分けます。単なる和訳ではなく、命名から設計を読むための補助線です。
すべて閉じたままでも本文は理解できます。気になる用語だけを開いてください。
mainプログラムの入口
main は「主要な」「中心の」という意味です。CではOSから最初に呼ばれる特別な関数名です。
「全処理を書く場所」ではなく、処理全体を組み立てる入口として読むと構造が見えます。
argc / argv起動時に渡された値
argc は argument count、argv は argument vector の略です。
kilo memo.txt なら、プログラム名とファイル名で数は2。argv[1] が memo.txt です。
event loop出来事を扱う反復
event は「出来事」、loop は「輪・反復」。入力などの出来事を待って処理し続ける構造です。
Kiloのソースにこの名前の関数がなくても、while (1) の構造そのものを指す概念名として使えます。
refresh / render再表示と描画
refresh は「新しくし直す」。render は、内部データを見える形へ変換して描くことです。
editorRefreshScreen() という名前は、「状態を持つ」より「状態を画面へ反映する」責務を示しています。
keypressキーを押す出来事
key + press で「キー押下」。process が付くため、この関数は読むだけでなく、押されたキーの意味を判断して状態へ反映すると推測できます。
raw mode端末の生入力モード
raw は「加工されていない」。通常の端末が行う行単位の入力処理などを外し、Kilo自身がキーを細かく扱える状態です。
これにより、Enterを待たずに矢印キーや Ctrl 系の操作を受け取れます。
stateある瞬間の内部状態
state は「状態」。カーソル位置、テキスト行、スクロール位置、ファイル名など、その瞬間のKiloを再現するための値の集合です。
Kiloでは主にグローバルな編集設定 E にまとめられています。
STDIN_FILENO標準入力の番号
standard input file number を表す定数です。通常はキーボード入力につながる「標準入力」を指定します。
細かな数値を覚えるより、「どの入力元を使うかを明示している」と捉えれば十分です。
3つの理解チェック
答えを暗記するテストではなく、頭の中にできた実行モデルを確かめる問いです。考えてから開いてください。
Q1もし「入力 → 描画」の順にしたら、起動直後に何が起きる?
入力処理が先に待つため、最初のキーを押すまで編集画面が描かれない可能性があります。先に描画する現在の順序なら、ユーザーは画面を見てから操作できます。
Q2a は、どのタイミングで画面に見える?
入力処理が内部状態へ a を追加した直後ではなく、ループ先頭へ戻り、次の editorRefreshScreen() が走ったときです。
Q3return 0; は、通常の終了時に実行される?
通常は実行されません。while (1) 自体には脱出条件がなく、終了キーは入力処理側でプログラムを終了させます。したがって末尾は通常経路では到達不能です。
ここまでの要点
細かな関数の中身へ進む前に、今回作った実行モデルを短く固定します。
Kiloは、入力で内部状態を変え、その状態を画面へ描き直す循環として動く。
- main() は地図。
起動時の準備と、実行中に繰り返す処理の境界を示します。 - 状態が中心。
入力は画面を直接変えず、まず編集データとカーソルを変えます。 - 描画は結果。
次の周回で最新状態を画面へ変換し、ユーザーに見せます。