書けば書くほどVim Scriptのアレな点が気になってしょうがない。Vim scriptは基本的にCommand-line modeで入力するEx commandsをそのまま書き下しただけのもので、インタラクティブにちょちょっと使っているだけなら特に気にならないのですが、プログラミング言語として見るとかなりアレです。

Ex commandsをベースにしていることに由来する制限事項
基本的に1行につき1コマンドしか記述できない。
  • 一応、各コマンドを|で区切ることで1行に複数のコマンドを記述することができるが、コマンドによっては|を引数として解釈するために後続に複数のコマンドを記述できない場合がある。その一貫性のなさ。
  • 1コマンドが複数行に渡る場合、必ず行継続の記号\を書かなければならない。しかも\は後続の行頭に書かなければならず、他のほとんどの言語のスタイル(行末に特定の記号を記述するか、文脈に応じて適宜判定されるか、そもそも改行に深い意味がないもの)と比較すると違和感がある(これは各コマンドの引数の解釈方法が統一されてないことが原因で、行頭以外の場所の文字を使うことが不可能に近いからだ)。
各コマンドごとに引数の解釈がバラバラ
  • 適切なsyntax highlightの設定を書くことが非常に困難である。どのぐらい困難かというと、Vim自身に添付されているvim scriptのsyntax highlightの設定ですら不完全である($MYVIMRCでごく一部については修正するようにしているけれど、微妙なレベルの修正が多く神経を使うため、九分九厘放置気味)。
Vimの実装に由来しているであろうダサいインターフェース
tabpagesの各種情報を得るには各tabpageに対応する「番号」を使わなければならない(例: tabpagebuflist(3))。
  • 最悪なのが、この「番号」に対応するtabpageが固定でないこと。「番号」はtabpageの配置によって決まり、最も左側のtabpageが1、その右隣が2、以下1づつ増加していく。例えば3に対応するtabpageは左から3番目のtabpageである(これをAとしよう)。別のtabpage Bとtabpage Aの位置を入れ替えたとすると、その時点から3に対応するtabpageはAからBに変化するということだ。
  • (せっかくVim7でDictionary-function等のそれなりの機能が追加されたのだから、「番号」の代わりにtabpageを表すDictionaryを使えばいいのに)
windowsの各種情報を得るには各windowに対応する「番号」を使わなければならない。細かいことはtabpageの「番号」と同様。ただ、tabpageと違ってwindowの配置は立て分割と横分割が入り混じった複雑な状態になり得るため、「3番は上から3番目のwindow」のような単純な解釈はできない。
buffersの各種情報を得るには各bufferに対応する「番号」を使わなければならない。ただ、tabpageやwindowと異なり、「番号」はbuffer毎に一意で固定であるため、比較的軽傷ではある(ただbufferが作成される度に1づつ増加していくため、長期間起動しているとアレな気もするが、まあ実用上は問題ないか)。
ユーザーインターフェースが多過ぎる。あるいは統一されていない。
一つの機能を提供するにしても、key mappings、Ex commands、functionsと3つものインターフェースがある。プラグインを書く場合はこれらを一々書くのが結構面倒臭い。
Key mappingsもEx commandsもfunctionsも各々にしかない機能がある。つまり、全ての機能がどれか一つのインターフェースに統一されていない。
  • 例えばカーソル移動のhjklは、それに対応するEx commandsやfunctionsは存在しない(同等の機能を実現することは不可能ではないが、Emacsのように対応する関数がある訳ではない)。
  • このため、key mappingsでしか提供されていない機能を使うには:normal! hjklのような間接的な方法を取るしかない(全部functionsで統一すればいいのに)。
Key mappingsの諸問題
Key mappingsでしか提供されていない機能は、名前でその機能を参照できないため、key mappingsの記述の解読は困難になりがち。
名前のあるEx commandsやfunctionsに比べると覚えにくかったり検索しづらかったりする。
ポータブルなkey mappingsを記述することが難しい、というか面倒臭い。
  • Key mappingsの定義時、{rhs}のresursive/nonrecursiveの指定はどちらか一方でなければならず、一部だけに限定することはできない。
  • 安易にrecursiveなkey mappingsを使うと、他のkey mappingsの定義のために期待通りの動作を得られなくなる可能性が高い。
  • かといって全てnonrecursiveにすると記述が面倒になりがちか、不可能に近くなる(例: 2-stroke keysのprefixを入れ替える)。
一部の状況下ではkey mappingsが無効になる。常にデフォルトのものを使わなければならない(例: ins-completion-menuが表示されているときの一部キー)。
:command:functionの名前の制限
ユーザー定義の:command:functionの名前は大文字で始めなければならない。
  • 組み込みのものとの区別のためらしく、実際、実装の方もそれを当てにしたコードが書かれている。
  • :commandはまだ一貫性があるのでマシ。
  • :functionの方は次の場合ならこの名前の制限がないため、一貫性に欠ける: (1) スコープの接頭辞を明示する(s:foo()); (2) numbered-functionによる定義を行う(:function foo.bar()); (3) autoloadされる関数を使う(foo#bar())

他にも色々とあった気がしますけど、ぱっと思いついたのはこれぐらい。後で思い出したら追記しておきます。

:command:functionの名前の制限」を追加。