1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
local script = debug.getinfo(1, "S").source:sub(2)
local root = script:match("^(.*)/tests/plugin_conformance%.lua$") or "."
vim.opt.runtimepath:prepend(root)
local domain = require("clever_tee.domain")
local assertions = dofile(root .. "/tests/assertions.lua")
local same = assertions.same
local truthy = assertions.truthy
vim.g.clever_tee_mark_cursor = 0
vim.g.clever_tee_mark_char = 0
vim.g.clever_tee_mark_direct = 0
vim.g.clever_tee_hide_cursor_on_cmdline = 0
vim.g.clever_tee_clean_labels_eagerly = 1
vim.g.clever_tee_highlight_timeout_ms = 0
vim.cmd.runtime("plugin/clever_tee.lua")
local clever_tee = require("clever_tee")
local checks = 0
local function check_same(expected, actual, message)
same(expected, actual, message)
checks = checks + 1
end
local function check_truthy(value, message)
truthy(value, message)
checks = checks + 1
end
local function feed(keys)
vim.api.nvim_feedkeys(vim.keycode(keys), "xt", false)
vim.cmd("redraw")
vim.wait(10)
end
local function setup(lines, column)
feed("<Esc>")
clever_tee._diagnostic_full_reset()
vim.g.clever_tee_mark_char = 0
vim.g.clever_tee_highlight_timeout_ms = 0
vim.api.nvim_buf_set_lines(0, 0, -1, true, lines)
vim.api.nvim_win_set_cursor(0, { 1, (column or 1) - 1 })
end
local visual_cases = {
{ prefix = "v", mode = "v", adjusted = true },
{ prefix = "V", mode = "V", adjusted = true },
{ prefix = "<C-v>", mode = string.char(0x16), adjusted = false },
}
for _, selection in ipairs({ "inclusive", "exclusive" }) do
vim.o.selection = selection
for _, case in ipairs(visual_cases) do
setup({ "axz", "second" })
feed(case.prefix .. "fx")
local expected_column = selection == "exclusive" and case.adjusted and 2 or 1
check_same(expected_column, vim.api.nvim_win_get_cursor(0)[2], selection .. case.prefix)
check_same(case.mode, vim.api.nvim_get_mode().mode, selection .. case.prefix)
end
end
vim.o.selection = "inclusive"
local select_cases = {
{ prefix = "gh", mode = "s" },
{ prefix = "gH", mode = "S" },
{ prefix = "g<C-h>", mode = string.char(0x13) },
}
for _, case in ipairs(select_cases) do
setup({ "axz", "second" })
feed(case.prefix)
check_same(case.mode, vim.api.nvim_get_mode().mode, case.prefix)
vim.api.nvim_feedkeys("x", "n", false)
local outcome = clever_tee.StartFindForward()
check_same(domain.ActionKind.MOVEMENT, outcome.kind, case.prefix)
check_same(1, vim.api.nvim_win_get_cursor(0)[2], case.prefix)
check_same(case.mode, vim.api.nvim_get_mode().mode, case.prefix)
end
local source = "hoge fuge piye poye"
local operator_cases = {
{ keys = "dfe", column = 1, text = " fuge piye poye", cursor = 0 },
{ keys = "dte", column = 1, text = "e fuge piye poye", cursor = 0 },
{ keys = "dFe", column = 19, text = "hoge fuge piye", cursor = 13 },
{ keys = "dTe", column = 19, text = "hoge fuge piyee", cursor = 14 },
}
for _, selection in ipairs({ "inclusive", "exclusive" }) do
vim.o.selection = selection
for _, case in ipairs(operator_cases) do
setup({ source }, case.column)
feed(case.keys)
check_same(case.text, vim.api.nvim_get_current_line(), selection .. case.keys)
check_same(case.cursor, vim.api.nvim_win_get_cursor(0)[2], selection .. case.keys)
check_same(selection, vim.o.selection, selection .. case.keys)
end
end
vim.o.selection = "inclusive"
local multibyte = "\227\129\130"
setup({ "x" .. multibyte .. "x" .. multibyte })
feed("f" .. multibyte)
check_same(1, vim.api.nvim_win_get_cursor(0)[2], "first multibyte target")
feed("f")
check_same(5, vim.api.nvim_win_get_cursor(0)[2], "second multibyte target")
feed("F")
check_same(1, vim.api.nvim_win_get_cursor(0)[2], "backward multibyte target")
setup({ "abc" })
feed("f<F1>")
check_same(0, vim.api.nvim_win_get_cursor(0)[2], "encoded special key")
check_same(
domain.TargetKind.SPECIAL_KEY.value,
clever_tee.state():get_previous_target("n").kind.value,
"encoded special key target kind"
)
setup({ "1a 2a 3a 4a 5a" })
vim.fn.setreg("q", "fax")
feed("5@q")
check_same("1 2 3 4 5", vim.api.nvim_get_current_line(), "macro acquisitions")
local saved_foldmethod = vim.wo.foldmethod
local saved_foldopen = vim.o.foldopen
setup({ "one", "two", "xax", "four", "five" })
vim.wo.foldmethod = "manual"
vim.cmd("1,5fold")
vim.cmd("2,4fold")
vim.cmd("normal! zM")
vim.o.foldopen = "hor"
vim.api.nvim_win_set_cursor(0, { 3, 0 })
check_truthy(vim.fn.foldclosed(3) ~= -1, "nested fold starts closed")
feed("fa")
check_same(-1, vim.fn.foldclosed(3), "nested folds opened")
check_same(1, vim.api.nvim_win_get_cursor(0)[2], "fold motion endpoint")
vim.cmd("normal! zE")
vim.wo.foldmethod = saved_foldmethod
vim.o.foldopen = saved_foldopen
local function setup_feedback(timeout)
setup({ "ahahah" })
vim.g.clever_tee_mark_char = 1
vim.g.clever_tee_highlight_timeout_ms = timeout or 0
feed("fh")
local state = clever_tee.state():to_table()
check_same(1, #state.target_overlays, "target overlay created")
check_same(1, #state.finalizers, "finalizer created")
return state
end
setup_feedback()
vim.api.nvim_win_set_cursor(0, { 1, 2 })
vim.api.nvim_exec_autocmds("CursorMoved", { buffer = 0 })
local finalized = clever_tee.state():to_table()
check_same(0, #finalized.target_overlays, "CursorMoved overlay cleanup")
check_same(0, #finalized.finalizers, "CursorMoved finalizer cleanup")
check_same(nil, finalized.contexts.n.previous_landing, "CursorMoved landing cleanup")
setup_feedback()
vim.api.nvim_exec_autocmds("InsertEnter", { buffer = 0 })
finalized = clever_tee.state():to_table()
check_same(0, #finalized.target_overlays, "InsertEnter overlay cleanup")
check_same(nil, finalized.contexts.n.previous_landing, "InsertEnter landing cleanup")
setup_feedback()
vim.api.nvim_exec_autocmds("TextChanged", { buffer = 0 })
finalized = clever_tee.state():to_table()
check_same(0, #finalized.target_overlays, "TextChanged overlay cleanup")
check_same(nil, finalized.contexts.n.previous_landing, "TextChanged landing cleanup")
for _, event in ipairs({ "WinEnter", "WinLeave", "CmdwinLeave" }) do
local before = setup_feedback()
vim.api.nvim_exec_autocmds(event, {})
local eager = clever_tee.state():to_table()
check_same(0, #eager.target_overlays, event .. " overlay cleanup")
check_same(1, #eager.finalizers, event .. " finalizer retention")
check_same(
before.contexts.n.previous_landing.byte_column,
eager.contexts.n.previous_landing.byte_column,
event .. " landing retention"
)
end
setup_feedback(20)
local timed_landing = clever_tee.state():get_previous_landing("n")
vim.wait(60)
local timed = clever_tee.state():to_table()
check_same(0, #timed.target_overlays, "timer overlay cleanup")
check_same(nil, timed.highlight_timer, "timer identity cleanup")
check_same(timed_landing, clever_tee.state():get_previous_landing("n"), "timer history retention")
feed("f")
local restored = clever_tee.state():to_table()
check_same(4, restored.contexts.n.previous_landing.byte_column, "repeat after timer cleanup")
check_same(1, #restored.target_overlays, "repeat restores target overlay")
check_truthy(restored.highlight_timer ~= nil, "repeat starts a replacement timer")
clever_tee._diagnostic_full_reset()
io.stdout:write(string.format("Phase 16 plugin conformance: %d checks passed\n", checks))
|