vimamsa 0.1.22 → 0.1.24
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/.dockerignore +32 -0
- data/Dockerfile +45 -0
- data/README.md +2 -2
- data/custom_example.rb +38 -9
- data/docker_cmd.sh +7 -0
- data/exe/run_tests.rb +23 -0
- data/img/screenshot1.png +0 -0
- data/img/screenshot2.png +0 -0
- data/lib/vimamsa/actions.rb +8 -0
- data/lib/vimamsa/buffer.rb +165 -53
- data/lib/vimamsa/buffer_changetext.rb +68 -14
- data/lib/vimamsa/buffer_cursor.rb +9 -3
- data/lib/vimamsa/buffer_list.rb +14 -28
- data/lib/vimamsa/buffer_manager.rb +1 -1
- data/lib/vimamsa/conf.rb +33 -1
- data/lib/vimamsa/diff_buffer.rb +185 -0
- data/lib/vimamsa/editor.rb +149 -80
- data/lib/vimamsa/file_finder.rb +6 -2
- data/lib/vimamsa/gui.rb +330 -135
- data/lib/vimamsa/gui_dialog.rb +2 -0
- data/lib/vimamsa/gui_file_panel.rb +94 -0
- data/lib/vimamsa/gui_form_generator.rb +4 -2
- data/lib/vimamsa/gui_func_panel.rb +127 -0
- data/lib/vimamsa/gui_image.rb +2 -4
- data/lib/vimamsa/gui_menu.rb +54 -1
- data/lib/vimamsa/gui_select_window.rb +18 -6
- data/lib/vimamsa/gui_settings.rb +486 -0
- data/lib/vimamsa/gui_sourceview.rb +196 -8
- data/lib/vimamsa/gui_text.rb +0 -22
- data/lib/vimamsa/hyper_plain_text.rb +1 -0
- data/lib/vimamsa/key_actions.rb +54 -31
- data/lib/vimamsa/key_binding_tree.rb +154 -8
- data/lib/vimamsa/key_bindings_vimlike.rb +48 -35
- data/lib/vimamsa/langservp.rb +161 -7
- data/lib/vimamsa/macro.rb +54 -7
- data/lib/vimamsa/main.rb +1 -0
- data/lib/vimamsa/rbvma.rb +5 -0
- data/lib/vimamsa/string_util.rb +56 -0
- data/lib/vimamsa/test_framework.rb +137 -0
- data/lib/vimamsa/util.rb +3 -36
- data/lib/vimamsa/version.rb +1 -1
- data/modules/calculator/calculator.rb +318 -0
- data/modules/calculator/calculator_info.rb +3 -0
- data/modules/terminal/terminal.rb +140 -0
- data/modules/terminal/terminal_info.rb +3 -0
- data/run_tests.rb +89 -0
- data/styles/dark.xml +1 -1
- data/styles/molokai_edit.xml +2 -2
- data/tests/key_bindings.rb +2 -0
- data/tests/test_basic_editing.rb +86 -0
- data/tests/test_copy_paste.rb +88 -0
- data/tests/test_key_bindings.rb +152 -0
- data/tests/test_module_interface.rb +98 -0
- data/tests/test_undo.rb +201 -0
- data/vimamsa.gemspec +6 -5
- metadata +52 -14
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
class TestCopyPaste < VmaTest
|
|
2
|
+
|
|
3
|
+
def test_copy_line_paste_after
|
|
4
|
+
act 'buf.insert_txt("hello\n")'
|
|
5
|
+
act :jump_to_start_of_buffer
|
|
6
|
+
act :copy_cur_line
|
|
7
|
+
act :jump_to_end_of_buffer
|
|
8
|
+
act :paste_after_cursor
|
|
9
|
+
assert_buf "hello\n\nhello\n"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_copy_line_paste_before
|
|
13
|
+
act 'buf.insert_txt("hello\n")'
|
|
14
|
+
act 'buf.insert_txt("world")'
|
|
15
|
+
act :jump_to_start_of_buffer
|
|
16
|
+
act :copy_cur_line
|
|
17
|
+
act "buf.move(FORWARD_LINE)"
|
|
18
|
+
act :paste_before_cursor
|
|
19
|
+
assert_buf "hello\nhello\nworld\n"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_copy_paste_twice
|
|
23
|
+
act 'buf.insert_txt("abc")'
|
|
24
|
+
act :jump_to_start_of_buffer
|
|
25
|
+
act :copy_cur_line
|
|
26
|
+
act :jump_to_end_of_buffer
|
|
27
|
+
act :paste_after_cursor
|
|
28
|
+
act :paste_after_cursor
|
|
29
|
+
assert_buf "abc\nabc\nabc\n"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_cut_selection_paste
|
|
33
|
+
act 'buf.insert_txt("hello world")'
|
|
34
|
+
act :jump_to_start_of_buffer
|
|
35
|
+
# Select "hello" (5 chars)
|
|
36
|
+
act "buf.start_selection"
|
|
37
|
+
4.times { act "buf.move(FORWARD_CHAR)" }
|
|
38
|
+
act :cut_selection
|
|
39
|
+
assert_buf " world\n"
|
|
40
|
+
act "buf.jump(END_OF_LINE)"
|
|
41
|
+
act :paste_after_cursor
|
|
42
|
+
assert_buf " worldhello\n"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_copy_selection_paste
|
|
46
|
+
act 'buf.insert_txt("foo bar")'
|
|
47
|
+
act :jump_to_start_of_buffer
|
|
48
|
+
act "buf.start_selection"
|
|
49
|
+
2.times { act "buf.move(FORWARD_CHAR)" }
|
|
50
|
+
act :copy_selection
|
|
51
|
+
# Original buffer unchanged
|
|
52
|
+
assert_buf "foo bar\n"
|
|
53
|
+
act "buf.jump(END_OF_LINE)"
|
|
54
|
+
act :paste_after_cursor
|
|
55
|
+
assert_buf "foo barfoo\n"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_clipboard_set_get
|
|
59
|
+
vma.clipboard.set("testvalue")
|
|
60
|
+
assert_eq "testvalue", vma.clipboard.get
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_copy_line_updates_clipboard
|
|
64
|
+
act 'buf.insert_txt("myline")'
|
|
65
|
+
act :jump_to_start_of_buffer
|
|
66
|
+
act :copy_cur_line
|
|
67
|
+
assert_eq "myline\n", vma.clipboard.get
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_cut_selection_updates_clipboard
|
|
71
|
+
act 'buf.insert_txt("hello")'
|
|
72
|
+
act :jump_to_start_of_buffer
|
|
73
|
+
act "buf.start_selection"
|
|
74
|
+
2.times { act "buf.move(FORWARD_CHAR)" }
|
|
75
|
+
act :cut_selection
|
|
76
|
+
assert_eq "hel", vma.clipboard.get
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_paste_multiline
|
|
80
|
+
act 'buf.insert_txt("line1\nline2\nline3")'
|
|
81
|
+
act :jump_to_start_of_buffer
|
|
82
|
+
act :copy_cur_line
|
|
83
|
+
act :jump_to_end_of_buffer
|
|
84
|
+
act :paste_after_cursor
|
|
85
|
+
assert_buf "line1\nline2\nline3\nline1\n"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
class TestKeyBindings < VmaTest
|
|
2
|
+
|
|
3
|
+
# ── bindkey / basic dispatch ─────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
def test_bindkey_symbol_action_fires
|
|
6
|
+
triggered = false
|
|
7
|
+
reg_act(:_test_bindkey_symbol, proc { triggered = true }, "test")
|
|
8
|
+
bindkey "C t e s t 1", :_test_bindkey_symbol
|
|
9
|
+
keys "t e s t 1"
|
|
10
|
+
assert triggered, "action should have fired"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_bindkey_string_action_fires
|
|
14
|
+
$test_str_fired = false
|
|
15
|
+
bindkey "C t e s t 2", '$test_str_fired = true'
|
|
16
|
+
keys "t e s t 2"
|
|
17
|
+
assert $test_str_fired, "string action should have fired"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_bindkey_proc_via_array
|
|
21
|
+
$test_arr_fired = false
|
|
22
|
+
bindkey "C t e s t 3", [:_test_arr_action, proc { $test_arr_fired = true }, "test"]
|
|
23
|
+
keys "t e s t 3"
|
|
24
|
+
assert $test_arr_fired, "array-style action should have fired"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# ── multi-key chord ──────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
def test_chord_requires_full_sequence
|
|
30
|
+
count = 0
|
|
31
|
+
reg_act(:_test_chord, proc { count += 1 }, "test chord")
|
|
32
|
+
bindkey "C , x q", :_test_chord
|
|
33
|
+
|
|
34
|
+
keys "," # partial — should not fire yet
|
|
35
|
+
assert_eq 0, count, "should not fire after partial chord"
|
|
36
|
+
|
|
37
|
+
keys "x q" # complete chord
|
|
38
|
+
assert_eq 1, count, "should fire after complete chord"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_chord_wrong_key_resets
|
|
42
|
+
count = 0
|
|
43
|
+
reg_act(:_test_chord_reset, proc { count += 1 }, "test")
|
|
44
|
+
bindkey "C , x r", :_test_chord_reset
|
|
45
|
+
|
|
46
|
+
keys ", x z" # wrong last key — resets, does not fire
|
|
47
|
+
assert_eq 0, count, "wrong key should not fire the action"
|
|
48
|
+
|
|
49
|
+
keys ", x r" # correct sequence
|
|
50
|
+
assert_eq 1, count, "correct chord should fire"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# ── mode specificity ─────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
def test_command_binding_does_not_fire_in_insert_mode
|
|
56
|
+
count = 0
|
|
57
|
+
reg_act(:_test_cmd_only, proc { count += 1 }, "test")
|
|
58
|
+
bindkey "C , x c", :_test_cmd_only
|
|
59
|
+
|
|
60
|
+
# Switch to insert mode and send the keys
|
|
61
|
+
vma.kbd.set_mode(:insert)
|
|
62
|
+
keys ", x c"
|
|
63
|
+
vma.kbd.set_mode(:command)
|
|
64
|
+
assert_eq 0, count, "command binding should not fire in insert mode"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_insert_binding_fires_in_insert_mode
|
|
68
|
+
count = 0
|
|
69
|
+
reg_act(:_test_ins_only, proc { count += 1 }, "test")
|
|
70
|
+
bindkey "I ctrl-F9", :_test_ins_only # unlikely to conflict
|
|
71
|
+
|
|
72
|
+
vma.kbd.set_mode(:insert)
|
|
73
|
+
keys "ctrl-F9"
|
|
74
|
+
vma.kbd.set_mode(:command)
|
|
75
|
+
assert_eq 1, count, "insert binding should fire in insert mode"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# ── unbindkey ────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
def test_unbindkey_removes_binding
|
|
81
|
+
count = 0
|
|
82
|
+
reg_act(:_test_unbind, proc { count += 1 }, "test")
|
|
83
|
+
bindkey "C , x u", :_test_unbind
|
|
84
|
+
|
|
85
|
+
keys ", x u"
|
|
86
|
+
assert_eq 1, count, "should fire before unbind"
|
|
87
|
+
|
|
88
|
+
unbindkey "C , x u"
|
|
89
|
+
|
|
90
|
+
keys ", x u"
|
|
91
|
+
assert_eq 1, count, "should not fire after unbind"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_unbindkey_pipe_syntax
|
|
95
|
+
count = 0
|
|
96
|
+
reg_act(:_test_unbind_pipe, proc { count += 1 }, "test")
|
|
97
|
+
bindkey "C , x p || C , x q", :_test_unbind_pipe
|
|
98
|
+
|
|
99
|
+
keys ", x p"
|
|
100
|
+
keys ", x q"
|
|
101
|
+
assert_eq 2, count, "both bindings should fire"
|
|
102
|
+
|
|
103
|
+
unbindkey "C , x p || C , x q"
|
|
104
|
+
|
|
105
|
+
keys ", x p"
|
|
106
|
+
keys ", x q"
|
|
107
|
+
assert_eq 2, count, "neither binding should fire after unbind"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# ── || (pipe) multi-binding syntax ───────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
def test_pipe_syntax_both_keys_trigger_same_action
|
|
113
|
+
count = 0
|
|
114
|
+
reg_act(:_test_pipe, proc { count += 1 }, "test")
|
|
115
|
+
bindkey "C , x a || C , x b", :_test_pipe
|
|
116
|
+
|
|
117
|
+
keys ", x a"
|
|
118
|
+
assert_eq 1, count
|
|
119
|
+
keys ", x b"
|
|
120
|
+
assert_eq 2, count
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# ── repeat count ─────────────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
def test_repeat_count_executes_action_n_times
|
|
126
|
+
count = 0
|
|
127
|
+
reg_act(:_test_repeat, proc { count += 1 }, "test")
|
|
128
|
+
bindkey "C , x 9", :_test_repeat
|
|
129
|
+
|
|
130
|
+
# Set repeat count to 3 then fire action
|
|
131
|
+
vma.kbd.set_next_command_count(3)
|
|
132
|
+
keys ", x 9"
|
|
133
|
+
assert_eq 3, count, "action should run 3 times with count=3"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# ── mode switching ───────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
def test_escape_returns_to_command_from_insert
|
|
139
|
+
keys "i"
|
|
140
|
+
assert_mode :insert
|
|
141
|
+
keys "esc"
|
|
142
|
+
assert_mode :command
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_i_enters_insert_mode
|
|
146
|
+
assert_mode :command
|
|
147
|
+
keys "i"
|
|
148
|
+
assert_mode :insert
|
|
149
|
+
keys "esc"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
class TestModuleInterface < VmaTest
|
|
2
|
+
# Ensure the calculator is inactive before each test that needs a clean slate.
|
|
3
|
+
def ensure_disabled
|
|
4
|
+
if vma.actions.include?(:insert_calculator)
|
|
5
|
+
calculator_disable if respond_to?(:calculator_disable, true)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def load_calculator
|
|
10
|
+
load ppath("modules/calculator/calculator.rb")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# --- _info ---
|
|
14
|
+
|
|
15
|
+
def test_info_structure
|
|
16
|
+
load ppath("modules/calculator/calculator_info.rb")
|
|
17
|
+
info = calculator_info
|
|
18
|
+
assert info[:name].is_a?(String), "name should be a String"
|
|
19
|
+
assert !info[:name].empty?, "name should not be empty"
|
|
20
|
+
assert info.key?(:no_restart), "no_restart key missing"
|
|
21
|
+
assert_eq true, info[:no_restart], "calculator should be no_restart"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# --- _init ---
|
|
25
|
+
|
|
26
|
+
def test_init_registers_action
|
|
27
|
+
ensure_disabled
|
|
28
|
+
load_calculator
|
|
29
|
+
calculator_init
|
|
30
|
+
assert vma.actions.include?(:insert_calculator), "action not registered after init"
|
|
31
|
+
ensure
|
|
32
|
+
calculator_disable
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_init_adds_menu_item
|
|
36
|
+
ensure_disabled
|
|
37
|
+
load_calculator
|
|
38
|
+
calculator_init
|
|
39
|
+
assert vma.gui.menu.module_action?(:insert_calculator), "menu item missing after init"
|
|
40
|
+
ensure
|
|
41
|
+
calculator_disable
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# --- _disable ---
|
|
45
|
+
|
|
46
|
+
def test_disable_unregisters_action
|
|
47
|
+
ensure_disabled
|
|
48
|
+
load_calculator
|
|
49
|
+
calculator_init
|
|
50
|
+
calculator_disable
|
|
51
|
+
assert !vma.actions.include?(:insert_calculator), "action still registered after disable"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_disable_removes_menu_item
|
|
55
|
+
ensure_disabled
|
|
56
|
+
load_calculator
|
|
57
|
+
calculator_init
|
|
58
|
+
calculator_disable
|
|
59
|
+
assert !vma.gui.menu.module_action?(:insert_calculator), "menu item still present after disable"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# --- cycle ---
|
|
63
|
+
|
|
64
|
+
def test_init_disable_cycle
|
|
65
|
+
ensure_disabled
|
|
66
|
+
load_calculator
|
|
67
|
+
3.times do |i|
|
|
68
|
+
calculator_init
|
|
69
|
+
assert vma.actions.include?(:insert_calculator), "action missing after init (cycle #{i})"
|
|
70
|
+
assert vma.gui.menu.module_action?(:insert_calculator), "menu missing after init (cycle #{i})"
|
|
71
|
+
calculator_disable
|
|
72
|
+
assert !vma.actions.include?(:insert_calculator), "action present after disable (cycle #{i})"
|
|
73
|
+
assert !vma.gui.menu.module_action?(:insert_calculator), "menu present after disable (cycle #{i})"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# --- all_settings_defs ---
|
|
78
|
+
|
|
79
|
+
def test_settings_defs_has_modules_section
|
|
80
|
+
defs = all_settings_defs
|
|
81
|
+
assert defs.any? { |s| s[:label] == "Modules" }, "no Modules section"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_settings_defs_calculator_key_present
|
|
85
|
+
defs = all_settings_defs
|
|
86
|
+
mod = defs.find { |s| s[:label] == "Modules" }
|
|
87
|
+
assert !mod.nil?, "no Modules section"
|
|
88
|
+
calc = mod[:settings].find { |s| s[:key] == [:modules, :calculator, :enabled] }
|
|
89
|
+
assert !calc.nil?, "calculator key missing from Modules section"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_settings_defs_no_restart_flag
|
|
93
|
+
defs = all_settings_defs
|
|
94
|
+
mod = defs.find { |s| s[:label] == "Modules" }
|
|
95
|
+
calc = mod[:settings].find { |s| s[:key] == [:modules, :calculator, :enabled] }
|
|
96
|
+
assert_eq true, calc[:no_restart], "calculator should have no_restart: true"
|
|
97
|
+
end
|
|
98
|
+
end
|
data/tests/test_undo.rb
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
class TestUndo < VmaTest
|
|
2
|
+
|
|
3
|
+
# ── Basic undo / redo ────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
def test_undo_restores_empty_buffer
|
|
6
|
+
act 'buf.insert_txt("hello")'
|
|
7
|
+
act :undo
|
|
8
|
+
assert_buf "\n"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_undo_on_empty_buffer_is_noop
|
|
12
|
+
act :undo
|
|
13
|
+
assert_buf "\n"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_redo_after_undo
|
|
17
|
+
act 'buf.insert_txt("hello")'
|
|
18
|
+
act :undo
|
|
19
|
+
act :redo
|
|
20
|
+
assert_buf "hello\n"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_redo_on_empty_stack_is_noop
|
|
24
|
+
act :undo
|
|
25
|
+
act :redo
|
|
26
|
+
assert_buf "\n"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_new_edit_clears_redo_stack
|
|
30
|
+
act 'buf.insert_txt("hello")'
|
|
31
|
+
act :undo
|
|
32
|
+
assert_buf "\n"
|
|
33
|
+
act 'buf.insert_txt("world")'
|
|
34
|
+
# redo stack was cleared — redo should be a no-op
|
|
35
|
+
act :redo
|
|
36
|
+
assert_buf "world\n"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_undo_delete_char
|
|
40
|
+
act 'buf.insert_txt("abcde")'
|
|
41
|
+
act :jump_to_start_of_buffer
|
|
42
|
+
vma.buf.new_undo_group
|
|
43
|
+
act :delete_char_forward
|
|
44
|
+
act :delete_char_forward
|
|
45
|
+
vma.buf.new_undo_group
|
|
46
|
+
assert_buf "cde\n"
|
|
47
|
+
act :undo
|
|
48
|
+
assert_buf "abcde\n"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_undo_delete_line
|
|
52
|
+
act 'buf.insert_txt("first\n")'
|
|
53
|
+
act 'buf.insert_txt("second")'
|
|
54
|
+
vma.buf.new_undo_group
|
|
55
|
+
act :jump_to_start_of_buffer
|
|
56
|
+
act :delete_line
|
|
57
|
+
vma.buf.new_undo_group
|
|
58
|
+
assert_buf "second\n"
|
|
59
|
+
act :undo
|
|
60
|
+
assert_buf "first\nsecond\n"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_undo_redo_multiple_times
|
|
64
|
+
act 'buf.insert_txt("first")'
|
|
65
|
+
vma.buf.new_undo_group
|
|
66
|
+
act 'buf.insert_txt(" second")'
|
|
67
|
+
assert_buf "first second\n"
|
|
68
|
+
|
|
69
|
+
act :undo
|
|
70
|
+
assert_buf "first\n"
|
|
71
|
+
act :redo
|
|
72
|
+
assert_buf "first second\n"
|
|
73
|
+
act :undo
|
|
74
|
+
assert_buf "first\n"
|
|
75
|
+
act :undo
|
|
76
|
+
assert_buf "\n"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# ── Explicit group boundaries ─────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
def test_new_undo_group_creates_separate_steps
|
|
82
|
+
act 'buf.insert_txt("aaa")'
|
|
83
|
+
vma.buf.new_undo_group
|
|
84
|
+
act 'buf.insert_txt("bbb")'
|
|
85
|
+
vma.buf.new_undo_group
|
|
86
|
+
act 'buf.insert_txt("ccc")'
|
|
87
|
+
vma.buf.new_undo_group
|
|
88
|
+
assert_buf "aaabbbccc\n"
|
|
89
|
+
|
|
90
|
+
act :undo
|
|
91
|
+
assert_buf "aaabbb\n"
|
|
92
|
+
act :undo
|
|
93
|
+
assert_buf "aaa\n"
|
|
94
|
+
act :undo
|
|
95
|
+
assert_buf "\n"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# ── Mode-change group boundaries ─────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
def test_mode_change_creates_undo_group_boundary
|
|
101
|
+
# Each insert-mode session should be a separate undo group
|
|
102
|
+
keys "i h e l l o esc"
|
|
103
|
+
keys "i space w o r l d esc"
|
|
104
|
+
assert_buf "hello world\n"
|
|
105
|
+
|
|
106
|
+
act :undo
|
|
107
|
+
assert_buf "hello\n" # second insert session (" world") undone
|
|
108
|
+
act :undo
|
|
109
|
+
assert_buf "\n" # first insert session ("hello") undone
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# ── Macro undo ────────────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
def test_macro_run_is_single_undo_group
|
|
115
|
+
# An entire macro run should collapse into one undo step
|
|
116
|
+
vma.macro.run_actions([
|
|
117
|
+
'buf.insert_txt("line1\n")',
|
|
118
|
+
'buf.insert_txt("line2\n")',
|
|
119
|
+
'buf.insert_txt("line3")',
|
|
120
|
+
])
|
|
121
|
+
drain_idle
|
|
122
|
+
assert_buf "line1\nline2\nline3\n"
|
|
123
|
+
|
|
124
|
+
act :undo
|
|
125
|
+
assert_buf "\n"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def test_macro_multiple_runs_each_undoable_separately
|
|
129
|
+
# Each run of the macro should be its own undo group
|
|
130
|
+
vma.macro.run_actions(['buf.insert_txt("abc")'])
|
|
131
|
+
drain_idle
|
|
132
|
+
vma.macro.run_actions(['buf.insert_txt("def")'])
|
|
133
|
+
drain_idle
|
|
134
|
+
assert_buf "abcdef\n"
|
|
135
|
+
|
|
136
|
+
act :undo
|
|
137
|
+
assert_buf "abc\n"
|
|
138
|
+
act :undo
|
|
139
|
+
assert_buf "\n"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_macro_does_not_undo_pre_existing_content
|
|
143
|
+
# Content that existed before the macro run should survive macro undo
|
|
144
|
+
act 'buf.insert_txt("base")'
|
|
145
|
+
vma.buf.new_undo_group
|
|
146
|
+
vma.macro.run_actions(['buf.insert_txt(" appended")'])
|
|
147
|
+
drain_idle
|
|
148
|
+
assert_buf "base appended\n"
|
|
149
|
+
|
|
150
|
+
act :undo
|
|
151
|
+
assert_buf "base\n"
|
|
152
|
+
act :undo
|
|
153
|
+
assert_buf "\n"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_macro_record_and_run_then_undo
|
|
157
|
+
# Record a macro via key sequence, run it, then undo each step
|
|
158
|
+
keys "q a" # start recording into slot "a"
|
|
159
|
+
keys "i f o o esc" # insert "foo", return to (macro) command mode
|
|
160
|
+
keys "q" # end recording
|
|
161
|
+
drain_idle
|
|
162
|
+
assert_buf "foo\n" # recording-time insertion is in the buffer
|
|
163
|
+
|
|
164
|
+
vma.macro.run_macro("a")
|
|
165
|
+
drain_idle
|
|
166
|
+
assert_buf "foofoo\n"
|
|
167
|
+
|
|
168
|
+
act :undo # undo the macro run
|
|
169
|
+
assert_buf "foo\n"
|
|
170
|
+
act :undo # undo the recording-time insertion
|
|
171
|
+
assert_buf "\n"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def test_macro_redo_after_undo
|
|
175
|
+
vma.macro.run_actions(['buf.insert_txt("hello")'])
|
|
176
|
+
drain_idle
|
|
177
|
+
assert_buf "hello\n"
|
|
178
|
+
|
|
179
|
+
act :undo
|
|
180
|
+
assert_buf "\n"
|
|
181
|
+
act :redo
|
|
182
|
+
assert_buf "hello\n"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_macro_with_delete_is_single_undo_group
|
|
186
|
+
act 'buf.insert_txt("hello world")'
|
|
187
|
+
vma.buf.new_undo_group
|
|
188
|
+
|
|
189
|
+
# Macro that jumps to start and deletes a word
|
|
190
|
+
vma.macro.run_actions([
|
|
191
|
+
'buf.jump(BEGINNING_OF_LINE)',
|
|
192
|
+
'buf.delete2(:to_word_end)',
|
|
193
|
+
])
|
|
194
|
+
drain_idle
|
|
195
|
+
assert_buf " world\n"
|
|
196
|
+
|
|
197
|
+
act :undo
|
|
198
|
+
assert_buf "hello world\n"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
end
|
data/vimamsa.gemspec
CHANGED
|
@@ -22,17 +22,18 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
23
23
|
spec.require_paths = ["lib","ext"]
|
|
24
24
|
|
|
25
|
-
spec.add_development_dependency "bundler", "
|
|
25
|
+
spec.add_development_dependency "bundler", ">= 2.4"
|
|
26
26
|
spec.add_development_dependency "rake", "~> 13.1.0"
|
|
27
27
|
|
|
28
28
|
spec.add_runtime_dependency 'rufo', '~> 0.16.2'
|
|
29
29
|
|
|
30
30
|
spec.add_runtime_dependency 'ripl', '~> 0.7.1'
|
|
31
31
|
spec.add_runtime_dependency 'ripl-multi_line', '~> 0.3.1'
|
|
32
|
-
spec.add_runtime_dependency 'gdk4', '~> 4.
|
|
33
|
-
spec.add_runtime_dependency 'gtk4', '~> 4.
|
|
34
|
-
spec.add_runtime_dependency 'gtksourceview5', '~> 4.
|
|
35
|
-
spec.add_runtime_dependency 'gstreamer', '~> 4.
|
|
32
|
+
spec.add_runtime_dependency 'gdk4', '~> 4.3.5'
|
|
33
|
+
spec.add_runtime_dependency 'gtk4', '~> 4.3.5'
|
|
34
|
+
spec.add_runtime_dependency 'gtksourceview5', '~> 4.3.5'
|
|
35
|
+
spec.add_runtime_dependency 'gstreamer', '~> 4.3.5'
|
|
36
|
+
spec.add_runtime_dependency 'vte4', '~> 4.3.5'
|
|
36
37
|
spec.add_runtime_dependency 'rambling-trie', '~> 2.3.1'
|
|
37
38
|
|
|
38
39
|
spec.add_runtime_dependency 'differ', '~> 0.1.2'
|