summaryrefslogtreecommitdiff
path: root/test/vis
diff options
context:
space:
mode:
authorRandy Palamar <randy@rnpnr.xyz>2024-05-21 19:53:22 -0600
committerRandy Palamar <randy@rnpnr.xyz>2024-05-21 19:53:22 -0600
commitb7074021b7bfb0932b889b9560dd22df31cef818 (patch)
tree0295b18de8fb8ea5289cbda95675687ae06025ff /test/vis
parentb7f8018a00be930e3f2b864949aec1f91291309c (diff)
parentefafa3c178268a4149fc3e432bc1174a013c16de (diff)
Merge vis-tests into test directory
Going forward all tests should be submitted here directly.
Diffstat (limited to 'test/vis')
-rw-r--r--test/vis/.gitignore3
-rw-r--r--test/vis/Makefile12
-rw-r--r--test/vis/README.md17
-rw-r--r--test/vis/errors/filter.in1
-rw-r--r--test/vis/errors/filter.keys1
-rw-r--r--test/vis/errors/filter.ref1
-rw-r--r--test/vis/errors/pipe-in.in1
-rw-r--r--test/vis/errors/pipe-in.keys1
-rw-r--r--test/vis/errors/pipe-in.ref1
-rw-r--r--test/vis/insert-mode/autoindent.in4
-rw-r--r--test/vis/insert-mode/autoindent.keys17
-rw-r--r--test/vis/insert-mode/autoindent.ref21
-rw-r--r--test/vis/insert-mode/digraph.in7
-rw-r--r--test/vis/insert-mode/digraph.keys7
-rw-r--r--test/vis/insert-mode/digraph.ref7
-rw-r--r--test/vis/insert-mode/verbatim.in24
-rw-r--r--test/vis/insert-mode/verbatim.keys41
-rw-r--r--test/vis/insert-mode/verbatim.ref24
-rw-r--r--test/vis/interop/pre-save-grows.in2
-rw-r--r--test/vis/interop/pre-save-grows.keys0
-rw-r--r--test/vis/interop/pre-save-grows.lua7
-rw-r--r--test/vis/interop/pre-save-grows.ref2
-rw-r--r--test/vis/interop/pre-save-shrinks.in1
-rw-r--r--test/vis/interop/pre-save-shrinks.keys0
-rw-r--r--test/vis/interop/pre-save-shrinks.lua7
-rw-r--r--test/vis/interop/pre-save-shrinks.ref1
-rw-r--r--test/vis/mappings/insert-mode.in0
-rw-r--r--test/vis/mappings/insert-mode.keys6
-rw-r--r--test/vis/mappings/insert-mode.ref3
-rw-r--r--test/vis/motions/line-begin.in13
-rw-r--r--test/vis/motions/line-begin.keys13
-rw-r--r--test/vis/motions/line-begin.ref13
-rw-r--r--test/vis/motions/line-char-first.in13
-rw-r--r--test/vis/motions/line-char-first.keys13
-rw-r--r--test/vis/motions/line-char-first.ref13
-rw-r--r--test/vis/motions/line-char-last.in13
-rw-r--r--test/vis/motions/line-char-last.keys13
-rw-r--r--test/vis/motions/line-char-last.ref13
-rw-r--r--test/vis/motions/line-end.in13
-rw-r--r--test/vis/motions/line-end.keys13
-rw-r--r--test/vis/motions/line-end.ref13
-rw-r--r--test/vis/motions/next-end-of-bigword.in11
-rw-r--r--test/vis/motions/next-end-of-bigword.keys11
-rw-r--r--test/vis/motions/next-end-of-bigword.ref11
-rw-r--r--test/vis/motions/next-end-of-word.in12
-rw-r--r--test/vis/motions/next-end-of-word.keys12
-rw-r--r--test/vis/motions/next-end-of-word.ref12
-rw-r--r--test/vis/motions/next-start-of-bigword.in11
-rw-r--r--test/vis/motions/next-start-of-bigword.keys11
-rw-r--r--test/vis/motions/next-start-of-bigword.ref12
-rw-r--r--test/vis/motions/next-start-of-word.in12
-rw-r--r--test/vis/motions/next-start-of-word.keys12
-rw-r--r--test/vis/motions/next-start-of-word.ref13
-rw-r--r--test/vis/motions/percent.in5
-rw-r--r--test/vis/motions/percent.keys3
-rw-r--r--test/vis/motions/percent.ref6
-rw-r--r--test/vis/motions/prev-end-of-bigword.in10
-rw-r--r--test/vis/motions/prev-end-of-bigword.keys10
-rw-r--r--test/vis/motions/prev-end-of-bigword.ref10
-rw-r--r--test/vis/motions/prev-end-of-word.in10
-rw-r--r--test/vis/motions/prev-end-of-word.keys10
-rw-r--r--test/vis/motions/prev-end-of-word.ref10
-rw-r--r--test/vis/motions/prev-start-of-bigword.in9
-rw-r--r--test/vis/motions/prev-start-of-bigword.keys10
-rw-r--r--test/vis/motions/prev-start-of-bigword.ref9
-rw-r--r--test/vis/motions/prev-start-of-word.in9
-rw-r--r--test/vis/motions/prev-start-of-word.keys10
-rw-r--r--test/vis/motions/prev-start-of-word.ref9
-rw-r--r--test/vis/motions/till-left.in15
-rw-r--r--test/vis/motions/till-left.keys15
-rw-r--r--test/vis/motions/till-left.ref15
-rw-r--r--test/vis/motions/till-right.in15
-rw-r--r--test/vis/motions/till-right.keys15
-rw-r--r--test/vis/motions/till-right.ref15
-rw-r--r--test/vis/motions/to-left.in15
-rw-r--r--test/vis/motions/to-left.keys15
-rw-r--r--test/vis/motions/to-left.ref15
-rw-r--r--test/vis/motions/to-right.in15
-rw-r--r--test/vis/motions/to-right.keys15
-rw-r--r--test/vis/motions/to-right.ref15
-rw-r--r--test/vis/prompt/history.in3
-rw-r--r--test/vis/prompt/history.keys6
-rw-r--r--test/vis/prompt/history.ref3
-rw-r--r--test/vis/selections/align-indent-columns.in5
-rw-r--r--test/vis/selections/align-indent-columns.keys3
-rw-r--r--test/vis/selections/align-indent-columns.ref5
-rw-r--r--test/vis/selections/align-indent.in5
-rw-r--r--test/vis/selections/align-indent.keys2
-rw-r--r--test/vis/selections/align-indent.ref5
-rw-r--r--test/vis/selections/align.in5
-rw-r--r--test/vis/selections/align.keys3
-rw-r--r--test/vis/selections/align.ref5
-rw-r--r--test/vis/selections/complement-whole.in10
-rw-r--r--test/vis/selections/complement-whole.keys3
-rw-r--r--test/vis/selections/complement-whole.ref10
-rw-r--r--test/vis/selections/complement.in10
-rw-r--r--test/vis/selections/complement.keys4
-rw-r--r--test/vis/selections/complement.ref10
-rw-r--r--test/vis/selections/end-of-file.in9
-rw-r--r--test/vis/selections/end-of-file.keys6
-rw-r--r--test/vis/selections/end-of-file.ref12
-rw-r--r--test/vis/selections/intersect-adjacent.in10
-rw-r--r--test/vis/selections/intersect-adjacent.keys5
-rw-r--r--test/vis/selections/intersect-adjacent.ref10
-rw-r--r--test/vis/selections/intersect-contained.in10
-rw-r--r--test/vis/selections/intersect-contained.keys5
-rw-r--r--test/vis/selections/intersect-contained.ref10
-rw-r--r--test/vis/selections/intersect-empty.in10
-rw-r--r--test/vis/selections/intersect-empty.keys3
-rw-r--r--test/vis/selections/intersect-empty.ref10
-rw-r--r--test/vis/selections/intersect-overlapping.in10
-rw-r--r--test/vis/selections/intersect-overlapping.keys5
-rw-r--r--test/vis/selections/intersect-overlapping.ref10
-rw-r--r--test/vis/selections/intersect-whole.in10
-rw-r--r--test/vis/selections/intersect-whole.keys5
-rw-r--r--test/vis/selections/intersect-whole.ref10
-rw-r--r--test/vis/selections/minus-adjacent.in10
-rw-r--r--test/vis/selections/minus-adjacent.keys5
-rw-r--r--test/vis/selections/minus-adjacent.ref10
-rw-r--r--test/vis/selections/minus-contained.in10
-rw-r--r--test/vis/selections/minus-contained.keys5
-rw-r--r--test/vis/selections/minus-contained.ref10
-rw-r--r--test/vis/selections/minus-empty.in10
-rw-r--r--test/vis/selections/minus-empty.keys3
-rw-r--r--test/vis/selections/minus-empty.ref10
-rw-r--r--test/vis/selections/minus-overlapping.in10
-rw-r--r--test/vis/selections/minus-overlapping.keys5
-rw-r--r--test/vis/selections/minus-overlapping.ref10
-rw-r--r--test/vis/selections/minus-whole.in10
-rw-r--r--test/vis/selections/minus-whole.keys5
-rw-r--r--test/vis/selections/minus-whole.ref10
-rw-r--r--test/vis/selections/new-above-first-below-last.in5
-rw-r--r--test/vis/selections/new-above-first-below-last.keys4
-rw-r--r--test/vis/selections/new-above-first-below-last.ref5
-rw-r--r--test/vis/selections/new-below-above.in5
-rw-r--r--test/vis/selections/new-below-above.keys5
-rw-r--r--test/vis/selections/new-below-above.ref5
-rw-r--r--test/vis/selections/new-end-of-line.in4
-rw-r--r--test/vis/selections/new-end-of-line.keys7
-rw-r--r--test/vis/selections/new-end-of-line.ref4
-rw-r--r--test/vis/selections/new-start-of-line.in4
-rw-r--r--test/vis/selections/new-start-of-line.keys6
-rw-r--r--test/vis/selections/new-start-of-line.ref4
-rw-r--r--test/vis/selections/normal-mode-wq.in8
-rw-r--r--test/vis/selections/normal-mode-wq.keys4
-rw-r--r--test/vis/selections/normal-mode-wq.ref8
-rw-r--r--test/vis/selections/odd-even.in10
-rw-r--r--test/vis/selections/odd-even.keys1
-rw-r--r--test/vis/selections/odd-even.ref10
-rw-r--r--test/vis/selections/out-of-view.in.disabled999
-rw-r--r--test/vis/selections/out-of-view.keys7
-rw-r--r--test/vis/selections/out-of-view.ref899
-rw-r--r--test/vis/selections/remove-column.in3
-rw-r--r--test/vis/selections/remove-column.keys8
-rw-r--r--test/vis/selections/remove-column.ref3
-rw-r--r--test/vis/selections/select-match.in3
-rw-r--r--test/vis/selections/select-match.keys8
-rw-r--r--test/vis/selections/select-match.ref3
-rw-r--r--test/vis/selections/selections-rotate.in3
-rw-r--r--test/vis/selections/selections-rotate.keys6
-rw-r--r--test/vis/selections/selections-rotate.ref3
-rw-r--r--test/vis/selections/selections-trim.in3
-rw-r--r--test/vis/selections/selections-trim.keys5
-rw-r--r--test/vis/selections/selections-trim.ref3
-rw-r--r--test/vis/selections/union-adjacent.in10
-rw-r--r--test/vis/selections/union-adjacent.keys5
-rw-r--r--test/vis/selections/union-adjacent.ref10
-rw-r--r--test/vis/selections/union-contained.in10
-rw-r--r--test/vis/selections/union-contained.keys5
-rw-r--r--test/vis/selections/union-contained.ref10
-rw-r--r--test/vis/selections/union-empty.in10
-rw-r--r--test/vis/selections/union-empty.keys3
-rw-r--r--test/vis/selections/union-empty.ref10
-rw-r--r--test/vis/selections/union-overlapping.in10
-rw-r--r--test/vis/selections/union-overlapping.keys5
-rw-r--r--test/vis/selections/union-overlapping.ref10
-rw-r--r--test/vis/selections/union-whole.in10
-rw-r--r--test/vis/selections/union-whole.keys5
-rw-r--r--test/vis/selections/union-whole.ref11
-rw-r--r--test/vis/structural-regex/addresses/marks.in1
-rw-r--r--test/vis/structural-regex/addresses/marks.keys6
-rw-r--r--test/vis/structural-regex/addresses/marks.ref1
-rw-r--r--test/vis/structural-regex/addresses/round-down.in16
-rw-r--r--test/vis/structural-regex/addresses/round-down.keys5
-rw-r--r--test/vis/structural-regex/addresses/round-down.ref18
-rw-r--r--test/vis/structural-regex/addresses/round-up.in16
-rw-r--r--test/vis/structural-regex/addresses/round-up.keys5
-rw-r--r--test/vis/structural-regex/addresses/round-up.ref18
-rwxr-xr-xtest/vis/test.sh48
-rw-r--r--test/vis/text-objects/indentation.in16
-rw-r--r--test/vis/text-objects/indentation.keys4
-rw-r--r--test/vis/text-objects/indentation.ref16
-rw-r--r--test/vis/text-objects/lexer.in6
-rw-r--r--test/vis/text-objects/lexer.keys5
-rw-r--r--test/vis/text-objects/lexer.ref6
-rw-r--r--test/vis/text-objects/line.in6
-rw-r--r--test/vis/text-objects/line.keys9
-rw-r--r--test/vis/text-objects/line.ref2
-rw-r--r--test/vis/text-objects/search-result.in8
-rw-r--r--test/vis/text-objects/search-result.keys8
-rw-r--r--test/vis/text-objects/search-result.ref8
-rw-r--r--test/vis/visrc.lua27
-rw-r--r--test/vis/visual-mode/orientation.in1
-rw-r--r--test/vis/visual-mode/orientation.keys8
-rw-r--r--test/vis/visual-mode/orientation.ref1
205 files changed, 3639 insertions, 0 deletions
diff --git a/test/vis/.gitignore b/test/vis/.gitignore
new file mode 100644
index 0000000..589a89a
--- /dev/null
+++ b/test/vis/.gitignore
@@ -0,0 +1,3 @@
+*.out
+*.err
+*.disabled \ No newline at end of file
diff --git a/test/vis/Makefile b/test/vis/Makefile
new file mode 100644
index 0000000..be58c44
--- /dev/null
+++ b/test/vis/Makefile
@@ -0,0 +1,12 @@
+test: ../../vis clean
+ @./test.sh
+
+../../vis: ../../*.[ch]
+ @echo Compiling vis
+ @$(MAKE) -C ../..
+
+clean:
+ @echo cleaning
+ @find . -name '*.out' -o -name '*.err' | xargs rm -f
+
+.PHONY: clean test
diff --git a/test/vis/README.md b/test/vis/README.md
new file mode 100644
index 0000000..e7e655d
--- /dev/null
+++ b/test/vis/README.md
@@ -0,0 +1,17 @@
+Tests for vis specific editing features
+---------------------------------------
+
+The basic idea is to feed keyboard input to `vis` and compare the
+produced output with a known reference solution.
+
+A test constitutes of 3 files:
+
+ * `test.in` the file/buffer content with which the editor is started
+ * `test.keys` a file containing the keyboard input as would normally
+ be typed by a user
+ * `test.ref` a reference file at the end of the editing session
+
+The toplevel shell script `test.sh` looks for these files in sub
+directories, feeds the keys to `vis` and compares the produces output.
+
+Type `make` to run all tests.
diff --git a/test/vis/errors/filter.in b/test/vis/errors/filter.in
new file mode 100644
index 0000000..4afca5f
--- /dev/null
+++ b/test/vis/errors/filter.in
@@ -0,0 +1 @@
+Filter command failed
diff --git a/test/vis/errors/filter.keys b/test/vis/errors/filter.keys
new file mode 100644
index 0000000..ebb3939
--- /dev/null
+++ b/test/vis/errors/filter.keys
@@ -0,0 +1 @@
+:1 | tr a-z A-Z && false<Enter>
diff --git a/test/vis/errors/filter.ref b/test/vis/errors/filter.ref
new file mode 100644
index 0000000..4afca5f
--- /dev/null
+++ b/test/vis/errors/filter.ref
@@ -0,0 +1 @@
+Filter command failed
diff --git a/test/vis/errors/pipe-in.in b/test/vis/errors/pipe-in.in
new file mode 100644
index 0000000..b130b9a
--- /dev/null
+++ b/test/vis/errors/pipe-in.in
@@ -0,0 +1 @@
+Pipe in command failed
diff --git a/test/vis/errors/pipe-in.keys b/test/vis/errors/pipe-in.keys
new file mode 100644
index 0000000..9f6a290
--- /dev/null
+++ b/test/vis/errors/pipe-in.keys
@@ -0,0 +1 @@
+:1 < echo FAILED && false<Enter>
diff --git a/test/vis/errors/pipe-in.ref b/test/vis/errors/pipe-in.ref
new file mode 100644
index 0000000..b130b9a
--- /dev/null
+++ b/test/vis/errors/pipe-in.ref
@@ -0,0 +1 @@
+Pipe in command failed
diff --git a/test/vis/insert-mode/autoindent.in b/test/vis/insert-mode/autoindent.in
new file mode 100644
index 0000000..9a1b93a
--- /dev/null
+++ b/test/vis/insert-mode/autoindent.in
@@ -0,0 +1,4 @@
+int foo(int a) {
+ for (;;) {
+ }
+}
diff --git a/test/vis/insert-mode/autoindent.keys b/test/vis/insert-mode/autoindent.keys
new file mode 100644
index 0000000..6dda2f2
--- /dev/null
+++ b/test/vis/insert-mode/autoindent.keys
@@ -0,0 +1,17 @@
+:set ai<Enter>
+/for<Enter>
+o<Enter>
+<C-t>
+if (a > 0) {<Enter>
+<C-t>// positive<Enter><Enter>
+return --a;<Enter>
+<C-d>} else if (a < 0) {<Enter>
+<C-t>// negative<Enter><Enter>
+return ++a;<Enter>
+<C-d>} else {<Enter>
+<C-t>// equal<Enter><Enter>
+return a;<Enter>
+<C-d>}<Enter>
+<Escape>
+n
+O<Enter>// optimized loop
diff --git a/test/vis/insert-mode/autoindent.ref b/test/vis/insert-mode/autoindent.ref
new file mode 100644
index 0000000..6668daf
--- /dev/null
+++ b/test/vis/insert-mode/autoindent.ref
@@ -0,0 +1,21 @@
+int foo(int a) {
+
+ // optimized loop
+ for (;;) {
+
+ if (a > 0) {
+ // positive
+
+ return --a;
+ } else if (a < 0) {
+ // negative
+
+ return ++a;
+ } else {
+ // equal
+
+ return a;
+ }
+
+ }
+}
diff --git a/test/vis/insert-mode/digraph.in b/test/vis/insert-mode/digraph.in
new file mode 100644
index 0000000..fa3922e
--- /dev/null
+++ b/test/vis/insert-mode/digraph.in
@@ -0,0 +1,7 @@
+digraphs
+l* =
+l* =
+FA =
+FA =
+(- =
+(- =
diff --git a/test/vis/insert-mode/digraph.keys b/test/vis/insert-mode/digraph.keys
new file mode 100644
index 0000000..960d086
--- /dev/null
+++ b/test/vis/insert-mode/digraph.keys
@@ -0,0 +1,7 @@
+/=<Enter>
+a<Space><C-k>l*<Escape>
+n.n
+a<Space><C-k>FA<Escape>
+n.n
+a<Space><C-k>(-<Escape>
+n.
diff --git a/test/vis/insert-mode/digraph.ref b/test/vis/insert-mode/digraph.ref
new file mode 100644
index 0000000..f56303a
--- /dev/null
+++ b/test/vis/insert-mode/digraph.ref
@@ -0,0 +1,7 @@
+digraphs
+l* = λ
+l* = λ
+FA = ∀
+FA = ∀
+(- = ∈
+(- = ∈
diff --git a/test/vis/insert-mode/verbatim.in b/test/vis/insert-mode/verbatim.in
new file mode 100644
index 0000000..6fcb11a
--- /dev/null
+++ b/test/vis/insert-mode/verbatim.in
@@ -0,0 +1,24 @@
+U+033b =
+U+033b =
+U+2200 =
+U+2200 =
+U+2208 =
+U+2208 =
+U+00002208 =
+U+00002208 =
+0x40 =
+0X40 =
+o100 =
+O100 =
+64 =
+U+07FF =
+U+D7FF =
+U+DFFF = /* not really correct */
+U+FFFD =
+U+FFFF = /* not really correct */
+U+10FFFF =
+U+11000 = /* invalid */
+<Escape> =
+<Tab> =
+<Space> =
+<Enter> =
diff --git a/test/vis/insert-mode/verbatim.keys b/test/vis/insert-mode/verbatim.keys
new file mode 100644
index 0000000..ba71c21
--- /dev/null
+++ b/test/vis/insert-mode/verbatim.keys
@@ -0,0 +1,41 @@
+/=<Enter>
+a<Space><C-v>u03bb<Escape>
+n.n
+a<Space><C-v>u2200<Escape>
+n.n
+a<Space><C-v>u2208<Escape>
+n.n
+a<Space><C-v>U2208<Escape>
+n.n
+a<Space><C-v>x40<Escape>
+n
+a<Space><C-v>X40<Escape>
+n
+a<Space><C-v>o100<Escape>
+n
+a<Space><C-v>O100<Escape>
+n
+a<Space><C-v>64<Escape>
+n
+a<Space><C-v>u07FF<Escape>
+n
+a<Space><C-v>uD7FF<Escape>
+n
+a<Space><C-v>uDFFF<Escape>
+n
+a<Space><C-v>uFFFD<Escape>
+n
+a<Space><C-v>uFFFF<Escape>
+n
+a<Space><C-v>U0010FFFF<Escape>
+n
+a<Space><C-v>U00110000<Escape>
+n
+a<Space><C-v><Escape><Escape>
+n
+:set et<Enter>
+a<Space><C-v><Tab><Escape>
+n
+a<Space><C-v><Space><Escape>
+n
+a<Space><C-v><Enter><Escape>
diff --git a/test/vis/insert-mode/verbatim.ref b/test/vis/insert-mode/verbatim.ref
new file mode 100644
index 0000000..28a5c8c
--- /dev/null
+++ b/test/vis/insert-mode/verbatim.ref
@@ -0,0 +1,24 @@
+U+033b = λ
+U+033b = λ
+U+2200 = ∀
+U+2200 = ∀
+U+2208 = ∈
+U+2208 = ∈
+U+00002208 = ∈
+U+00002208 = ∈
+0x40 = @
+0X40 = @
+o100 = @
+O100 = @
+64 = @
+U+07FF = ߿
+U+D7FF = ퟿
+U+DFFF = /* not really correct */
+U+FFFD = �
+U+FFFF = /* not really correct */
+U+10FFFF = 􏿿
+U+11000 = /* invalid */
+<Escape> = 
+<Tab> =
+<Space> =
+<Enter> =
diff --git a/test/vis/interop/pre-save-grows.in b/test/vis/interop/pre-save-grows.in
new file mode 100644
index 0000000..814f4a4
--- /dev/null
+++ b/test/vis/interop/pre-save-grows.in
@@ -0,0 +1,2 @@
+one
+two
diff --git a/test/vis/interop/pre-save-grows.keys b/test/vis/interop/pre-save-grows.keys
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/vis/interop/pre-save-grows.keys
diff --git a/test/vis/interop/pre-save-grows.lua b/test/vis/interop/pre-save-grows.lua
new file mode 100644
index 0000000..8cf4887
--- /dev/null
+++ b/test/vis/interop/pre-save-grows.lua
@@ -0,0 +1,7 @@
+vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file)
+ local lines = file.lines
+ for i=1, #lines do
+ lines[i] = lines[i]..' bigger'
+ end
+ return true
+end)
diff --git a/test/vis/interop/pre-save-grows.ref b/test/vis/interop/pre-save-grows.ref
new file mode 100644
index 0000000..c5bc0a5
--- /dev/null
+++ b/test/vis/interop/pre-save-grows.ref
@@ -0,0 +1,2 @@
+one bigger
+two bigger
diff --git a/test/vis/interop/pre-save-shrinks.in b/test/vis/interop/pre-save-shrinks.in
new file mode 100644
index 0000000..b6a2b1e
--- /dev/null
+++ b/test/vis/interop/pre-save-shrinks.in
@@ -0,0 +1 @@
+halfhalf
diff --git a/test/vis/interop/pre-save-shrinks.keys b/test/vis/interop/pre-save-shrinks.keys
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/vis/interop/pre-save-shrinks.keys
diff --git a/test/vis/interop/pre-save-shrinks.lua b/test/vis/interop/pre-save-shrinks.lua
new file mode 100644
index 0000000..d8a7e94
--- /dev/null
+++ b/test/vis/interop/pre-save-shrinks.lua
@@ -0,0 +1,7 @@
+vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file)
+ local lines = file.lines
+ for i=1, #lines do
+ lines[i] = lines[i]:sub(lines[i]:len()/2+1)
+ end
+ return true
+end)
diff --git a/test/vis/interop/pre-save-shrinks.ref b/test/vis/interop/pre-save-shrinks.ref
new file mode 100644
index 0000000..68f2f23
--- /dev/null
+++ b/test/vis/interop/pre-save-shrinks.ref
@@ -0,0 +1 @@
+half
diff --git a/test/vis/mappings/insert-mode.in b/test/vis/mappings/insert-mode.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/vis/mappings/insert-mode.in
diff --git a/test/vis/mappings/insert-mode.keys b/test/vis/mappings/insert-mode.keys
new file mode 100644
index 0000000..f244449
--- /dev/null
+++ b/test/vis/mappings/insert-mode.keys
@@ -0,0 +1,6 @@
+:map! insert jj <vis-nop> <Enter>
+ij<Escape>
+:map! insert jj >< <Enter>
+Ojj<Escape>
+:map! insert >> ><>x> <Enter>
+o>><Escape>
diff --git a/test/vis/mappings/insert-mode.ref b/test/vis/mappings/insert-mode.ref
new file mode 100644
index 0000000..79edf01
--- /dev/null
+++ b/test/vis/mappings/insert-mode.ref
@@ -0,0 +1,3 @@
+><
+><>x>
+j \ No newline at end of file
diff --git a/test/vis/motions/line-begin.in b/test/vis/motions/line-begin.in
new file mode 100644
index 0000000..0f3aa12
--- /dev/null
+++ b/test/vis/motions/line-begin.in
@@ -0,0 +1,13 @@
+0 To the first character of the line.
+1 From start to start
+2 From _ to start
+3 From end to start 4 empty line \n 5 empty line \r\n
+
+
+ 6 Spaces
+ 7 Tabs
+  8 Backspace
+ 9 Vertical tab
+ 10 Form feed
+ 11 Carriage return
+ 12 Idempotent (count has no effect)
diff --git a/test/vis/motions/line-begin.keys b/test/vis/motions/line-begin.keys
new file mode 100644
index 0000000..07fd54e
--- /dev/null
+++ b/test/vis/motions/line-begin.keys
@@ -0,0 +1,13 @@
++
+d0+
+f_.+
+$.+
+.+
+./[0-9]+ <Enter>
+.$n
+.$n
+.$n
+.$n
+.$n
+.$n
+99.$n
diff --git a/test/vis/motions/line-begin.ref b/test/vis/motions/line-begin.ref
new file mode 100644
index 0000000..1575cfa
--- /dev/null
+++ b/test/vis/motions/line-begin.ref
@@ -0,0 +1,13 @@
+0 To the first character of the line.
+1 From start to start
+_ to start
+
+
+
+6 Spaces
+7 Tabs
+8 Backspace
+9 Vertical tab
+10 Form feed
+11 Carriage return
+12 Idempotent (count has no effect)
diff --git a/test/vis/motions/line-char-first.in b/test/vis/motions/line-char-first.in
new file mode 100644
index 0000000..35b8c73
--- /dev/null
+++ b/test/vis/motions/line-char-first.in
@@ -0,0 +1,13 @@
+^ To the first non-blank character of the line.
+1 From start to start
+2 From _ to start
+3 From end to start 4 empty line \n 5 empty line \r\n
+
+
+ 6 Spaces
+ 7 Tabs
+  8 Backspace
+ 9 Vertical tab
+ 10 Form feed
+ 11 Carriage return
+ 12 Idempotent (count has no effect)
diff --git a/test/vis/motions/line-char-first.keys b/test/vis/motions/line-char-first.keys
new file mode 100644
index 0000000..28c8ce1
--- /dev/null
+++ b/test/vis/motions/line-char-first.keys
@@ -0,0 +1,13 @@
++
+d^+
+f_.+
+$.+
+.+
+.+
+0.+
+0.+
+0.+
+0.+
+0.+
+0.+
+099.+
diff --git a/test/vis/motions/line-char-first.ref b/test/vis/motions/line-char-first.ref
new file mode 100644
index 0000000..e417d16
--- /dev/null
+++ b/test/vis/motions/line-char-first.ref
@@ -0,0 +1,13 @@
+^ To the first non-blank character of the line.
+1 From start to start
+_ to start
+
+
+
+6 Spaces
+7 Tabs
+ 8 Backspace
+ 9 Vertical tab
+ 10 Form feed
+ 11 Carriage return
+12 Idempotent (count has no effect)
diff --git a/test/vis/motions/line-char-last.in b/test/vis/motions/line-char-last.in
new file mode 100644
index 0000000..c58af39
--- /dev/null
+++ b/test/vis/motions/line-char-last.in
@@ -0,0 +1,13 @@
+g_ To the last non-blank character of the line.
+1 From start to end
+2 From _ to end
+3 From end to end 4 empty line \n 5 empty line \r\n
+
+
+6 Spaces
+7 Tabs
+8 Backspace 
+9 Vertical tab
+10 Form feed
+11 Carriage return
+12 Idempotent (count has no effect)
diff --git a/test/vis/motions/line-char-last.keys b/test/vis/motions/line-char-last.keys
new file mode 100644
index 0000000..ecd36c6
--- /dev/null
+++ b/test/vis/motions/line-char-last.keys
@@ -0,0 +1,13 @@
++
+dg_+
+f_.+
+$.+
+.+
+.+
+$.+
+$.+
+$.+
+$.+
+$.+
+$.+
+$99.+
diff --git a/test/vis/motions/line-char-last.ref b/test/vis/motions/line-char-last.ref
new file mode 100644
index 0000000..948986a
--- /dev/null
+++ b/test/vis/motions/line-char-last.ref
@@ -0,0 +1,13 @@
+g_ To the last non-blank character of the line.
+
+2 From
+3 From end to end 4 empty line \n 5 empty line \r\
+
+
+6 Space
+7 Tab
+8 Backspace
+9 Vertical tab
+10 Form feed
+11 Carriage return
+12 Idempotent (count has no effect
diff --git a/test/vis/motions/line-end.in b/test/vis/motions/line-end.in
new file mode 100644
index 0000000..e54bb63
--- /dev/null
+++ b/test/vis/motions/line-end.in
@@ -0,0 +1,13 @@
+$ To the end of the line.
+1 From start to end
+2 From _ to end
+3 From end to end 4 empty line \n 5 empty line \r\n
+
+
+6 Spaces
+7 Tabs
+8 Backspace 
+9 Vertical tab
+10 Form feed
+11 Carriage return
+12 Idempotent (count has no effect)
diff --git a/test/vis/motions/line-end.keys b/test/vis/motions/line-end.keys
new file mode 100644
index 0000000..4cfdb79
--- /dev/null
+++ b/test/vis/motions/line-end.keys
@@ -0,0 +1,13 @@
++
+d$+
+f_.+
+$.+
+.+
+.+
+2f<Space>.+
+2;.+
+2;.+
+2;.+
+2;.+
+2;.+
+2;99.+
diff --git a/test/vis/motions/line-end.ref b/test/vis/motions/line-end.ref
new file mode 100644
index 0000000..b2dd26b
--- /dev/null
+++ b/test/vis/motions/line-end.ref
@@ -0,0 +1,13 @@
+$ To the end of the line.
+
+2 From
+3 From end to end 4 empty line \n 5 empty line \r\n
+
+
+
+7 Tabs
+8 Backspace
+9 Vertical
+10 Form
+11 Carriage
+12 Idempotent
diff --git a/test/vis/motions/next-end-of-bigword.in b/test/vis/motions/next-end-of-bigword.in
new file mode 100644
index 0000000..26ec987
--- /dev/null
+++ b/test/vis/motions/next-end-of-bigword.in
@@ -0,0 +1,11 @@
+_start-word next
+mid_dle-word next
+end-word_ next
+ starting from a space
+ starting from a tab
+a b c d : single letter words
+skipping-tab next
++-*/\"'`^%&,;|_(){}<>[]=?! special symbols
+
+next line
+word_at_end
diff --git a/test/vis/motions/next-end-of-bigword.keys b/test/vis/motions/next-end-of-bigword.keys
new file mode 100644
index 0000000..4bec703
--- /dev/null
+++ b/test/vis/motions/next-end-of-bigword.keys
@@ -0,0 +1,11 @@
+f_Er|+
+;E.+
+;E.+
+0E.+
+0E.+
+4E.+
+2E.+
+E.+
+E
+.+
+E.
diff --git a/test/vis/motions/next-end-of-bigword.ref b/test/vis/motions/next-end-of-bigword.ref
new file mode 100644
index 0000000..fe57a91
--- /dev/null
+++ b/test/vis/motions/next-end-of-bigword.ref
@@ -0,0 +1,11 @@
+_start-wor| next
+mid_dle-wor| next
+end-word_ nex|
+ startin| from a space
+ startin| from a tab
+a b c d | single letter words
+skipping-tab nex|
++-*/\"'`^%&,;|_(){}<>[]=?| special symbols
+
+nex| line
+word_at_en|
diff --git a/test/vis/motions/next-end-of-word.in b/test/vis/motions/next-end-of-word.in
new file mode 100644
index 0000000..d67d828
--- /dev/null
+++ b/test/vis/motions/next-end-of-word.in
@@ -0,0 +1,12 @@
+_start next
+mid_dle next
+end_ next
+ starting from a space
+ starting from a tab
+a b c d : single letter words
+tab next
+word with count
++-*/\"'`^%&,;|_(){}<>[]=?! special symbols
+
+next line
+word_at_end
diff --git a/test/vis/motions/next-end-of-word.keys b/test/vis/motions/next-end-of-word.keys
new file mode 100644
index 0000000..9aff65e
--- /dev/null
+++ b/test/vis/motions/next-end-of-word.keys
@@ -0,0 +1,12 @@
+f_er|+
+;e.+
+;e.+
+0e.+
+0e.+
+4e.+
+2e.+
+2e.+
+e.+
+e
+.+
+e.
diff --git a/test/vis/motions/next-end-of-word.ref b/test/vis/motions/next-end-of-word.ref
new file mode 100644
index 0000000..6510a23
--- /dev/null
+++ b/test/vis/motions/next-end-of-word.ref
@@ -0,0 +1,12 @@
+_star| next
+mid_dl| next
+end_ nex|
+ startin| from a space
+ startin| from a tab
+a b c d | single letter words
+tab nex|
+word wit| count
++-*/\"'`^%&,;|_(){}<>[]=?! special symbols
+
+nex| line
+word_at_en|
diff --git a/test/vis/motions/next-start-of-bigword.in b/test/vis/motions/next-start-of-bigword.in
new file mode 100644
index 0000000..4b9848d
--- /dev/null
+++ b/test/vis/motions/next-start-of-bigword.in
@@ -0,0 +1,11 @@
+_start-word next
+mid_dle-word next
+end-word_ next
+ starting from a space
+ starting from a tab
+a b c d : single letter words
+tab next
++-*/\"'`^%&,;|_(){}<>[]=?! special symbols
+
+next line
+word_at_end
diff --git a/test/vis/motions/next-start-of-bigword.keys b/test/vis/motions/next-start-of-bigword.keys
new file mode 100644
index 0000000..51112dc
--- /dev/null
+++ b/test/vis/motions/next-start-of-bigword.keys
@@ -0,0 +1,11 @@
+f_Wr|+
+;W.+
+;W.+
+0W.+
+0W.+
+4W.+
+W.+
+W.+
+W
+.+
+Wi<Enter>|<Escape>
diff --git a/test/vis/motions/next-start-of-bigword.ref b/test/vis/motions/next-start-of-bigword.ref
new file mode 100644
index 0000000..d015890
--- /dev/null
+++ b/test/vis/motions/next-start-of-bigword.ref
@@ -0,0 +1,12 @@
+_start-word |ext
+mid_dle-word |ext
+end-word_ |ext
+ |tarting from a space
+ |tarting from a tab
+a b c d | single letter words
+tab |ext
++-*/\"'`^%&,;|_(){}<>[]=?! |pecial symbols
+
+|ext line
+word_at_end
+|
diff --git a/test/vis/motions/next-start-of-word.in b/test/vis/motions/next-start-of-word.in
new file mode 100644
index 0000000..c1b55b6
--- /dev/null
+++ b/test/vis/motions/next-start-of-word.in
@@ -0,0 +1,12 @@
+_start next
+mid_dle next
+end_ next
+ starting from a space
+ starting from a tab
+a b c d : single letter words
+tab next
++-*/\"'`^%&,;|_(){}<>[]=?! special symbols
+word with count
+
+next line
+word_at_end
diff --git a/test/vis/motions/next-start-of-word.keys b/test/vis/motions/next-start-of-word.keys
new file mode 100644
index 0000000..b42c9f2
--- /dev/null
+++ b/test/vis/motions/next-start-of-word.keys
@@ -0,0 +1,12 @@
+f_wr|+
+;w.+
+;w.+
+0w.+
+0w.+
+4w.+
+w.+
+w.+
+2w.+
+w
+.+
+wi<Enter>|<Escape>
diff --git a/test/vis/motions/next-start-of-word.ref b/test/vis/motions/next-start-of-word.ref
new file mode 100644
index 0000000..436964a
--- /dev/null
+++ b/test/vis/motions/next-start-of-word.ref
@@ -0,0 +1,13 @@
+_start |ext
+mid_dle |ext
+end_ |ext
+ |tarting from a space
+ |tarting from a tab
+a b c d | single letter words
+tab |ext
++-*/\"'`^%&,;||(){}<>[]=?! special symbols
+word with |ount
+
+|ext line
+word_at_end
+|
diff --git a/test/vis/motions/percent.in b/test/vis/motions/percent.in
new file mode 100644
index 0000000..8a1218a
--- /dev/null
+++ b/test/vis/motions/percent.in
@@ -0,0 +1,5 @@
+1
+2
+3
+4
+5
diff --git a/test/vis/motions/percent.keys b/test/vis/motions/percent.keys
new file mode 100644
index 0000000..daeb1ef
--- /dev/null
+++ b/test/vis/motions/percent.keys
@@ -0,0 +1,3 @@
+50%i=<Escape>
+1%i|<Escape>
+100%.
diff --git a/test/vis/motions/percent.ref b/test/vis/motions/percent.ref
new file mode 100644
index 0000000..93cf66e
--- /dev/null
+++ b/test/vis/motions/percent.ref
@@ -0,0 +1,6 @@
+|1
+2
+3=
+4
+5
+| \ No newline at end of file
diff --git a/test/vis/motions/prev-end-of-bigword.in b/test/vis/motions/prev-end-of-bigword.in
new file mode 100644
index 0000000..defda4e
--- /dev/null
+++ b/test/vis/motions/prev-end-of-bigword.in
@@ -0,0 +1,10 @@
+
+prev WORD-end_
+prev WORD-mid_dle
+prev WORD-word _start
+prev WORD-tab _
+starting from a space
+starting from a tab
+single letter words a b c d _
+special +-*/\"'`^%&,;|_(){}<>[]=?!
+prev WORD-word with count _
diff --git a/test/vis/motions/prev-end-of-bigword.keys b/test/vis/motions/prev-end-of-bigword.keys
new file mode 100644
index 0000000..a0c18c7
--- /dev/null
+++ b/test/vis/motions/prev-end-of-bigword.keys
@@ -0,0 +1,10 @@
+dgE+
+f_gEr|+
+;gE.+
+;gE.+
+;gE.+
+$hgE.+
+$hgE.+
+g_4gE.+
+$2gE.+
+;3gE.+
diff --git a/test/vis/motions/prev-end-of-bigword.ref b/test/vis/motions/prev-end-of-bigword.ref
new file mode 100644
index 0000000..346778b
--- /dev/null
+++ b/test/vis/motions/prev-end-of-bigword.ref
@@ -0,0 +1,10 @@
+
+pre| WORD-end_
+pre| WORD-mid_dle
+prev WORD-wor| _start
+prev WORD-ta| _
+starting from a spac|
+starting from a ta|
+single letter words | b c d _
+specia| +-*/\"'`^%&,;|_(){}<>[]=?!
+prev WORD-wor| with count _
diff --git a/test/vis/motions/prev-end-of-word.in b/test/vis/motions/prev-end-of-word.in
new file mode 100644
index 0000000..7f6a80c
--- /dev/null
+++ b/test/vis/motions/prev-end-of-word.in
@@ -0,0 +1,10 @@
+
+prev word end_
+prev word mid_dle
+prev word _start
+prev word tab _
+starting from a space
+starting from a tab
+single letter words a b c d _
+special +-*/\"'`^%&,;|_(){}<>[]=?!
+prev word with count _
diff --git a/test/vis/motions/prev-end-of-word.keys b/test/vis/motions/prev-end-of-word.keys
new file mode 100644
index 0000000..d2b8ef4
--- /dev/null
+++ b/test/vis/motions/prev-end-of-word.keys
@@ -0,0 +1,10 @@
+dge+
+f_ger|+
+;ge.+
+;ge.+
+;ge.+
+$hge.+
+$hge.+
+g_4ge.+
+g_ge.+
+;3ge.+
diff --git a/test/vis/motions/prev-end-of-word.ref b/test/vis/motions/prev-end-of-word.ref
new file mode 100644
index 0000000..7b30238
--- /dev/null
+++ b/test/vis/motions/prev-end-of-word.ref
@@ -0,0 +1,10 @@
+
+prev wor| end_
+prev wor| mid_dle
+prev wor| _start
+prev word ta| _
+starting from a spac|
+starting from a ta|
+single letter words | b c d _
+special +-*/\"'`^%&,;||(){}<>[]=?!
+prev wor| with count _
diff --git a/test/vis/motions/prev-start-of-bigword.in b/test/vis/motions/prev-start-of-bigword.in
new file mode 100644
index 0000000..8f287f1
--- /dev/null
+++ b/test/vis/motions/prev-start-of-bigword.in
@@ -0,0 +1,9 @@
+prev WORD-end_
+prev WORD-mid_dle
+prev WORD-word _start
+prev WORD-tab _
+starting from space
+starting from tab
+single letter words a b c d _
+special symbols +-*/\"'`^%&,;|_(){}<>[]=?!
+prev WORD-word with count _
diff --git a/test/vis/motions/prev-start-of-bigword.keys b/test/vis/motions/prev-start-of-bigword.keys
new file mode 100644
index 0000000..037a2c7
--- /dev/null
+++ b/test/vis/motions/prev-start-of-bigword.keys
@@ -0,0 +1,10 @@
+dB
+f_Br|+
+;B.+
+;B.+
+;B.+
+$hB.+
+$hB.+
+g_4B.+
+$B.+
+;3B.+
diff --git a/test/vis/motions/prev-start-of-bigword.ref b/test/vis/motions/prev-start-of-bigword.ref
new file mode 100644
index 0000000..80ef519
--- /dev/null
+++ b/test/vis/motions/prev-start-of-bigword.ref
@@ -0,0 +1,9 @@
+prev |ORD-end_
+prev |ORD-mid_dle
+prev |ORD-word _start
+prev |ORD-tab _
+starting from |pace
+starting from |ab
+single letter words | b c d _
+special symbols |-*/\"'`^%&,;|_(){}<>[]=?!
+prev |ORD-word with count _
diff --git a/test/vis/motions/prev-start-of-word.in b/test/vis/motions/prev-start-of-word.in
new file mode 100644
index 0000000..23871b0
--- /dev/null
+++ b/test/vis/motions/prev-start-of-word.in
@@ -0,0 +1,9 @@
+prev word-end_
+prev word-mid_dle
+prev word-word _start
+prev word-tab _
+starting from space
+starting from tab
+single letter words a b c d _
+special symbols +-*/\"'`^%&,;|_(){}<>[]=?!
+prev word-word with count _
diff --git a/test/vis/motions/prev-start-of-word.keys b/test/vis/motions/prev-start-of-word.keys
new file mode 100644
index 0000000..a397494
--- /dev/null
+++ b/test/vis/motions/prev-start-of-word.keys
@@ -0,0 +1,10 @@
+db
+f_br|+
+;b.+
+;b.+
+;b.+
+$hb.+
+$hb.+
+g_4b.+
+$b.+
+;3b.+
diff --git a/test/vis/motions/prev-start-of-word.ref b/test/vis/motions/prev-start-of-word.ref
new file mode 100644
index 0000000..c75a3a5
--- /dev/null
+++ b/test/vis/motions/prev-start-of-word.ref
@@ -0,0 +1,9 @@
+prev word-|nd_
+prev word-|id_dle
+prev word-|ord _start
+prev word-|ab _
+starting from |pace
+starting from |ab
+single letter words | b c d _
+special symbols +-*/\"'`^%&,;|_|){}<>[]=?!
+prev word-|ord with count _
diff --git a/test/vis/motions/till-left.in b/test/vis/motions/till-left.in
new file mode 100644
index 0000000..2b1694a
--- /dev/null
+++ b/test/vis/motions/till-left.in
@@ -0,0 +1,15 @@
+T{char} Till after [count]'th occurrence of {char} to the left.
+1 till char c (T)
+2 till char c with count (2T)
+3 till char c using repeat and count (2;)
+4 till char c in reverse direction with count (^2,)
+5 till consecutive char ### with count (3T)
+6 till consecutive char ### using repeat (;;;)
+7 till consecutive char ### using repeat and count (3;)
+8 till consecutive char ### in reverse direction with count (^3,)
+9 delete # found (d;)
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 till æ unicode
+13 till space
+14 till tab
diff --git a/test/vis/motions/till-left.keys b/test/vis/motions/till-left.keys
new file mode 100644
index 0000000..44cb62f
--- /dev/null
+++ b/test/vis/motions/till-left.keys
@@ -0,0 +1,15 @@
++
+$Tcr|+
+$2Tc.+
+$2;.+
+^2,.+
+$3T#.+
+$;;;.+
+$3;.+
+^3,.+
+$d;+
+$d;+
+$d2;+
+$Tær|+
+$T<Space>.+
+$T<Tab>.+
diff --git a/test/vis/motions/till-left.ref b/test/vis/motions/till-left.ref
new file mode 100644
index 0000000..fff633e
--- /dev/null
+++ b/test/vis/motions/till-left.ref
@@ -0,0 +1,15 @@
+T{char} Till after [count]'th occurrence of {char} to the left.
+1 till char c|(T)
+2 till char c|with count (2T)
+3 till char c|using repeat and count (2;)
+4 till char|c in reverse direction with count (^2,)
+5 till consecutive char #|# with count (3T)
+6 till consecutive char #|# using repeat (;;;)
+7 till consecutive char #|# using repeat and count (3;)
+8 till consecutive char #|# in reverse direction with count (^3,)
+9 delete #
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 till æ|unicode
+13 till |pace
+14 till |tab
diff --git a/test/vis/motions/till-right.in b/test/vis/motions/till-right.in
new file mode 100644
index 0000000..c6202c9
--- /dev/null
+++ b/test/vis/motions/till-right.in
@@ -0,0 +1,15 @@
+t{char} Till before [count]'th occurrence of {char} to the right.
+1 till char c (t)
+2 till char c with count (2t)
+3 till char c using repeat and count (2;)
+4 till char c in reverse direction with count ($3,)
+5 till consecutive char ### with count (3t#)
+6 till consecutive char ### using repeat (;;;)
+7 till consecutive char ### using repeat and count (3;)
+8 till consecutive char ### in reverse direction with count ($3,)
+9 delete # found (d;)
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 till unicode æ
+13 till space
+14 till tab
diff --git a/test/vis/motions/till-right.keys b/test/vis/motions/till-right.keys
new file mode 100644
index 0000000..5824698
--- /dev/null
+++ b/test/vis/motions/till-right.keys
@@ -0,0 +1,15 @@
++
+tcr|+
+2tc.+
+2;.+
+$3,.+
+3t#.+
+;;;.+
+3;.+
+$3,.+
+d;+
+d;+
+d2;+
+tær|+
+t<Space>.+
+t<Tab>.+
diff --git a/test/vis/motions/till-right.ref b/test/vis/motions/till-right.ref
new file mode 100644
index 0000000..d833df1
--- /dev/null
+++ b/test/vis/motions/till-right.ref
@@ -0,0 +1,15 @@
+t{char} Till before [count]'th occurrence of {char} to the right.
+1 till|char c (t)
+2 till char|c with count (2t)
+3 till char|c using repeat and count (2;)
+4 till char c|in reverse direction with count ($3,)
+5 till consecutive char #|# with count (3t#)
+6 till consecutive char #|# using repeat (;;;)
+7 till consecutive char #|# using repeat and count (3;)
+8 till consecutive char #|# in reverse direction with count ($3,)
+# found (d;)
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 till unicode|æ
+1| till space
+14 till tab|
diff --git a/test/vis/motions/to-left.in b/test/vis/motions/to-left.in
new file mode 100644
index 0000000..f0dcde3
--- /dev/null
+++ b/test/vis/motions/to-left.in
@@ -0,0 +1,15 @@
+F{char} To [count]'th occurrence of {char} to the left.
+1 find char c (F)
+2 find char c with count (2F)
+3 find char c using repeat and count (2;)
+4 find char c in reverse direction with count (^2,)
+5 find consecutive char ### with count (2F)
+6 find consecutive char ### using repeat (;;)
+7 find consecutive char ### using repeat and count (2;)
+8 find consecutive char ### in reverse direction with count ($2,)
+9 delete # found (d;)
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 till æ unicode
+13 till space
+14 till tab
diff --git a/test/vis/motions/to-left.keys b/test/vis/motions/to-left.keys
new file mode 100644
index 0000000..f4597a2
--- /dev/null
+++ b/test/vis/motions/to-left.keys
@@ -0,0 +1,15 @@
++
+$Fcr|+
+$2Fc.+
+$2;.+
+^2,.+
+$2F#.+
+$;;.+
+$2;.+
+^2,.+
+$d;+
+$d;+
+$d2;+
+$Fær|+
+$F<Space>.+
+$F<Tab>.+
diff --git a/test/vis/motions/to-left.ref b/test/vis/motions/to-left.ref
new file mode 100644
index 0000000..dc360f4
--- /dev/null
+++ b/test/vis/motions/to-left.ref
@@ -0,0 +1,15 @@
+F{char} To [count]'th occurrence of {char} to the left.
+1 find char | (F)
+2 find char | with count (2F)
+3 find char | using repeat and count (2;)
+4 find char | in reverse direction with count (^2,)
+5 find consecutive char #|# with count (2F)
+6 find consecutive char #|# using repeat (;;)
+7 find consecutive char #|# using repeat and count (2;)
+8 find consecutive char #|# in reverse direction with count ($2,)
+9 delete
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 till | unicode
+13 till|space
+14 till | tab
diff --git a/test/vis/motions/to-right.in b/test/vis/motions/to-right.in
new file mode 100644
index 0000000..ed15516
--- /dev/null
+++ b/test/vis/motions/to-right.in
@@ -0,0 +1,15 @@
+f{char} To [count]'th occurrence of char to the right.
+1 find char c (f)
+2 find char c with count (2f)
+3 find char c using repeat and count (2;)
+4 find char c in reverse direction with count ($3,)
+5 find consecutive char ### with count (2f#)
+6 find consecutive char ### using repeat (;;)
+7 find consecutive char ### using repeat and count (2;)
+8 find consecutive char ### in reverse direction with count ($2,)
+9 delete # found (d;)
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 find unicode æ
+13 find space
+14 find tab
diff --git a/test/vis/motions/to-right.keys b/test/vis/motions/to-right.keys
new file mode 100644
index 0000000..ac1e51b
--- /dev/null
+++ b/test/vis/motions/to-right.keys
@@ -0,0 +1,15 @@
++
+fcr|+
+2fc.+
+2;.+
+$3,.+
+2f#.+
+;;.+
+2;.+
+$2,.+
+d;+
+d;+
+d2;+
+fær|+
+f<Space>.+
+f<Tab>.+
diff --git a/test/vis/motions/to-right.ref b/test/vis/motions/to-right.ref
new file mode 100644
index 0000000..5265c38
--- /dev/null
+++ b/test/vis/motions/to-right.ref
@@ -0,0 +1,15 @@
+f{char} To [count]'th occurrence of char to the right.
+1 find |har c (f)
+2 find char | with count (2f)
+3 find char | using repeat and count (2;)
+4 find char | in reverse direction with count ($3,)
+5 find consecutive char #|# with count (2f#)
+6 find consecutive char #|# using repeat (;;)
+7 find consecutive char #|# using repeat and count (2;)
+8 find consecutive char #|# in reverse direction with count ($2,)
+ found (d;)
+10 delete not found (d;)
+11 delete invalid count # (d2;)
+12 find unicode |
+13|find space
+14 find tab |
diff --git a/test/vis/prompt/history.in b/test/vis/prompt/history.in
new file mode 100644
index 0000000..a92d664
--- /dev/null
+++ b/test/vis/prompt/history.in
@@ -0,0 +1,3 @@
+line 1
+line 2
+line 3
diff --git a/test/vis/prompt/history.keys b/test/vis/prompt/history.keys
new file mode 100644
index 0000000..ee7b037
--- /dev/null
+++ b/test/vis/prompt/history.keys
@@ -0,0 +1,6 @@
+:-0+0x/line/c/word/<Enter>
+:2<Enter>l
+:<Up><Up><Enter>
+:e<Backspace><Backspace>
+:3<Enter>l
+:<Up><Up><Enter>
diff --git a/test/vis/prompt/history.ref b/test/vis/prompt/history.ref
new file mode 100644
index 0000000..7d45533
--- /dev/null
+++ b/test/vis/prompt/history.ref
@@ -0,0 +1,3 @@
+word 1
+word 2
+word 3
diff --git a/test/vis/selections/align-indent-columns.in b/test/vis/selections/align-indent-columns.in
new file mode 100644
index 0000000..ce7fc31
--- /dev/null
+++ b/test/vis/selections/align-indent-columns.in
@@ -0,0 +1,5 @@
+1 2
+ 3 4
+ 5 6
+ 7 8
+ 9 10
diff --git a/test/vis/selections/align-indent-columns.keys b/test/vis/selections/align-indent-columns.keys
new file mode 100644
index 0000000..e1a751f
--- /dev/null
+++ b/test/vis/selections/align-indent-columns.keys
@@ -0,0 +1,3 @@
+:x/[0-9]+<Enter>
+<Tab>
+<Escape>
diff --git a/test/vis/selections/align-indent-columns.ref b/test/vis/selections/align-indent-columns.ref
new file mode 100644
index 0000000..3d3fd0f
--- /dev/null
+++ b/test/vis/selections/align-indent-columns.ref
@@ -0,0 +1,5 @@
+ 1 2
+ 3 4
+ 5 6
+ 7 8
+ 9 10
diff --git a/test/vis/selections/align-indent.in b/test/vis/selections/align-indent.in
new file mode 100644
index 0000000..a8a36d8
--- /dev/null
+++ b/test/vis/selections/align-indent.in
@@ -0,0 +1,5 @@
+1
+ 2
+ 3
+ 4
+ 5
diff --git a/test/vis/selections/align-indent.keys b/test/vis/selections/align-indent.keys
new file mode 100644
index 0000000..84f8735
--- /dev/null
+++ b/test/vis/selections/align-indent.keys
@@ -0,0 +1,2 @@
+vGI
+i<S-Tab>|<Escape>
diff --git a/test/vis/selections/align-indent.ref b/test/vis/selections/align-indent.ref
new file mode 100644
index 0000000..d42da43
--- /dev/null
+++ b/test/vis/selections/align-indent.ref
@@ -0,0 +1,5 @@
+ |1
+ |2
+ |3
+ |4
+ |5
diff --git a/test/vis/selections/align.in b/test/vis/selections/align.in
new file mode 100644
index 0000000..a8a36d8
--- /dev/null
+++ b/test/vis/selections/align.in
@@ -0,0 +1,5 @@
+1
+ 2
+ 3
+ 4
+ 5
diff --git a/test/vis/selections/align.keys b/test/vis/selections/align.keys
new file mode 100644
index 0000000..e335797
--- /dev/null
+++ b/test/vis/selections/align.keys
@@ -0,0 +1,3 @@
+vGI
+<Tab>
+i|<Escape>
diff --git a/test/vis/selections/align.ref b/test/vis/selections/align.ref
new file mode 100644
index 0000000..34adc53
--- /dev/null
+++ b/test/vis/selections/align.ref
@@ -0,0 +1,5 @@
+|1
+| 2
+| 3
+| 4
+| 5
diff --git a/test/vis/selections/complement-whole.in b/test/vis/selections/complement-whole.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/vis/selections/complement-whole.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/complement-whole.keys b/test/vis/selections/complement-whole.keys
new file mode 100644
index 0000000..e1eea50
--- /dev/null
+++ b/test/vis/selections/complement-whole.keys
@@ -0,0 +1,3 @@
+:x <Enter>
+~
+:i/|/ <Enter>
diff --git a/test/vis/selections/complement-whole.ref b/test/vis/selections/complement-whole.ref
new file mode 100644
index 0000000..20f1f63
--- /dev/null
+++ b/test/vis/selections/complement-whole.ref
@@ -0,0 +1,10 @@
+1|
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/complement.in b/test/vis/selections/complement.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/complement.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/complement.keys b/test/vis/selections/complement.keys
new file mode 100644
index 0000000..70f8243
--- /dev/null
+++ b/test/vis/selections/complement.keys
@@ -0,0 +1,4 @@
+:x/.*/ x/./ g2 <Enter>
+~
+:y/\n/ <Enter>
+:v-1 { i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/complement.ref b/test/vis/selections/complement.ref
new file mode 100644
index 0000000..8d93ba5
--- /dev/null
+++ b/test/vis/selections/complement.ref
@@ -0,0 +1,10 @@
+[1]0[0]
+[1]0[1]
+[1]0[2]
+[1]0[3]
+[1]0[4]
+[1]0[5]
+[1]0[6]
+[1]0[7]
+[1]0[8]
+[1]0[9]
diff --git a/test/vis/selections/end-of-file.in b/test/vis/selections/end-of-file.in
new file mode 100644
index 0000000..81acc4a
--- /dev/null
+++ b/test/vis/selections/end-of-file.in
@@ -0,0 +1,9 @@
+01
+
+12
+
+23
+
+34
+
+4
diff --git a/test/vis/selections/end-of-file.keys b/test/vis/selections/end-of-file.keys
new file mode 100644
index 0000000..fe21064
--- /dev/null
+++ b/test/vis/selections/end-of-file.keys
@@ -0,0 +1,6 @@
+Gll
+<C-k>
+i5
+<Enter>
+<Escape>
+<Escape>
diff --git a/test/vis/selections/end-of-file.ref b/test/vis/selections/end-of-file.ref
new file mode 100644
index 0000000..63293a1
--- /dev/null
+++ b/test/vis/selections/end-of-file.ref
@@ -0,0 +1,12 @@
+01
+
+12
+
+23
+
+34
+
+45
+
+5
+
diff --git a/test/vis/selections/intersect-adjacent.in b/test/vis/selections/intersect-adjacent.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/vis/selections/intersect-adjacent.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/intersect-adjacent.keys b/test/vis/selections/intersect-adjacent.keys
new file mode 100644
index 0000000..c3da851
--- /dev/null
+++ b/test/vis/selections/intersect-adjacent.keys
@@ -0,0 +1,5 @@
+:x g%2 <Enter>
+m <Escape><Escape>
+:x v%2 <Enter>
+&
+:i/|/ <Enter>
diff --git a/test/vis/selections/intersect-adjacent.ref b/test/vis/selections/intersect-adjacent.ref
new file mode 100644
index 0000000..20f1f63
--- /dev/null
+++ b/test/vis/selections/intersect-adjacent.ref
@@ -0,0 +1,10 @@
+1|
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/intersect-contained.in b/test/vis/selections/intersect-contained.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/intersect-contained.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/intersect-contained.keys b/test/vis/selections/intersect-contained.keys
new file mode 100644
index 0000000..2334fde
--- /dev/null
+++ b/test/vis/selections/intersect-contained.keys
@@ -0,0 +1,5 @@
+:x/.*/ x/./ g2 <Enter>
+m <Escape><Escape>
+:x/.*/ g%2 <Enter>
+&
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/intersect-contained.ref b/test/vis/selections/intersect-contained.ref
new file mode 100644
index 0000000..c9eb2ba
--- /dev/null
+++ b/test/vis/selections/intersect-contained.ref
@@ -0,0 +1,10 @@
+100
+1[0]1
+102
+1[0]3
+104
+1[0]5
+106
+1[0]7
+108
+1[0]9
diff --git a/test/vis/selections/intersect-empty.in b/test/vis/selections/intersect-empty.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/intersect-empty.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/intersect-empty.keys b/test/vis/selections/intersect-empty.keys
new file mode 100644
index 0000000..d039fd6
--- /dev/null
+++ b/test/vis/selections/intersect-empty.keys
@@ -0,0 +1,3 @@
+:x v%2 <Enter>
+&
+:i/|/ <Enter>
diff --git a/test/vis/selections/intersect-empty.ref b/test/vis/selections/intersect-empty.ref
new file mode 100644
index 0000000..1f2cf48
--- /dev/null
+++ b/test/vis/selections/intersect-empty.ref
@@ -0,0 +1,10 @@
+100|
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/intersect-overlapping.in b/test/vis/selections/intersect-overlapping.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/intersect-overlapping.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/intersect-overlapping.keys b/test/vis/selections/intersect-overlapping.keys
new file mode 100644
index 0000000..9a1f166
--- /dev/null
+++ b/test/vis/selections/intersect-overlapping.keys
@@ -0,0 +1,5 @@
+:x/.*/ x/^../ <Enter>
+m <Escape><Escape>
+:x/.*/ x/..$/ <Enter>
+&
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/intersect-overlapping.ref b/test/vis/selections/intersect-overlapping.ref
new file mode 100644
index 0000000..70eeb2c
--- /dev/null
+++ b/test/vis/selections/intersect-overlapping.ref
@@ -0,0 +1,10 @@
+1[0]0
+1[0]1
+1[0]2
+1[0]3
+1[0]4
+1[0]5
+1[0]6
+1[0]7
+1[0]8
+1[0]9
diff --git a/test/vis/selections/intersect-whole.in b/test/vis/selections/intersect-whole.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/intersect-whole.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/intersect-whole.keys b/test/vis/selections/intersect-whole.keys
new file mode 100644
index 0000000..a99747a
--- /dev/null
+++ b/test/vis/selections/intersect-whole.keys
@@ -0,0 +1,5 @@
+:, <Enter>
+m
+:x/.*/ v%2 <Enter>
+&
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/intersect-whole.ref b/test/vis/selections/intersect-whole.ref
new file mode 100644
index 0000000..e8ceccb
--- /dev/null
+++ b/test/vis/selections/intersect-whole.ref
@@ -0,0 +1,10 @@
+[100]
+101
+[102]
+103
+[104]
+105
+[106]
+107
+[108]
+109
diff --git a/test/vis/selections/minus-adjacent.in b/test/vis/selections/minus-adjacent.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/vis/selections/minus-adjacent.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/minus-adjacent.keys b/test/vis/selections/minus-adjacent.keys
new file mode 100644
index 0000000..9897785
--- /dev/null
+++ b/test/vis/selections/minus-adjacent.keys
@@ -0,0 +1,5 @@
+:x g%2 <Enter>
+m <Escape><Escape>
+:x v%2 <Enter>
+\
+:i/* / <Enter>
diff --git a/test/vis/selections/minus-adjacent.ref b/test/vis/selections/minus-adjacent.ref
new file mode 100644
index 0000000..fa5063a
--- /dev/null
+++ b/test/vis/selections/minus-adjacent.ref
@@ -0,0 +1,10 @@
+* 1
+2
+* 3
+4
+* 5
+6
+* 7
+8
+* 9
+10
diff --git a/test/vis/selections/minus-contained.in b/test/vis/selections/minus-contained.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/minus-contained.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/minus-contained.keys b/test/vis/selections/minus-contained.keys
new file mode 100644
index 0000000..5478045
--- /dev/null
+++ b/test/vis/selections/minus-contained.keys
@@ -0,0 +1,5 @@
+:x/.*/ x/./ g2 <Enter>
+m <Escape><Escape>
+:x/.*/ g%2 <Enter>
+\
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/minus-contained.ref b/test/vis/selections/minus-contained.ref
new file mode 100644
index 0000000..6aa9513
--- /dev/null
+++ b/test/vis/selections/minus-contained.ref
@@ -0,0 +1,10 @@
+100
+[1]0[1]
+102
+[1]0[3]
+104
+[1]0[5]
+106
+[1]0[7]
+108
+[1]0[9]
diff --git a/test/vis/selections/minus-empty.in b/test/vis/selections/minus-empty.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/minus-empty.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/minus-empty.keys b/test/vis/selections/minus-empty.keys
new file mode 100644
index 0000000..ab30a19
--- /dev/null
+++ b/test/vis/selections/minus-empty.keys
@@ -0,0 +1,3 @@
+:x/.*/ v%2 <Enter>
+\
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/minus-empty.ref b/test/vis/selections/minus-empty.ref
new file mode 100644
index 0000000..e8ceccb
--- /dev/null
+++ b/test/vis/selections/minus-empty.ref
@@ -0,0 +1,10 @@
+[100]
+101
+[102]
+103
+[104]
+105
+[106]
+107
+[108]
+109
diff --git a/test/vis/selections/minus-overlapping.in b/test/vis/selections/minus-overlapping.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/minus-overlapping.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/minus-overlapping.keys b/test/vis/selections/minus-overlapping.keys
new file mode 100644
index 0000000..6b3b29c
--- /dev/null
+++ b/test/vis/selections/minus-overlapping.keys
@@ -0,0 +1,5 @@
+:x/.*/ x/^../ <Enter>
+m <Escape><Escape>
+:x/.*/ x/..$/ <Enter>
+\
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/minus-overlapping.ref b/test/vis/selections/minus-overlapping.ref
new file mode 100644
index 0000000..b061b47
--- /dev/null
+++ b/test/vis/selections/minus-overlapping.ref
@@ -0,0 +1,10 @@
+10[0]
+10[1]
+10[2]
+10[3]
+10[4]
+10[5]
+10[6]
+10[7]
+10[8]
+10[9]
diff --git a/test/vis/selections/minus-whole.in b/test/vis/selections/minus-whole.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/minus-whole.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/minus-whole.keys b/test/vis/selections/minus-whole.keys
new file mode 100644
index 0000000..2615c3e
--- /dev/null
+++ b/test/vis/selections/minus-whole.keys
@@ -0,0 +1,5 @@
+:, <Enter>
+m
+:x v%2 <Enter>
+\
+:i/|/ <Enter>
diff --git a/test/vis/selections/minus-whole.ref b/test/vis/selections/minus-whole.ref
new file mode 100644
index 0000000..1f2cf48
--- /dev/null
+++ b/test/vis/selections/minus-whole.ref
@@ -0,0 +1,10 @@
+100|
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/new-above-first-below-last.in b/test/vis/selections/new-above-first-below-last.in
new file mode 100644
index 0000000..8a1218a
--- /dev/null
+++ b/test/vis/selections/new-above-first-below-last.in
@@ -0,0 +1,5 @@
+1
+2
+3
+4
+5
diff --git a/test/vis/selections/new-above-first-below-last.keys b/test/vis/selections/new-above-first-below-last.keys
new file mode 100644
index 0000000..1602e33
--- /dev/null
+++ b/test/vis/selections/new-above-first-below-last.keys
@@ -0,0 +1,4 @@
+/3<Enter>
+2<M-C-k>
+2<M-C-j>
+i><Escape>
diff --git a/test/vis/selections/new-above-first-below-last.ref b/test/vis/selections/new-above-first-below-last.ref
new file mode 100644
index 0000000..5852f72
--- /dev/null
+++ b/test/vis/selections/new-above-first-below-last.ref
@@ -0,0 +1,5 @@
+>1
+>2
+>3
+>4
+>5
diff --git a/test/vis/selections/new-below-above.in b/test/vis/selections/new-below-above.in
new file mode 100644
index 0000000..7e7bac6
--- /dev/null
+++ b/test/vis/selections/new-below-above.in
@@ -0,0 +1,5 @@
+1
+
+2
+
+3
diff --git a/test/vis/selections/new-below-above.keys b/test/vis/selections/new-below-above.keys
new file mode 100644
index 0000000..0872e3c
--- /dev/null
+++ b/test/vis/selections/new-below-above.keys
@@ -0,0 +1,5 @@
+10<C-j>
+iv<Escape>
+g0<Escape>
+10<C-k>
+i^<Escape>
diff --git a/test/vis/selections/new-below-above.ref b/test/vis/selections/new-below-above.ref
new file mode 100644
index 0000000..685ddbe
--- /dev/null
+++ b/test/vis/selections/new-below-above.ref
@@ -0,0 +1,5 @@
+^v1
+^v
+^v2
+^v
+^v3
diff --git a/test/vis/selections/new-end-of-line.in b/test/vis/selections/new-end-of-line.in
new file mode 100644
index 0000000..949ea37
--- /dev/null
+++ b/test/vis/selections/new-end-of-line.in
@@ -0,0 +1,4 @@
+1 : first
+2 : second
+3 : third
+4 : fourth
diff --git a/test/vis/selections/new-end-of-line.keys b/test/vis/selections/new-end-of-line.keys
new file mode 100644
index 0000000..d44cc50
--- /dev/null
+++ b/test/vis/selections/new-end-of-line.keys
@@ -0,0 +1,7 @@
+vGA$
+dT<Space>
+.
+dF<Space>
+Ibegin : <Escape>
+.
+u
diff --git a/test/vis/selections/new-end-of-line.ref b/test/vis/selections/new-end-of-line.ref
new file mode 100644
index 0000000..bafb72b
--- /dev/null
+++ b/test/vis/selections/new-end-of-line.ref
@@ -0,0 +1,4 @@
+begin : 1
+begin : 2
+begin : 3
+begin : 4
diff --git a/test/vis/selections/new-start-of-line.in b/test/vis/selections/new-start-of-line.in
new file mode 100644
index 0000000..949ea37
--- /dev/null
+++ b/test/vis/selections/new-start-of-line.in
@@ -0,0 +1,4 @@
+1 : first
+2 : second
+3 : third
+4 : fourth
diff --git a/test/vis/selections/new-start-of-line.keys b/test/vis/selections/new-start-of-line.keys
new file mode 100644
index 0000000..0290010
--- /dev/null
+++ b/test/vis/selections/new-start-of-line.keys
@@ -0,0 +1,6 @@
+vGI
+df<Space>
+.
+A : end<Escape>
+.
+u
diff --git a/test/vis/selections/new-start-of-line.ref b/test/vis/selections/new-start-of-line.ref
new file mode 100644
index 0000000..7c5bd13
--- /dev/null
+++ b/test/vis/selections/new-start-of-line.ref
@@ -0,0 +1,4 @@
+first : end
+second : end
+third : end
+fourth : end
diff --git a/test/vis/selections/normal-mode-wq.in b/test/vis/selections/normal-mode-wq.in
new file mode 100644
index 0000000..3f723c4
--- /dev/null
+++ b/test/vis/selections/normal-mode-wq.in
@@ -0,0 +1,8 @@
+make
+sure
+:wq
+works
+when
+multiple
+cursors
+exist
diff --git a/test/vis/selections/normal-mode-wq.keys b/test/vis/selections/normal-mode-wq.keys
new file mode 100644
index 0000000..12c1412
--- /dev/null
+++ b/test/vis/selections/normal-mode-wq.keys
@@ -0,0 +1,4 @@
+vGI
+<C-k>
+<C-p>
+i
diff --git a/test/vis/selections/normal-mode-wq.ref b/test/vis/selections/normal-mode-wq.ref
new file mode 100644
index 0000000..3f723c4
--- /dev/null
+++ b/test/vis/selections/normal-mode-wq.ref
@@ -0,0 +1,8 @@
+make
+sure
+:wq
+works
+when
+multiple
+cursors
+exist
diff --git a/test/vis/selections/odd-even.in b/test/vis/selections/odd-even.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/vis/selections/odd-even.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/odd-even.keys b/test/vis/selections/odd-even.keys
new file mode 100644
index 0000000..5aa92c6
--- /dev/null
+++ b/test/vis/selections/odd-even.keys
@@ -0,0 +1 @@
+:x { g%2 i/+/ v%2 i/-/ } <Enter>
diff --git a/test/vis/selections/odd-even.ref b/test/vis/selections/odd-even.ref
new file mode 100644
index 0000000..b12ac91
--- /dev/null
+++ b/test/vis/selections/odd-even.ref
@@ -0,0 +1,10 @@
+-1
++2
+-3
++4
+-5
++6
+-7
++8
+-9
++10
diff --git a/test/vis/selections/out-of-view.in.disabled b/test/vis/selections/out-of-view.in.disabled
new file mode 100644
index 0000000..aa9ee78
--- /dev/null
+++ b/test/vis/selections/out-of-view.in.disabled
@@ -0,0 +1,999 @@
+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
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
diff --git a/test/vis/selections/out-of-view.keys b/test/vis/selections/out-of-view.keys
new file mode 100644
index 0000000..472b81f
--- /dev/null
+++ b/test/vis/selections/out-of-view.keys
@@ -0,0 +1,7 @@
+:x/1$/<Enter>
+V
+8j
+8k
+d
+<Escape>
+<Escape>
diff --git a/test/vis/selections/out-of-view.ref b/test/vis/selections/out-of-view.ref
new file mode 100644
index 0000000..63051a3
--- /dev/null
+++ b/test/vis/selections/out-of-view.ref
@@ -0,0 +1,899 @@
+2
+3
+4
+5
+6
+7
+8
+9
+10
+12
+13
+14
+15
+16
+17
+18
+19
+20
+22
+23
+24
+25
+26
+27
+28
+29
+30
+32
+33
+34
+35
+36
+37
+38
+39
+40
+42
+43
+44
+45
+46
+47
+48
+49
+50
+52
+53
+54
+55
+56
+57
+58
+59
+60
+62
+63
+64
+65
+66
+67
+68
+69
+70
+72
+73
+74
+75
+76
+77
+78
+79
+80
+82
+83
+84
+85
+86
+87
+88
+89
+90
+92
+93
+94
+95
+96
+97
+98
+99
+100
+102
+103
+104
+105
+106
+107
+108
+109
+110
+112
+113
+114
+115
+116
+117
+118
+119
+120
+122
+123
+124
+125
+126
+127
+128
+129
+130
+132
+133
+134
+135
+136
+137
+138
+139
+140
+142
+143
+144
+145
+146
+147
+148
+149
+150
+152
+153
+154
+155
+156
+157
+158
+159
+160
+162
+163
+164
+165
+166
+167
+168
+169
+170
+172
+173
+174
+175
+176
+177
+178
+179
+180
+182
+183
+184
+185
+186
+187
+188
+189
+190
+192
+193
+194
+195
+196
+197
+198
+199
+200
+202
+203
+204
+205
+206
+207
+208
+209
+210
+212
+213
+214
+215
+216
+217
+218
+219
+220
+222
+223
+224
+225
+226
+227
+228
+229
+230
+232
+233
+234
+235
+236
+237
+238
+239
+240
+242
+243
+244
+245
+246
+247
+248
+249
+250
+252
+253
+254
+255
+256
+257
+258
+259
+260
+262
+263
+264
+265
+266
+267
+268
+269
+270
+272
+273
+274
+275
+276
+277
+278
+279
+280
+282
+283
+284
+285
+286
+287
+288
+289
+290
+292
+293
+294
+295
+296
+297
+298
+299
+300
+302
+303
+304
+305
+306
+307
+308
+309
+310
+312
+313
+314
+315
+316
+317
+318
+319
+320
+322
+323
+324
+325
+326
+327
+328
+329
+330
+332
+333
+334
+335
+336
+337
+338
+339
+340
+342
+343
+344
+345
+346
+347
+348
+349
+350
+352
+353
+354
+355
+356
+357
+358
+359
+360
+362
+363
+364
+365
+366
+367
+368
+369
+370
+372
+373
+374
+375
+376
+377
+378
+379
+380
+382
+383
+384
+385
+386
+387
+388
+389
+390
+392
+393
+394
+395
+396
+397
+398
+399
+400
+402
+403
+404
+405
+406
+407
+408
+409
+410
+412
+413
+414
+415
+416
+417
+418
+419
+420
+422
+423
+424
+425
+426
+427
+428
+429
+430
+432
+433
+434
+435
+436
+437
+438
+439
+440
+442
+443
+444
+445
+446
+447
+448
+449
+450
+452
+453
+454
+455
+456
+457
+458
+459
+460
+462
+463
+464
+465
+466
+467
+468
+469
+470
+472
+473
+474
+475
+476
+477
+478
+479
+480
+482
+483
+484
+485
+486
+487
+488
+489
+490
+492
+493
+494
+495
+496
+497
+498
+499
+500
+502
+503
+504
+505
+506
+507
+508
+509
+510
+512
+513
+514
+515
+516
+517
+518
+519
+520
+522
+523
+524
+525
+526
+527
+528
+529
+530
+532
+533
+534
+535
+536
+537
+538
+539
+540
+542
+543
+544
+545
+546
+547
+548
+549
+550
+552
+553
+554
+555
+556
+557
+558
+559
+560
+562
+563
+564
+565
+566
+567
+568
+569
+570
+572
+573
+574
+575
+576
+577
+578
+579
+580
+582
+583
+584
+585
+586
+587
+588
+589
+590
+592
+593
+594
+595
+596
+597
+598
+599
+600
+602
+603
+604
+605
+606
+607
+608
+609
+610
+612
+613
+614
+615
+616
+617
+618
+619
+620
+622
+623
+624
+625
+626
+627
+628
+629
+630
+632
+633
+634
+635
+636
+637
+638
+639
+640
+642
+643
+644
+645
+646
+647
+648
+649
+650
+652
+653
+654
+655
+656
+657
+658
+659
+660
+662
+663
+664
+665
+666
+667
+668
+669
+670
+672
+673
+674
+675
+676
+677
+678
+679
+680
+682
+683
+684
+685
+686
+687
+688
+689
+690
+692
+693
+694
+695
+696
+697
+698
+699
+700
+702
+703
+704
+705
+706
+707
+708
+709
+710
+712
+713
+714
+715
+716
+717
+718
+719
+720
+722
+723
+724
+725
+726
+727
+728
+729
+730
+732
+733
+734
+735
+736
+737
+738
+739
+740
+742
+743
+744
+745
+746
+747
+748
+749
+750
+752
+753
+754
+755
+756
+757
+758
+759
+760
+762
+763
+764
+765
+766
+767
+768
+769
+770
+772
+773
+774
+775
+776
+777
+778
+779
+780
+782
+783
+784
+785
+786
+787
+788
+789
+790
+792
+793
+794
+795
+796
+797
+798
+799
+800
+802
+803
+804
+805
+806
+807
+808
+809
+810
+812
+813
+814
+815
+816
+817
+818
+819
+820
+822
+823
+824
+825
+826
+827
+828
+829
+830
+832
+833
+834
+835
+836
+837
+838
+839
+840
+842
+843
+844
+845
+846
+847
+848
+849
+850
+852
+853
+854
+855
+856
+857
+858
+859
+860
+862
+863
+864
+865
+866
+867
+868
+869
+870
+872
+873
+874
+875
+876
+877
+878
+879
+880
+882
+883
+884
+885
+886
+887
+888
+889
+890
+892
+893
+894
+895
+896
+897
+898
+899
+900
+902
+903
+904
+905
+906
+907
+908
+909
+910
+912
+913
+914
+915
+916
+917
+918
+919
+920
+922
+923
+924
+925
+926
+927
+928
+929
+930
+932
+933
+934
+935
+936
+937
+938
+939
+940
+942
+943
+944
+945
+946
+947
+948
+949
+950
+952
+953
+954
+955
+956
+957
+958
+959
+960
+962
+963
+964
+965
+966
+967
+968
+969
+970
+972
+973
+974
+975
+976
+977
+978
+979
+980
+982
+983
+984
+985
+986
+987
+988
+989
+990
+992
+993
+994
+995
+996
+997
+998
+999
diff --git a/test/vis/selections/remove-column.in b/test/vis/selections/remove-column.in
new file mode 100644
index 0000000..e115855
--- /dev/null
+++ b/test/vis/selections/remove-column.in
@@ -0,0 +1,3 @@
+1 2 3
+4 5 6
+7 8 9
diff --git a/test/vis/selections/remove-column.keys b/test/vis/selections/remove-column.keys
new file mode 100644
index 0000000..958c8b2
--- /dev/null
+++ b/test/vis/selections/remove-column.keys
@@ -0,0 +1,8 @@
+:x/[0-9]+<Enter>
+2<C-l>
+:{ i/{/ a/}/ }<Enter>
+<Escape><Escape>
+:<Up><Up><Enter>
+2<C-c>
+:{ i/>/ a/</ }<Enter>
+<Escape><Escape>
diff --git a/test/vis/selections/remove-column.ref b/test/vis/selections/remove-column.ref
new file mode 100644
index 0000000..fae2eab
--- /dev/null
+++ b/test/vis/selections/remove-column.ref
@@ -0,0 +1,3 @@
+>1< {2} >3<
+>4< {5} >6<
+>7< {8} >9<
diff --git a/test/vis/selections/select-match.in b/test/vis/selections/select-match.in
new file mode 100644
index 0000000..511ed3e
--- /dev/null
+++ b/test/vis/selections/select-match.in
@@ -0,0 +1,3 @@
+void print(char *msg) {
+ printf("msg: %s\n", msg);
+}
diff --git a/test/vis/selections/select-match.keys b/test/vis/selections/select-match.keys
new file mode 100644
index 0000000..44b8449
--- /dev/null
+++ b/test/vis/selections/select-match.keys
@@ -0,0 +1,8 @@
+?msg<Enter>
+<C-n>
+<C-n>
+<C-x>
+<C-p>
+<C-n>
+<C-x>
+cinfo<Escape>
diff --git a/test/vis/selections/select-match.ref b/test/vis/selections/select-match.ref
new file mode 100644
index 0000000..5dcee46
--- /dev/null
+++ b/test/vis/selections/select-match.ref
@@ -0,0 +1,3 @@
+void print(char *info) {
+ printf("msg: %s\n", info);
+}
diff --git a/test/vis/selections/selections-rotate.in b/test/vis/selections/selections-rotate.in
new file mode 100644
index 0000000..e115855
--- /dev/null
+++ b/test/vis/selections/selections-rotate.in
@@ -0,0 +1,3 @@
+1 2 3
+4 5 6
+7 8 9
diff --git a/test/vis/selections/selections-rotate.keys b/test/vis/selections/selections-rotate.keys
new file mode 100644
index 0000000..48759a0
--- /dev/null
+++ b/test/vis/selections/selections-rotate.keys
@@ -0,0 +1,6 @@
+:x/[0-9]+<Enter>
+2+
+2-
++
+2-
+<Escape><Escape>
diff --git a/test/vis/selections/selections-rotate.ref b/test/vis/selections/selections-rotate.ref
new file mode 100644
index 0000000..8968398
--- /dev/null
+++ b/test/vis/selections/selections-rotate.ref
@@ -0,0 +1,3 @@
+2 3 1
+5 6 4
+8 9 7
diff --git a/test/vis/selections/selections-trim.in b/test/vis/selections/selections-trim.in
new file mode 100644
index 0000000..154eeee
--- /dev/null
+++ b/test/vis/selections/selections-trim.in
@@ -0,0 +1,3 @@
+1, 2, 3
+4, 5, 6
+7, 8, 9
diff --git a/test/vis/selections/selections-trim.keys b/test/vis/selections/selections-trim.keys
new file mode 100644
index 0000000..049b115
--- /dev/null
+++ b/test/vis/selections/selections-trim.keys
@@ -0,0 +1,5 @@
+:y/[,\n]<Enter>
+<C-k>
+<C-p>
+_
+:{ i/>/ a/</ }<Enter>
diff --git a/test/vis/selections/selections-trim.ref b/test/vis/selections/selections-trim.ref
new file mode 100644
index 0000000..3e1f200
--- /dev/null
+++ b/test/vis/selections/selections-trim.ref
@@ -0,0 +1,3 @@
+>1<, >2<, >3<
+>4<, >5<, >6<
+>7<, >8<, >9<
diff --git a/test/vis/selections/union-adjacent.in b/test/vis/selections/union-adjacent.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/vis/selections/union-adjacent.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/vis/selections/union-adjacent.keys b/test/vis/selections/union-adjacent.keys
new file mode 100644
index 0000000..fecd5c7
--- /dev/null
+++ b/test/vis/selections/union-adjacent.keys
@@ -0,0 +1,5 @@
+:x g%2 <Enter>
+m <Escape><Escape>
+:x v%2 <Enter>
+|
+:i/* / <Enter>
diff --git a/test/vis/selections/union-adjacent.ref b/test/vis/selections/union-adjacent.ref
new file mode 100644
index 0000000..96f652d
--- /dev/null
+++ b/test/vis/selections/union-adjacent.ref
@@ -0,0 +1,10 @@
+* 1
+* 2
+* 3
+* 4
+* 5
+* 6
+* 7
+* 8
+* 9
+* 10
diff --git a/test/vis/selections/union-contained.in b/test/vis/selections/union-contained.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/union-contained.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/union-contained.keys b/test/vis/selections/union-contained.keys
new file mode 100644
index 0000000..015d624
--- /dev/null
+++ b/test/vis/selections/union-contained.keys
@@ -0,0 +1,5 @@
+:x/.*/ x/./ g2 <Enter>
+m <Escape><Escape>
+:x/.*/ g%2 <Enter>
+|
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/union-contained.ref b/test/vis/selections/union-contained.ref
new file mode 100644
index 0000000..27f18d1
--- /dev/null
+++ b/test/vis/selections/union-contained.ref
@@ -0,0 +1,10 @@
+1[0]0
+[101]
+1[0]2
+[103]
+1[0]4
+[105]
+1[0]6
+[107]
+1[0]8
+[109]
diff --git a/test/vis/selections/union-empty.in b/test/vis/selections/union-empty.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/union-empty.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/union-empty.keys b/test/vis/selections/union-empty.keys
new file mode 100644
index 0000000..58816b4
--- /dev/null
+++ b/test/vis/selections/union-empty.keys
@@ -0,0 +1,3 @@
+:x/.*/ v%2 <Enter>
+|
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/union-empty.ref b/test/vis/selections/union-empty.ref
new file mode 100644
index 0000000..e8ceccb
--- /dev/null
+++ b/test/vis/selections/union-empty.ref
@@ -0,0 +1,10 @@
+[100]
+101
+[102]
+103
+[104]
+105
+[106]
+107
+[108]
+109
diff --git a/test/vis/selections/union-overlapping.in b/test/vis/selections/union-overlapping.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/union-overlapping.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/union-overlapping.keys b/test/vis/selections/union-overlapping.keys
new file mode 100644
index 0000000..d188449
--- /dev/null
+++ b/test/vis/selections/union-overlapping.keys
@@ -0,0 +1,5 @@
+:x/.*/ x/^../ <Enter>
+m <Escape><Escape>
+:x/.*/ x/..$/ <Enter>
+|
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/union-overlapping.ref b/test/vis/selections/union-overlapping.ref
new file mode 100644
index 0000000..b78bc90
--- /dev/null
+++ b/test/vis/selections/union-overlapping.ref
@@ -0,0 +1,10 @@
+[100]
+[101]
+[102]
+[103]
+[104]
+[105]
+[106]
+[107]
+[108]
+[109]
diff --git a/test/vis/selections/union-whole.in b/test/vis/selections/union-whole.in
new file mode 100644
index 0000000..96c2a08
--- /dev/null
+++ b/test/vis/selections/union-whole.in
@@ -0,0 +1,10 @@
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
diff --git a/test/vis/selections/union-whole.keys b/test/vis/selections/union-whole.keys
new file mode 100644
index 0000000..c430335
--- /dev/null
+++ b/test/vis/selections/union-whole.keys
@@ -0,0 +1,5 @@
+:, <Enter>
+m
+:x v%2 <Enter>
+|
+:{ i/[/ a/]/ } <Enter>
diff --git a/test/vis/selections/union-whole.ref b/test/vis/selections/union-whole.ref
new file mode 100644
index 0000000..c1b9636
--- /dev/null
+++ b/test/vis/selections/union-whole.ref
@@ -0,0 +1,11 @@
+[100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+] \ No newline at end of file
diff --git a/test/vis/structural-regex/addresses/marks.in b/test/vis/structural-regex/addresses/marks.in
new file mode 100644
index 0000000..2fe6575
--- /dev/null
+++ b/test/vis/structural-regex/addresses/marks.in
@@ -0,0 +1 @@
+The quick brown fox jumps over the lazy dog.
diff --git a/test/vis/structural-regex/addresses/marks.keys b/test/vis/structural-regex/addresses/marks.keys
new file mode 100644
index 0000000..5c6641a
--- /dev/null
+++ b/test/vis/structural-regex/addresses/marks.keys
@@ -0,0 +1,6 @@
+:'a,'b { i/>/ a/</ }<Enter>
+fq
+'am
+el
+'bm
+:<Up><Enter>
diff --git a/test/vis/structural-regex/addresses/marks.ref b/test/vis/structural-regex/addresses/marks.ref
new file mode 100644
index 0000000..df68a3b
--- /dev/null
+++ b/test/vis/structural-regex/addresses/marks.ref
@@ -0,0 +1 @@
+The >quick< brown fox jumps over the lazy dog.
diff --git a/test/vis/structural-regex/addresses/round-down.in b/test/vis/structural-regex/addresses/round-down.in
new file mode 100644
index 0000000..72a8eff
--- /dev/null
+++ b/test/vis/structural-regex/addresses/round-down.in
@@ -0,0 +1,16 @@
+static const KeyBinding bindings_basic[] = {
+ { "<C-z>", ACTION(EDITOR_SUSPEND) },
+ { "<Down>", ACTION(CURSOR_LINE_DOWN) },
+ { "<End>", ACTION(CURSOR_LINE_END) },
+ { "<Home>", ACTION(CURSOR_LINE_BEGIN) },
+ { "<Left>", ACTION(CURSOR_CHAR_PREV) },
+ { "<PageDown>", ACTION(WINDOW_PAGE_DOWN) },
+ { "<PageUp>", ACTION(WINDOW_PAGE_UP) },
+ { "<Right>", ACTION(CURSOR_CHAR_NEXT) },
+ { "<S-Left>", ACTION(CURSOR_LONGWORD_START_PREV) },
+ { "<S-PageDown>", ACTION(WINDOW_HALFPAGE_DOWN) },
+ { "<S-PageUp>", ACTION(WINDOW_HALFPAGE_UP) },
+ { "<S-Right>", ACTION(CURSOR_LONGWORD_START_NEXT) },
+ { "<Up>", ACTION(CURSOR_LINE_UP) },
+ { 0 /* empty last element, array terminator */ },
+};
diff --git a/test/vis/structural-regex/addresses/round-down.keys b/test/vis/structural-regex/addresses/round-down.keys
new file mode 100644
index 0000000..b605515
--- /dev/null
+++ b/test/vis/structural-regex/addresses/round-down.keys
@@ -0,0 +1,5 @@
+:/Left/,/Right/<Enter>
+:{ i/|/ a/|/ }<Enter><Escape><Escape>
+:0/Left/,0/Right/<Enter>
+:-0+,+0-<Enter>
+:{ i/>>\n/ a/<<\n/ }<Enter>
diff --git a/test/vis/structural-regex/addresses/round-down.ref b/test/vis/structural-regex/addresses/round-down.ref
new file mode 100644
index 0000000..7cc0254
--- /dev/null
+++ b/test/vis/structural-regex/addresses/round-down.ref
@@ -0,0 +1,18 @@
+static const KeyBinding bindings_basic[] = {
+ { "<C-z>", ACTION(EDITOR_SUSPEND) },
+ { "<Down>", ACTION(CURSOR_LINE_DOWN) },
+ { "<End>", ACTION(CURSOR_LINE_END) },
+ { "<Home>", ACTION(CURSOR_LINE_BEGIN) },
+ { "<|Left>", ACTION(CURSOR_CHAR_PREV) },
+>>
+ { "<PageDown>", ACTION(WINDOW_PAGE_DOWN) },
+ { "<PageUp>", ACTION(WINDOW_PAGE_UP) },
+<<
+ { "<Right|>", ACTION(CURSOR_CHAR_NEXT) },
+ { "<S-Left>", ACTION(CURSOR_LONGWORD_START_PREV) },
+ { "<S-PageDown>", ACTION(WINDOW_HALFPAGE_DOWN) },
+ { "<S-PageUp>", ACTION(WINDOW_HALFPAGE_UP) },
+ { "<S-Right>", ACTION(CURSOR_LONGWORD_START_NEXT) },
+ { "<Up>", ACTION(CURSOR_LINE_UP) },
+ { 0 /* empty last element, array terminator */ },
+};
diff --git a/test/vis/structural-regex/addresses/round-up.in b/test/vis/structural-regex/addresses/round-up.in
new file mode 100644
index 0000000..72a8eff
--- /dev/null
+++ b/test/vis/structural-regex/addresses/round-up.in
@@ -0,0 +1,16 @@
+static const KeyBinding bindings_basic[] = {
+ { "<C-z>", ACTION(EDITOR_SUSPEND) },
+ { "<Down>", ACTION(CURSOR_LINE_DOWN) },
+ { "<End>", ACTION(CURSOR_LINE_END) },
+ { "<Home>", ACTION(CURSOR_LINE_BEGIN) },
+ { "<Left>", ACTION(CURSOR_CHAR_PREV) },
+ { "<PageDown>", ACTION(WINDOW_PAGE_DOWN) },
+ { "<PageUp>", ACTION(WINDOW_PAGE_UP) },
+ { "<Right>", ACTION(CURSOR_CHAR_NEXT) },
+ { "<S-Left>", ACTION(CURSOR_LONGWORD_START_PREV) },
+ { "<S-PageDown>", ACTION(WINDOW_HALFPAGE_DOWN) },
+ { "<S-PageUp>", ACTION(WINDOW_HALFPAGE_UP) },
+ { "<S-Right>", ACTION(CURSOR_LONGWORD_START_NEXT) },
+ { "<Up>", ACTION(CURSOR_LINE_UP) },
+ { 0 /* empty last element, array terminator */ },
+};
diff --git a/test/vis/structural-regex/addresses/round-up.keys b/test/vis/structural-regex/addresses/round-up.keys
new file mode 100644
index 0000000..0acac9c
--- /dev/null
+++ b/test/vis/structural-regex/addresses/round-up.keys
@@ -0,0 +1,5 @@
+:/Left/,/Right/<Enter>
+:{ i/|/ a/|/ }<Enter><Escape><Escape>
+:0/Left/,0/Right/<Enter>
+:-0,+0<Enter>
+:{ i/>>\n/ a/<<\n/ }<Enter>
diff --git a/test/vis/structural-regex/addresses/round-up.ref b/test/vis/structural-regex/addresses/round-up.ref
new file mode 100644
index 0000000..2b9dba3
--- /dev/null
+++ b/test/vis/structural-regex/addresses/round-up.ref
@@ -0,0 +1,18 @@
+static const KeyBinding bindings_basic[] = {
+ { "<C-z>", ACTION(EDITOR_SUSPEND) },
+ { "<Down>", ACTION(CURSOR_LINE_DOWN) },
+ { "<End>", ACTION(CURSOR_LINE_END) },
+ { "<Home>", ACTION(CURSOR_LINE_BEGIN) },
+>>
+ { "<|Left>", ACTION(CURSOR_CHAR_PREV) },
+ { "<PageDown>", ACTION(WINDOW_PAGE_DOWN) },
+ { "<PageUp>", ACTION(WINDOW_PAGE_UP) },
+ { "<Right|>", ACTION(CURSOR_CHAR_NEXT) },
+<<
+ { "<S-Left>", ACTION(CURSOR_LONGWORD_START_PREV) },
+ { "<S-PageDown>", ACTION(WINDOW_HALFPAGE_DOWN) },
+ { "<S-PageUp>", ACTION(WINDOW_HALFPAGE_UP) },
+ { "<S-Right>", ACTION(CURSOR_LONGWORD_START_NEXT) },
+ { "<Up>", ACTION(CURSOR_LINE_UP) },
+ { 0 /* empty last element, array terminator */ },
+};
diff --git a/test/vis/test.sh b/test/vis/test.sh
new file mode 100755
index 0000000..26702d3
--- /dev/null
+++ b/test/vis/test.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+export VIS_PATH=.
+export PATH="$(pwd)/../..:$PATH"
+export LANG="en_US.UTF-8"
+[ -z "$VIS" ] && VIS="../../vis"
+$VIS -v
+
+if ! $VIS -v | grep '+lua' >/dev/null 2>&1; then
+ echo "vis compiled without lua support, skipping tests"
+ exit 0
+fi
+
+TESTS_OK=0
+TESTS_RUN=0
+
+if [ $# -gt 0 ]; then
+ test_files=$*
+else
+ printf ':help\n:/ Lua paths/,$ w help\n:qall\n' | $VIS 2> /dev/null && cat help && rm -f help
+ test_files="$(find . -type f -name '*.in')"
+fi
+
+for t in $test_files; do
+ TESTS_RUN=$((TESTS_RUN + 1))
+ t=${t%.in}
+ t=${t#./}
+ $VIS '+qall!' "$t".in < /dev/null 2> /dev/null
+ RETURN_CODE=$?
+
+ printf "%-50s" "$t"
+ if [ $RETURN_CODE -eq 0 -a -e "$t".out ]; then
+ if cmp -s "$t".ref "$t".out 2> /dev/null; then
+ printf "PASS\n"
+ TESTS_OK=$((TESTS_OK + 1))
+ else
+ printf "FAIL\n"
+ diff -u "$t".ref "$t".out > "$t".err
+ fi
+ else
+ printf "ERROR\n"
+ fi
+done
+
+printf "Tests ok %d/%d\n" $TESTS_OK $TESTS_RUN
+
+# set exit status
+[ $TESTS_OK -eq $TESTS_RUN ]
diff --git a/test/vis/text-objects/indentation.in b/test/vis/text-objects/indentation.in
new file mode 100644
index 0000000..8ab6759
--- /dev/null
+++ b/test/vis/text-objects/indentation.in
@@ -0,0 +1,16 @@
+static ssize_t write_all(int fd, const char *buf, size_t count) {
+ size_t rem = count;
+ while (rem > 0) {
+ ssize_t written = write(fd, buf, rem);
+ if (written < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ return -1;
+ } else if (written == 0) {
+ break;
+ }
+ rem -= written;
+ buf += written;
+ }
+ return count - rem;
+}
diff --git a/test/vis/text-objects/indentation.keys b/test/vis/text-objects/indentation.keys
new file mode 100644
index 0000000..75c612d
--- /dev/null
+++ b/test/vis/text-objects/indentation.keys
@@ -0,0 +1,4 @@
+/continue<Enter>
+3vi<Tab>
+:x/^/ c/\/\/<Enter>
+<Escape>
diff --git a/test/vis/text-objects/indentation.ref b/test/vis/text-objects/indentation.ref
new file mode 100644
index 0000000..ad35e8e
--- /dev/null
+++ b/test/vis/text-objects/indentation.ref
@@ -0,0 +1,16 @@
+static ssize_t write_all(int fd, const char *buf, size_t count) {
+ size_t rem = count;
+ while (rem > 0) {
+// ssize_t written = write(fd, buf, rem);
+// if (written < 0) {
+// if (errno == EAGAIN || errno == EINTR)
+// continue;
+// return -1;
+// } else if (written == 0) {
+// break;
+// }
+// rem -= written;
+// buf += written;
+ }
+ return count - rem;
+}
diff --git a/test/vis/text-objects/lexer.in b/test/vis/text-objects/lexer.in
new file mode 100644
index 0000000..275fc5f
--- /dev/null
+++ b/test/vis/text-objects/lexer.in
@@ -0,0 +1,6 @@
+/*
+ * cafe or tea?
+ */
+void drink() {
+ printf("cafe: %d\n", 0xcafebeef);
+}
diff --git a/test/vis/text-objects/lexer.keys b/test/vis/text-objects/lexer.keys
new file mode 100644
index 0000000..b738fa5
--- /dev/null
+++ b/test/vis/text-objects/lexer.keys
@@ -0,0 +1,5 @@
+:set syntax ansi_c<Enter>
+:x/cafe<Enter>
+ii
+:{ i/>/ a/</ }<Enter>
+<Escape>
diff --git a/test/vis/text-objects/lexer.ref b/test/vis/text-objects/lexer.ref
new file mode 100644
index 0000000..45b7ed5
--- /dev/null
+++ b/test/vis/text-objects/lexer.ref
@@ -0,0 +1,6 @@
+>/*
+ * cafe or tea?
+ */<
+void drink() {
+ printf(>"cafe: %d\n"<, >0xcafebeef<);
+}
diff --git a/test/vis/text-objects/line.in b/test/vis/text-objects/line.in
new file mode 100644
index 0000000..0c6acfa
--- /dev/null
+++ b/test/vis/text-objects/line.in
@@ -0,0 +1,6 @@
+normal line
+ normal line with white space
+normal line
+ normal line with white space
+inner line
+ inner line with white space
diff --git a/test/vis/text-objects/line.keys b/test/vis/text-objects/line.keys
new file mode 100644
index 0000000..0c3ee72
--- /dev/null
+++ b/test/vis/text-objects/line.keys
@@ -0,0 +1,9 @@
+dal
+.
+2.
+cil>was an inner line<<Escape>
+.
+j
+.
+g0i|<Escape>
+$.
diff --git a/test/vis/text-objects/line.ref b/test/vis/text-objects/line.ref
new file mode 100644
index 0000000..4a8cc7b
--- /dev/null
+++ b/test/vis/text-objects/line.ref
@@ -0,0 +1,2 @@
+>was an inner line<
+| >was an inner line< |
diff --git a/test/vis/text-objects/search-result.in b/test/vis/text-objects/search-result.in
new file mode 100644
index 0000000..44421e4
--- /dev/null
+++ b/test/vis/text-objects/search-result.in
@@ -0,0 +1,8 @@
+// add static using gn
+void f1(void);
+void f2(void);
+void f3(void);
+// add static using gN
+void f4(void);
+void f5(void);
+void f6(void);
diff --git a/test/vis/text-objects/search-result.keys b/test/vis/text-objects/search-result.keys
new file mode 100644
index 0000000..051b4e2
--- /dev/null
+++ b/test/vis/text-objects/search-result.keys
@@ -0,0 +1,8 @@
+/void<Enter>
+cgnstatic void<Escape>
+2.
+.
+G$
+c2gNstatic void<Escape>
+3.
+.
diff --git a/test/vis/text-objects/search-result.ref b/test/vis/text-objects/search-result.ref
new file mode 100644
index 0000000..3713c1c
--- /dev/null
+++ b/test/vis/text-objects/search-result.ref
@@ -0,0 +1,8 @@
+// add static using gn
+static void f1(void);
+static void f2(void);
+static void f3(void);
+// add static using gN
+static void f4(void);
+static void f5(void);
+static void f6(void);
diff --git a/test/vis/visrc.lua b/test/vis/visrc.lua
new file mode 100644
index 0000000..da34920
--- /dev/null
+++ b/test/vis/visrc.lua
@@ -0,0 +1,27 @@
+package.path = '../../lua/?.lua;'..package.path
+dofile("../../lua/vis.lua")
+
+local function run_if_exists(luafile)
+ local f = io.open(luafile, "r")
+ if f ~= nil then
+ f:close()
+ dofile(luafile)
+ end
+end
+
+vis.events.subscribe(vis.events.WIN_OPEN, function(win)
+ -- test.in file passed to vis
+ local name = win.file.name
+ if name then
+ -- use the corresponding test.lua file
+ name = string.gsub(name, '%.in$', '')
+ run_if_exists(string.format("%s.lua", name))
+ local file = io.open(string.format("%s.keys", name))
+ local keys = file:read('*all')
+ keys = string.gsub(keys, '%s*\n', '')
+ keys = string.gsub(keys, '<Space>', ' ')
+ file:close()
+ vis:feedkeys(keys..'<Escape>')
+ vis:command(string.format("w! '%s.out'", name))
+ end
+end)
diff --git a/test/vis/visual-mode/orientation.in b/test/vis/visual-mode/orientation.in
new file mode 100644
index 0000000..84a8a20
--- /dev/null
+++ b/test/vis/visual-mode/orientation.in
@@ -0,0 +1 @@
+ { { = } }
diff --git a/test/vis/visual-mode/orientation.keys b/test/vis/visual-mode/orientation.keys
new file mode 100644
index 0000000..5af0d83
--- /dev/null
+++ b/test/vis/visual-mode/orientation.keys
@@ -0,0 +1,8 @@
+f=
+v2i{
+<Escape>
+i<<Escape>
+gv
+o
+<Escape>
+a><Escape>
diff --git a/test/vis/visual-mode/orientation.ref b/test/vis/visual-mode/orientation.ref
new file mode 100644
index 0000000..f2da79c
--- /dev/null
+++ b/test/vis/visual-mode/orientation.ref
@@ -0,0 +1 @@
+ { > { = } < }