Kilo Deep Reading / 01

main()とイベントループ

22行を順番に暗記するのではなく、Kiloが起動してから終了するまで、何を繰り返しているのかを一本の流れとして読み解きます。

  • 読了目安 12分
  • C言語 初学者向け
  • 英語補足は折りたたみ式
  • オフライン閲覧可
kilo.c / main
// prepare editor
initEditor();
editorOpen(filename);
enableRawMode(stdin);
while (true) {
refreshScreen(); processKeypress(); }
最初の問いなぜ、この2行を
繰り返すのか?
01

まず「骨格」だけを見る

最初からファイルの1行目へは行きません。入口である main() から、起動・準備・反復という大きな形を取り出します。

このプログラムは、起動してから終了するまで何を繰り返しているのか?
First concept
Event loop

イベントループとは、入力などの出来事を待ち、それを処理し、結果を画面へ反映する循環です。Kiloの中心は、巨大な命令列ではなく、この短い反復にあります。

02

main() を4つに分けて読む

構文を一語ずつ追う前に、処理を「入口の確認」「起動準備」「案内表示」「反復」の4ブロックに分けます。右のカードを選ぶと対応行が明るくなります。

Ckilo.c カードを選んで対応行を確認
1int 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}

読解のコツ: 関数名は、作者が残した小さな見出しです。initopenrefreshprocess という動詞だけを先に読むと、Cの細部が分からなくても処理の向きはつかめます。

03

a を押した瞬間を追う

イベントループは抽象語のままだと掴みにくいため、文字を1つ入力したときの時間の流れへ変換します。

  1. refresh 現在の編集状態を描く。 起動直後なら、読み込んだファイルとカーソルが初めて画面に現れます。
  2. process キー入力を待つ。 ここでプログラムは、次の1キーが来るまで入力処理の中にいます。
  3. a ユーザーが文字キーを押す。 端末からKiloへ、入力データとして a が届きます。
  4. state ← “a” 内部の編集状態が変わる。 カーソル位置の行データへ文字が入り、カーソル位置も進みます。
  5. loop ↩ 入力処理が終わり、ループ先頭へ戻る。 この時点でデータは変わりましたが、次の描画はまだです。
  6. refresh 更新後の状態を描き直す。 ここで初めて、画面上にも a が見えます。
Core insight / 第一の理解ポイント
キーを押したから、直接画面に文字が現れるのではない。
Event入力ユーザーが a を押す
Model状態変更行データとカーソルが変わる
View描画新しい状態を端末へ出す
04

なぜ「描画 → 入力」の順なのか

短い2行にも順序の理由があります。関数名だけでなく、どこで待ち、いつ次の周回へ戻るかを想像します。

01 / DRAW FIRST

待つ前に、最新状態を見せる

editorProcessKeypress() は入力待ちを含みます。その前に描画することで、Kiloは現在の編集内容とカーソルを表示した状態でユーザーを待てます。

02 / NEXT ROUND

変更後は、次の周回で見せる

キー処理が状態を変えると関数から戻り、ループ先頭の描画へ進みます。「変更したら次の周回で描く」という一定のリズムになります。

while (1) は、画面を無制限に高速描画する命令ではありません。 入力処理の内側に待機があるため、概念的には「描く → 待つ → 変える → 描く」です。また、通常の終了は末尾の return 0 へ到達するのではなく、Ctrl + Q を扱う入力処理側から行われます。末尾の return は形として残っていますが、通常経路では到達しません。

05

この4行が示す設計上の意味

Deep Readingでは「何をしているか」で止まりません。実装から、責務の分け方・背景概念・変更時の確認点まで視野を広げます。

LEVEL 1

What / 何を

画面を更新し、キー入力を1つ処理する。それを終了まで繰り返します。

LEVEL 2

How / どうやって

入力処理が内部状態を変更し、次の editorRefreshScreen() がその状態を端末表示へ変換します。

LEVEL 3

Why / なぜ

入力・状態・表示を一つの直線的な周期に揃えると、「今どの状態が画面に出るか」を追いやすくなります。

LEVEL 4

CS / 背景概念

イベントループ、状態管理、レンダリング、ブロッキング入力というGUIやゲームにも通じる基礎概念が見えます。

LEVEL 5

Review / 変更確認

新しいキー操作を加えるなら、「状態が正しく変わるか」「次の描画に反映されるか」「終了や保存を壊さないか」を確認します。

この設計の強み

  • 処理順が直線的で追いやすい
  • 画面を状態から再構成できる
  • 小さなプログラムでは全体像が明快

規模が大きくなると考えること

  • 一つの共有状態への依存が増えないか
  • 重い処理が入力待ちを妨げないか
  • 毎回の再描画コストが高くないか
06

English / Naming 補足

英語は本文の途中に割り込ませず、必要なときだけ開ける層に分けます。単なる和訳ではなく、命名から設計を読むための補助線です。

すべて閉じたままでも本文は理解できます。気になる用語だけを開いてください。

mainプログラムの入口

main は「主要な」「中心の」という意味です。CではOSから最初に呼ばれる特別な関数名です。

「全処理を書く場所」ではなく、処理全体を組み立てる入口として読むと構造が見えます。

argc / argv起動時に渡された値

argcargument countargvargument 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 を表す定数です。通常はキーボード入力につながる「標準入力」を指定します。

細かな数値を覚えるより、「どの入力元を使うかを明示している」と捉えれば十分です。

07

3つの理解チェック

答えを暗記するテストではなく、頭の中にできた実行モデルを確かめる問いです。考えてから開いてください。

Q1もし「入力 → 描画」の順にしたら、起動直後に何が起きる?

入力処理が先に待つため、最初のキーを押すまで編集画面が描かれない可能性があります。先に描画する現在の順序なら、ユーザーは画面を見てから操作できます。

Q2a は、どのタイミングで画面に見える?

入力処理が内部状態へ a を追加した直後ではなく、ループ先頭へ戻り、次の editorRefreshScreen() が走ったときです。

Q3return 0; は、通常の終了時に実行される?

通常は実行されません。while (1) 自体には脱出条件がなく、終了キーは入力処理側でプログラムを終了させます。したがって末尾は通常経路では到達不能です。

08

ここまでの要点

細かな関数の中身へ進む前に、今回作った実行モデルを短く固定します。

One-sentence model

Kiloは、入力で内部状態を変え、その状態を画面へ描き直す循環として動く。

  1. main() は地図。
    起動時の準備と、実行中に繰り返す処理の境界を示します。
  2. 状態が中心。
    入力は画面を直接変えず、まず編集データとカーソルを変えます。
  3. 描画は結果。
    次の周回で最新状態を画面へ変換し、ユーザーに見せます。
Next question

では、その「内部状態」はどこにあり、画面描画はどの値を読んでいるのか? — 次は struct editorConfigE を追います。