ruvim 0.1.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.
- checksums.yaml +7 -0
- data/.github/workflows/test.yml +15 -0
- data/README.md +135 -0
- data/Rakefile +36 -0
- data/docs/binding.md +125 -0
- data/docs/command.md +306 -0
- data/docs/config.md +155 -0
- data/docs/done.md +112 -0
- data/docs/plugin.md +559 -0
- data/docs/spec.md +655 -0
- data/docs/todo.md +63 -0
- data/docs/tutorial.md +490 -0
- data/docs/vim_diff.md +179 -0
- data/exe/ruvim +6 -0
- data/lib/ruvim/app.rb +1600 -0
- data/lib/ruvim/buffer.rb +421 -0
- data/lib/ruvim/cli.rb +264 -0
- data/lib/ruvim/clipboard.rb +73 -0
- data/lib/ruvim/command_invocation.rb +14 -0
- data/lib/ruvim/command_line.rb +63 -0
- data/lib/ruvim/command_registry.rb +38 -0
- data/lib/ruvim/config_dsl.rb +134 -0
- data/lib/ruvim/config_loader.rb +68 -0
- data/lib/ruvim/context.rb +26 -0
- data/lib/ruvim/dispatcher.rb +120 -0
- data/lib/ruvim/display_width.rb +110 -0
- data/lib/ruvim/editor.rb +1025 -0
- data/lib/ruvim/ex_command_registry.rb +80 -0
- data/lib/ruvim/global_commands.rb +1889 -0
- data/lib/ruvim/highlighter.rb +52 -0
- data/lib/ruvim/input.rb +66 -0
- data/lib/ruvim/keymap_manager.rb +96 -0
- data/lib/ruvim/screen.rb +452 -0
- data/lib/ruvim/terminal.rb +30 -0
- data/lib/ruvim/text_metrics.rb +96 -0
- data/lib/ruvim/version.rb +5 -0
- data/lib/ruvim/window.rb +71 -0
- data/lib/ruvim.rb +30 -0
- data/sig/ruvim.rbs +4 -0
- data/test/app_completion_test.rb +39 -0
- data/test/app_dot_repeat_test.rb +54 -0
- data/test/app_motion_test.rb +73 -0
- data/test/app_register_test.rb +47 -0
- data/test/app_scenario_test.rb +77 -0
- data/test/app_startup_test.rb +199 -0
- data/test/app_text_object_test.rb +54 -0
- data/test/app_unicode_behavior_test.rb +66 -0
- data/test/buffer_test.rb +72 -0
- data/test/cli_test.rb +165 -0
- data/test/config_dsl_test.rb +78 -0
- data/test/dispatcher_test.rb +124 -0
- data/test/editor_mark_test.rb +69 -0
- data/test/editor_register_test.rb +64 -0
- data/test/fixtures/render_basic_snapshot.txt +8 -0
- data/test/fixtures/render_basic_snapshot_nonumber.txt +8 -0
- data/test/fixtures/render_unicode_scrolled_snapshot.txt +7 -0
- data/test/highlighter_test.rb +16 -0
- data/test/input_screen_integration_test.rb +69 -0
- data/test/keymap_manager_test.rb +48 -0
- data/test/render_snapshot_test.rb +70 -0
- data/test/screen_test.rb +123 -0
- data/test/search_option_test.rb +39 -0
- data/test/test_helper.rb +15 -0
- data/test/text_metrics_test.rb +42 -0
- data/test/window_test.rb +21 -0
- metadata +106 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5d2d270426e0c654c22de404d8745368dbc7a5eb98fc91eecad94624a3b91b6c
|
|
4
|
+
data.tar.gz: 75ad40c44e89934ab1746d43aee2ac09c695513d6edb6f7e71d0b888126931a8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 938e1eb393efd57f97260526fc40f375d27ca0aecf9b370d0b0b41b7c3f535026b1c8be82588a2713025c615e4e5222abe871f46918fbc08f3fef9b35347e023
|
|
7
|
+
data.tar.gz: f0a3fb80d5f3e2395daf0c689fd4129bfd6ff026e3184eb8f0e58ffc68f19ede36be7ac6c914fa3a2a70bd9b7c9bb95ae60bf292f760ce7691b498a0b12d66a7
|
data/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# RuVim
|
|
2
|
+
|
|
3
|
+
Ruby で実装した Vim ライクなターミナルエディタです。
|
|
4
|
+
|
|
5
|
+
- raw mode + ANSI 描画
|
|
6
|
+
- Normal / Insert / Command-line / Visual
|
|
7
|
+
- Ex コマンド(`:w`, `:q`, `:e`, `:help`, `:set` など)
|
|
8
|
+
- split / vsplit / tab(最小実装)
|
|
9
|
+
- Ruby DSL 設定(XDG)
|
|
10
|
+
|
|
11
|
+
## 起動
|
|
12
|
+
|
|
13
|
+
起動:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ruvim
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
ファイルを開いて起動:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ruvim path/to/file.txt
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
主な CLI オプション:
|
|
26
|
+
|
|
27
|
+
- `ruvim --help`
|
|
28
|
+
- ヘルプを表示して終了
|
|
29
|
+
- `ruvim --version`
|
|
30
|
+
- バージョンを表示して終了
|
|
31
|
+
- `ruvim --clean`
|
|
32
|
+
- ユーザー設定 / ftplugin を読まずに起動
|
|
33
|
+
- `ruvim -R file.txt`
|
|
34
|
+
- readonly モードで開く(`w` を拒否)
|
|
35
|
+
- `ruvim -M file.txt`
|
|
36
|
+
- modifiable off 相当(編集操作を拒否、readonly も有効化)
|
|
37
|
+
- `ruvim -Z file.txt`
|
|
38
|
+
- restricted mode(config/ftplugin 無効、`:ruby` 無効)
|
|
39
|
+
- `ruvim -u /tmp/init.rb`
|
|
40
|
+
- 設定ファイルを指定
|
|
41
|
+
- `ruvim -u NONE`
|
|
42
|
+
- ユーザー設定を読まない(ftplugin は有効)
|
|
43
|
+
- `ruvim --cmd 'set number' file.txt`
|
|
44
|
+
- user config 読み込み前に Ex コマンドを実行
|
|
45
|
+
- `ruvim -c 'set number' file.txt`
|
|
46
|
+
- 起動後に Ex コマンドを実行
|
|
47
|
+
- `ruvim +10 file.txt`
|
|
48
|
+
- 起動後に 10 行目へ移動
|
|
49
|
+
- `ruvim + file.txt`
|
|
50
|
+
- 起動後に最終行へ移動
|
|
51
|
+
- `ruvim -o a.rb b.rb`
|
|
52
|
+
- 複数ファイルを水平 split で開く(最小実装)
|
|
53
|
+
- `ruvim -O a.rb b.rb`
|
|
54
|
+
- 複数ファイルを垂直 split で開く(最小実装)
|
|
55
|
+
- `ruvim -p a.rb b.rb`
|
|
56
|
+
- 複数ファイルを tab で開く(最小実装)
|
|
57
|
+
- `ruvim -d file.txt`
|
|
58
|
+
- diff mode placeholder(現状は未実装メッセージのみ)
|
|
59
|
+
- `ruvim -q errors.log`
|
|
60
|
+
- quickfix startup placeholder(現状は未実装メッセージのみ)
|
|
61
|
+
- `ruvim -S Session.vim`
|
|
62
|
+
- session startup placeholder(現状は未実装メッセージのみ)
|
|
63
|
+
|
|
64
|
+
開発環境で gem 未インストールのまま試す場合:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
ruby -Ilib exe/ruvim
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 主な操作(抜粋)
|
|
71
|
+
|
|
72
|
+
- 移動: `h j k l`, `w b e`, `0 ^ $`, `gg`, `G`
|
|
73
|
+
- 挿入: `i`, `a`, `A`, `I`, `o`, `O`
|
|
74
|
+
- 編集: `x`, `dd`, `d{motion}`, `c{motion}`, `yy`, `yw`, `p`, `P`, `r<char>`
|
|
75
|
+
- 検索: `/`, `?`, `n`, `N`, `*`, `#`, `g*`, `g#`
|
|
76
|
+
- Visual: `v`, `V`, `y`, `d`
|
|
77
|
+
- Undo/Redo: `u`, `Ctrl-r`
|
|
78
|
+
- Ex: `:w`, `:q`, `:e`, `:help`, `:commands`, `:set`
|
|
79
|
+
|
|
80
|
+
詳しくは `docs/tutorial.md` を参照してください。
|
|
81
|
+
|
|
82
|
+
## 設定
|
|
83
|
+
|
|
84
|
+
設定ファイルは Ruby DSL です。
|
|
85
|
+
|
|
86
|
+
- `$XDG_CONFIG_HOME/ruvim/init.rb`
|
|
87
|
+
- `~/.config/ruvim/init.rb`
|
|
88
|
+
|
|
89
|
+
filetype ごとの設定:
|
|
90
|
+
|
|
91
|
+
- `$XDG_CONFIG_HOME/ruvim/ftplugin/<filetype>.rb`
|
|
92
|
+
- `~/.config/ruvim/ftplugin/<filetype>.rb`
|
|
93
|
+
|
|
94
|
+
`--clean` で user config / ftplugin を無効化できます。
|
|
95
|
+
|
|
96
|
+
詳しくは `docs/config.md` を参照してください。
|
|
97
|
+
|
|
98
|
+
## ドキュメント
|
|
99
|
+
|
|
100
|
+
- `docs/tutorial.md` - 使い方
|
|
101
|
+
- `docs/spec.md` - 実装仕様 / 設計
|
|
102
|
+
- `docs/command.md` - コマンド一覧
|
|
103
|
+
- `docs/binding.md` - キーバインド
|
|
104
|
+
- `docs/config.md` - 設定
|
|
105
|
+
- `docs/plugin.md` - 拡張 / plugin 的な書き方(現状)
|
|
106
|
+
- `docs/vim_diff.md` - Vim との差分
|
|
107
|
+
- `docs/todo.md` - TODO / 次フェーズ案
|
|
108
|
+
|
|
109
|
+
## 開発
|
|
110
|
+
|
|
111
|
+
テスト実行:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
rake test
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
CI 相当(test + docs 整合チェック):
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
rake ci
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
lint / format 方針(現状):
|
|
124
|
+
|
|
125
|
+
- `rubocop` / 自動 formatter は未導入
|
|
126
|
+
- 変更時は `rake test` と必要に応じて `ruby -c` で構文確認
|
|
127
|
+
- docs を触ったときは `rake docs:check`(`rake ci` に含まれる)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 注意(現状)
|
|
131
|
+
|
|
132
|
+
- Vim 完全互換ではありません
|
|
133
|
+
- 正規表現は Vim regex ではなく Ruby `Regexp` を使います
|
|
134
|
+
- 文字幅 / Unicode は改善済みですが、完全互換ではありません
|
|
135
|
+
- 複数ファイル引数や一部 Vim CLI オプションは未実装です
|
data/Rakefile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << "lib" << "test"
|
|
8
|
+
t.test_files = FileList["test/*_test.rb"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
namespace :docs do
|
|
12
|
+
task :check do
|
|
13
|
+
required = %w[
|
|
14
|
+
README.md
|
|
15
|
+
docs/tutorial.md
|
|
16
|
+
docs/spec.md
|
|
17
|
+
docs/command.md
|
|
18
|
+
docs/binding.md
|
|
19
|
+
docs/config.md
|
|
20
|
+
docs/vim_diff.md
|
|
21
|
+
docs/todo.md
|
|
22
|
+
]
|
|
23
|
+
missing = required.reject { |p| File.file?(p) }
|
|
24
|
+
raise "Missing docs: #{missing.join(', ')}" unless missing.empty?
|
|
25
|
+
|
|
26
|
+
refs = Dir["README.md", "docs/*.md"].flat_map do |path|
|
|
27
|
+
File.read(path).scan(/`(docs\/[^`]+\.md)`/).flatten
|
|
28
|
+
end.uniq
|
|
29
|
+
bad_refs = refs.reject { |p| File.file?(p) }
|
|
30
|
+
raise "Broken docs refs: #{bad_refs.join(', ')}" unless bad_refs.empty?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
task :ci => %i[test docs:check]
|
|
35
|
+
|
|
36
|
+
task default: %i[test]
|
data/docs/binding.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# RuVim キーバインディング一覧
|
|
2
|
+
|
|
3
|
+
## Normal mode
|
|
4
|
+
|
|
5
|
+
- `h` : 左へ移動
|
|
6
|
+
- `j` : 下へ移動
|
|
7
|
+
- `k` : 上へ移動
|
|
8
|
+
- `l` : 右へ移動
|
|
9
|
+
- `0` : 行頭へ移動
|
|
10
|
+
- `$` : 行末へ移動
|
|
11
|
+
- `^` : 行頭の最初の非空白へ移動
|
|
12
|
+
- `w` : 次の単語へ移動
|
|
13
|
+
- `b` : 前の単語へ移動
|
|
14
|
+
- `e` : 単語末へ移動
|
|
15
|
+
- `f{char}` / `F{char}` : 行内で次/前の文字へ移動
|
|
16
|
+
- `t{char}` / `T{char}` : 行内で文字の手前/直後へ移動
|
|
17
|
+
- `;` / `,` : 直前の `f/F/t/T` を再実行 / 逆方向再実行
|
|
18
|
+
- `%` : 対応する括弧へジャンプ(`()[]{}`)
|
|
19
|
+
- `gg` : バッファ先頭へ移動
|
|
20
|
+
- `G` : バッファ末尾へ移動
|
|
21
|
+
- `i` : Insert mode に入る
|
|
22
|
+
- `a` : カーソル後ろから Insert mode
|
|
23
|
+
- `A` : 行末から Insert mode
|
|
24
|
+
- `I` : 行頭の最初の非空白から Insert mode
|
|
25
|
+
- `o` : 下に新規行を開いて Insert mode
|
|
26
|
+
- `O` : 上に新規行を開いて Insert mode
|
|
27
|
+
- `:` : Command-line mode に入る
|
|
28
|
+
- `/` : 前方検索入力に入る
|
|
29
|
+
- `?` : 後方検索入力に入る
|
|
30
|
+
- `x` : カーソル位置の文字削除
|
|
31
|
+
- `dd` : 現在行を削除
|
|
32
|
+
- `d` + motion : operator-pending delete(`dw`, `dj`, `dk`, `d$`, `dh`, `dl`)
|
|
33
|
+
- `diw` / `daw` : 単語 text object delete(簡易)
|
|
34
|
+
- `di"` / `da"` : quote text object delete(簡易)
|
|
35
|
+
- `di)` / `da)` : paren text object delete(簡易)
|
|
36
|
+
- `di]` / `da]`, `di}` / `da}` : bracket / brace text object delete(簡易)
|
|
37
|
+
- ``di` `` / ``da` `` : backtick quote text object delete(簡易)
|
|
38
|
+
- `dip` / `dap` : paragraph text object delete(簡易)
|
|
39
|
+
- `yy` / `yw` : yank
|
|
40
|
+
- `yiw` / `yaw` : 単語 text object yank(簡易)
|
|
41
|
+
- `yi"` / `ya"` : quote text object yank(簡易)
|
|
42
|
+
- `yi)` / `ya)` : paren text object yank(簡易)
|
|
43
|
+
- `yi]` / `ya]`, `yi}` / `ya}`, ``yi` `` / ``ya` ``, `yip` / `yap`(簡易)
|
|
44
|
+
- `p` / `P` : paste
|
|
45
|
+
- `"a`, `"A`, `"_`, `"+`, `"*` + operator/paste : register 指定
|
|
46
|
+
- `m{a-zA-Z}` : mark を設定(小文字 local / 大文字 global)
|
|
47
|
+
- `'{mark}` / `` `{mark} `` : mark へ jump(行頭寄せ / 正確位置)
|
|
48
|
+
- `''` / `` `` `` : jumplist で前の位置へ jump(行頭寄せ / 正確位置)
|
|
49
|
+
- `r<char>` : 1文字置換
|
|
50
|
+
- `c` + motion / `cc` : change(削除して Insert mode)
|
|
51
|
+
- `ciw` / `caw` : 単語 text object change(簡易)
|
|
52
|
+
- `ci"` / `ca"` : quote text object change(簡易)
|
|
53
|
+
- `ci)` / `ca)` : paren text object change(簡易)
|
|
54
|
+
- `ci]` / `ca]`, `ci}` / `ca}`, ``ci` `` / ``ca` ``, `cip` / `cap`(簡易)
|
|
55
|
+
- `v` : Visual (characterwise)
|
|
56
|
+
- `V` : Visual (linewise)
|
|
57
|
+
- `Ctrl-w w` : 次の window へ移動
|
|
58
|
+
- `Ctrl-w h/j/k/l` : window 間移動(split UI)
|
|
59
|
+
- `u` : Undo
|
|
60
|
+
- `Ctrl-r` : Redo
|
|
61
|
+
- `.` : 直前変更の repeat(現状: `x`, `dd`, `d{motion}`, `p/P`, `r<char>`)
|
|
62
|
+
- `Ctrl-o` : jumplist の古い位置へ
|
|
63
|
+
- `Ctrl-i` : jumplist の新しい位置へ(端末では Tab と同じコード)
|
|
64
|
+
- `q{reg}` : macro 記録開始/終了(再度 `q` で停止)
|
|
65
|
+
- `@{reg}` / `@@` : macro 再生 / 直前 macro 再生
|
|
66
|
+
- `n` : 直前検索を次へ
|
|
67
|
+
- `N` : 直前検索を前へ(逆方向)
|
|
68
|
+
- `*` / `#` : カーソル下の単語検索(前/後)
|
|
69
|
+
- `g*` / `g#` : カーソル下の単語を部分一致検索(前/後)
|
|
70
|
+
- `Esc` : メッセージ/保留入力のクリア
|
|
71
|
+
- `矢印キー` : 移動
|
|
72
|
+
- `PageUp` / `PageDown` : 画面単位で移動(概ね表示高さ - 1 行)
|
|
73
|
+
|
|
74
|
+
### count 対応(現状)
|
|
75
|
+
|
|
76
|
+
- `3j`, `5k`, `2x`, `3dd` など
|
|
77
|
+
- `0` は count ではなく行頭移動として扱う
|
|
78
|
+
|
|
79
|
+
## Insert mode
|
|
80
|
+
|
|
81
|
+
- `文字` : 挿入
|
|
82
|
+
- `Enter` : 改行
|
|
83
|
+
- `Backspace` : 削除
|
|
84
|
+
- `Ctrl-n` : buffer words 補完(次候補)
|
|
85
|
+
- `Ctrl-p` : buffer words 補完(前候補)
|
|
86
|
+
- `Esc` : Normal mode に戻る
|
|
87
|
+
- `Ctrl-c` : Normal mode に戻る
|
|
88
|
+
- `矢印キー` : 移動
|
|
89
|
+
- `PageUp` / `PageDown` : 画面単位で移動
|
|
90
|
+
|
|
91
|
+
## Visual mode(characterwise / linewise)
|
|
92
|
+
|
|
93
|
+
- `h/j/k/l`, `w/b/e`, `0/$/^`, `gg/G`, `矢印キー` : 範囲を伸縮
|
|
94
|
+
- `PageUp` / `PageDown` : 範囲を画面単位で伸縮
|
|
95
|
+
- `v` : characterwise Visual の開始/終了
|
|
96
|
+
- `V` : linewise Visual の開始/切替
|
|
97
|
+
- `y` : 選択範囲を yank
|
|
98
|
+
- `d` : 選択範囲を delete
|
|
99
|
+
- `i` / `a` + object : text object を選択(`iw`, `aw`, `ip`, `ap`, `i"`, `a"`, ``i` ``, ``a` ``, `i)`, `a)`, `i]`, `a]`, `i}`, `a}`)
|
|
100
|
+
- `Esc` / `Ctrl-c` : Normal mode に戻る
|
|
101
|
+
|
|
102
|
+
## Command-line mode
|
|
103
|
+
|
|
104
|
+
- `文字` : 入力
|
|
105
|
+
- `Enter` : Ex コマンド実行
|
|
106
|
+
- `Backspace` : 1文字削除
|
|
107
|
+
- `Up` / `Down` : 履歴移動
|
|
108
|
+
- `Left` / `Right` : カーソル移動
|
|
109
|
+
- `Tab` (`Ctrl-i`) : Ex 補完(`:` prefix 時、コマンド名/一部引数の文脈対応)
|
|
110
|
+
- `Esc` : キャンセル
|
|
111
|
+
- `Ctrl-c` : キャンセル
|
|
112
|
+
|
|
113
|
+
### prefix 別の Enter 動作
|
|
114
|
+
|
|
115
|
+
- `:` で始まる場合: Ex コマンドとして実行
|
|
116
|
+
- `/` で始まる場合: 前方検索
|
|
117
|
+
- `?` で始まる場合: 後方検索
|
|
118
|
+
|
|
119
|
+
## メモ
|
|
120
|
+
|
|
121
|
+
- 実装場所(初期バインド): `lib/ruvim/app.rb`
|
|
122
|
+
- `d` は keymap の固定列ではなく operator-pending 状態機械で解釈
|
|
123
|
+
- keymap 解決順(現状実装): `filetype-local -> buffer-local -> mode-local -> global`
|
|
124
|
+
- `~/.config/ruvim/init.rb`(または `$XDG_CONFIG_HOME/ruvim/init.rb`)の `nmap` / `imap` / `map_global` で上書き・追加可能
|
|
125
|
+
- `~/.config/ruvim/ftplugin/<filetype>.rb`(または `$XDG_CONFIG_HOME/ruvim/ftplugin/<filetype>.rb`)では `nmap` / `imap` が filetype-local として登録される
|
data/docs/command.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# RuVim コマンド一覧
|
|
2
|
+
|
|
3
|
+
## 起動オプション(CLI, 現状)
|
|
4
|
+
|
|
5
|
+
- `--help`, `--version`
|
|
6
|
+
- `--clean`
|
|
7
|
+
- `-d`(diff mode placeholder, 未実装メッセージ表示)
|
|
8
|
+
- `-q {errorfile}`(quickfix startup placeholder。現状は未実装メッセージ表示)
|
|
9
|
+
- `-S [session]`(session startup placeholder, 未実装メッセージ表示)
|
|
10
|
+
- `-R`
|
|
11
|
+
- `-M`
|
|
12
|
+
- `-Z`
|
|
13
|
+
- `-n`(現状 no-op)
|
|
14
|
+
- `-o[N]`, `-O[N]`, `-p[N]`
|
|
15
|
+
- `-V[N]`, `--verbose[=N]`
|
|
16
|
+
- `--startuptime FILE`
|
|
17
|
+
- `--cmd {cmd}`(user config 読み込み前に Ex 実行)
|
|
18
|
+
- `-u {path|NONE}`
|
|
19
|
+
- `-c {cmd}`
|
|
20
|
+
- `+{cmd}`, `+{line}`, `+`
|
|
21
|
+
|
|
22
|
+
## Ex コマンド(builtin)
|
|
23
|
+
|
|
24
|
+
### `:w` / `:write`
|
|
25
|
+
|
|
26
|
+
- 形式: `:w [path]`
|
|
27
|
+
- 現在バッファを保存
|
|
28
|
+
- `path` 指定時はそのパスに保存
|
|
29
|
+
- `!` 対応: `:w!`(現状は保存メッセージに反映、権限昇格などは未実装)
|
|
30
|
+
|
|
31
|
+
### `:q` / `:quit`
|
|
32
|
+
|
|
33
|
+
- 形式: `:q`, `:q!`
|
|
34
|
+
- 複数 window があるとき: current window を閉じる
|
|
35
|
+
- window が1つで tab が複数あるとき: current tab を閉じる
|
|
36
|
+
- 最後の window / tab のとき: エディタ終了
|
|
37
|
+
- 最後の window / tab で未保存変更がある場合、`!` なしでは拒否
|
|
38
|
+
|
|
39
|
+
### `:wq`
|
|
40
|
+
|
|
41
|
+
- 形式: `:wq`, `:wq!`, `:wq [path]`
|
|
42
|
+
- 保存して `:q` 相当(window / tab / app を閉じる)
|
|
43
|
+
|
|
44
|
+
### `:e` / `:edit`
|
|
45
|
+
|
|
46
|
+
- 形式: `:e[!] [path]`
|
|
47
|
+
- 引数あり: 別ファイルを開く
|
|
48
|
+
- 引数なし: 現在ファイルを再読込
|
|
49
|
+
- 未保存変更がある場合は `!` なしで拒否
|
|
50
|
+
- `:e!` は未保存変更を破棄して開き直す(undo/redo もクリア)
|
|
51
|
+
|
|
52
|
+
### `:help`
|
|
53
|
+
|
|
54
|
+
- 形式: `:help [topic]`
|
|
55
|
+
- help 用の read-only バッファを開く(仮想バッファ)
|
|
56
|
+
- 例:
|
|
57
|
+
- `:help`
|
|
58
|
+
- `:help regex`
|
|
59
|
+
- `:help options`
|
|
60
|
+
- `:help w`
|
|
61
|
+
|
|
62
|
+
### `:commands`
|
|
63
|
+
|
|
64
|
+
- 形式: `:commands`
|
|
65
|
+
- Ex コマンド一覧(alias 含む)を read-only バッファに表示
|
|
66
|
+
|
|
67
|
+
### quickfix / location list(最小)
|
|
68
|
+
|
|
69
|
+
- `:vimgrep /pattern/`
|
|
70
|
+
- 現在開いている file buffer 群を検索して quickfix list を作成
|
|
71
|
+
- `:lvimgrep /pattern/`
|
|
72
|
+
- current window の current buffer を検索して location list を作成
|
|
73
|
+
- `:copen` / `:cclose`
|
|
74
|
+
- quickfix list を read-only な `qf` バッファで開く / 閉じる
|
|
75
|
+
- `:cnext` / `:cn`, `:cprev` / `:cp`
|
|
76
|
+
- quickfix 項目を前後移動して該当位置へジャンプ
|
|
77
|
+
- `:lopen` / `:lclose`
|
|
78
|
+
- current window の location list を開く / 閉じる
|
|
79
|
+
- `:lnext` / `:ln`, `:lprev` / `:lp`
|
|
80
|
+
- location list 項目を前後移動して該当位置へジャンプ
|
|
81
|
+
- 現状の制限:
|
|
82
|
+
- `:grep`, `:make`, `:cfile`, `:lgrep` は未実装
|
|
83
|
+
- 一覧バッファ上で `Enter` からのジャンプは未実装
|
|
84
|
+
|
|
85
|
+
### `:command`
|
|
86
|
+
|
|
87
|
+
- 形式: `:command Name ex_body`
|
|
88
|
+
- 形式: `:command! Name ex_body`(上書き)
|
|
89
|
+
- ユーザー定義 Ex コマンドを追加
|
|
90
|
+
- `:command`(引数なし)でユーザー定義コマンド一覧を表示
|
|
91
|
+
|
|
92
|
+
### `:ruby` / `:rb`
|
|
93
|
+
|
|
94
|
+
- 形式: `:ruby <code>`
|
|
95
|
+
- 形式: `:rb <code>`
|
|
96
|
+
- Ruby コードを評価し、返り値をステータスに表示
|
|
97
|
+
- 利用可能: `ctx`, `editor`, `buffer`, `window`
|
|
98
|
+
|
|
99
|
+
### `:ls` / `:buffers`
|
|
100
|
+
|
|
101
|
+
- 形式: `:ls`
|
|
102
|
+
- 形式: `:buffers`
|
|
103
|
+
- バッファ一覧をステータスに表示
|
|
104
|
+
- `%=current`, `#=alternate`, `+=modified` のフラグを含む
|
|
105
|
+
|
|
106
|
+
### `:bnext` / `:bn`
|
|
107
|
+
|
|
108
|
+
- 形式: `:bnext`
|
|
109
|
+
- 次のバッファへ切替
|
|
110
|
+
- `!` 対応(未保存変更を無視して切替)
|
|
111
|
+
|
|
112
|
+
### `:bprev` / `:bp`
|
|
113
|
+
|
|
114
|
+
- 形式: `:bprev`
|
|
115
|
+
- 前のバッファへ切替
|
|
116
|
+
- `!` 対応(未保存変更を無視して切替)
|
|
117
|
+
|
|
118
|
+
### `:buffer` / `:b`
|
|
119
|
+
|
|
120
|
+
- 形式: `:buffer <id|name|#>`
|
|
121
|
+
- バッファ ID / 名前 / `#`(alternate)で切替
|
|
122
|
+
- `!` 対応(未保存変更を無視して切替)
|
|
123
|
+
|
|
124
|
+
### `:split`
|
|
125
|
+
|
|
126
|
+
- 形式: `:split`
|
|
127
|
+
- 現在 window を水平分割(簡易タイル)
|
|
128
|
+
- 同じ buffer を新しい window に表示
|
|
129
|
+
|
|
130
|
+
### `:vsplit`
|
|
131
|
+
|
|
132
|
+
- 形式: `:vsplit`
|
|
133
|
+
- 現在 window を垂直分割(簡易タイル)
|
|
134
|
+
- 同じ buffer を新しい window に表示
|
|
135
|
+
|
|
136
|
+
### `:tabnew`
|
|
137
|
+
|
|
138
|
+
- 形式: `:tabnew [path]`
|
|
139
|
+
- 新しいタブを作成
|
|
140
|
+
- `path` 指定時はそのファイルを開く
|
|
141
|
+
|
|
142
|
+
### `:tabnext` / `:tabn`
|
|
143
|
+
|
|
144
|
+
- 形式: `:tabnext`
|
|
145
|
+
- 次のタブへ移動
|
|
146
|
+
|
|
147
|
+
### `:tabprev` / `:tabp`
|
|
148
|
+
|
|
149
|
+
- 形式: `:tabprev`
|
|
150
|
+
- 前のタブへ移動
|
|
151
|
+
|
|
152
|
+
## 内部コマンド(主なもの)
|
|
153
|
+
|
|
154
|
+
内部コマンドは主に key binding から使われ、`RuVim::CommandRegistry` に登録されます。
|
|
155
|
+
|
|
156
|
+
- `cursor.left`
|
|
157
|
+
- `cursor.right`
|
|
158
|
+
- `cursor.up`
|
|
159
|
+
- `cursor.down`
|
|
160
|
+
- `cursor.line_start`
|
|
161
|
+
- `cursor.line_end`
|
|
162
|
+
- `cursor.first_nonblank`
|
|
163
|
+
- `cursor.buffer_start`
|
|
164
|
+
- `cursor.buffer_end`
|
|
165
|
+
- `cursor.word_forward`
|
|
166
|
+
- `cursor.word_backward`
|
|
167
|
+
- `cursor.word_end`
|
|
168
|
+
- `mode.insert`
|
|
169
|
+
- `mode.append`
|
|
170
|
+
- `mode.append_line_end`
|
|
171
|
+
- `mode.insert_nonblank`
|
|
172
|
+
- `mode.open_below`
|
|
173
|
+
- `mode.open_above`
|
|
174
|
+
- `mode.visual_char`
|
|
175
|
+
- `mode.visual_line`
|
|
176
|
+
- `window.split`
|
|
177
|
+
- `window.vsplit`
|
|
178
|
+
- `window.focus_next`
|
|
179
|
+
- `window.focus_left`
|
|
180
|
+
- `window.focus_right`
|
|
181
|
+
- `window.focus_up`
|
|
182
|
+
- `window.focus_down`
|
|
183
|
+
- `tab_new`
|
|
184
|
+
- `tab_next`
|
|
185
|
+
- `tab_prev`
|
|
186
|
+
- `mode.command_line`
|
|
187
|
+
- `mode.search_forward`
|
|
188
|
+
- `mode.search_backward`
|
|
189
|
+
- `buffer.delete_char`
|
|
190
|
+
- `buffer.delete_line`
|
|
191
|
+
- `buffer.delete_motion`
|
|
192
|
+
- `buffer.change_motion`
|
|
193
|
+
- `buffer.change_line`
|
|
194
|
+
- `buffer.yank_line`
|
|
195
|
+
- `buffer.yank_motion`
|
|
196
|
+
- `buffer.paste_after`
|
|
197
|
+
- `buffer.paste_before`
|
|
198
|
+
- `buffer.visual_yank`
|
|
199
|
+
- `buffer.visual_delete`
|
|
200
|
+
- `buffer.undo`
|
|
201
|
+
- `buffer.redo`
|
|
202
|
+
- `search.next`
|
|
203
|
+
- `search.prev`
|
|
204
|
+
- `editor.buffer_next`
|
|
205
|
+
- `editor.buffer_prev`
|
|
206
|
+
- `buffer.replace_char`
|
|
207
|
+
- `ui.clear_message`
|
|
208
|
+
|
|
209
|
+
## 検索コマンド(Normal mode)
|
|
210
|
+
|
|
211
|
+
検索は Ex コマンドではなく、command-line prefix `/` `?` を使う入力経路です。
|
|
212
|
+
|
|
213
|
+
- `/pattern` : 前方検索
|
|
214
|
+
- `?pattern` : 後方検索
|
|
215
|
+
- `n` : repeat
|
|
216
|
+
- `N` : reverse repeat
|
|
217
|
+
- `*` / `#` : カーソル下の単語検索(単語境界)
|
|
218
|
+
- `g*` / `g#` : カーソル下の単語検索(部分一致)
|
|
219
|
+
- `:vimgrep` / `:lvimgrep` : 検索結果を quickfix/location list に積む
|
|
220
|
+
|
|
221
|
+
### `:%s/.../.../g`(最小実装)
|
|
222
|
+
|
|
223
|
+
- バッファ全体置換
|
|
224
|
+
- Ruby 正規表現 + Ruby 置換文字列を利用
|
|
225
|
+
- `g` フラグ対応(全置換)
|
|
226
|
+
|
|
227
|
+
## Operator-pending(Normal mode)
|
|
228
|
+
|
|
229
|
+
現状は delete / yank operator を実装:
|
|
230
|
+
|
|
231
|
+
- `d` + motion
|
|
232
|
+
- `y` + motion(現状 `yy`, `yw`)
|
|
233
|
+
- `c` + motion / `cc`
|
|
234
|
+
- 実装の内部コマンド: `buffer.delete_motion`
|
|
235
|
+
- `dd` は linewise delete として扱う
|
|
236
|
+
|
|
237
|
+
### text object(現状)
|
|
238
|
+
|
|
239
|
+
- `iw`, `aw`, `ip`, `ap`(簡易)
|
|
240
|
+
- `i"`, `a"`, ``i` ``, ``a` ``(簡易)
|
|
241
|
+
- `i)`, `a)`, `i]`, `a]`, `i}`, `a}`(簡易)
|
|
242
|
+
- `d`, `y`, `c` から利用可能
|
|
243
|
+
- Visual mode からも利用可能(選択更新)
|
|
244
|
+
|
|
245
|
+
## Visual mode
|
|
246
|
+
|
|
247
|
+
- `v` / `V` / `Ctrl-v` で characterwise / linewise / blockwise Visual mode
|
|
248
|
+
- `buffer.visual_yank`
|
|
249
|
+
- `buffer.visual_delete`
|
|
250
|
+
- blockwise は最小実装(矩形選択 + `y/d`)
|
|
251
|
+
- blockwise の text object 選択 / paste の Vim 互換挙動は未対応
|
|
252
|
+
|
|
253
|
+
## repeat(Normal mode)
|
|
254
|
+
|
|
255
|
+
- `.` : 直前変更の repeat(拡張版)
|
|
256
|
+
- 現状の対象:
|
|
257
|
+
- `x`
|
|
258
|
+
- `dd`, `d{motion}`
|
|
259
|
+
- `p`, `P`
|
|
260
|
+
- `r<char>`
|
|
261
|
+
- `i`, `a`, `A`, `I`, `o`, `O`(Insert 入力列)
|
|
262
|
+
- `cc`, `c{motion}`(text object を含む)
|
|
263
|
+
- macro 記録中に `.` を押した場合、内部で再生されるキーは macro に混ざらない
|
|
264
|
+
|
|
265
|
+
## レジスタ(現状)
|
|
266
|
+
|
|
267
|
+
- unnamed register(`"`)、named register(`"a`..`"z`)、append(`"A`..`"Z`)
|
|
268
|
+
- black hole register(`"_`)
|
|
269
|
+
- yank register `0`
|
|
270
|
+
- numbered delete registers `1-9`(簡易回転)
|
|
271
|
+
- `"+`, `"*` は system clipboard register(利用可能環境のみ)
|
|
272
|
+
- delete / yank で更新
|
|
273
|
+
- `p`, `P` で paste(register prefix 対応)
|
|
274
|
+
|
|
275
|
+
## Option / Ex(現状)
|
|
276
|
+
|
|
277
|
+
- `:set`, `:setlocal`, `:setglobal`
|
|
278
|
+
- 現状の接続済み option:
|
|
279
|
+
- `number`(window-local / 行番号表示)
|
|
280
|
+
- `relativenumber`(window-local / 相対行番号)
|
|
281
|
+
- `ignorecase` / `smartcase` / `hlsearch`(global / 検索系)
|
|
282
|
+
- `tabstop`(buffer-local / タブ展開幅)
|
|
283
|
+
- `filetype`(buffer-local / 自動検出 + ftplugin 用)
|
|
284
|
+
|
|
285
|
+
## 実装ポリシー
|
|
286
|
+
|
|
287
|
+
- Ex コマンド名(`:w` など)と内部コマンド名(`file_write` / `buffer.undo` など)を分離
|
|
288
|
+
- builtin は `Symbol` ベースで `RuVim::GlobalCommands` のメソッドに実装
|
|
289
|
+
- 拡張用に `Proc` の登録も可能
|
|
290
|
+
- key binding は `KeymapManager` の layered resolution(filetype / buffer / mode / global)で解決
|
|
291
|
+
- XDG 設定ファイル(`$XDG_CONFIG_HOME/ruvim/init.rb` または `~/.config/ruvim/init.rb`)から `ConfigDSL` 経由で command / ex command / key binding を追加可能
|
|
292
|
+
|
|
293
|
+
## UI メモ(現状)
|
|
294
|
+
|
|
295
|
+
- `Screen` は行キャッシュを使った簡易差分描画を行う
|
|
296
|
+
- `SIGWINCH` + self-pipe + `IO.select` で入力待機中でもリサイズに即追従
|
|
297
|
+
- command-line は履歴と Ex 補完(コマンド名 + 一部引数の文脈補完)を持つ
|
|
298
|
+
- Insert mode は `Ctrl-n` / `Ctrl-p` の buffer words 補完を持つ
|
|
299
|
+
- 文字幅は `DisplayWidth` の近似実装(tab 展開 + 一部全角幅2)
|
|
300
|
+
|
|
301
|
+
## テスト(現状)
|
|
302
|
+
|
|
303
|
+
- `Minitest`
|
|
304
|
+
- `test/buffer_test.rb`
|
|
305
|
+
- `test/dispatcher_test.rb`
|
|
306
|
+
- `test/keymap_manager_test.rb`
|