ruvim

RuVim 仕様(現状実装 + 設計方針)

目的

RuVim は Ruby で実装する Vim ライクなターミナルエディタです。

この文書は「現状の実装」と「今後の拡張前提の設計」をまとめた仕様です。

基本概念

1. Buffer

テキスト本体を保持する単位です。

Buffer は表示状態(カーソル位置・スクロール)を持ちません。

Buffer 構造メモ(性能検討)

現状の RuVim::Buffer は「行配列 + Ruby String 直接編集」です。

将来の候補(検討済み):

当面の方針:

2. Window

Buffer をどの位置で表示するかを持つビューです。

同一 buffer を複数 window で表示できる前提の設計です(現状 UI は単一 window)。 同一 buffer を複数 window で表示できる前提の設計です(現状 UI は simple split 対応)。

座標系(現状の単位)

RuVim は Vim と同様に、用途ごとに座標系を分けています。

役割分担(現状):

3. Editor

エディタ全体の実行状態です。

コマンドモデル

方針

内部コマンド (CommandRegistry)

内部コマンドは ID で管理します(例: cursor.left, buffer.delete_line)。

例:

RuVim::CommandRegistry.instance.register(
  "cursor.left",
  call: :cursor_left,
  desc: "Move cursor left"
)

Ex コマンド (ExCommandRegistry)

ユーザーが : 行で入力するコマンド名を管理します。

例:

RuVim::ExCommandRegistry.instance.register(
  "w",
  call: :file_write,
  aliases: %w[write],
  nargs: :maybe_one,
  bang: true,
  desc: "Write current buffer"
)

alias_for は持ちません。aliases を登録時に展開し、同じ spec を参照させます。

コマンド実装 (GlobalCommands)

コマンド本体は RuVim::GlobalCommands.instance のメソッドで実装します。

想定の引数形:

入力と実行の流れ

  1. RuVim::Input が raw mode のキー入力を読む
  2. RuVim::App が mode ごとに処理を分岐
  3. Normal mode のキーは RuVim::KeymapManager で解決
  4. RuVim::Dispatcher が内部コマンド or Ex コマンドを実行
  5. Insert mode でキー処理後、stdin に未読データが残っていればレンダリングをスキップして追加のキーを読み取り・処理する(ペースト高速化)。このバッチ処理中は autoindent を抑制し、貼り付けテキストが余分にインデントされるのを防ぐ
  6. RuVim::Screen が再描画

起動オプション(CLI, 現状)

インストール後の ruvim コマンド(実体は exe/ruvim)は RuVim::CLI を通して起動オプションを解釈します(bin/ruvim は互換ラッパー)。

補足(現状実装):

起動時コマンド(-c, +...)は、初期 buffer / file open / intro screen 構築の後に実行します。 --cmd はそれより前で、user config 読み込み前に実行します。

Keymap layering(現状)

RuVim::KeymapManager は以下の優先順で解決します(高 -> 低)。

  1. filetype-local
  2. buffer-local
  3. mode-local
  4. global

現状の標準バインドは mode-local のみですが、内部 API として各レイヤーの登録を持っています。

モード仕様(現状)

Normal mode

Insert mode

Visual mode(現状)

Rich mode

Command-line mode

Hit-enter prompt(複数行メッセージ表示)

:ls:set(引数なし)など、複数行にわたる出力を行うコマンドの結果を表示するモード。

キー操作

Ex コマンド仕様(現状 builtin)

検索仕様(現状)

仕様メモ

補足:

:command(現状仕様)

:ruby / :rb(現状仕様)

:r / :read(ファイル・コマンド出力の挿入)

:w !(バッファ内容をコマンドへパイプ)

:!(shell 実行, 最小)

バッファ管理 Ex コマンド(現状仕様)

alternate buffer(#

arglist(引数リスト)

画面描画仕様(現状)

ANSI エスケープシーケンスによる再描画です。

split UI

Tabpage(現状)

リサイズ対応

suspend / resume(現状)

Command-line 改善(現状)

文字幅対応(現状ベースライン)

描画の幅処理(現状):

制約:

エンコーディング方針(現状)

Undo / Redo 仕様(現状)

undo 粒度(現状)

Vim 完全互換ではなく、まずは扱いやすい粒度を優先した仕様です。

Operator-pending 仕様(現状)

対応している d + motion:

設計上は operator-pending 状態機械を導入しており、d/y/c/= を同じ流れで扱います。

補足:

text object(現状)

レジスタ仕様(現状の基礎)

Mark / Jump List(現状の基礎)

Macro(現状の基礎)

Option system(現状の基礎)

Filetype / ftplugin(現状の基礎)

Lang モジュール on_save フック

シンタックスハイライト(最小)

Rich mode(構造化データ表示)

構造化データ(TSV/CSV)や Markdown を見やすく整形して表示するモードです。 Visual mode と同様に Normal mode の上に乗るモードとして設計されています。

シングルトン方針

グローバルに共有して良い「定義系」だけシングルトンにしています。

RuVim::Editor はシングルトンではありません(実行状態の分離のため)。

設定ファイル(現状)

安全性メモ:

Git 連携

Git Blame

<C-g>:git プリセットのコマンドラインモードに入る。:git <subcommand> で実行。 未知のサブコマンドは :! と同様に alternate screen を抜けてシェルで直接実行する(例: :git stash)。:gh も同様(例: :gh issue list)。

GitStatus

:git statusgit status の結果を kind: :git_status の読み取り専用バッファで表示。

GitDiff

:git diffgit diff の結果を kind: :git_diff の読み取り専用バッファで表示(filetype: diff)。追加引数をそのまま渡せる(例: :git diff --cached)。差分がない場合はメッセージ表示のみ。Enter で差分行に対応するファイルの該当行にジャンプ。:git log -p バッファでも同様に動作する。

GitLog

:git loggit log の結果を kind: :git_log の読み取り専用バッファで表示。追加引数をそのまま渡せる(例: :git log -p)。-p 指定時は filetype: diff で syntax highlight が効く。出力はストリーミングで逐次表示(カーソルは先頭行に固定)。バッファを閉じるとプロセスも停止する。

GitBranch

:git branchgit branch -a の結果を kind: :git_branch の読み取り専用バッファで表示。コミット日時の新しい順にソート。各行にブランチ名、日付、最新コミットのサブジェクトを表示。Enter でカーソル行のブランチ名を :git checkout <branch> としてコマンドラインにプリフィル(確認ステップあり、即時実行ではない)。

GitGrep

:git grep <pattern> [<args>...]git grep -n を実行し、結果を kind: :git_grep の読み取り専用バッファで表示。追加引数をそのまま渡せる(例: :git grep -i pattern)。マッチがない場合はメッセージ表示のみ。Enter で該当ファイルの該当行にジャンプ。Esc / Ctrl-C でバッファを閉じる。

GitCommit

:git commit でコミットメッセージ編集バッファ(kind: :git_commit)を開く。# で始まる行はコメント(git status 情報を表示)。insert モードで開始。:w または :wq でコミット実行。:q! でキャンセル。メッセージが空の場合はコミットを中止。

GitBlame

Blame バッファ内のバッファローカルバインディング:

実装: lib/ruvim/git/blame.rb(blame パース・実行)、lib/ruvim/git/commands.rb(status/diff/log 実行)、lib/ruvim/global_commands.rb(コマンドハンドラ)

GitHub 連携

:gh link で現在のファイル・カーソル行の GitHub URL を生成し、message line に表示する。同時に OSC 52 エスケープシーケンスでクリップボードにコピーする。

gh browse

:gh browse で現在のファイル・カーソル行の GitHub URL をブラウザで開く。

gh pr

:gh pr で現在のブランチの PR ページをブラウザで開く。

実装: lib/ruvim/gh/link.rb, lib/ruvim/browser.rb

テスト(現状)

既知の未実装 / 今後の仕様候補(現状)