develop.txt For Vim バージョン 8.2. Last change: 2020 Aug 15
VIMリファレンスマニュアル by Bram Moolenaar
Vimの開発 development
この文書は、Vimの更なる開発に参加しようという人にとって重要である。
1. 設計上の目標 design-goals
2. コーディングスタイル coding-style
3. 決定事項 design-decisions
4. 想定していること design-assumptions
ソースコードの概要については "src" ディレクトリのREADME.txtを見てください。
Vimはオープンソースソフトウェアです。誰でもVimの開発に協力できます。パッチを送
る時はなるべく "unified diff" 形式 ("diff -u" で作る) でお願いします。
GitHub上でプルリクエストを作ることも可能ですが、必須ではありません。
http://vim.wikia.com/wiki/How_to_make_and_submit_a_patch も見てください。
==============================================================================
1. 設計上の目標 design-goals
重要度の順に従って書かれている(大雑把であるが)。
かなりの項目が矛盾していることを注意しておく。これは故意である。それらの間で、
バランスを取っていかねばならない。
VIM IS... VI COMPATIBLE design-compatible
何より、VimはViの気軽な置き換えとして使うことができるべきである。ユーザーが望
むなら、Vimは、オリジナルのViとの区別がほとんど付かない互換モードで使うことが
できる。
例外:
- 明白なViのバグをVimに再現しない。
- Viには異なるバージョンが存在する。私はバージョン3.7(6/7/85)を参考として
使っている。しかし、他のバージョンのサポートも可能な限り取り込まれる。
POSIXにおけるViのパートは、決定的な資料とは考えない。
- Vimは新しいコマンドを持つため、Viにないコマンドを入力しても機能してしまう
場合がある。
- VimはViの持っていない多くの特徴を持つ。VimからViへ戻ることは問題を引き起こ
すが、これは避けられないことである。
- いくつかの事柄はめったに使われた例がない(オープンモード、クラッシュ時の
e-mailの送信、など)。これらは、誰かが何らかの理由でそれを入れるべきだと考
え、さらにその機能が働き過ぎない場合に限って取り入れられる。
- いくつかの項目に関しては、Vi互換を保つべきかどうか、議論の余地がある。これ
らに関しては、オプションフラグが作られるだろう。
VIM IS... IMPROVED design-improved
Vimの改良点は、それをよりよいViにすべきであって、まったく違ったエディタに
してしまってはならない。拡張は "Viの精神" に従って行われる。
- 可能な限りキーボードを使う。マウスは私たちの持たぬ第3の手を必要とする。
多くの端末はマウスを備えていない。
- それでもマウスを使うようであれば、キーボードに切り替える必要をなくす。
マウスとキーボードの操作の混在を避けよ。
- コマンドとオプションを矛盾なく追加せよ。でなければ、それらを見つけ出し、思い
出すのに、人々は苦労を強いられるだろう。後々、さらにコマンドやオプションが
追加されることを忘れてはならない。
- 特性は、人々が知らなければ役に立たない。目立たない特性は追加しない、あるいは、
少なくともその特性が存在するというヒントをドキュメントに追加すること。
- CTRLや他の修飾子の使用は最小限に留めよ、これらはタイプしにくい。
- 多くの初心者、不慣れなVimユーザーがいる。Vimを使いはじめること、そしてより多
くを学んでいくことが、簡単にできるようにせよ。
- 特性は限りなく追加できる。新しく追加される特性は、(1)ユーザーが求めているこ
と、(2)実装にどれほどの労力が必要か、そして(3)誰かが実際に実装している、と
いったことに基づいて選択される。
VIM IS... MULTI PLATFORM design-multi-platform
Vimは、可能な限り、多くのプラットフォーム上の多くのユーザーの助けでありたい。
- 多くの種類の端末をサポートする。最低限の要求は、カーソルの配置機能と画面の
クリアである。コマンドはたいていのキーボードが持つキーのみを使う。マッピン
グには、キーボード上の全てのキーを使うことができる。
- 多くのプラットフォームをサポートする。必要条件は、誰かがそのプラットフォーム
上でVimの開発をしたいと考えること、それによってコードに混乱をきたさないこと、
である。
- 多くのコンパイラとライブラリをサポートする。全ての人が、他のコンパイラや
GUIライブラリをインストールできるわけではないからである。
- 人々は、あるプラットフォームから別のプラットフォームへ、そしてGUIから端末
バージョンへ移行する。特性は全てのバージョン、あるいは、少なくとも理に叶った
労力でできる限りのバージョンで、提供されるべきである。ユーザーが能率的に仕事
を仕上げるために、プラットフォームを切り替えねばならないような事態は避けたい。
- いくつかのプラットフォームでは実現できない、または、ただひとつのプラット
フォームでしか実現できないような特性も、実装できないというわけではない。[こ
れは前項と故意に矛盾するものであり、両者の間でバランスが取られる。]
VIM IS... WELL DOCUMENTED design-documented
- 文書化されていない特性は、役に立たない。新しい特性を含んだパッチには、必ず
ドキュメントが含まれているべきである。
- ドキュメントは、わかりやすく、理解できるものであるべきだ。例を使うことが推
奨される。
- 文章を不必要に長くしてはならない。短い文章は、その項目を見つけやすくする。
VIM IS... HIGH SPEED AND SMALL IN SIZE design-speed-size
Vimを使うことで、システムリソースに大打撃を与えてはならない。Vimを小さく、
速く保つこと。
- コンピュータは年毎により速く、大容量になっている。Vimも成長しうるが、コン
ピュータの成長速度より速くなってはならない。Vimを古いシステム上でも使える
よう保つ必要がある。
- 多くのユーザーは、Vimを頻繁にシェルから立ち上げる。起動は短時間でなくてはな
らない。
- コマンドは能率的に働く必要がある。コマンドが消費する時間は、可能な限り短く
あるべきだ。役に立つコマンドなら、多少時間がかかってもよい。
- Vimを、遅い接続を通して使う人がいることを忘れてはならない。通信にかかるオー
バーヘッドは最小にすること。
- サイズがかなり大きく、多くの人によって使われるわけではない項目は、無効化で
きる特性とすべきである。
- Vimは、他のいろいろな構成要素の中にある、ひとつのコンポーネントである。巨大
なアプリケーションに変えてはならない、むしろ他のプログラムとよく協調するよう
にせよ。
VIM IS... MAINTAINABLE design-maintain
- ソースコードは乱雑になってはならない。そして、信頼できるものでなくてはな
らない。
- 読みやすくするため、すべてのファイルで同じレイアウトを取ること
coding-style。
- 役に立つコメントをいれること!関数名と引数名を引用しても役に立たない。それ
が何のためにあるのか説明すること。
- プラットフォーム独立のコードに多くの変更を加える必要をなくし、他のプラット
フォームへの移植を簡単にできるようにすること。
- オブジェクト指向の精神を使う: データとコードを同じ場所に。コードの他の部分
に関する知識は最小で済むように。
VIM IS... FLEXIBLE design-flexible
Vimは、そのユーザーに特定の作業パターンを強いるよりは、ユーザーの好むスタイル
での作業を支援すべきである。これは大きなインパクトをもつ項目(例えば、
'compatible' オプション)や、その他の詳細によって実現される。デフォルトは、多く
のユーザーがそのままのVimを楽しんで使えるように、慎重に選ばれている。コマンド
とオプションは、Vimをユーザーの希望と環境に調整するために使われる。
VIM IS... NOT design-not
- Vim はシェルでもオペレーティングシステムでもない。Vim はターミナルウィンドウ
を提供し、その中でシェルやデバッガを走らせることができる。例えば、ssh 接続越
しにこれをすることが可能だ。しかし、このようなものにテキストエディタが必要な
いなら守備範囲外だ (代わりに screen や tmux のようなものを使おう)。
風刺を込めて曰く: "Vim は Emacs のように流し台以外ならなんでもかんでも取り込
んでしまうようなことはしないが、Vim で流し台を洗うことはできるぞ。 ;-)"
Vim と gdb を連携させる方法については terminal-debugger を参照。他の(古い)
ツールは http://www.agide.org と http://clewn.sf.net で見つけることができる。
- Vimは、全てのプラットフォームに渡って調和を欠くという代償を払って、見栄えを
よくしようとする装飾的なGUIエディタではない。しかし、機能的なGUI特性は歓迎さ
れる。
==============================================================================
2. コーディングスタイル coding-style
Vimのソースコードに変更を加える際、守るべきルールがある。ソースを読めるもの、
保守できるものとして保つため、これらのルールに従って欲しい。
このリストは完全ではない。より多くの例は、ソースコードを見て欲しい。
MAKING CHANGES style-changes
コードに変更を加える基本的なステップは:
1. GitHub からコードを取得する。これによりあなたが変更したコードをメインのコー
ドベースに同期するのがより簡単になる (あなたの変更がメインのコードベースに
含まれるようになるまで少しかかるかもしれない) 。いくらか時間を費やして git
について学ぶ必要がある。git はあまりユーザーフレンドリーなツールではない。
2. ドキュメントを調整する。最初にこれをやることで、あなたの行う変更がユーザー
に与える影響について、おおまかな印象をもつことができる。
3. ソースコードに変更を加える。
4. 変更がリストされた項目に影響を与えていないか、../doc/todo.txtをチェックす
る。
5. "git diff" でパッチを作成する。GitHub でプルリクエストを作成しても良いが、
重要なのはその diff である。
6. 何が変更されたかのノートを作成する。問題点とその解決策について書かれている
のが望ましい。vim-dev のメーリングリストに説明と diff を含めたメールを送
るか GitHub でプルリクエストを作成する。
C COMPILER style-compiler ANSI-C C89 C99
サポートされている最小の C コンパイラのバージョンは C89 (ANSI C とも呼ばれてい
る) である。C99 のような後継の標準規格はあまり普及していない、もしくは少なくと
も 100% サポートされているわけではない。したがって C99 のいくつかの機能だけを
使用し、その他の使用は (少なくとも現時点では) 禁止する。
現存するパッチに対してマージの問題を引き起こすため、C99の機能を使う変更を至る
所に入れてはいけない。新しくコードを書く場合、もしくは既存のコードを書き直す場
合に限り使用してもよい。
コメント
慣習的に Vim では /* コメント */ を使用する。ファイルや関数のヘッダ、コードの
大きめなブロックに関してはこれを維持するつもりである。例:
/*
* The "foo" argument does something useful.
* Return OK or FAIL.
*/
新しいコードもしくは変更するコードの行については、// コメント を使うことが好ま
れる。特にコードの後ろに続くコメントなど:
int some_var; // single line comment useful here
列挙型 (Enums)
列挙型の末尾の要素にコンマ (trailing comma) が付いていてもよい。C89 では認めら
れていなかった。
型 (Types)
"long long" は使用してもよく、64 bit を想定している。printf では %lld を使用す
ること。同じように "long long unsigned" では %llu を使用する。
使用してはいけないもの
これらの C99 の機能は、コンパイラのサポートが不十分なため使用してはいけない。
- ステートメントの後の宣言 (MSVC 2012 はこれをサポートしていない)。すべての宣
言はブロックの先頭になければならない。
- 可変長配列 (C11 でもこれはオプショナルな機能である)。
- _Bool 型と _Complex 型。
- "inline" (ほとんど必要ない、コンパイラに最適化させよう。)
- フレキシブル配列メンバ: HP-UX C コンパイラはサポートしていない。(John
Marriott)
USE OF COMMON FUNCTIONS style-functions
よく使われる関数のうち、特別なVimバージョンを持つものがある。これらは理由あっ
て導入されたものなので、常にVimバージョンを使うように意識すること。
NORMAL NAME VIM NAME DIFFERENCE OF VIM VERSION
free() vim_free() NULLの解放をチェックする
malloc() alloc() アウトオブメモリの状況をチェックする
malloc() lalloc() alloc()に似ているが、long型の引数を持つ
strcpy() STRCPY() char_u *引数を、(char *)へキャストする
strchr() vim_strchr() スペシャルキャラクタを受け入れる
strrchr() vim_strrchr() スペシャルキャラクタを受け入れる
isspace() vim_isspace() 128以上のキャラクタを扱うことができる
iswhite() vim_iswhite() Tabとスペースに対してのみTRUE
memcpy() mch_memmove() オーバーラップしたコピーを扱う
bcopy() mch_memmove() オーバーラップしたコピーを扱う
memset() vim_memset() 全てのシステムで一定である
NAMES style-names
関数の名前に31文字より長い名前は使えない。(VMSのために)
"delete" や "this" という名前の変数を使わないこと。C++で問題となる。
Vimができる限り多くのシステム上で走るという必要上、システムによってすでに定義
されている名前を使うことは避けねばならない。これは、問題となることが知られて
いる名前のリストである。名前はregexpパターンとして与えられている。
is.*() POSIX, ctype.h
to.*() POSIX, ctype.h
d_.* POSIX, dirent.h
l_.* POSIX, fcntl.h
gr_.* POSIX, grp.h
pw_.* POSIX, pwd.h
sa_.* POSIX, signal.h
mem.* POSIX, string.h
str.* POSIX, string.h
wcs.* POSIX, string.h
st_.* POSIX, stat.h
tms_.* POSIX, times.h
tm_.* POSIX, time.h
c_.* POSIX, termios.h
MAX.* POSIX, limits.h
__.* POSIX, system
_[A-Z].* POSIX, system
E[A-Z0-9]* POSIX, errno.h
.*_t POSIX, for typedefs, *_T を使うこと。
wait types.hとコンフリクトするため、関数の引数として使わない
index グローバル宣言を覆い隠す
time グローバル宣言を覆い隠す
new C++の予約語
clear Mac curses.h
echo Mac curses.h
instr Mac curses.h
meta Mac curses.h
newwin Mac curses.h
nl Mac curses.h
overwrite Mac curses.h
refresh Mac curses.h
scroll Mac curses.h
typeahead Mac curses.h
basename() GNU 文字列関数(GNU string function)
dirname() GNU 文字列関数(GNU string function)
get_env_value() Linux システム関数
VARIOUS style-various
型の定義に使う名前は最後を "_T" にする:
'\"' を使わない、あるコンパイラはこれを扱えない。'"' はうまく機能する。
次を使ってはならない:
#if HAVE_SOME
あるコンパイラはこれを扱えず、"HAVE_SOME" が定義されていないと訴える。
次を使う
#ifdef HAVE_SOME
または
#if defined(HAVE_SOME)
STYLE style-examples
一般的なルール: 1行に1つのステートメント。
間違い: if (cond) a = 1;
OK: if (cond)
a = 1;
間違い: while (cond);
OK: while (cond)
;
間違い: do a = 1; while (cond);
OK: do
a = 1;
while (cond);
間違い: if (cond) {
cmd;
cmd;
} else {
cmd;
cmd;
}
OK: if (cond)
{
cmd;
cmd;
}
else
{
cmd;
cmd;
}
ブロックが1行の場合は、波括弧を省くことができる。if/else の1つのブロックに波括
弧がある場合、他のブロックにも波括弧があると、通常は見栄えが良くなる:
OK: if (cond)
cmd;
else
cmd;
OK: if (cond)
{
cmd;
}
else
{
cmd;
cmd;
}
関数宣言には ANSI スタイルを使い、戻り値の型は独立した行にインデントをつけて書
くこと。
間違い: int function_name(int arg1, int arg2)
OK: /*
* Explanation of what this function is used for.
* この関数が何に使われるかの説明。
*
* Return value explanation.
* 戻り値の説明。
*/
int
function_name(
int arg1, // short comment about arg1
int arg2) // short comment about arg2
{
int local; // comment about local
local = arg1 * arg2;
SPACES AND PUNCTUATION style-spaces
関数名とブラケットの間にスペースを入れないこと:
間違い: func (arg);
OK: func(arg);
if、while、switchなどの後には、スペースを入れること。
間違い: if(arg) for(;;)
OK: if (arg) for (;;)
コンマ、セミコロンの後にはスペースを入れること:
間違い: func(arg1,arg2); for (i = 0;i < 2;++i)
OK: func(arg1, arg2); for (i = 0; i < 2; ++i)
'='、'+'、'/' などの前と後には、スペースを入れること。
間違い: var=a*5;
OK: var = a * 5;
一般的なこと: コードの行をグループ分けするために、空行を使う。行グループのす
ぐ上にコメントを入れる。こうすることによって、何が行われるのかをより簡単に知
ることができる。
OK: /* Prepare for building the table. */
/* テーブルの作成の準備 */
get_first_item();
table_idx = 0;
/* Build the table */
/* テーブルの作成 */
while (has_item())
table[table_idx++] = next_item();
/* Finish up. */
/* 仕上げ */
cleanup_items();
generate_hash(table);
==============================================================================
3. 決定事項 design-decisions
折り畳み(folding)
同じバッファにいくつもの折り畳み状態を設定可能にする。例えば、あるウィンドウに
関数を折り畳んだ状態で表示し、他のウィンドウで関数の中身を表示するなど。
折り畳みはテキストを表示する方法である。テキストを変更すべきではない。したがっ
てバッファ内のテキストをウィンドウに表示する際のフィルタとして実行される。
ウィンドウの名前
"ウィンドウ" という単語は一般にいくつかの意味で使われている。スクリーン上のウィ
ンドウ、xtermのウィンドウ、Vimのバッファを表示するウィンドウなど。
混乱を避けるため、時にウィンドウと呼ばれる他の物には別の名前が付けられている。
ここに関連する物の概観を示す。
スクリーン(screen) ディスプレイ全体。GUIでは例えば1024x768ピクセルの画
面。Vimシェルはスクリーン全体を使うことも一部を使う
こともできる。
シェル(shell) Vimアプリケーション。スクリーン全体(例えばコンソール
で実行した時)、あるいはその一部(xtermやGUI)。
ウィンドウ(window) バッファの表示画面。Vimは複数のウィンドウを持つこと
ができる。ウィンドウはコマンドラインやメニューバー、
ツールバーなどといっしょに表示される。これらはシェル
に納まる。
スペルチェック develop-spell
Vim にスペルチェックを追加することになったとき、利用可能なスペルチェックのライ
ブラリやプログラムについて調査が行われた。その結果は残念なことに、Vim 内でスペ
ルチェックエンジンとして使えるものはないとわかった。これには様々な理由がある:
- マルチバイトエンコーディングをサポートしていない。1つのファイル内で複数の言
語を使えるようにするために、少なくとも UTF-8 はサポートしていなければならな
い。
オンザフライな変換は常に可能とは限らない(iconv に対応している必要がある)。
- プログラムとライブラリに対して: それらをそのまま(as-is)使うには、Vim と別個
にインストールしなければならない。これはたいてい不可能ではないが、難点である。
- パフォーマンス: いくつかのテストによると、スペルチェックを構文強調のようにオ
ンザフライで(再描画中に)行うことは可能であった。しかし他のコードで使われたメ
カニズムはもっと遅かった。例えば、Myspell はハッシュテーブルを使用する。ほと
んどのスペルチェッカが使用している接辞圧縮を使うと遅くなった。
- aspell のような外部プログラムを使うには、通信メカニズムを用意しなければなら
ない。これをポータブルな方法で行うのは複雑過ぎる(Unix だけなら比較的簡単だが、
それでは十分ではない)。そしてパフォーマンスが問題になる(何回ものプロセス切替
が行われる)。
- "Etten-Leur" や "et al." など、単語でない単語のサポートを欠いている。そのた
めこれらの部分を OK とマークしなければならないが、そうすると信頼性が低下する。
- 地域や方言のサポートを欠いている。英語の単語をすべて受け付け、カナダ語でない
単語を別に扱うことが難しくなる。
- 頻度が低い単語のサポートを欠いている。正しいがめったに使われないたくさんの単
語が、よく使われる単語のスペルミスとみなされてしまう。
- スペル候補を作成するには速度はそれほど重要ではなく、他のプログラムやライブラ
リをインストールすることは許容できる。しかし、単語リストが異なるとスペル候補
が誤単語になってしまう。
スペル候補 develop-spell-suggestions
候補の作成には2つの基本的なメカニズムがある:
1. 誤った単語を少し変更して正しい単語とマッチするかチェックする。あるいは、正
しい単語全てに対し、それを少し変更して誤った単語とマッチするかチェックする。
変更とは、文字の削除・文字の挿入・2つの文字の交換などである。
2. 誤った単語と正しい単語のリストの両方に soundfolding (発音が近い単語を同じグ
ループとみなすこと) を行って、そこでマッチを見つける。1番目のメカニズムと同
様にいくつか変更をしてもよい。
最初のメカニズムはタイプミスを見つけるのにはよい。ハッシュテーブルの実験と、他
のスペルチェッカのソリューションを見ると、これにはtrie(ツリー構造の一種)が最適
であるとの結論になった。メモリ使用量の削減と、賢い変更を試みるということの両方
の面でである。例えば、文字を挿入するときは正しい単語につながる文字だけを試せば
よい。他の(ハッシュテーブルを使った)メカニズムは、単語のすべての位置で、ありう
るすべての文字を試さねばならない、また、ハッシュテーブルを使うには、単語の境界
が個別に認識されなければならないのに対し、trie はそれを要求しない。そのためメ
カニズムがより単純になる。
ある単語の発音は知っているがスペルを知らないという場合に soundfolding は有用で
ある。例えば、"dictionary" という単語を "daktonerie" と書いてしまうかもしれな
い。これを最初の方法で訂正しようとすると変更回数が非常に多くなってしまい、正し
いスペルを見つけるのは困難である。それに対し、これらの単語にsoundfoldingを行う
と "tktnr" と "tkxnry" になり、2文字しか違わない。
soundfoldの同値(音が似ている単語)により単語を見つけるには全てのsoundfolded
wordsのリストが必要である。どれが最良の方法かを探すための実験が行われた。案:
1. 修正候補を探すときに、その場でsound foldingを行う。つまり、正しい単語のtrie
をたどりながら、各単語をsoundfoldingし、それがスペルミスしている単語からど
れだけ異なるかをチェックする。これはメモリ効率の面でとても優れているが、時
間は長くかかる。英語の場合、高速なPCで2秒ほどかかる。これは対話的な利用とし
て受け入れられる。しかしいくつかの言語(ドイツ語、カタルニャ語など)に対して
は10秒以上かかり、受け入れがたい。バッチ処理(自動訂正)に使うには全ての言語
で遅すぎる。
2. soundfoldされた単語に対してtrieを使い、soundfoldingなしのときとまったく同じ
ように検索できるようにする。そのためには、soundfoldされた各単語に対し、正し
い単語のリストを記憶しておく必要がある。そうすると照合がとても高速になるが、
1MB〜10MBのオーダーの大量のメモリを必要とする。ある言語の場合は元の単語のリ
ストよりも多くなる。
3. 2番目の案と同様だが、接辞圧縮を使い、soundfoldした基本単語だけを保存するこ
とによりメモリ消費量を減らす。これはAspellが採用している方法である。不利点
は、誤った単語をsoundfoldする前に接辞を取り除いておかねばならないことである。
そのため、単語の先頭・末尾における誤りに対しては対応できない。また、誤った
単語が正しい単語から大きく異なるときは遅くなる。
我々が採用したのは、2番目のメカニズムを使い、別ファイルを使う方法である。こう
することによって、十分なメモリを持っているユーザーはとてもよい候補を得ることが
できるし、メモリが不足しているユーザーやスペルチェックだけで候補は出さなくてよ
いというユーザーはそれほどメモリを使わなくてすむ。
単語の頻度
候補をソートするにはどの単語が共通であるかを知ると役に立つ。理論的には単語の頻
度は単語とともに辞書の中に保持することができる。しかしそうすると単語につき回数
を保持しなければならない。これは単語ツリー圧縮を大いに劣化させる。また、全ての
言語に対して単語の頻度を保守するのは大変な作業である。
また、テキストに既に出てきている単語を優先するとよいだろう。このようにして特定
のテキスト内に表れる単語は候補の中で優先度が高くなる。
実装されたのは、表示中に単語を数えることである。ハッシュテーブルを使ってその単
語の回数を高速に検索する。回数は接辞ファイルでCOMMONアイテムにリストされている
単語から初期化される。そのため新規ファイルの編集を始めたときも機能する。
これは理想的ではない。Vimが長時間稼動しているほど回数は大きくなるためである。
しかし実用的には単語の回数を使わない場合に比べて注目に値するほどの改善である。
==============================================================================
4. 想定していること design-assumptions
変数のサイズ:
char 8 bit signed
char_u 8 bit unsigned
int 32 or 64 bit signed (限定された機能については16ビットもありうる)
unsigned 32 or 64 bit unsigned (16ビットについてはintと同様)
long 32 or 64 bit signed, can hold a pointer
Note いくつかのコンパイラは長すぎる行は文字列をうまく扱えない。C89の標準規格で
は509文字までに制限されている。
vim:tw=78:ts=8:noet:ft=help:norl:
VIMリファレンスマニュアル by Bram Moolenaar
Vimの開発 development
この文書は、Vimの更なる開発に参加しようという人にとって重要である。
1. 設計上の目標 design-goals
2. コーディングスタイル coding-style
3. 決定事項 design-decisions
4. 想定していること design-assumptions
ソースコードの概要については "src" ディレクトリのREADME.txtを見てください。
Vimはオープンソースソフトウェアです。誰でもVimの開発に協力できます。パッチを送
る時はなるべく "unified diff" 形式 ("diff -u" で作る) でお願いします。
GitHub上でプルリクエストを作ることも可能ですが、必須ではありません。
http://vim.wikia.com/wiki/How_to_make_and_submit_a_patch も見てください。
==============================================================================
1. 設計上の目標 design-goals
重要度の順に従って書かれている(大雑把であるが)。
かなりの項目が矛盾していることを注意しておく。これは故意である。それらの間で、
バランスを取っていかねばならない。
VIM IS... VI COMPATIBLE design-compatible
何より、VimはViの気軽な置き換えとして使うことができるべきである。ユーザーが望
むなら、Vimは、オリジナルのViとの区別がほとんど付かない互換モードで使うことが
できる。
例外:
- 明白なViのバグをVimに再現しない。
- Viには異なるバージョンが存在する。私はバージョン3.7(6/7/85)を参考として
使っている。しかし、他のバージョンのサポートも可能な限り取り込まれる。
POSIXにおけるViのパートは、決定的な資料とは考えない。
- Vimは新しいコマンドを持つため、Viにないコマンドを入力しても機能してしまう
場合がある。
- VimはViの持っていない多くの特徴を持つ。VimからViへ戻ることは問題を引き起こ
すが、これは避けられないことである。
- いくつかの事柄はめったに使われた例がない(オープンモード、クラッシュ時の
e-mailの送信、など)。これらは、誰かが何らかの理由でそれを入れるべきだと考
え、さらにその機能が働き過ぎない場合に限って取り入れられる。
- いくつかの項目に関しては、Vi互換を保つべきかどうか、議論の余地がある。これ
らに関しては、オプションフラグが作られるだろう。
VIM IS... IMPROVED design-improved
Vimの改良点は、それをよりよいViにすべきであって、まったく違ったエディタに
してしまってはならない。拡張は "Viの精神" に従って行われる。
- 可能な限りキーボードを使う。マウスは私たちの持たぬ第3の手を必要とする。
多くの端末はマウスを備えていない。
- それでもマウスを使うようであれば、キーボードに切り替える必要をなくす。
マウスとキーボードの操作の混在を避けよ。
- コマンドとオプションを矛盾なく追加せよ。でなければ、それらを見つけ出し、思い
出すのに、人々は苦労を強いられるだろう。後々、さらにコマンドやオプションが
追加されることを忘れてはならない。
- 特性は、人々が知らなければ役に立たない。目立たない特性は追加しない、あるいは、
少なくともその特性が存在するというヒントをドキュメントに追加すること。
- CTRLや他の修飾子の使用は最小限に留めよ、これらはタイプしにくい。
- 多くの初心者、不慣れなVimユーザーがいる。Vimを使いはじめること、そしてより多
くを学んでいくことが、簡単にできるようにせよ。
- 特性は限りなく追加できる。新しく追加される特性は、(1)ユーザーが求めているこ
と、(2)実装にどれほどの労力が必要か、そして(3)誰かが実際に実装している、と
いったことに基づいて選択される。
VIM IS... MULTI PLATFORM design-multi-platform
Vimは、可能な限り、多くのプラットフォーム上の多くのユーザーの助けでありたい。
- 多くの種類の端末をサポートする。最低限の要求は、カーソルの配置機能と画面の
クリアである。コマンドはたいていのキーボードが持つキーのみを使う。マッピン
グには、キーボード上の全てのキーを使うことができる。
- 多くのプラットフォームをサポートする。必要条件は、誰かがそのプラットフォーム
上でVimの開発をしたいと考えること、それによってコードに混乱をきたさないこと、
である。
- 多くのコンパイラとライブラリをサポートする。全ての人が、他のコンパイラや
GUIライブラリをインストールできるわけではないからである。
- 人々は、あるプラットフォームから別のプラットフォームへ、そしてGUIから端末
バージョンへ移行する。特性は全てのバージョン、あるいは、少なくとも理に叶った
労力でできる限りのバージョンで、提供されるべきである。ユーザーが能率的に仕事
を仕上げるために、プラットフォームを切り替えねばならないような事態は避けたい。
- いくつかのプラットフォームでは実現できない、または、ただひとつのプラット
フォームでしか実現できないような特性も、実装できないというわけではない。[こ
れは前項と故意に矛盾するものであり、両者の間でバランスが取られる。]
VIM IS... WELL DOCUMENTED design-documented
- 文書化されていない特性は、役に立たない。新しい特性を含んだパッチには、必ず
ドキュメントが含まれているべきである。
- ドキュメントは、わかりやすく、理解できるものであるべきだ。例を使うことが推
奨される。
- 文章を不必要に長くしてはならない。短い文章は、その項目を見つけやすくする。
VIM IS... HIGH SPEED AND SMALL IN SIZE design-speed-size
Vimを使うことで、システムリソースに大打撃を与えてはならない。Vimを小さく、
速く保つこと。
- コンピュータは年毎により速く、大容量になっている。Vimも成長しうるが、コン
ピュータの成長速度より速くなってはならない。Vimを古いシステム上でも使える
よう保つ必要がある。
- 多くのユーザーは、Vimを頻繁にシェルから立ち上げる。起動は短時間でなくてはな
らない。
- コマンドは能率的に働く必要がある。コマンドが消費する時間は、可能な限り短く
あるべきだ。役に立つコマンドなら、多少時間がかかってもよい。
- Vimを、遅い接続を通して使う人がいることを忘れてはならない。通信にかかるオー
バーヘッドは最小にすること。
- サイズがかなり大きく、多くの人によって使われるわけではない項目は、無効化で
きる特性とすべきである。
- Vimは、他のいろいろな構成要素の中にある、ひとつのコンポーネントである。巨大
なアプリケーションに変えてはならない、むしろ他のプログラムとよく協調するよう
にせよ。
VIM IS... MAINTAINABLE design-maintain
- ソースコードは乱雑になってはならない。そして、信頼できるものでなくてはな
らない。
- 読みやすくするため、すべてのファイルで同じレイアウトを取ること
coding-style。
- 役に立つコメントをいれること!関数名と引数名を引用しても役に立たない。それ
が何のためにあるのか説明すること。
- プラットフォーム独立のコードに多くの変更を加える必要をなくし、他のプラット
フォームへの移植を簡単にできるようにすること。
- オブジェクト指向の精神を使う: データとコードを同じ場所に。コードの他の部分
に関する知識は最小で済むように。
VIM IS... FLEXIBLE design-flexible
Vimは、そのユーザーに特定の作業パターンを強いるよりは、ユーザーの好むスタイル
での作業を支援すべきである。これは大きなインパクトをもつ項目(例えば、
'compatible' オプション)や、その他の詳細によって実現される。デフォルトは、多く
のユーザーがそのままのVimを楽しんで使えるように、慎重に選ばれている。コマンド
とオプションは、Vimをユーザーの希望と環境に調整するために使われる。
VIM IS... NOT design-not
- Vim はシェルでもオペレーティングシステムでもない。Vim はターミナルウィンドウ
を提供し、その中でシェルやデバッガを走らせることができる。例えば、ssh 接続越
しにこれをすることが可能だ。しかし、このようなものにテキストエディタが必要な
いなら守備範囲外だ (代わりに screen や tmux のようなものを使おう)。
風刺を込めて曰く: "Vim は Emacs のように流し台以外ならなんでもかんでも取り込
んでしまうようなことはしないが、Vim で流し台を洗うことはできるぞ。 ;-)"
Vim と gdb を連携させる方法については terminal-debugger を参照。他の(古い)
ツールは http://www.agide.org と http://clewn.sf.net で見つけることができる。
- Vimは、全てのプラットフォームに渡って調和を欠くという代償を払って、見栄えを
よくしようとする装飾的なGUIエディタではない。しかし、機能的なGUI特性は歓迎さ
れる。
==============================================================================
2. コーディングスタイル coding-style
Vimのソースコードに変更を加える際、守るべきルールがある。ソースを読めるもの、
保守できるものとして保つため、これらのルールに従って欲しい。
このリストは完全ではない。より多くの例は、ソースコードを見て欲しい。
MAKING CHANGES style-changes
コードに変更を加える基本的なステップは:
1. GitHub からコードを取得する。これによりあなたが変更したコードをメインのコー
ドベースに同期するのがより簡単になる (あなたの変更がメインのコードベースに
含まれるようになるまで少しかかるかもしれない) 。いくらか時間を費やして git
について学ぶ必要がある。git はあまりユーザーフレンドリーなツールではない。
2. ドキュメントを調整する。最初にこれをやることで、あなたの行う変更がユーザー
に与える影響について、おおまかな印象をもつことができる。
3. ソースコードに変更を加える。
4. 変更がリストされた項目に影響を与えていないか、../doc/todo.txtをチェックす
る。
5. "git diff" でパッチを作成する。GitHub でプルリクエストを作成しても良いが、
重要なのはその diff である。
6. 何が変更されたかのノートを作成する。問題点とその解決策について書かれている
のが望ましい。vim-dev のメーリングリストに説明と diff を含めたメールを送
るか GitHub でプルリクエストを作成する。
C COMPILER style-compiler ANSI-C C89 C99
サポートされている最小の C コンパイラのバージョンは C89 (ANSI C とも呼ばれてい
る) である。C99 のような後継の標準規格はあまり普及していない、もしくは少なくと
も 100% サポートされているわけではない。したがって C99 のいくつかの機能だけを
使用し、その他の使用は (少なくとも現時点では) 禁止する。
現存するパッチに対してマージの問題を引き起こすため、C99の機能を使う変更を至る
所に入れてはいけない。新しくコードを書く場合、もしくは既存のコードを書き直す場
合に限り使用してもよい。
コメント
慣習的に Vim では /* コメント */ を使用する。ファイルや関数のヘッダ、コードの
大きめなブロックに関してはこれを維持するつもりである。例:
/*
* The "foo" argument does something useful.
* Return OK or FAIL.
*/
新しいコードもしくは変更するコードの行については、// コメント を使うことが好ま
れる。特にコードの後ろに続くコメントなど:
int some_var; // single line comment useful here
列挙型 (Enums)
列挙型の末尾の要素にコンマ (trailing comma) が付いていてもよい。C89 では認めら
れていなかった。
型 (Types)
"long long" は使用してもよく、64 bit を想定している。printf では %lld を使用す
ること。同じように "long long unsigned" では %llu を使用する。
使用してはいけないもの
これらの C99 の機能は、コンパイラのサポートが不十分なため使用してはいけない。
- ステートメントの後の宣言 (MSVC 2012 はこれをサポートしていない)。すべての宣
言はブロックの先頭になければならない。
- 可変長配列 (C11 でもこれはオプショナルな機能である)。
- _Bool 型と _Complex 型。
- "inline" (ほとんど必要ない、コンパイラに最適化させよう。)
- フレキシブル配列メンバ: HP-UX C コンパイラはサポートしていない。(John
Marriott)
USE OF COMMON FUNCTIONS style-functions
よく使われる関数のうち、特別なVimバージョンを持つものがある。これらは理由あっ
て導入されたものなので、常にVimバージョンを使うように意識すること。
NORMAL NAME VIM NAME DIFFERENCE OF VIM VERSION
free() vim_free() NULLの解放をチェックする
malloc() alloc() アウトオブメモリの状況をチェックする
malloc() lalloc() alloc()に似ているが、long型の引数を持つ
strcpy() STRCPY() char_u *引数を、(char *)へキャストする
strchr() vim_strchr() スペシャルキャラクタを受け入れる
strrchr() vim_strrchr() スペシャルキャラクタを受け入れる
isspace() vim_isspace() 128以上のキャラクタを扱うことができる
iswhite() vim_iswhite() Tabとスペースに対してのみTRUE
memcpy() mch_memmove() オーバーラップしたコピーを扱う
bcopy() mch_memmove() オーバーラップしたコピーを扱う
memset() vim_memset() 全てのシステムで一定である
NAMES style-names
関数の名前に31文字より長い名前は使えない。(VMSのために)
"delete" や "this" という名前の変数を使わないこと。C++で問題となる。
Vimができる限り多くのシステム上で走るという必要上、システムによってすでに定義
されている名前を使うことは避けねばならない。これは、問題となることが知られて
いる名前のリストである。名前はregexpパターンとして与えられている。
is.*() POSIX, ctype.h
to.*() POSIX, ctype.h
d_.* POSIX, dirent.h
l_.* POSIX, fcntl.h
gr_.* POSIX, grp.h
pw_.* POSIX, pwd.h
sa_.* POSIX, signal.h
mem.* POSIX, string.h
str.* POSIX, string.h
wcs.* POSIX, string.h
st_.* POSIX, stat.h
tms_.* POSIX, times.h
tm_.* POSIX, time.h
c_.* POSIX, termios.h
MAX.* POSIX, limits.h
__.* POSIX, system
_[A-Z].* POSIX, system
E[A-Z0-9]* POSIX, errno.h
.*_t POSIX, for typedefs, *_T を使うこと。
wait types.hとコンフリクトするため、関数の引数として使わない
index グローバル宣言を覆い隠す
time グローバル宣言を覆い隠す
new C++の予約語
clear Mac curses.h
echo Mac curses.h
instr Mac curses.h
meta Mac curses.h
newwin Mac curses.h
nl Mac curses.h
overwrite Mac curses.h
refresh Mac curses.h
scroll Mac curses.h
typeahead Mac curses.h
basename() GNU 文字列関数(GNU string function)
dirname() GNU 文字列関数(GNU string function)
get_env_value() Linux システム関数
VARIOUS style-various
型の定義に使う名前は最後を "_T" にする:
typedef int some_T;
マクロ定義はすべて大文字にする: #define SOME_THING
機能に関する定義は "FEAT_" で始める: #define FEAT_FOO
'\"' を使わない、あるコンパイラはこれを扱えない。'"' はうまく機能する。
次を使ってはならない:
#if HAVE_SOME
あるコンパイラはこれを扱えず、"HAVE_SOME" が定義されていないと訴える。
次を使う
#ifdef HAVE_SOME
または
#if defined(HAVE_SOME)
STYLE style-examples
一般的なルール: 1行に1つのステートメント。
間違い: if (cond) a = 1;
OK: if (cond)
a = 1;
間違い: while (cond);
OK: while (cond)
;
間違い: do a = 1; while (cond);
OK: do
a = 1;
while (cond);
間違い: if (cond) {
cmd;
cmd;
} else {
cmd;
cmd;
}
OK: if (cond)
{
cmd;
cmd;
}
else
{
cmd;
cmd;
}
ブロックが1行の場合は、波括弧を省くことができる。if/else の1つのブロックに波括
弧がある場合、他のブロックにも波括弧があると、通常は見栄えが良くなる:
OK: if (cond)
cmd;
else
cmd;
OK: if (cond)
{
cmd;
}
else
{
cmd;
cmd;
}
関数宣言には ANSI スタイルを使い、戻り値の型は独立した行にインデントをつけて書
くこと。
間違い: int function_name(int arg1, int arg2)
OK: /*
* Explanation of what this function is used for.
* この関数が何に使われるかの説明。
*
* Return value explanation.
* 戻り値の説明。
*/
int
function_name(
int arg1, // short comment about arg1
int arg2) // short comment about arg2
{
int local; // comment about local
local = arg1 * arg2;
SPACES AND PUNCTUATION style-spaces
関数名とブラケットの間にスペースを入れないこと:
間違い: func (arg);
OK: func(arg);
if、while、switchなどの後には、スペースを入れること。
間違い: if(arg) for(;;)
OK: if (arg) for (;;)
コンマ、セミコロンの後にはスペースを入れること:
間違い: func(arg1,arg2); for (i = 0;i < 2;++i)
OK: func(arg1, arg2); for (i = 0; i < 2; ++i)
'='、'+'、'/' などの前と後には、スペースを入れること。
間違い: var=a*5;
OK: var = a * 5;
一般的なこと: コードの行をグループ分けするために、空行を使う。行グループのす
ぐ上にコメントを入れる。こうすることによって、何が行われるのかをより簡単に知
ることができる。
OK: /* Prepare for building the table. */
/* テーブルの作成の準備 */
get_first_item();
table_idx = 0;
/* Build the table */
/* テーブルの作成 */
while (has_item())
table[table_idx++] = next_item();
/* Finish up. */
/* 仕上げ */
cleanup_items();
generate_hash(table);
==============================================================================
3. 決定事項 design-decisions
折り畳み(folding)
同じバッファにいくつもの折り畳み状態を設定可能にする。例えば、あるウィンドウに
関数を折り畳んだ状態で表示し、他のウィンドウで関数の中身を表示するなど。
折り畳みはテキストを表示する方法である。テキストを変更すべきではない。したがっ
てバッファ内のテキストをウィンドウに表示する際のフィルタとして実行される。
ウィンドウの名前
"ウィンドウ" という単語は一般にいくつかの意味で使われている。スクリーン上のウィ
ンドウ、xtermのウィンドウ、Vimのバッファを表示するウィンドウなど。
混乱を避けるため、時にウィンドウと呼ばれる他の物には別の名前が付けられている。
ここに関連する物の概観を示す。
スクリーン(screen) ディスプレイ全体。GUIでは例えば1024x768ピクセルの画
面。Vimシェルはスクリーン全体を使うことも一部を使う
こともできる。
シェル(shell) Vimアプリケーション。スクリーン全体(例えばコンソール
で実行した時)、あるいはその一部(xtermやGUI)。
ウィンドウ(window) バッファの表示画面。Vimは複数のウィンドウを持つこと
ができる。ウィンドウはコマンドラインやメニューバー、
ツールバーなどといっしょに表示される。これらはシェル
に納まる。
スペルチェック develop-spell
Vim にスペルチェックを追加することになったとき、利用可能なスペルチェックのライ
ブラリやプログラムについて調査が行われた。その結果は残念なことに、Vim 内でスペ
ルチェックエンジンとして使えるものはないとわかった。これには様々な理由がある:
- マルチバイトエンコーディングをサポートしていない。1つのファイル内で複数の言
語を使えるようにするために、少なくとも UTF-8 はサポートしていなければならな
い。
オンザフライな変換は常に可能とは限らない(iconv に対応している必要がある)。
- プログラムとライブラリに対して: それらをそのまま(as-is)使うには、Vim と別個
にインストールしなければならない。これはたいてい不可能ではないが、難点である。
- パフォーマンス: いくつかのテストによると、スペルチェックを構文強調のようにオ
ンザフライで(再描画中に)行うことは可能であった。しかし他のコードで使われたメ
カニズムはもっと遅かった。例えば、Myspell はハッシュテーブルを使用する。ほと
んどのスペルチェッカが使用している接辞圧縮を使うと遅くなった。
- aspell のような外部プログラムを使うには、通信メカニズムを用意しなければなら
ない。これをポータブルな方法で行うのは複雑過ぎる(Unix だけなら比較的簡単だが、
それでは十分ではない)。そしてパフォーマンスが問題になる(何回ものプロセス切替
が行われる)。
- "Etten-Leur" や "et al." など、単語でない単語のサポートを欠いている。そのた
めこれらの部分を OK とマークしなければならないが、そうすると信頼性が低下する。
- 地域や方言のサポートを欠いている。英語の単語をすべて受け付け、カナダ語でない
単語を別に扱うことが難しくなる。
- 頻度が低い単語のサポートを欠いている。正しいがめったに使われないたくさんの単
語が、よく使われる単語のスペルミスとみなされてしまう。
- スペル候補を作成するには速度はそれほど重要ではなく、他のプログラムやライブラ
リをインストールすることは許容できる。しかし、単語リストが異なるとスペル候補
が誤単語になってしまう。
スペル候補 develop-spell-suggestions
候補の作成には2つの基本的なメカニズムがある:
1. 誤った単語を少し変更して正しい単語とマッチするかチェックする。あるいは、正
しい単語全てに対し、それを少し変更して誤った単語とマッチするかチェックする。
変更とは、文字の削除・文字の挿入・2つの文字の交換などである。
2. 誤った単語と正しい単語のリストの両方に soundfolding (発音が近い単語を同じグ
ループとみなすこと) を行って、そこでマッチを見つける。1番目のメカニズムと同
様にいくつか変更をしてもよい。
最初のメカニズムはタイプミスを見つけるのにはよい。ハッシュテーブルの実験と、他
のスペルチェッカのソリューションを見ると、これにはtrie(ツリー構造の一種)が最適
であるとの結論になった。メモリ使用量の削減と、賢い変更を試みるということの両方
の面でである。例えば、文字を挿入するときは正しい単語につながる文字だけを試せば
よい。他の(ハッシュテーブルを使った)メカニズムは、単語のすべての位置で、ありう
るすべての文字を試さねばならない、また、ハッシュテーブルを使うには、単語の境界
が個別に認識されなければならないのに対し、trie はそれを要求しない。そのためメ
カニズムがより単純になる。
ある単語の発音は知っているがスペルを知らないという場合に soundfolding は有用で
ある。例えば、"dictionary" という単語を "daktonerie" と書いてしまうかもしれな
い。これを最初の方法で訂正しようとすると変更回数が非常に多くなってしまい、正し
いスペルを見つけるのは困難である。それに対し、これらの単語にsoundfoldingを行う
と "tktnr" と "tkxnry" になり、2文字しか違わない。
soundfoldの同値(音が似ている単語)により単語を見つけるには全てのsoundfolded
wordsのリストが必要である。どれが最良の方法かを探すための実験が行われた。案:
1. 修正候補を探すときに、その場でsound foldingを行う。つまり、正しい単語のtrie
をたどりながら、各単語をsoundfoldingし、それがスペルミスしている単語からど
れだけ異なるかをチェックする。これはメモリ効率の面でとても優れているが、時
間は長くかかる。英語の場合、高速なPCで2秒ほどかかる。これは対話的な利用とし
て受け入れられる。しかしいくつかの言語(ドイツ語、カタルニャ語など)に対して
は10秒以上かかり、受け入れがたい。バッチ処理(自動訂正)に使うには全ての言語
で遅すぎる。
2. soundfoldされた単語に対してtrieを使い、soundfoldingなしのときとまったく同じ
ように検索できるようにする。そのためには、soundfoldされた各単語に対し、正し
い単語のリストを記憶しておく必要がある。そうすると照合がとても高速になるが、
1MB〜10MBのオーダーの大量のメモリを必要とする。ある言語の場合は元の単語のリ
ストよりも多くなる。
3. 2番目の案と同様だが、接辞圧縮を使い、soundfoldした基本単語だけを保存するこ
とによりメモリ消費量を減らす。これはAspellが採用している方法である。不利点
は、誤った単語をsoundfoldする前に接辞を取り除いておかねばならないことである。
そのため、単語の先頭・末尾における誤りに対しては対応できない。また、誤った
単語が正しい単語から大きく異なるときは遅くなる。
我々が採用したのは、2番目のメカニズムを使い、別ファイルを使う方法である。こう
することによって、十分なメモリを持っているユーザーはとてもよい候補を得ることが
できるし、メモリが不足しているユーザーやスペルチェックだけで候補は出さなくてよ
いというユーザーはそれほどメモリを使わなくてすむ。
単語の頻度
候補をソートするにはどの単語が共通であるかを知ると役に立つ。理論的には単語の頻
度は単語とともに辞書の中に保持することができる。しかしそうすると単語につき回数
を保持しなければならない。これは単語ツリー圧縮を大いに劣化させる。また、全ての
言語に対して単語の頻度を保守するのは大変な作業である。
また、テキストに既に出てきている単語を優先するとよいだろう。このようにして特定
のテキスト内に表れる単語は候補の中で優先度が高くなる。
実装されたのは、表示中に単語を数えることである。ハッシュテーブルを使ってその単
語の回数を高速に検索する。回数は接辞ファイルでCOMMONアイテムにリストされている
単語から初期化される。そのため新規ファイルの編集を始めたときも機能する。
これは理想的ではない。Vimが長時間稼動しているほど回数は大きくなるためである。
しかし実用的には単語の回数を使わない場合に比べて注目に値するほどの改善である。
==============================================================================
4. 想定していること design-assumptions
変数のサイズ:
char 8 bit signed
char_u 8 bit unsigned
int 32 or 64 bit signed (限定された機能については16ビットもありうる)
unsigned 32 or 64 bit unsigned (16ビットについてはintと同様)
long 32 or 64 bit signed, can hold a pointer
Note いくつかのコンパイラは長すぎる行は文字列をうまく扱えない。C89の標準規格で
は509文字までに制限されている。
vim:tw=78:ts=8:noet:ft=help:norl: