ruvim 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +18 -6
  3. data/README.md +15 -1
  4. data/docs/binding.md +16 -0
  5. data/docs/command.md +78 -4
  6. data/docs/config.md +10 -2
  7. data/docs/spec.md +60 -9
  8. data/docs/tutorial.md +24 -0
  9. data/docs/vim_diff.md +18 -8
  10. data/lib/ruvim/app.rb +290 -8
  11. data/lib/ruvim/buffer.rb +14 -2
  12. data/lib/ruvim/cli.rb +6 -0
  13. data/lib/ruvim/editor.rb +12 -1
  14. data/lib/ruvim/file_watcher.rb +243 -0
  15. data/lib/ruvim/git/blame.rb +245 -0
  16. data/lib/ruvim/git/branch.rb +97 -0
  17. data/lib/ruvim/git/commit.rb +102 -0
  18. data/lib/ruvim/git/diff.rb +129 -0
  19. data/lib/ruvim/git/handler.rb +84 -0
  20. data/lib/ruvim/git/log.rb +41 -0
  21. data/lib/ruvim/git/status.rb +103 -0
  22. data/lib/ruvim/global_commands.rb +176 -42
  23. data/lib/ruvim/highlighter.rb +3 -1
  24. data/lib/ruvim/input.rb +1 -0
  25. data/lib/ruvim/lang/diff.rb +41 -0
  26. data/lib/ruvim/lang/json.rb +34 -0
  27. data/lib/ruvim/rich_view/json_renderer.rb +131 -0
  28. data/lib/ruvim/rich_view/jsonl_renderer.rb +57 -0
  29. data/lib/ruvim/rich_view.rb +16 -0
  30. data/lib/ruvim/screen.rb +9 -12
  31. data/lib/ruvim/version.rb +1 -1
  32. data/lib/ruvim.rb +10 -0
  33. data/test/app_completion_test.rb +25 -0
  34. data/test/app_scenario_test.rb +169 -0
  35. data/test/cli_test.rb +14 -0
  36. data/test/clipboard_test.rb +67 -0
  37. data/test/command_line_test.rb +118 -0
  38. data/test/config_dsl_test.rb +87 -0
  39. data/test/display_width_test.rb +41 -0
  40. data/test/file_watcher_test.rb +197 -0
  41. data/test/follow_test.rb +199 -0
  42. data/test/git_blame_test.rb +713 -0
  43. data/test/highlighter_test.rb +44 -0
  44. data/test/indent_test.rb +86 -0
  45. data/test/rich_view_test.rb +256 -0
  46. data/test/search_option_test.rb +19 -0
  47. data/test/test_helper.rb +9 -0
  48. metadata +17 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c463658b0badbad140842446b82818bb797930372d4ccb8ff5e4275fbe627904
4
- data.tar.gz: 92b3c9f004f8b075f603d4b8f2e4c48255ac0ef3eea768dd3e290495ab661033
3
+ metadata.gz: affafdf81175fc15f4d0f0053982743caa863aa371053095bfdd24160aee857d
4
+ data.tar.gz: 9abd61f0ba641b3f7dc429c4104f2e5d09243ebeb821baa8ad7521c6b4a3eca7
5
5
  SHA512:
6
- metadata.gz: 46ec215ad18a1e72a62d54e0a95b24d87b7ee5b9093300a4597c8d96754ef4a1ce30f964101e1f2cd3dda8ecefcc74d7565602bb80f0eba6ce28cd2fb835a9ad
7
- data.tar.gz: 49827d053ac4b9c827b0cbe86ebb00ff8a6609af4998ef5060a2407d0022f33b47327c11eaef4efc75aca03e0ddc07660a8bf12214db28e8c98f58c83c705b60
6
+ metadata.gz: 7a5dc6394f0905831d384fb66d88992d20691b58347a2c1673179f0036585f82aa54c6681f8bb79dd9c0e3ffa77389cb5e7a62d7eec27571be0b7f79529a58fb
7
+ data.tar.gz: 203a49cce3d46575fa743c5635874af2e320ddd225fe973d74a82851b1bfb6112e379e084e1e8afa262c5eac3d596c5c7b23ad572e77f8bf6ed5d2296e9fe992
data/AGENTS.md CHANGED
@@ -9,6 +9,7 @@ This project is RuVim, a Vim-like editor written in Ruby. Always run the full te
9
9
  * catch up changes
10
10
  * move completed tasks to done.md
11
11
  * update CLAUDE.md Source Tree section if files were added, removed, or renamed
12
+ * note that CLAUDE.md is a symbolic link to AGENTS.md. Commit AGENTS.md if modify CLAUDE.md
12
13
  * commit it
13
14
  * After committing, show the commit message
14
15
 
@@ -49,21 +50,32 @@ CLI (exe/ruvim) → CLI.parse() → App.new() → App.run_ui_loop()
49
50
  | `lang/base.rb` | Default lang module (no-op fallback for indent/dedent) |
50
51
  | `lang/markdown.rb` | Markdown parsing, detection helpers, and syntax highlight colors |
51
52
  | `lang/ruby.rb` | Ruby syntax highlighting via Prism lexer; auto-indent calculation |
52
- | `lang/json.rb` | JSON syntax highlighting via regex |
53
+ | `lang/json.rb` | JSON syntax highlighting via regex; auto-indent |
53
54
  | `lang/scheme.rb` | Scheme syntax highlighting via regex |
55
+ | `lang/diff.rb` | Diff syntax highlighting (add/delete/hunk/header colors) |
54
56
  | `lang/tsv.rb` | TSV detection and RichView renderer registration |
55
57
  | `lang/csv.rb` | CSV detection and RichView renderer registration |
58
+ | `git/blame.rb` | Git blame: parser, runner, command handlers |
59
+ | `git/status.rb` | Git status: runner, filename parser, command handlers |
60
+ | `git/diff.rb` | Git diff: runner, command handlers |
61
+ | `git/log.rb` | Git log: runner, command handlers |
62
+ | `git/branch.rb` | Git branch: listing, checkout, command handlers |
63
+ | `git/commit.rb` | Git commit: message buffer, execute, command handlers |
64
+ | `git/handler.rb` | Git module (repo_root), dispatcher, close, shared helpers |
65
+ | `file_watcher.rb` | File change monitoring (inotify with fiddle fallback to polling) |
56
66
  | `clipboard.rb` | System clipboard access (xclip, pbpaste, etc.) |
57
67
  | `context.rb` | Command handler context (editor, window, buffer, invocation) |
58
68
  | `command_invocation.rb` | Single command invocation (id, argv, count, bang) |
59
69
  | `rich_view.rb` | Rich view mode (TSV/CSV/Markdown rendering) |
60
70
  | `rich_view/table_renderer.rb` | Table formatting with display-width-aware column alignment |
61
71
  | `rich_view/markdown_renderer.rb` | Markdown rendering (headings, inline, tables, code blocks, HR) |
72
+ | `rich_view/json_renderer.rb` | JSON pretty-print into virtual buffer |
73
+ | `rich_view/jsonl_renderer.rb` | JSONL per-line pretty-print into virtual buffer |
62
74
 
63
75
  ### Tests (test/)
64
76
 
65
- - Unit: `buffer_test`, `window_test`, `editor_test`, `screen_test`, `display_width_test`, `text_metrics_test`, `keymap_manager_test`, `highlighter_test`, `dispatcher_test`, `config_*_test`, `indent_test`
66
- - Integration: `app_scenario_test`, `app_motion_test`, `app_text_object_test`, `app_register_test`, `app_dot_repeat_test`, `app_completion_test`, `app_unicode_behavior_test`, `render_snapshot_test`, `on_save_hook_test`
77
+ - Unit: `buffer_test`, `window_test`, `editor_test`, `screen_test`, `display_width_test`, `text_metrics_test`, `keymap_manager_test`, `highlighter_test`, `dispatcher_test`, `config_*_test`, `indent_test`, `file_watcher_test`, `clipboard_test`, `command_line_test`
78
+ - Integration: `app_scenario_test`, `app_motion_test`, `app_text_object_test`, `app_register_test`, `app_dot_repeat_test`, `app_completion_test`, `app_unicode_behavior_test`, `render_snapshot_test`, `on_save_hook_test`, `follow_test`, `git_blame_test`
67
79
  - Helper: `test_helper.rb` (fresh_editor, Minitest)
68
80
 
69
81
  ### Docs (docs/)
@@ -74,11 +86,11 @@ CLI (exe/ruvim) → CLI.parse() → App.new() → App.run_ui_loop()
74
86
 
75
87
  lumitrace is a tool that records runtime values of each Ruby expression.
76
88
  When a test fails, read `lumitrace help` first, then use it.
77
- Basic: `lumitrace -t exec rake test`
89
+ Basic: `lumitrace -j exec rake test`
90
+ This also provides coverage information for the test run.
78
91
 
79
92
  When fixing bugs, do NOT assume the first fix attempt is correct. After applying a fix, re-read the relevant code paths to verify the fix addresses the actual root cause, not a symptom. If the user says 'it hasn't changed' or equivalent, start fresh analysis from the failing behavior.
80
93
 
81
94
  ## misc
82
95
 
83
- The user communicates in both English and Japanese. Respond in the same language the user uses. When the user gives feedback like 変わってないですよ ('it hasn't changed'), treat it as a bug report requiring re-analysis.
84
-
96
+ The user communicates in both English and Japanese. Respond in the same language the user uses. When the user gives feedback like 変わってないですよ ('it hasn't changed'), treat it as a bug report requiring re-analysis.
data/README.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  Ruby で実装した Vim ライクなターミナルエディタです。
4
4
 
5
+ Vim の操作感をベースに、Ruby ならではの、もしくは ko1 が欲しい拡張性と独自機能を加えています。
6
+
7
+ ## Vim にない独自機能
8
+
9
+ - **Rich View (`gr`)** — TSV / CSV / Markdown をテーブル整形して閲覧。CJK 幅を考慮したカラム揃え
10
+ - **`g/` 検索フィルタ** — 検索にマッチする行だけを集めたバッファを作成。再帰的に絞り込み可能。ログ解析に便利
11
+ - **Follow mode (`-f` / `:follow`)** — `tail -f` 相当のファイル追従。inotify 対応
12
+ - Ruby related:
13
+ - **Ruby DSL 設定** — `~/.config/ruvim/init.rb` に Ruby で `nmap`, `set`, `command` を記述。Vim script 不要
14
+ - **Ruby 正規表現** — 検索・置換は Ruby `Regexp`。Ruby ユーザーにそのまま馴染む
15
+ - **`:ruby` eval** — 実行中に任意の Ruby コードを評価。`ctx.editor` / `ctx.buffer` API でエディタを操作
16
+
17
+ ## 概要
18
+
5
19
  - raw mode + ANSI 描画
6
20
  - Normal / Insert / Command-line / Visual
7
21
  - Ex コマンド(`:w`, `:q`, `:e`, `:help`, `:set` など)
@@ -132,4 +146,4 @@ lint / format 方針(現状):
132
146
  - Vim 完全互換ではありません
133
147
  - 正規表現は Vim regex ではなく Ruby `Regexp` を使います
134
148
  - 文字幅 / Unicode は改善済みですが、完全互換ではありません
135
- - 複数ファイル引数や一部 Vim CLI オプションは未実装です
149
+ - 複数ファイル引数や一部 Vim CLI オプションは未実装です
data/docs/binding.md CHANGED
@@ -30,6 +30,14 @@
30
30
  - `/` : 前方検索入力に入る
31
31
  - `?` : 後方検索入力に入る
32
32
  - `x` : カーソル位置の文字削除
33
+ - `X` : カーソル前の文字削除
34
+ - `s` : カーソル位置の文字を削除して Insert mode(substitute)
35
+ - `~` : カーソル位置の文字の大文字小文字を切替
36
+ - `J` : 現在行と次の行を結合
37
+ - `D` : カーソルから行末まで削除
38
+ - `C` : カーソルから行末まで変更(削除して Insert mode)
39
+ - `S` : 行全体を変更(削除して Insert mode)
40
+ - `Y` : 行全体をヤンク
33
41
  - `dd` : 現在行を削除
34
42
  - `d` + motion : operator-pending delete(`dw`, `dj`, `dk`, `d$`, `dh`, `dl`)
35
43
  - `diw` / `daw` : 単語 text object delete(簡易)
@@ -68,6 +76,9 @@
68
76
  - `Ctrl-d` / `Ctrl-u` : 半ページ下/上へ移動(概ね表示高さの半分)
69
77
  - `Ctrl-f` / `Ctrl-b` : 1ページ下/上へ移動(`PageDown` / `PageUp` 相当)
70
78
  - `Ctrl-e` / `Ctrl-y` : カーソル位置をなるべく保ったまま画面を1行下/上へスクロール(最小実装)
79
+ - `zt` : カーソル行を画面上端に移動
80
+ - `zz` : カーソル行を画面中央に移動
81
+ - `zb` : カーソル行を画面下端に移動
71
82
  - `q{reg}` : macro 記録開始/終了(再度 `q` で停止)
72
83
  - `@{reg}` / `@@` : macro 再生 / 直前 macro 再生
73
84
  - `n` : 直前検索を次へ
@@ -77,6 +88,11 @@
77
88
  - `gf` : カーソル下のファイル名を開く(最小。`path` / `suffixesadd` を参照)
78
89
  - `file:line` 形式なら開いた後に `line` 行目へ移動
79
90
  - `gr` : Rich mode をトグル(TSV/CSV をテーブル整形表示、同一バッファ上で動作)
91
+ - `g/` : 検索パターンにマッチする行だけを集めたフィルタバッファを作成(再帰フィルタ可、Enter で元行へジャンプ、`:q` で戻る)
92
+ - `Ctrl-g` : Git コマンドモード(`:git ` がプリセットされたコマンドラインに入る)
93
+ - `blame` → Git blame を開く / `status` → Git status / `diff` → Git diff / `log` → Git log
94
+ - Blame バッファ内: `p` 親コミットの blame へ遷移 / `P` 前の blame へ戻る / `c` コミット詳細を表示
95
+ - `Ctrl-c` : stdin stream 停止(stdin バッファ表示時)
80
96
  - `Esc` : メッセージ/保留入力のクリア
81
97
  - `Ctrl-z` : shell へ suspend(`fg` で復帰)
82
98
  - `矢印キー` : 移動
data/docs/command.md CHANGED
@@ -3,6 +3,7 @@
3
3
  ## 起動オプション(CLI, 現状)
4
4
 
5
5
  - `--help`, `--version`
6
+ - `-f`(follow mode: ファイルを開いて末尾から `tail -f` 相当の追従モードで起動)
6
7
  - `--clean`
7
8
  - `-d`(diff mode placeholder, 未実装メッセージ表示)
8
9
  - `-q {errorfile}`(quickfix startup placeholder。現状は未実装メッセージ表示)
@@ -114,8 +115,12 @@
114
115
  - current window の location list を開く / 閉じる
115
116
  - `:lnext` / `:ln`, `:lprev` / `:lp`
116
117
  - location list 項目を前後移動して該当位置へジャンプ
118
+ - `:grep /pattern/ [path...]`
119
+ - 外部 grep(`grepprg`)を実行して quickfix list を作成
120
+ - `:lgrep /pattern/ [path...]`
121
+ - 外部 grep(`grepprg`)を実行して location list を作成
117
122
  - 現状の制限:
118
- - `:grep`, `:make`, `:cfile`, `:lgrep` は未実装
123
+ - `:make`, `:cfile`, `:lfile` は未実装
119
124
  - 一覧バッファ上で `Enter` からのジャンプは未実装
120
125
 
121
126
  ### `:rich`
@@ -129,6 +134,36 @@
129
134
  - 列幅は画面に見えている行だけから計算(大規模ファイルでも高速)
130
135
  - `Esc` / `Ctrl-C` で Normal mode に戻る
131
136
 
137
+ ### `:filter`
138
+
139
+ - 形式: `:filter [/pattern/]`
140
+ - 現在の検索パターン(引数なし)または指定パターンにマッチする行だけを集めたフィルタバッファを作成
141
+ - フィルタバッファ上で再度 `:filter` や `g/` を使うと再帰的に絞り込める
142
+ - Enter で元バッファの該当行へジャンプ(フィルタバッファは閉じる)
143
+ - `:q` でフィルタバッファを閉じて前のバッファに戻る
144
+ - 元バッファの filetype を引き継ぐ(TSV なら `gr` でテーブル表示可能)
145
+ - Normal mode では `g/` キーバインドで実行可能
146
+
147
+ ### `:follow`
148
+
149
+ - 形式: `:follow`
150
+ - ファイルの follow mode をトグルする(`tail -f` 相当)
151
+ - follow 中はファイルへの追記がリアルタイムにバッファへ反映される
152
+ - カーソルが最終行にいる場合は末尾を自動追従(auto-scroll)
153
+ - カーソルが途中にある場合はスクロール位置を維持
154
+ - `G` で末尾に移動すれば追従が再開される
155
+ - `:follow` を再度実行すると停止
156
+ - `Ctrl-C`(ノーマルモード)で follow を停止
157
+ - ステータスラインに `[follow]` と表示される(inotify 使用時は `[follow/i]`)
158
+ - ファイルが紐づいていないバッファではエラー
159
+ - 未保存の変更があるバッファでは follow 開始不可
160
+ - follow 中のバッファは変更不可(modifiable が false)
161
+ - ファイルが truncate された場合はメッセージを表示し監視を継続
162
+ - ファイルが削除された場合はメッセージを表示し、再作成を待って監視を再開
163
+ - follow 停止時、バッファ内容はそのまま保持(`:e!` で再読み込み可能)
164
+ - 監視方式: Linux では inotify(fiddle 経由)を優先し、使えない場合は polling にフォールバック
165
+ - polling は exponential backoff(0.1s → 3s)で CPU 負荷を抑える
166
+
132
167
  ### `:command`
133
168
 
134
169
  - 形式: `:command Name ex_body`
@@ -247,6 +282,16 @@
247
282
  - 各タブに含まれるウィンドウとバッファ名を表示
248
283
  - 現在のタブ / ウィンドウは `>` マーカーで示す
249
284
 
285
+ ### `:d` / `:delete`
286
+
287
+ - 形式: `:d [count]`, `:{range}d`
288
+ - 行を削除
289
+
290
+ ### `:y` / `:yank`
291
+
292
+ - 形式: `:y [count]`, `:{range}y`
293
+ - 行をヤンク
294
+
250
295
  ## 内部コマンド(主なもの)
251
296
 
252
297
  内部コマンドは主に key binding から使われ、`RuVim::CommandRegistry` に登録されます。
@@ -302,6 +347,33 @@
302
347
  - `editor.buffer_next`
303
348
  - `editor.buffer_prev`
304
349
  - `buffer.replace_char`
350
+ - `buffer.substitute_char`
351
+ - `buffer.swapcase_char`
352
+ - `buffer.join_lines`
353
+ - `buffer.indent_lines`
354
+ - `buffer.indent_motion`
355
+ - `buffer.visual_indent`
356
+ - `buffer.visual_select_text_object`
357
+ - `mode.visual_block`
358
+ - `cursor.page_up` / `cursor.page_down`
359
+ - `cursor.page_up.default` / `cursor.page_down.default`
360
+ - `cursor.page_up.half` / `cursor.page_down.half`
361
+ - `cursor.match_bracket`
362
+ - `window.scroll_up` / `window.scroll_down`
363
+ - `window.scroll_up.line` / `window.scroll_down.line`
364
+ - `window.cursor_line_top` / `window.cursor_line_center` / `window.cursor_line_bottom`
365
+ - `window.focus_or_split_left` / `window.focus_or_split_right` / `window.focus_or_split_up` / `window.focus_or_split_down`
366
+ - `normal.register_pending_start`
367
+ - `normal.operator_delete_start` / `normal.operator_yank_start` / `normal.operator_change_start` / `normal.operator_indent_start`
368
+ - `normal.replace_pending_start`
369
+ - `normal.find_char_forward_start` / `normal.find_char_backward_start` / `normal.find_till_forward_start` / `normal.find_till_backward_start`
370
+ - `normal.find_repeat` / `normal.find_repeat_reverse`
371
+ - `normal.change_repeat`
372
+ - `normal.macro_record_toggle` / `normal.macro_play_pending_start`
373
+ - `normal.mark_pending_start`
374
+ - `normal.jump_mark_linewise_pending_start` / `normal.jump_mark_exact_pending_start`
375
+ - `quickfix.next` / `quickfix.prev` / `quickfix.open`
376
+ - `stdin.stream_stop`
305
377
  - `ui.clear_message`
306
378
  - `rich.toggle`
307
379
 
@@ -316,12 +388,14 @@
316
388
  - `*` / `#` : カーソル下の単語検索(単語境界)
317
389
  - `g*` / `g#` : カーソル下の単語検索(部分一致)
318
390
  - `:vimgrep` / `:lvimgrep` : 検索結果を quickfix/location list に積む
391
+ - `:nohlsearch` (`:noh`) : 検索ハイライトを一時的にクリア(次の検索で自動復帰)
319
392
 
320
- ### `:%s/.../.../g`(最小実装)
393
+ ### `:%s/.../.../[flags]`
321
394
 
322
- - バッファ全体置換
395
+ - バッファ全体置換(レンジ指定対応: `:{range}s/.../.../`)
323
396
  - Ruby 正規表現 + Ruby 置換文字列を利用
324
- - `g` フラグ対応(全置換)
397
+ - 対応フラグ: `g`(全置換), `i`(大文字小文字無視), `I`(大文字小文字区別), `n`(置換せずマッチ数表示), `e`(エラー抑制)
398
+ - `c`(確認)フラグは未実装
325
399
 
326
400
  ## Operator-pending(Normal mode)
327
401
 
data/docs/config.md CHANGED
@@ -244,11 +244,11 @@ setglobal "tabstop=8"
244
244
  - Tab 入力/削除時の編集幅を指定します。
245
245
  - 現状は Insert mode の Tab 入力と、`expandtab` 時の空白 Backspace(最小)で使用します。
246
246
 
247
- - `autoindent` (`bool`, default `false`) [`DONE`]
247
+ - `autoindent` (`bool`, default `true`) [`DONE`]
248
248
  - 改行時に前行の先頭インデントを引き継ぎます。
249
249
  - Insert mode `Enter`、`o`/`O` に反映されます。
250
250
 
251
- - `smartindent` (`bool`, default `false`) [`PARTIAL`]
251
+ - `smartindent` (`bool`, default `true`) [`PARTIAL`]
252
252
  - 簡易な自動インデントを行います。
253
253
  - 現状は前行が `{` `[` `(` で終わる場合に `shiftwidth` 分の空白を追加します。
254
254
 
@@ -265,6 +265,14 @@ setglobal "tabstop=8"
265
265
  - ftplugin 読み込み対象、filetype-local keymap、簡易 syntax highlight の判定に使います。
266
266
  - 手動で変更した場合の ftplugin 再適用は現状未対応です。
267
267
 
268
+ ### Global options(検索・grep)
269
+
270
+ - `grepprg` (`string`, default `"grep -nH"`) [`DONE`]
271
+ - `:grep` / `:lgrep` が使用する外部コマンドを指定します。
272
+
273
+ - `grepformat` (`string`, default `"%f:%l:%m"`) [`DONE`]
274
+ - `:grep` / `:lgrep` の出力パース書式を指定します。
275
+
268
276
  ## 制限(現状)
269
277
 
270
278
  - Vim の option 全部は未実装(ごく一部のみ)
data/docs/spec.md CHANGED
@@ -166,7 +166,7 @@ RuVim::ExCommandRegistry.instance.register(
166
166
  2. `RuVim::App` が mode ごとに処理を分岐
167
167
  3. Normal mode のキーは `RuVim::KeymapManager` で解決
168
168
  4. `RuVim::Dispatcher` が内部コマンド or Ex コマンドを実行
169
- 5. Insert mode でキー処理後、stdin に未読データが残っていればレンダリングをスキップして追加のキーを読み取り・処理する(ペースト高速化)
169
+ 5. Insert mode でキー処理後、stdin に未読データが残っていればレンダリングをスキップして追加のキーを読み取り・処理する(ペースト高速化)。このバッチ処理中は autoindent を抑制し、貼り付けテキストが余分にインデントされるのを防ぐ
170
170
  6. `RuVim::Screen` が再描画
171
171
 
172
172
  ## 起動オプション(CLI, 現状)
@@ -265,7 +265,7 @@ RuVim::ExCommandRegistry.instance.register(
265
265
  - `p`, `P`: paste
266
266
  - `r<char>`: 1文字置換
267
267
  - `c` + motion / `cc`: change(削除して Insert mode)
268
- - `=` + motion / `==`: auto-indent(Ruby filetype でインデント自動調整。`=j`, `=G` 等)
268
+ - `=` + motion / `==`: auto-indent(Ruby / JSON filetype でインデント自動調整。`=j`, `=G` 等)
269
269
  - `v`: Visual (characterwise)
270
270
  - `V`: Visual (linewise)
271
271
  - `Ctrl-v`: Visual (blockwise, 最小)
@@ -370,7 +370,13 @@ RuVim::ExCommandRegistry.instance.register(
370
370
  - `:vimgrep`, `:lvimgrep`
371
371
  - `:copen`, `:cclose`, `:cnext` / `:cn`, `:cprev` / `:cp`
372
372
  - `:lopen`, `:lclose`, `:lnext` / `:ln`, `:lprev` / `:lp`
373
+ - `:grep /pattern/ [path...]`, `:lgrep /pattern/ [path...]`
374
+ - `:filter [/pattern/]` : 検索マッチ行のみのフィルタバッファを作成(`g/` キーバインド)
373
375
  - `:rich [format]`
376
+ - `:d [count]` / `:delete`
377
+ - `:y [count]` / `:yank`
378
+ - `:tabs`
379
+ - `:args`, `:next`, `:prev`, `:first`, `:last`
374
380
 
375
381
  ## 検索仕様(現状)
376
382
 
@@ -380,7 +386,7 @@ RuVim::ExCommandRegistry.instance.register(
380
386
  - `N` : 直前検索を逆方向に繰り返し
381
387
  - `*`, `#` : カーソル下の単語を前/後方検索(単語境界つき)
382
388
  - `g*`, `g#` : カーソル下の単語を前/後方検索(部分一致)
383
- - `:%s/pat/repl/g` : バッファ全体 substitute(最小実装)
389
+ - `:{range}s/pat/repl/[flags]` : substitute(フラグ: `g`, `i`, `I`, `n`, `e` 対応。`c` は未実装)
384
390
 
385
391
  ### 仕様メモ
386
392
 
@@ -706,7 +712,7 @@ Vim 完全互換ではなく、まずは扱いやすい粒度を優先した仕
706
712
  - 描画時に filetype ごとの regex ベース highlighter を適用
707
713
  - 現状の対応 filetype:
708
714
  - `ruby`
709
- - `json`
715
+ - `json` / `jsonl`
710
716
  - `markdown`(見出し・フェンス・HR・ブロック引用・インライン装飾)
711
717
  - 優先度(高 -> 低):
712
718
  - cursor / visual
@@ -723,7 +729,10 @@ Visual mode と同様に Normal mode の上に乗るモードとして設計さ
723
729
  - **アーキテクチャ**: filetype ごとにレンダラーを登録できる汎用フレームワーク
724
730
  - `RuVim::RichView` モジュール(`lib/ruvim/rich_view.rb`)
725
731
  - レンダラー登録: `RichView.register(filetype, renderer)`
726
- - レンダラー: `TableRenderer`(TSV/CSV)、`MarkdownRenderer`(Markdown)
732
+ - レンダラー: `TableRenderer`(TSV/CSV)、`MarkdownRenderer`(Markdown)、`JsonRenderer`(JSON)、`JsonlRenderer`(JSONL
733
+ - `JsonRenderer` は仮想バッファ方式: ミニファイ JSON を `JSON.pretty_generate` で整形し、読み取り専用バッファに表示
734
+ - `JsonlRenderer` は仮想バッファ方式: 各行を個別にパース・整形し、`---` セパレータで区切って読み取り専用バッファに表示。パースエラー行はエラーマーカー付きで表示
735
+ - 仮想バッファ方式のレンダラーでは `Esc` / `C-c` でバッファを閉じて元に戻れる
727
736
  - **起動方法**:
728
737
  - `:rich [format]` Ex コマンド(トグル)
729
738
  - `gr` Normal mode キーバインド(トグル)
@@ -786,6 +795,9 @@ Visual mode と同様に Normal mode の上に乗るモードとして設計さ
786
795
  - `nmap`
787
796
  - `imap`
788
797
  - `map_global`
798
+ - `set`
799
+ - `setlocal`
800
+ - `setglobal`
789
801
  - `command`
790
802
  - `ex_command`
791
803
  - `ex_command_call`
@@ -795,6 +807,47 @@ Visual mode と同様に Normal mode の上に乗るモードとして設計さ
795
807
  - XDG 設定ファイル(`init.rb`)は Ruby として評価されるため、信頼できる内容のみ使用する
796
808
  - 直接内部状態に触る代わりに、まずは DSL API を通す設計
797
809
 
810
+ ## Git 連携
811
+
812
+ ### Git Blame
813
+
814
+ `<C-g>` で `:git ` プリセットのコマンドラインモードに入る。`:git <subcommand>` で実行。
815
+
816
+ ### GitStatus
817
+
818
+ `:git status` で `git status` の結果を `kind: :git_status` の読み取り専用バッファで表示。
819
+
820
+ ### GitDiff
821
+
822
+ `:git diff` で `git diff` の結果を `kind: :git_diff` の読み取り専用バッファで表示(filetype: diff)。追加引数をそのまま渡せる(例: `:git diff --cached`)。差分がない場合はメッセージ表示のみ。Enter で差分行に対応するファイルの該当行にジャンプ。`:git log -p` バッファでも同様に動作する。
823
+
824
+ ### GitLog
825
+
826
+ `:git log` で `git log` の結果を `kind: :git_log` の読み取り専用バッファで表示。追加引数をそのまま渡せる(例: `:git log -p`)。`-p` 指定時は filetype: diff で syntax highlight が効く。出力はストリーミングで逐次表示(カーソルは先頭行に固定)。バッファを閉じるとプロセスも停止する。
827
+
828
+ ### GitBranch
829
+
830
+ `:git branch` で `git branch -a` の結果を `kind: :git_branch` の読み取り専用バッファで表示。コミット日時の新しい順にソート。各行にブランチ名、日付、最新コミットのサブジェクトを表示。Enter でカーソル行のブランチをチェックアウト。
831
+
832
+ ### GitCommit
833
+
834
+ `:git commit` でコミットメッセージ編集バッファ(`kind: :git_commit`)を開く。`#` で始まる行はコメント(git status 情報を表示)。insert モードで開始。`:w` または `:wq` でコミット実行。`:q!` でキャンセル。メッセージが空の場合はコミットを中止。
835
+
836
+ ### GitBlame
837
+
838
+ - **Blame バッファ**: `kind: :blame`、readonly、modifiable=false
839
+ - 表示形式: `短縮ハッシュ 著者名 日付 コード行`
840
+ - 内部で `git blame --porcelain` を使用して構造化パース
841
+ - ソースファイルのカーソル行位置を引き継ぐ
842
+
843
+ Blame バッファ内のバッファローカルバインディング:
844
+
845
+ - `p` (GitBlamePrev): カーソル行のコミット C に対し `git blame C^` の結果に更新。履歴スタックに現在の状態を push
846
+ - `P` (GitBlameBack): 履歴スタックから pop して前の blame 状態に復元
847
+ - `c` (GitBlameCommit): カーソル行のコミットの `git show` 結果を `kind: :git_show` の読み取り専用バッファで表示(filetype: diff)
848
+
849
+ 実装: `lib/ruvim/git/blame.rb`(blame パース・実行)、`lib/ruvim/git/commands.rb`(status/diff/log 実行)、`lib/ruvim/global_commands.rb`(コマンドハンドラ)
850
+
798
851
  ## テスト(現状)
799
852
 
800
853
  - `Minitest` を利用
@@ -807,10 +860,8 @@ Visual mode と同様に Normal mode の上に乗るモードとして設計さ
807
860
 
808
861
  - 永続 undo(`undofile` / `undodir` 相当)
809
862
  - session 保存/復元(`-S` / `:mksession` 相当の実体)
810
- - `:grep` / `:make` / `:cfile` / `:lgrep` / `:lfile` など quickfix 入口
811
- - Ex range/address(`:1,10d`, `:.,$s/.../.../` など)
812
- - `:substitute` フラグ拡張(`c`, `i`, `I`, `n`, `e` など)
813
- - arglist(複数ファイル起動 + `:args`, `:next`, `:prev` 等)
863
+ - `:make` / `:cfile` / `:lfile` など quickfix 入口(`:grep` / `:lgrep` は実装済み)
864
+ - `:substitute` の `c`(confirm)フラグ(`g`, `i`, `I`, `n`, `e` は実装済み)
814
865
  - `Ctrl-w` resize / close-others / equalize など window 操作拡張
815
866
  - `:set` 高度構文(`+=`, `-=`, `:set all`, 短縮名)
816
867
  - tag jump / folds / `:global` / `:normal`
data/docs/tutorial.md CHANGED
@@ -28,6 +28,7 @@ ruvim path/to/file.txt
28
28
  - `-R`(readonly で開く。現在バッファの `:w` を拒否)
29
29
  - `-M`(modifiable off 相当。編集操作を拒否し、あわせて readonly)
30
30
  - `-Z`(restricted mode。config/ftplugin を読まず、`:ruby` と `:!` を無効化)
31
+ - `-f`(follow mode: `tail -f` 相当。ファイルの追記をリアルタイムに追従)
31
32
  - `-n`(現状 no-op。将来の swap/永続機能向け互換フラグ)
32
33
  - `-o[N]` / `-O[N]` / `-p[N]`(複数ファイルを split / vsplit / tab で開く)
33
34
  - `-V[N]` / `--verbose[=N]`(起動/設定/Ex のログを stderr に出す)
@@ -140,11 +141,33 @@ ruvim -p a.rb b.rb
140
141
  - `:tabnew [path]`
141
142
  - `:tabnext` / `:tabn`
142
143
  - `:tabprev` / `:tabp`
144
+ - `:follow`(`tail -f` 相当の追従モードをトグル)
143
145
  - `:vimgrep /foo/`
144
146
  - `:copen`, `:cnext`, `:cprev`, `:cclose`
145
147
  - `:lvimgrep /foo/`
146
148
  - `:lopen`, `:lnext`, `:lprev`, `:lclose`
147
149
 
150
+ ## Follow mode(`tail -f` 相当)
151
+
152
+ ファイルへの追記をリアルタイムにバッファへ反映する追従モードです。
153
+
154
+ ```bash
155
+ ruvim -f /var/log/syslog # 起動時から follow mode
156
+ ruvim -f log1.txt log2.txt # 複数ファイルすべて follow
157
+ ```
158
+
159
+ 起動後に切り替えることもできます:
160
+
161
+ ```vim
162
+ :follow " follow 開始(トグル)
163
+ :follow " もう一度で停止
164
+ ```
165
+
166
+ - `Ctrl-C`(ノーマルモード)でも停止できます
167
+ - カーソルが最終行(`G`)にいると末尾を自動追従、途中にいればスクロール位置を維持
168
+ - follow 中はバッファ変更不可(停止後に編集可能)
169
+ - ファイルが truncate/削除された場合はメッセージを表示し、監視を継続(削除時は再作成を待機)
170
+
148
171
  ## Undo / Redo
149
172
 
150
173
  - `u`: 直前の変更を取り消す
@@ -238,6 +261,7 @@ register prefix を付けると register を指定できます。
238
261
  - `:set ignorecase` / `:set noignorecase` : 検索の大文字小文字を無視(global)
239
262
  - `:set smartcase` / `:set nosmartcase` : `ignorecase` 有効時に大文字を含む検索を大文字小文字区別にする(global)
240
263
  - `:set hlsearch` / `:set nohlsearch` : 検索ハイライトの ON/OFF(global)
264
+ - `:nohlsearch` (`:noh`) : 検索ハイライトを一時的にクリア(次の検索で自動復帰)
241
265
  - `:set tabstop=4` : tab 幅設定(既定スコープは buffer-local)
242
266
  - `:setlocal number` : 現在 window のみ変更
243
267
  - `:setglobal tabstop=8` : global 値を変更
data/docs/vim_diff.md CHANGED
@@ -7,7 +7,7 @@ RuVim は「Vim ライクな Ruby 製ターミナルエディタ」です。Vim
7
7
  ### Ruby ネイティブな拡張性
8
8
 
9
9
  - 設定ファイルは Ruby DSL(`~/.config/ruvim/init.rb`)
10
- - `nmap`, `imap`, `map_global`, `command`, `ex_command`, `ex_command_call`
10
+ - `nmap`, `imap`, `map_global`, `set`, `setlocal`, `setglobal`, `command`, `ex_command`, `ex_command_call`
11
11
  - Vim script 不要で Ruby の全機能を利用可能
12
12
  - `:ruby` / `:rb` で実行中に Ruby eval が可能(Vim の `:ruby` とは別物)
13
13
  - plugin 向け `ctx.editor / ctx.buffer / ctx.window` API
@@ -26,6 +26,13 @@ RuVim は「Vim ライクな Ruby 製ターミナルエディタ」です。Vim
26
26
  - TSV / CSV / Markdown をフォーマットして閲覧できる構造化データ表示モード
27
27
  - CJK 文字幅を考慮したカラム整列
28
28
 
29
+ ### Follow mode(`tail -f` 相当)
30
+
31
+ - `:follow` コマンドまたは `-f` CLI フラグでファイル追従モード
32
+ - Linux では inotify(fiddle 経由)を優先、使えない場合は polling(exponential backoff)にフォールバック
33
+ - ファイルの truncation/deletion を検知してメッセージ表示・自動復帰
34
+ - Vim にはない RuVim 独自機能
35
+
29
36
  ### 検索は Ruby 正規表現
30
37
 
31
38
  - `/`, `?`, `:s` はすべて Ruby の `Regexp` を使用
@@ -53,10 +60,12 @@ RuVim は「Vim ライクな Ruby 製ターミナルエディタ」です。Vim
53
60
 
54
61
  ### Ex コマンド
55
62
 
56
- - `:w`, `:q`, `:wq`, `:e`, `:buffer`, `:bnext`, `:bprev`, `:ls`, `:split`, `:vsplit`
63
+ - `:w`, `:q`, `:wq`, `:e`, `:buffer`, `:bnext`, `:bprev`, `:bdelete`, `:ls`, `:split`, `:vsplit`
57
64
  - `:qa`, `:qa!`, `:wqa`
58
- - quickfix / location list: `:vimgrep`, `:lvimgrep`, `:copen`, `:cnext`, `:lopen`, `:lnext`
59
- - tabpage: `:tabnew`, `:tabnext`, `:tabprev`
65
+ - quickfix / location list: `:vimgrep`, `:lvimgrep`, `:grep`, `:lgrep`, `:copen`, `:cnext`, `:lopen`, `:lnext`
66
+ - tabpage: `:tabnew`, `:tabnext`, `:tabprev`, `:tabs`
67
+ - arglist: `:args`, `:next`, `:prev`, `:first`, `:last`
68
+ - 行操作: `:d` / `:delete`, `:y` / `:yank`
60
69
 
61
70
  ### option system
62
71
 
@@ -65,14 +74,15 @@ RuVim は「Vim ライクな Ruby 製ターミナルエディタ」です。Vim
65
74
  - インデント: `shiftwidth`, `softtabstop`, `expandtab`, `autoindent`, `smartindent`, `tabstop`
66
75
  - 検索: `ignorecase`, `smartcase`, `hlsearch`, `incsearch`
67
76
  - 分割: `splitbelow`, `splitright`
68
- - その他: `hidden`, `autowrite`, `clipboard`, `timeoutlen`, `ttimeoutlen`, `backspace`, `whichwrap`, `iskeyword`, `filetype`, `path`, `suffixesadd`, `grepprg`, `grepformat`, 補完系(`completeopt`, `pumheight`, `wildmode`, `wildmenu`, `wildignore`, `wildignorecase`)
77
+ - grep: `grepprg`, `grepformat`
78
+ - その他: `hidden`, `autowrite`, `clipboard`, `timeoutlen`, `ttimeoutlen`, `backspace`, `whichwrap`, `iskeyword`, `filetype`, `path`, `suffixesadd`, 補完系(`completeopt`, `pumheight`, `wildmode`, `wildmenu`, `wildignore`, `wildignorecase`)
69
79
 
70
80
  ### その他
71
81
 
72
82
  - filetype 検出(拡張子 + shebang)/ ftplugin
73
83
  - syntax highlight: Ruby(Prism lexer), JSON, Markdown, Scheme, TSV/CSV
74
84
  - 補完: Ex コマンド名 + 引数補完, Insert mode buffer words(`Ctrl-n` / `Ctrl-p`)
75
- - CLI: `--help`, `--version`, `--clean`, `-u`, `-R`, `-M`, `-Z`, `-o/-O/-p`, `-c`, `+{cmd}`, `-V`, `--startuptime`, `--cmd`
85
+ - CLI: `--help`, `--version`, `--clean`, `-u`, `-R`, `-M`, `-Z`, `-f`, `-o/-O/-p`, `-c`, `+{cmd}`, `-V`, `--startuptime`, `--cmd`
76
86
 
77
87
  ## 動作の微細な差分
78
88
 
@@ -96,7 +106,7 @@ RuVim は「Vim ライクな Ruby 製ターミナルエディタ」です。Vim
96
106
  - folds
97
107
  - LSP / diagnostics
98
108
  - job / channel / terminal 連携
99
- - `:grep`, `:make`, `:cfile`, `:lgrep`
100
- - substitute の高度なフラグ群(現状は `:%s/.../.../g` のみ)
109
+ - `:make`, `:cfile`, `:lfile`(`:grep`, `:lgrep` は実装済み)
110
+ - substitute `c`(confirm)フラグ(`g`, `i`, `I`, `n`, `e` は実装済み)
101
111
  - swap / backup / undofile(永続 undo)
102
112
  - `-d`(diff mode), `-q`(quickfix mode), `-S`(session)は placeholder のみ