ruvim 0.4.0 → 0.6.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 +4 -4
- data/AGENTS.md +53 -4
- data/README.md +15 -6
- data/Rakefile +7 -0
- data/benchmark/cext_compare.rb +165 -0
- data/benchmark/chunked_load.rb +256 -0
- data/benchmark/file_load.rb +140 -0
- data/benchmark/hotspots.rb +178 -0
- data/docs/binding.md +3 -2
- data/docs/command.md +81 -9
- data/docs/done.md +23 -0
- data/docs/spec.md +105 -19
- data/docs/todo.md +9 -0
- data/docs/tutorial.md +9 -1
- data/docs/vim_diff.md +13 -0
- data/ext/ruvim/extconf.rb +5 -0
- data/ext/ruvim/ruvim_ext.c +519 -0
- data/lib/ruvim/app.rb +217 -2778
- data/lib/ruvim/browser.rb +104 -0
- data/lib/ruvim/buffer.rb +39 -28
- data/lib/ruvim/command_invocation.rb +2 -2
- data/lib/ruvim/completion_manager.rb +708 -0
- data/lib/ruvim/dispatcher.rb +14 -8
- data/lib/ruvim/display_width.rb +91 -45
- data/lib/ruvim/editor.rb +64 -81
- data/lib/ruvim/ex_command_registry.rb +3 -1
- data/lib/ruvim/gh/link.rb +207 -0
- data/lib/ruvim/git/blame.rb +16 -6
- data/lib/ruvim/git/branch.rb +20 -5
- data/lib/ruvim/git/grep.rb +107 -0
- data/lib/ruvim/git/handler.rb +42 -1
- data/lib/ruvim/global_commands.rb +175 -35
- data/lib/ruvim/highlighter.rb +4 -13
- data/lib/ruvim/key_handler.rb +1510 -0
- data/lib/ruvim/keymap_manager.rb +7 -7
- data/lib/ruvim/lang/base.rb +5 -0
- data/lib/ruvim/lang/c.rb +116 -0
- data/lib/ruvim/lang/cpp.rb +107 -0
- data/lib/ruvim/lang/csv.rb +4 -1
- data/lib/ruvim/lang/diff.rb +2 -0
- data/lib/ruvim/lang/dockerfile.rb +36 -0
- data/lib/ruvim/lang/elixir.rb +85 -0
- data/lib/ruvim/lang/erb.rb +30 -0
- data/lib/ruvim/lang/go.rb +83 -0
- data/lib/ruvim/lang/html.rb +34 -0
- data/lib/ruvim/lang/javascript.rb +83 -0
- data/lib/ruvim/lang/json.rb +6 -0
- data/lib/ruvim/lang/lua.rb +76 -0
- data/lib/ruvim/lang/makefile.rb +36 -0
- data/lib/ruvim/lang/markdown.rb +3 -4
- data/lib/ruvim/lang/ocaml.rb +77 -0
- data/lib/ruvim/lang/perl.rb +91 -0
- data/lib/ruvim/lang/python.rb +85 -0
- data/lib/ruvim/lang/registry.rb +102 -0
- data/lib/ruvim/lang/ruby.rb +7 -0
- data/lib/ruvim/lang/rust.rb +95 -0
- data/lib/ruvim/lang/scheme.rb +5 -0
- data/lib/ruvim/lang/sh.rb +76 -0
- data/lib/ruvim/lang/sql.rb +52 -0
- data/lib/ruvim/lang/toml.rb +36 -0
- data/lib/ruvim/lang/tsv.rb +4 -1
- data/lib/ruvim/lang/typescript.rb +53 -0
- data/lib/ruvim/lang/yaml.rb +62 -0
- data/lib/ruvim/rich_view/table_renderer.rb +3 -3
- data/lib/ruvim/rich_view.rb +14 -7
- data/lib/ruvim/screen.rb +126 -72
- data/lib/ruvim/stream/file_load.rb +85 -0
- data/lib/ruvim/stream/follow.rb +40 -0
- data/lib/ruvim/stream/git.rb +43 -0
- data/lib/ruvim/stream/run.rb +74 -0
- data/lib/ruvim/stream/stdin.rb +55 -0
- data/lib/ruvim/stream.rb +35 -0
- data/lib/ruvim/stream_mixer.rb +394 -0
- data/lib/ruvim/terminal.rb +18 -4
- data/lib/ruvim/text_metrics.rb +84 -65
- data/lib/ruvim/version.rb +1 -1
- data/lib/ruvim/window.rb +5 -5
- data/lib/ruvim.rb +23 -6
- data/test/app_command_test.rb +382 -0
- data/test/app_completion_test.rb +43 -19
- data/test/app_dot_repeat_test.rb +27 -3
- data/test/app_ex_command_test.rb +154 -0
- data/test/app_motion_test.rb +13 -12
- data/test/app_register_test.rb +2 -1
- data/test/app_scenario_test.rb +15 -10
- data/test/app_startup_test.rb +70 -27
- data/test/app_text_object_test.rb +2 -1
- data/test/app_unicode_behavior_test.rb +3 -2
- data/test/browser_test.rb +88 -0
- data/test/buffer_test.rb +24 -0
- data/test/cli_test.rb +63 -0
- data/test/command_invocation_test.rb +33 -0
- data/test/config_dsl_test.rb +47 -0
- data/test/dispatcher_test.rb +74 -4
- data/test/ex_command_registry_test.rb +106 -0
- data/test/follow_test.rb +20 -21
- data/test/gh_link_test.rb +141 -0
- data/test/git_blame_test.rb +96 -17
- data/test/git_grep_test.rb +64 -0
- data/test/highlighter_test.rb +125 -0
- data/test/indent_test.rb +137 -0
- data/test/input_screen_integration_test.rb +1 -1
- data/test/keyword_chars_test.rb +85 -0
- data/test/lang_test.rb +634 -0
- data/test/markdown_renderer_test.rb +5 -5
- data/test/on_save_hook_test.rb +12 -8
- data/test/render_snapshot_test.rb +78 -0
- data/test/rich_view_test.rb +42 -42
- data/test/run_command_test.rb +307 -0
- data/test/screen_test.rb +68 -5
- data/test/stream_test.rb +165 -0
- data/test/window_test.rb +59 -0
- metadata +52 -2
data/test/git_blame_test.rb
CHANGED
|
@@ -9,17 +9,20 @@ class GitBlameTest < Minitest::Test
|
|
|
9
9
|
@app = RuVim::App.new(clean: true)
|
|
10
10
|
@editor = @app.instance_variable_get(:@editor)
|
|
11
11
|
@dispatcher = @app.instance_variable_get(:@dispatcher)
|
|
12
|
+
@key_handler = @app.instance_variable_get(:@key_handler)
|
|
13
|
+
@stream_mixer = @app.instance_variable_get(:@stream_mixer)
|
|
12
14
|
@editor.materialize_intro_buffer!
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def feed(*keys)
|
|
16
|
-
keys.each { |k| @
|
|
18
|
+
keys.each { |k| @key_handler.handle(k) }
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def drain_git_stream!
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
@editor.buffers.each_value do |buf|
|
|
23
|
+
buf.stream&.thread&.join
|
|
24
|
+
end
|
|
25
|
+
@stream_mixer.drain_events!
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
# --- Parsing ---
|
|
@@ -81,12 +84,66 @@ class GitBlameTest < Minitest::Test
|
|
|
81
84
|
{ short_hash: "abc12345", author: "Alice", date: "2023-11-14", text: "hello", orig_line: 1, hash: "abc12345" * 5 },
|
|
82
85
|
{ short_hash: "def67890", author: "Bob", date: "2023-11-15", text: "world", orig_line: 2, hash: "def67890" * 5 },
|
|
83
86
|
]
|
|
84
|
-
lines = RuVim::Git::Blame.format_lines(entries)
|
|
87
|
+
lines, labels = RuVim::Git::Blame.format_lines(entries)
|
|
85
88
|
assert_equal 2, lines.length
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
assert_includes
|
|
89
|
+
assert_equal "hello", lines[0]
|
|
90
|
+
assert_equal "world", lines[1]
|
|
91
|
+
assert_equal 2, labels.length
|
|
92
|
+
assert_includes labels[0], "abc12345"
|
|
93
|
+
assert_includes labels[0], "Alice"
|
|
94
|
+
assert_includes labels[1], "Bob"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_blame_buffer_has_source_filetype
|
|
98
|
+
Dir.mktmpdir do |dir|
|
|
99
|
+
setup_git_repo(dir, "test_file.rb", "puts 'hello'\n")
|
|
100
|
+
|
|
101
|
+
file_path = File.join(dir, "test_file.rb")
|
|
102
|
+
buf = @editor.add_buffer_from_file(file_path)
|
|
103
|
+
@editor.switch_to_buffer(buf.id)
|
|
104
|
+
assert_equal "ruby", buf.options["filetype"]
|
|
105
|
+
|
|
106
|
+
@dispatcher.dispatch_ex(@editor, "git blame")
|
|
107
|
+
|
|
108
|
+
blame_buf = @editor.current_buffer
|
|
109
|
+
assert_equal :blame, blame_buf.kind
|
|
110
|
+
assert_equal "ruby", blame_buf.options["filetype"]
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_blame_buffer_has_gutter_labels
|
|
115
|
+
Dir.mktmpdir do |dir|
|
|
116
|
+
setup_git_repo(dir, "test_file.txt", "line1\nline2\n")
|
|
117
|
+
|
|
118
|
+
file_path = File.join(dir, "test_file.txt")
|
|
119
|
+
buf = @editor.add_buffer_from_file(file_path)
|
|
120
|
+
@editor.switch_to_buffer(buf.id)
|
|
121
|
+
|
|
122
|
+
@dispatcher.dispatch_ex(@editor, "git blame")
|
|
123
|
+
|
|
124
|
+
blame_buf = @editor.current_buffer
|
|
125
|
+
labels = blame_buf.options["gutter_labels"]
|
|
126
|
+
assert_kind_of Array, labels
|
|
127
|
+
assert_equal 2, labels.length
|
|
128
|
+
# Labels should contain hash and author info
|
|
129
|
+
assert_match(/\A[0-9a-f]{8} /, labels[0])
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def test_blame_buffer_lines_are_code_only
|
|
134
|
+
Dir.mktmpdir do |dir|
|
|
135
|
+
setup_git_repo(dir, "test_file.txt", "line1\nline2\n")
|
|
136
|
+
|
|
137
|
+
file_path = File.join(dir, "test_file.txt")
|
|
138
|
+
buf = @editor.add_buffer_from_file(file_path)
|
|
139
|
+
@editor.switch_to_buffer(buf.id)
|
|
140
|
+
|
|
141
|
+
@dispatcher.dispatch_ex(@editor, "git blame")
|
|
142
|
+
|
|
143
|
+
blame_buf = @editor.current_buffer
|
|
144
|
+
assert_equal "line1", blame_buf.line_at(0)
|
|
145
|
+
assert_equal "line2", blame_buf.line_at(1)
|
|
146
|
+
end
|
|
90
147
|
end
|
|
91
148
|
|
|
92
149
|
# --- Status filename parsing ---
|
|
@@ -221,9 +278,14 @@ class GitBlameTest < Minitest::Test
|
|
|
221
278
|
end
|
|
222
279
|
end
|
|
223
280
|
|
|
224
|
-
def
|
|
225
|
-
|
|
226
|
-
|
|
281
|
+
def test_git_unknown_subcommand_runs_shell
|
|
282
|
+
executed = nil
|
|
283
|
+
fake_status = Struct.new(:exitstatus).new(0)
|
|
284
|
+
@editor.shell_executor = ->(cmd) { executed = cmd; fake_status }
|
|
285
|
+
|
|
286
|
+
@dispatcher.dispatch_ex(@editor, "git stash")
|
|
287
|
+
|
|
288
|
+
assert_equal "git stash", executed
|
|
227
289
|
end
|
|
228
290
|
|
|
229
291
|
def test_git_no_subcommand_shows_list
|
|
@@ -485,10 +547,9 @@ class GitBlameTest < Minitest::Test
|
|
|
485
547
|
assert_nil RuVim::Git::Branch.parse_branch_name("")
|
|
486
548
|
end
|
|
487
549
|
|
|
488
|
-
def
|
|
550
|
+
def test_git_branch_enter_populates_checkout_command
|
|
489
551
|
Dir.mktmpdir do |dir|
|
|
490
552
|
setup_git_repo(dir, "test_file.txt", "line1\n")
|
|
491
|
-
# Create a second branch
|
|
492
553
|
Dir.chdir(dir) do
|
|
493
554
|
system("git branch test-branch", exception: true)
|
|
494
555
|
end
|
|
@@ -507,9 +568,27 @@ class GitBlameTest < Minitest::Test
|
|
|
507
568
|
|
|
508
569
|
feed(:enter)
|
|
509
570
|
|
|
510
|
-
#
|
|
511
|
-
|
|
512
|
-
|
|
571
|
+
# Should enter command-line mode with checkout command pre-filled
|
|
572
|
+
assert_equal :command_line, @editor.mode
|
|
573
|
+
assert_equal "git checkout test-branch", @editor.command_line.text
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def test_git_checkout_subcommand_executes
|
|
578
|
+
Dir.mktmpdir do |dir|
|
|
579
|
+
setup_git_repo(dir, "test_file.txt", "line1\n")
|
|
580
|
+
Dir.chdir(dir) do
|
|
581
|
+
system("git branch test-branch", exception: true)
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
file_path = File.join(dir, "test_file.txt")
|
|
585
|
+
buf = @editor.add_buffer_from_file(file_path)
|
|
586
|
+
@editor.switch_to_buffer(buf.id)
|
|
587
|
+
|
|
588
|
+
@dispatcher.dispatch_ex(@editor, "git checkout test-branch")
|
|
589
|
+
|
|
590
|
+
refute @editor.message_error?, "Unexpected error: #{@editor.message}"
|
|
591
|
+
assert_includes @editor.message.to_s, "Switched to branch"
|
|
513
592
|
Dir.chdir(dir) do
|
|
514
593
|
current = `git rev-parse --abbrev-ref HEAD`.strip
|
|
515
594
|
assert_equal "test-branch", current
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
|
|
5
|
+
class GitGrepTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@app = RuVim::App.new(clean: true)
|
|
8
|
+
@editor = @app.instance_variable_get(:@editor)
|
|
9
|
+
@dispatcher = @app.instance_variable_get(:@dispatcher)
|
|
10
|
+
@key_handler = @app.instance_variable_get(:@key_handler)
|
|
11
|
+
@editor.materialize_intro_buffer!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def feed(*keys)
|
|
15
|
+
keys.each { |k| @key_handler.handle(k) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# --- Parsing ---
|
|
19
|
+
|
|
20
|
+
def test_parse_location_basic
|
|
21
|
+
line = "lib/ruvim/app.rb:42: def run"
|
|
22
|
+
result = RuVim::Git::Grep.parse_location(line)
|
|
23
|
+
assert_equal ["lib/ruvim/app.rb", 42], result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_parse_location_no_line_number
|
|
27
|
+
line = "lib/ruvim/app.rb: def run"
|
|
28
|
+
result = RuVim::Git::Grep.parse_location(line)
|
|
29
|
+
assert_nil result
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_parse_location_empty
|
|
33
|
+
result = RuVim::Git::Grep.parse_location("")
|
|
34
|
+
assert_nil result
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_parse_location_separator_line
|
|
38
|
+
result = RuVim::Git::Grep.parse_location("--")
|
|
39
|
+
assert_nil result
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_parse_location_with_colon_in_content
|
|
43
|
+
line = "config.rb:10: url = \"http://example.com\""
|
|
44
|
+
result = RuVim::Git::Grep.parse_location(line)
|
|
45
|
+
assert_equal ["config.rb", 10], result
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_parse_location_windows_style_path
|
|
49
|
+
line = "src/main.rb:5:hello"
|
|
50
|
+
result = RuVim::Git::Grep.parse_location(line)
|
|
51
|
+
assert_equal ["src/main.rb", 5], result
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# --- Command registration ---
|
|
55
|
+
|
|
56
|
+
def test_git_grep_subcommand_registered
|
|
57
|
+
assert RuVim::Git::Handler::GIT_SUBCOMMANDS.key?("grep")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_git_grep_open_file_command_registered
|
|
61
|
+
cmd = RuVim::CommandRegistry.instance
|
|
62
|
+
assert cmd.registered?("git.grep.open_file")
|
|
63
|
+
end
|
|
64
|
+
end
|
data/test/highlighter_test.rb
CHANGED
|
@@ -178,4 +178,129 @@ class HighlighterTest < Minitest::Test
|
|
|
178
178
|
refute_empty cols
|
|
179
179
|
assert_equal "\e[33m", cols[0]
|
|
180
180
|
end
|
|
181
|
+
|
|
182
|
+
# --- C ---
|
|
183
|
+
|
|
184
|
+
def test_c_keyword_if
|
|
185
|
+
cols = RuVim::Highlighter.color_columns("c", "if (x > 0) {")
|
|
186
|
+
assert_equal "\e[36m", cols[0] # "if"
|
|
187
|
+
assert_equal "\e[36m", cols[1]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def test_c_keyword_return
|
|
191
|
+
cols = RuVim::Highlighter.color_columns("c", " return 0;")
|
|
192
|
+
assert_equal "\e[36m", cols[2] # "return"
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def test_c_type_keyword
|
|
196
|
+
cols = RuVim::Highlighter.color_columns("c", "int main(void) {")
|
|
197
|
+
assert_equal "\e[36m", cols[0] # "int"
|
|
198
|
+
assert_equal "\e[36m", cols[9] # "void"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def test_c_string
|
|
202
|
+
cols = RuVim::Highlighter.color_columns("c", 'printf("hello");')
|
|
203
|
+
assert_equal "\e[32m", cols[7] # opening quote
|
|
204
|
+
assert_equal "\e[32m", cols[13] # closing quote
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def test_c_char_literal
|
|
208
|
+
cols = RuVim::Highlighter.color_columns("c", "char c = 'a';")
|
|
209
|
+
assert_equal "\e[32m", cols[9] # opening quote
|
|
210
|
+
assert_equal "\e[32m", cols[11] # closing quote
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def test_c_number_decimal
|
|
214
|
+
cols = RuVim::Highlighter.color_columns("c", "int x = 42;")
|
|
215
|
+
assert_equal "\e[33m", cols[8] # "4"
|
|
216
|
+
assert_equal "\e[33m", cols[9] # "2"
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_c_number_hex
|
|
220
|
+
cols = RuVim::Highlighter.color_columns("c", "int x = 0xFF;")
|
|
221
|
+
assert_equal "\e[33m", cols[8] # "0"
|
|
222
|
+
assert_equal "\e[33m", cols[11] # "F"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def test_c_line_comment
|
|
226
|
+
cols = RuVim::Highlighter.color_columns("c", "x = 1; // comment")
|
|
227
|
+
assert_equal "\e[90m", cols[7] # "//"
|
|
228
|
+
assert_equal "\e[90m", cols[16] # end of comment
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def test_c_block_comment_single_line
|
|
232
|
+
cols = RuVim::Highlighter.color_columns("c", "x = 1; /* comment */")
|
|
233
|
+
assert_equal "\e[90m", cols[7] # "/*"
|
|
234
|
+
assert_equal "\e[90m", cols[19] # "*/"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def test_c_preprocessor
|
|
238
|
+
cols = RuVim::Highlighter.color_columns("c", "#include <stdio.h>")
|
|
239
|
+
assert_equal "\e[35m", cols[0] # "#"
|
|
240
|
+
assert_equal "\e[35m", cols[7] # "e" of include
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_c_define_preprocessor
|
|
244
|
+
cols = RuVim::Highlighter.color_columns("c", "#define MAX 100")
|
|
245
|
+
assert_equal "\e[35m", cols[0] # "#"
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def test_c_constant_macro
|
|
249
|
+
cols = RuVim::Highlighter.color_columns("c", "if (ptr == NULL) {")
|
|
250
|
+
assert_equal "\e[96m", cols[11] # "N" of NULL
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def test_c_all_caps_identifier
|
|
254
|
+
cols = RuVim::Highlighter.color_columns("c", "x = MAX_SIZE;")
|
|
255
|
+
assert_equal "\e[96m", cols[4] # "M"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def test_c_empty_line
|
|
259
|
+
cols = RuVim::Highlighter.color_columns("c", "")
|
|
260
|
+
assert_empty cols
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# --- C++ ---
|
|
264
|
+
|
|
265
|
+
def test_cpp_keyword_class
|
|
266
|
+
cols = RuVim::Highlighter.color_columns("cpp", "class Foo {")
|
|
267
|
+
assert_equal "\e[36m", cols[0] # "class"
|
|
268
|
+
assert_equal "\e[36m", cols[4]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def test_cpp_keyword_namespace
|
|
272
|
+
cols = RuVim::Highlighter.color_columns("cpp", "namespace std {")
|
|
273
|
+
assert_equal "\e[36m", cols[0] # "namespace"
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def test_cpp_keyword_template
|
|
277
|
+
cols = RuVim::Highlighter.color_columns("cpp", "template <typename T>")
|
|
278
|
+
assert_equal "\e[36m", cols[0] # "template"
|
|
279
|
+
assert_equal "\e[36m", cols[10] # "typename"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def test_cpp_keyword_nullptr
|
|
283
|
+
cols = RuVim::Highlighter.color_columns("cpp", "int* p = nullptr;")
|
|
284
|
+
assert_equal "\e[36m", cols[9] # "nullptr"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def test_cpp_keyword_auto
|
|
288
|
+
cols = RuVim::Highlighter.color_columns("cpp", "auto x = 42;")
|
|
289
|
+
assert_equal "\e[36m", cols[0] # "auto"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def test_cpp_inherits_c_string
|
|
293
|
+
cols = RuVim::Highlighter.color_columns("cpp", 'std::cout << "hello";')
|
|
294
|
+
assert_equal "\e[32m", cols[13] # opening quote
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def test_cpp_inherits_c_comment
|
|
298
|
+
cols = RuVim::Highlighter.color_columns("cpp", "x = 1; // comment")
|
|
299
|
+
assert_equal "\e[90m", cols[7] # "//"
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def test_cpp_empty_line
|
|
303
|
+
cols = RuVim::Highlighter.color_columns("cpp", "")
|
|
304
|
+
assert_empty cols
|
|
305
|
+
end
|
|
181
306
|
end
|
data/test/indent_test.rb
CHANGED
|
@@ -285,3 +285,140 @@ class RubyIndentTest < Minitest::Test
|
|
|
285
285
|
assert_equal 0, calc(lines, 3) # end
|
|
286
286
|
end
|
|
287
287
|
end
|
|
288
|
+
|
|
289
|
+
class CIndentTest < Minitest::Test
|
|
290
|
+
def calc(lines, target_row, sw = 2)
|
|
291
|
+
RuVim::Lang::C.calculate_indent(lines, target_row, sw)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def test_first_line_is_zero
|
|
295
|
+
assert_equal 0, calc(["int main() {"], 0)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def test_after_open_brace
|
|
299
|
+
lines = ["int main() {", " return 0;"]
|
|
300
|
+
assert_equal 2, calc(lines, 1)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def test_close_brace
|
|
304
|
+
lines = ["int main() {", " return 0;", "}"]
|
|
305
|
+
assert_equal 0, calc(lines, 2)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def test_nested_braces
|
|
309
|
+
lines = [
|
|
310
|
+
"void foo() {",
|
|
311
|
+
" if (x) {",
|
|
312
|
+
" bar();",
|
|
313
|
+
" }",
|
|
314
|
+
"}"
|
|
315
|
+
]
|
|
316
|
+
assert_equal 2, calc(lines, 1)
|
|
317
|
+
assert_equal 4, calc(lines, 2)
|
|
318
|
+
assert_equal 2, calc(lines, 3)
|
|
319
|
+
assert_equal 0, calc(lines, 4)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def test_switch_case
|
|
323
|
+
lines = [
|
|
324
|
+
"switch (x) {",
|
|
325
|
+
"case 1:",
|
|
326
|
+
" foo();",
|
|
327
|
+
" break;",
|
|
328
|
+
"case 2:",
|
|
329
|
+
" bar();",
|
|
330
|
+
" break;",
|
|
331
|
+
"default:",
|
|
332
|
+
" baz();",
|
|
333
|
+
"}"
|
|
334
|
+
]
|
|
335
|
+
assert_equal 0, calc(lines, 1) # case 1:
|
|
336
|
+
assert_equal 2, calc(lines, 2) # foo()
|
|
337
|
+
assert_equal 2, calc(lines, 3) # break
|
|
338
|
+
assert_equal 0, calc(lines, 4) # case 2:
|
|
339
|
+
assert_equal 2, calc(lines, 5) # bar()
|
|
340
|
+
assert_equal 0, calc(lines, 7) # default:
|
|
341
|
+
assert_equal 2, calc(lines, 8) # baz()
|
|
342
|
+
assert_equal 0, calc(lines, 9) # }
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def test_shiftwidth_4
|
|
346
|
+
lines = ["void foo() {", " bar();", "}"]
|
|
347
|
+
assert_equal 4, calc(lines, 1, 4)
|
|
348
|
+
assert_equal 0, calc(lines, 2, 4)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def test_indent_trigger_open_brace
|
|
352
|
+
assert RuVim::Lang::C.indent_trigger?("int main() {")
|
|
353
|
+
assert RuVim::Lang::C.indent_trigger?("if (x) {")
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def test_indent_trigger_no_trigger
|
|
357
|
+
refute RuVim::Lang::C.indent_trigger?("return 0;")
|
|
358
|
+
refute RuVim::Lang::C.indent_trigger?("}")
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def test_dedent_trigger_close_brace
|
|
362
|
+
assert_kind_of Regexp, RuVim::Lang::C.dedent_trigger("}")
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def test_dedent_trigger_no_trigger
|
|
366
|
+
assert_nil RuVim::Lang::C.dedent_trigger("a")
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
class CppIndentTest < Minitest::Test
|
|
371
|
+
def calc(lines, target_row, sw = 2)
|
|
372
|
+
RuVim::Lang::Cpp.calculate_indent(lines, target_row, sw)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def test_class_body
|
|
376
|
+
lines = [
|
|
377
|
+
"class Foo {",
|
|
378
|
+
" int x;",
|
|
379
|
+
"};"
|
|
380
|
+
]
|
|
381
|
+
assert_equal 2, calc(lines, 1)
|
|
382
|
+
assert_equal 0, calc(lines, 2)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def test_namespace_body
|
|
386
|
+
lines = [
|
|
387
|
+
"namespace ns {",
|
|
388
|
+
" class Bar {",
|
|
389
|
+
" void f();",
|
|
390
|
+
" };",
|
|
391
|
+
"}"
|
|
392
|
+
]
|
|
393
|
+
assert_equal 2, calc(lines, 1)
|
|
394
|
+
assert_equal 4, calc(lines, 2)
|
|
395
|
+
assert_equal 2, calc(lines, 3)
|
|
396
|
+
assert_equal 0, calc(lines, 4)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def test_access_specifier_dedent
|
|
400
|
+
lines = [
|
|
401
|
+
"class Foo {",
|
|
402
|
+
"public:",
|
|
403
|
+
" int x;",
|
|
404
|
+
"private:",
|
|
405
|
+
" int y;",
|
|
406
|
+
"};"
|
|
407
|
+
]
|
|
408
|
+
assert_equal 0, calc(lines, 1) # public:
|
|
409
|
+
assert_equal 2, calc(lines, 2) # int x
|
|
410
|
+
assert_equal 0, calc(lines, 3) # private:
|
|
411
|
+
assert_equal 2, calc(lines, 4) # int y
|
|
412
|
+
assert_equal 0, calc(lines, 5) # };
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def test_indent_trigger
|
|
416
|
+
assert RuVim::Lang::Cpp.indent_trigger?("class Foo {")
|
|
417
|
+
assert RuVim::Lang::Cpp.indent_trigger?("namespace ns {")
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def test_dedent_trigger
|
|
421
|
+
assert_kind_of Regexp, RuVim::Lang::Cpp.dedent_trigger("}")
|
|
422
|
+
assert_nil RuVim::Lang::Cpp.dedent_trigger("x")
|
|
423
|
+
end
|
|
424
|
+
end
|
|
@@ -62,7 +62,7 @@ class InputScreenIntegrationTest < Minitest::Test
|
|
|
62
62
|
key = input.read_key(timeout: 0.2)
|
|
63
63
|
assert_equal :pagedown, key
|
|
64
64
|
|
|
65
|
-
app.send(:handle_normal_key, key)
|
|
65
|
+
app.instance_variable_get(:@key_handler).send(:handle_normal_key, key)
|
|
66
66
|
screen.render(editor)
|
|
67
67
|
|
|
68
68
|
assert_operator editor.current_window.cursor_y, :>, 0
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
|
|
5
|
+
class KeywordCharsTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
# Clear caches between tests
|
|
8
|
+
RuVim::KeywordChars.instance_variable_set(:@char_class_cache, nil)
|
|
9
|
+
RuVim::KeywordChars.instance_variable_set(:@regex_cache, nil)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# --- char_class ---
|
|
13
|
+
|
|
14
|
+
def test_char_class_default_for_empty
|
|
15
|
+
assert_equal "[:alnum:]_", RuVim::KeywordChars.char_class("")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_char_class_default_for_nil
|
|
19
|
+
assert_equal "[:alnum:]_", RuVim::KeywordChars.char_class(nil)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_char_class_single_char
|
|
23
|
+
result = RuVim::KeywordChars.char_class("-")
|
|
24
|
+
assert_includes result, "[:alnum:]_"
|
|
25
|
+
assert_includes result, "\\-"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_char_class_range
|
|
29
|
+
result = RuVim::KeywordChars.char_class("65-90")
|
|
30
|
+
assert_includes result, "[:alnum:]_"
|
|
31
|
+
# Should include A-Z range
|
|
32
|
+
assert_includes result, "A-Z"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_char_class_reversed_range
|
|
36
|
+
# minmax should handle reversed ranges
|
|
37
|
+
result = RuVim::KeywordChars.char_class("90-65")
|
|
38
|
+
assert_includes result, "A-Z"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_char_class_skips_at_sign
|
|
42
|
+
result = RuVim::KeywordChars.char_class("@")
|
|
43
|
+
assert_equal "[:alnum:]_", result
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_char_class_skips_out_of_range
|
|
47
|
+
result = RuVim::KeywordChars.char_class("256-300")
|
|
48
|
+
assert_equal "[:alnum:]_", result
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_char_class_mixed_spec
|
|
52
|
+
result = RuVim::KeywordChars.char_class("-,65-90")
|
|
53
|
+
assert_includes result, "\\-"
|
|
54
|
+
assert_includes result, "A-Z"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_char_class_caches_result
|
|
58
|
+
result1 = RuVim::KeywordChars.char_class("-")
|
|
59
|
+
result2 = RuVim::KeywordChars.char_class("-")
|
|
60
|
+
assert_same result1, result2
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# --- regex ---
|
|
64
|
+
|
|
65
|
+
def test_regex_default_for_empty
|
|
66
|
+
assert_equal RuVim::KeywordChars::DEFAULT_REGEX, RuVim::KeywordChars.regex("")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_regex_default_for_nil
|
|
70
|
+
assert_equal RuVim::KeywordChars::DEFAULT_REGEX, RuVim::KeywordChars.regex(nil)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_regex_matches_with_spec
|
|
74
|
+
re = RuVim::KeywordChars.regex("-")
|
|
75
|
+
assert_match re, "a"
|
|
76
|
+
assert_match re, "-"
|
|
77
|
+
refute_match re, " "
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_regex_caches_result
|
|
81
|
+
result1 = RuVim::KeywordChars.regex("-")
|
|
82
|
+
result2 = RuVim::KeywordChars.regex("-")
|
|
83
|
+
assert_same result1, result2
|
|
84
|
+
end
|
|
85
|
+
end
|