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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module RuVim
|
|
2
|
+
module TextMetrics
|
|
3
|
+
module_function
|
|
4
|
+
|
|
5
|
+
Cell = Struct.new(:glyph, :source_col, :display_width, keyword_init: true)
|
|
6
|
+
|
|
7
|
+
# Cursor positions in RuVim are currently "character index" (Ruby String#[] index on UTF-8),
|
|
8
|
+
# not byte offsets. Grapheme-aware movement is layered on top of that.
|
|
9
|
+
def previous_grapheme_char_index(line, char_index)
|
|
10
|
+
idx = [char_index.to_i, 0].max
|
|
11
|
+
return 0 if idx <= 0
|
|
12
|
+
|
|
13
|
+
left = line.to_s[0...idx].to_s
|
|
14
|
+
clusters = left.scan(/\X/)
|
|
15
|
+
return 0 if clusters.empty?
|
|
16
|
+
|
|
17
|
+
idx - clusters.last.length
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def next_grapheme_char_index(line, char_index)
|
|
21
|
+
s = line.to_s
|
|
22
|
+
idx = [[char_index.to_i, 0].max, s.length].min
|
|
23
|
+
return s.length if idx >= s.length
|
|
24
|
+
|
|
25
|
+
rest = s[idx..].to_s
|
|
26
|
+
m = /\A\X/.match(rest)
|
|
27
|
+
return idx + 1 unless m
|
|
28
|
+
|
|
29
|
+
idx + m[0].length
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def screen_col_for_char_index(line, char_index, tabstop: 2)
|
|
33
|
+
idx = [char_index.to_i, 0].max
|
|
34
|
+
prefix = line.to_s[0...idx].to_s
|
|
35
|
+
RuVim::DisplayWidth.display_width(prefix, tabstop:)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns a character index whose screen column is <= target_screen_col,
|
|
39
|
+
# aligned to a grapheme-cluster boundary.
|
|
40
|
+
def char_index_for_screen_col(line, target_screen_col, tabstop: 2, align: :floor)
|
|
41
|
+
s = line.to_s
|
|
42
|
+
target = [target_screen_col.to_i, 0].max
|
|
43
|
+
screen_col = 0
|
|
44
|
+
char_index = 0
|
|
45
|
+
|
|
46
|
+
s.scan(/\X/).each do |cluster|
|
|
47
|
+
width = RuVim::DisplayWidth.display_width(cluster, tabstop:, start_col: screen_col)
|
|
48
|
+
if screen_col + width > target
|
|
49
|
+
return align == :ceil ? (char_index + cluster.length) : char_index
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
screen_col += width
|
|
53
|
+
char_index += cluster.length
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
char_index
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def clip_cells_for_width(text, width, source_col_start: 0, tabstop: 2)
|
|
60
|
+
max_width = [width.to_i, 0].max
|
|
61
|
+
cells = []
|
|
62
|
+
display_col = 0
|
|
63
|
+
source_col = source_col_start.to_i
|
|
64
|
+
|
|
65
|
+
text.to_s.each_char do |ch|
|
|
66
|
+
if ch == "\t"
|
|
67
|
+
w = RuVim::DisplayWidth.cell_width(ch, col: display_col, tabstop:)
|
|
68
|
+
break if display_col + w > max_width
|
|
69
|
+
|
|
70
|
+
w.times do
|
|
71
|
+
cells << Cell.new(glyph: " ", source_col:, display_width: 1)
|
|
72
|
+
end
|
|
73
|
+
display_col += w
|
|
74
|
+
source_col += 1
|
|
75
|
+
next
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
w = RuVim::DisplayWidth.cell_width(ch, col: display_col, tabstop:)
|
|
79
|
+
break if display_col + w > max_width
|
|
80
|
+
|
|
81
|
+
cells << Cell.new(glyph: ch, source_col:, display_width: w)
|
|
82
|
+
display_col += w
|
|
83
|
+
source_col += 1
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
[cells, display_col]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def pad_plain_to_screen_width(text, width, tabstop: 2)
|
|
90
|
+
cells, used = clip_cells_for_width(text, width, tabstop:)
|
|
91
|
+
out = cells.map(&:glyph).join
|
|
92
|
+
out << (" " * [width.to_i - used, 0].max)
|
|
93
|
+
out
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/ruvim/window.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module RuVim
|
|
2
|
+
class Window
|
|
3
|
+
attr_reader :id
|
|
4
|
+
attr_accessor :buffer_id, :cursor_x, :cursor_y, :row_offset, :col_offset
|
|
5
|
+
attr_reader :options
|
|
6
|
+
|
|
7
|
+
def initialize(id:, buffer_id:)
|
|
8
|
+
@id = id
|
|
9
|
+
@buffer_id = buffer_id
|
|
10
|
+
@cursor_x = 0
|
|
11
|
+
@cursor_y = 0
|
|
12
|
+
@row_offset = 0
|
|
13
|
+
@col_offset = 0
|
|
14
|
+
@options = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def clamp_to_buffer(buffer)
|
|
18
|
+
@cursor_y = [[@cursor_y, 0].max, buffer.line_count - 1].min
|
|
19
|
+
@cursor_x = [[@cursor_x, 0].max, buffer.line_length(@cursor_y)].min
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def move_left(buffer, count = 1)
|
|
24
|
+
count.times do
|
|
25
|
+
break if @cursor_x <= 0
|
|
26
|
+
@cursor_x = RuVim::TextMetrics.previous_grapheme_char_index(buffer.line_at(@cursor_y), @cursor_x)
|
|
27
|
+
end
|
|
28
|
+
clamp_to_buffer(buffer)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def move_right(buffer, count = 1)
|
|
32
|
+
count.times do
|
|
33
|
+
line = buffer.line_at(@cursor_y)
|
|
34
|
+
break if @cursor_x >= line.length
|
|
35
|
+
@cursor_x = RuVim::TextMetrics.next_grapheme_char_index(line, @cursor_x)
|
|
36
|
+
end
|
|
37
|
+
clamp_to_buffer(buffer)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def move_up(buffer, count = 1)
|
|
41
|
+
@cursor_y -= count
|
|
42
|
+
clamp_to_buffer(buffer)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def move_down(buffer, count = 1)
|
|
46
|
+
@cursor_y += count
|
|
47
|
+
clamp_to_buffer(buffer)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def ensure_visible(buffer, height:, width:, tabstop: 2)
|
|
51
|
+
clamp_to_buffer(buffer)
|
|
52
|
+
|
|
53
|
+
@row_offset = @cursor_y if @cursor_y < @row_offset
|
|
54
|
+
@row_offset = @cursor_y - height + 1 if @cursor_y >= @row_offset + height
|
|
55
|
+
@row_offset = 0 if @row_offset.negative?
|
|
56
|
+
|
|
57
|
+
line = buffer.line_at(@cursor_y)
|
|
58
|
+
cursor_screen_col = RuVim::TextMetrics.screen_col_for_char_index(line, @cursor_x, tabstop:)
|
|
59
|
+
offset_screen_col = RuVim::TextMetrics.screen_col_for_char_index(line, @col_offset, tabstop:)
|
|
60
|
+
|
|
61
|
+
if cursor_screen_col < offset_screen_col
|
|
62
|
+
@col_offset = RuVim::TextMetrics.char_index_for_screen_col(line, cursor_screen_col, tabstop:)
|
|
63
|
+
elsif cursor_screen_col >= offset_screen_col + width
|
|
64
|
+
target_left = cursor_screen_col - width + 1
|
|
65
|
+
@col_offset = RuVim::TextMetrics.char_index_for_screen_col(line, target_left, tabstop:, align: :ceil)
|
|
66
|
+
end
|
|
67
|
+
@col_offset = 0 if @col_offset.negative?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
data/lib/ruvim.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require "singleton"
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
class CommandError < Error; end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require_relative "ruvim/version"
|
|
9
|
+
require_relative "ruvim/command_invocation"
|
|
10
|
+
require_relative "ruvim/display_width"
|
|
11
|
+
require_relative "ruvim/text_metrics"
|
|
12
|
+
require_relative "ruvim/clipboard"
|
|
13
|
+
require_relative "ruvim/highlighter"
|
|
14
|
+
require_relative "ruvim/context"
|
|
15
|
+
require_relative "ruvim/buffer"
|
|
16
|
+
require_relative "ruvim/window"
|
|
17
|
+
require_relative "ruvim/editor"
|
|
18
|
+
require_relative "ruvim/command_registry"
|
|
19
|
+
require_relative "ruvim/ex_command_registry"
|
|
20
|
+
require_relative "ruvim/global_commands"
|
|
21
|
+
require_relative "ruvim/dispatcher"
|
|
22
|
+
require_relative "ruvim/keymap_manager"
|
|
23
|
+
require_relative "ruvim/command_line"
|
|
24
|
+
require_relative "ruvim/input"
|
|
25
|
+
require_relative "ruvim/terminal"
|
|
26
|
+
require_relative "ruvim/screen"
|
|
27
|
+
require_relative "ruvim/config_dsl"
|
|
28
|
+
require_relative "ruvim/config_loader"
|
|
29
|
+
require_relative "ruvim/app"
|
|
30
|
+
require_relative "ruvim/cli"
|
data/sig/ruvim.rbs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require_relative "test_helper"
|
|
2
|
+
|
|
3
|
+
class AppCompletionTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
@app = RuVim::App.new
|
|
6
|
+
@editor = @app.instance_variable_get(:@editor)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_app_starts_with_intro_buffer_without_path
|
|
10
|
+
assert_equal :intro, @editor.current_buffer.kind
|
|
11
|
+
assert @editor.current_buffer.readonly?
|
|
12
|
+
refute @editor.current_buffer.modifiable?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_command_line_completion_for_set_option
|
|
16
|
+
@editor.materialize_intro_buffer!
|
|
17
|
+
@editor.enter_command_line_mode(":")
|
|
18
|
+
cmd = @editor.command_line
|
|
19
|
+
cmd.replace_text("set nu")
|
|
20
|
+
|
|
21
|
+
@app.send(:command_line_complete)
|
|
22
|
+
|
|
23
|
+
assert_equal "set number", cmd.text
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_insert_buffer_word_completion_ctrl_n
|
|
27
|
+
@editor.materialize_intro_buffer!
|
|
28
|
+
b = @editor.current_buffer
|
|
29
|
+
b.replace_all_lines!(["fo", "foobar", "fizz"])
|
|
30
|
+
@editor.current_window.cursor_y = 0
|
|
31
|
+
@editor.current_window.cursor_x = 2
|
|
32
|
+
@editor.enter_insert_mode
|
|
33
|
+
|
|
34
|
+
@app.send(:handle_insert_key, :ctrl_n)
|
|
35
|
+
|
|
36
|
+
assert_equal "foobar", b.line_at(0)
|
|
37
|
+
assert_equal 6, @editor.current_window.cursor_x
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require_relative "test_helper"
|
|
2
|
+
|
|
3
|
+
class AppDotRepeatTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
@app = RuVim::App.new(clean: true)
|
|
6
|
+
@editor = @app.instance_variable_get(:@editor)
|
|
7
|
+
@editor.materialize_intro_buffer!
|
|
8
|
+
@buffer = @editor.current_buffer
|
|
9
|
+
@win = @editor.current_window
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def press(*keys)
|
|
13
|
+
keys.each { |k| @app.send(:handle_normal_key, k) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_dot_repeats_x
|
|
17
|
+
@buffer.replace_all_lines!(["abcd"])
|
|
18
|
+
@win.cursor_x = 0
|
|
19
|
+
|
|
20
|
+
press("x")
|
|
21
|
+
press(".")
|
|
22
|
+
|
|
23
|
+
assert_equal "cd", @buffer.line_at(0)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_dot_repeats_dd
|
|
27
|
+
@buffer.replace_all_lines!(["one", "two", "three"])
|
|
28
|
+
|
|
29
|
+
press("d", "d")
|
|
30
|
+
press(".")
|
|
31
|
+
|
|
32
|
+
assert_equal ["three"], @buffer.lines
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_dot_repeats_paste
|
|
36
|
+
@buffer.replace_all_lines!(["one", "two"])
|
|
37
|
+
press("y", "y")
|
|
38
|
+
press("p")
|
|
39
|
+
press(".")
|
|
40
|
+
|
|
41
|
+
assert_equal ["one", "one", "one", "two"], @buffer.lines
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_dot_repeats_replace_char
|
|
45
|
+
@buffer.replace_all_lines!(["abcd"])
|
|
46
|
+
@win.cursor_x = 0
|
|
47
|
+
|
|
48
|
+
press("r", "x")
|
|
49
|
+
press("l")
|
|
50
|
+
press(".")
|
|
51
|
+
|
|
52
|
+
assert_equal "xxcd", @buffer.line_at(0)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require_relative "test_helper"
|
|
2
|
+
|
|
3
|
+
class AppMotionTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
@app = RuVim::App.new(clean: true)
|
|
6
|
+
@editor = @app.instance_variable_get(:@editor)
|
|
7
|
+
@editor.materialize_intro_buffer!
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def press(*keys)
|
|
11
|
+
keys.each { |k| @app.send(:handle_normal_key, k) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_find_char_and_repeat
|
|
15
|
+
b = @editor.current_buffer
|
|
16
|
+
b.replace_all_lines!(["abcabc"])
|
|
17
|
+
@editor.current_window.cursor_y = 0
|
|
18
|
+
@editor.current_window.cursor_x = 0
|
|
19
|
+
|
|
20
|
+
press("f", "c")
|
|
21
|
+
assert_equal 2, @editor.current_window.cursor_x
|
|
22
|
+
|
|
23
|
+
press(";")
|
|
24
|
+
assert_equal 5, @editor.current_window.cursor_x
|
|
25
|
+
|
|
26
|
+
press(",")
|
|
27
|
+
assert_equal 2, @editor.current_window.cursor_x
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_till_char_moves_before_match
|
|
31
|
+
b = @editor.current_buffer
|
|
32
|
+
b.replace_all_lines!(["abcabc"])
|
|
33
|
+
@editor.current_window.cursor_y = 0
|
|
34
|
+
@editor.current_window.cursor_x = 0
|
|
35
|
+
|
|
36
|
+
press("t", "c")
|
|
37
|
+
|
|
38
|
+
assert_equal 1, @editor.current_window.cursor_x
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_match_bracket_with_percent
|
|
42
|
+
b = @editor.current_buffer
|
|
43
|
+
b.replace_all_lines!(["x(a[b]c)d"])
|
|
44
|
+
@editor.current_window.cursor_y = 0
|
|
45
|
+
@editor.current_window.cursor_x = 1 # (
|
|
46
|
+
|
|
47
|
+
press("%")
|
|
48
|
+
assert_equal 7, @editor.current_window.cursor_x
|
|
49
|
+
|
|
50
|
+
press("%")
|
|
51
|
+
assert_equal 1, @editor.current_window.cursor_x
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_pageup_and_pagedown_move_by_visible_page_height
|
|
55
|
+
b = @editor.current_buffer
|
|
56
|
+
b.replace_all_lines!((1..20).map { |i| "line#{i}" })
|
|
57
|
+
@editor.current_window.cursor_y = 0
|
|
58
|
+
@editor.current_window.cursor_x = 0
|
|
59
|
+
|
|
60
|
+
screen = @app.instance_variable_get(:@screen)
|
|
61
|
+
screen.define_singleton_method(:current_window_view_height) { |_editor| 5 }
|
|
62
|
+
|
|
63
|
+
@app.send(:handle_normal_key, :pagedown)
|
|
64
|
+
assert_equal 4, @editor.current_window.cursor_y
|
|
65
|
+
|
|
66
|
+
@editor.pending_count = 2
|
|
67
|
+
@app.send(:handle_normal_key, :pagedown)
|
|
68
|
+
assert_equal 12, @editor.current_window.cursor_y
|
|
69
|
+
|
|
70
|
+
@app.send(:handle_normal_key, :pageup)
|
|
71
|
+
assert_equal 8, @editor.current_window.cursor_y
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require_relative "test_helper"
|
|
2
|
+
|
|
3
|
+
class AppRegisterTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
@app = RuVim::App.new(clean: true)
|
|
6
|
+
@editor = @app.instance_variable_get(:@editor)
|
|
7
|
+
@editor.materialize_intro_buffer!
|
|
8
|
+
@buffer = @editor.current_buffer
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def press(*keys)
|
|
12
|
+
keys.each { |k| @app.send(:handle_normal_key, k) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_yy_updates_register_zero
|
|
16
|
+
@buffer.replace_all_lines!(["alpha", "beta"])
|
|
17
|
+
|
|
18
|
+
press("y", "y")
|
|
19
|
+
|
|
20
|
+
assert_equal({ text: "alpha\n", type: :linewise }, @editor.get_register("0"))
|
|
21
|
+
assert_equal({ text: "alpha\n", type: :linewise }, @editor.get_register("\""))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_dd_rotates_numbered_registers
|
|
25
|
+
@buffer.replace_all_lines!(["one", "two", "three"])
|
|
26
|
+
|
|
27
|
+
press("d", "d")
|
|
28
|
+
assert_equal({ text: "one\n", type: :linewise }, @editor.get_register("1"))
|
|
29
|
+
|
|
30
|
+
press("d", "d")
|
|
31
|
+
assert_equal({ text: "two\n", type: :linewise }, @editor.get_register("1"))
|
|
32
|
+
assert_equal({ text: "one\n", type: :linewise }, @editor.get_register("2"))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_black_hole_register_does_not_change_unnamed_or_numbered
|
|
36
|
+
@buffer.replace_all_lines!(["one", "two"])
|
|
37
|
+
|
|
38
|
+
press("y", "y")
|
|
39
|
+
seed = @editor.get_register("\"")
|
|
40
|
+
|
|
41
|
+
press("\"", "_", "d", "d")
|
|
42
|
+
|
|
43
|
+
assert_equal seed, @editor.get_register("\"")
|
|
44
|
+
assert_equal({ text: "one\n", type: :linewise }, @editor.get_register("0"))
|
|
45
|
+
assert_nil @editor.get_register("1")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require_relative "test_helper"
|
|
2
|
+
|
|
3
|
+
class AppScenarioTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
@app = RuVim::App.new(clean: true)
|
|
6
|
+
@editor = @app.instance_variable_get(:@editor)
|
|
7
|
+
@editor.materialize_intro_buffer!
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def feed(*keys)
|
|
11
|
+
keys.each { |k| @app.send(:handle_key, k) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_insert_edit_search_and_delete_scenario
|
|
15
|
+
feed("i", "h", "e", "l", "l", "o", :enter, "w", "o", "r", "l", "d", :escape)
|
|
16
|
+
feed("k", "0", "x")
|
|
17
|
+
feed("/", "o", :enter)
|
|
18
|
+
feed("n")
|
|
19
|
+
|
|
20
|
+
assert_equal ["ello", "world"], @editor.current_buffer.lines
|
|
21
|
+
assert_equal :normal, @editor.mode
|
|
22
|
+
assert_equal "Search wrapped", @editor.message if @editor.message == "Search wrapped"
|
|
23
|
+
assert_operator @editor.current_window.cursor_y, :>=, 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_visual_block_yank
|
|
27
|
+
@editor.current_buffer.replace_all_lines!(["abcde", "ABCDE", "xyz"])
|
|
28
|
+
@editor.current_window.cursor_x = 1
|
|
29
|
+
@editor.current_window.cursor_y = 0
|
|
30
|
+
|
|
31
|
+
feed(:ctrl_v, "j", "l", "l", "y")
|
|
32
|
+
|
|
33
|
+
reg = @editor.get_register("\"")
|
|
34
|
+
assert_equal :normal, @editor.mode
|
|
35
|
+
assert_equal "bcd\nBCD", reg[:text]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_visual_block_delete
|
|
39
|
+
@editor.current_buffer.replace_all_lines!(["abcde", "ABCDE", "xyz"])
|
|
40
|
+
@editor.current_window.cursor_x = 1
|
|
41
|
+
@editor.current_window.cursor_y = 0
|
|
42
|
+
|
|
43
|
+
feed(:ctrl_v, "j", "l", "l", "d")
|
|
44
|
+
|
|
45
|
+
assert_equal ["ae", "AE", "xyz"], @editor.current_buffer.lines
|
|
46
|
+
assert_equal 0, @editor.current_window.cursor_y
|
|
47
|
+
assert_equal 1, @editor.current_window.cursor_x
|
|
48
|
+
assert_equal :normal, @editor.mode
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_dot_repeats_insert_change
|
|
52
|
+
@editor.current_buffer.replace_all_lines!([""])
|
|
53
|
+
feed("i", "a", "b", :escape)
|
|
54
|
+
feed(".")
|
|
55
|
+
|
|
56
|
+
assert_equal ["abab"], @editor.current_buffer.lines
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_dot_repeats_change_with_text_object
|
|
60
|
+
@editor.current_buffer.replace_all_lines!(["foo bar"])
|
|
61
|
+
feed("c", "i", "w", "X", :escape)
|
|
62
|
+
feed("w")
|
|
63
|
+
feed(".")
|
|
64
|
+
|
|
65
|
+
assert_equal ["X X"], @editor.current_buffer.lines
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_dot_repeat_works_inside_macro
|
|
69
|
+
@editor.current_buffer.replace_all_lines!(["abc", "abc", "abc"])
|
|
70
|
+
|
|
71
|
+
feed("x")
|
|
72
|
+
feed("j", "0", "q", "a", ".", "j", "q")
|
|
73
|
+
feed("@", "a")
|
|
74
|
+
|
|
75
|
+
assert_equal ["bc", "bc", "bc"], @editor.current_buffer.lines
|
|
76
|
+
end
|
|
77
|
+
end
|