changeset 19738:0208534b8a84 v8.2.0425

patch 8.2.0425: code for modeless selection not sufficiently tested Commit: https://github.com/vim/vim/commit/515545e11f523d14343b1e588dc0b9bd3d362bc2 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Mar 22 14:08:59 2020 +0100 patch 8.2.0425: code for modeless selection not sufficiently tested Problem: Code for modeless selection not sufficiently tested. Solution: Add tests. Move mouse code functionality to a common script file. (Yegappan Lakshmanan, closes #5821)
author Bram Moolenaar <Bram@vim.org>
date Sun, 22 Mar 2020 14:15:04 +0100
parents 5591829276ff
children c49354aed1b2
files src/testdir/Make_all.mak src/testdir/gen_opt_test.vim src/testdir/mouse.vim src/testdir/test_edit.vim src/testdir/test_global.vim src/testdir/test_modeless.vim src/testdir/test_normal.vim src/testdir/test_selectmode.vim src/testdir/test_termcodes.vim src/testdir/test_visual.vim src/ui.c src/version.c
diffstat 12 files changed, 856 insertions(+), 343 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -180,6 +180,7 @@ NEW_TESTS = \
 	test_method \
 	test_mksession \
 	test_mksession_utf8 \
+	test_modeless \
 	test_modeline \
 	test_move \
 	test_nested_function \
@@ -222,6 +223,7 @@ NEW_TESTS = \
 	test_search \
 	test_search_stat \
 	test_searchpos \
+	test_selectmode \
 	test_set \
 	test_sha256 \
 	test_shift \
@@ -406,6 +408,7 @@ NEW_TESTS_RES = \
 	test_messages.res \
 	test_method.res \
 	test_mksession.res \
+	test_modeless.res \
 	test_modeline.res \
 	test_nested_function.res \
 	test_netbeans.res \
@@ -440,6 +443,7 @@ NEW_TESTS_RES = \
 	test_scrollbind.res \
 	test_search.res \
 	test_search_stat.res \
+	test_selectmode.res \
 	test_shortpathname.res \
 	test_signals.res \
 	test_signs.res \
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -73,7 +73,7 @@ let test_values = {
       \ 'buftype': [['', 'help', 'nofile'], ['xxx', 'help,nofile']],
       \ 'casemap': [['', 'internal'], ['xxx']],
       \ 'cedit': [['', '\<Esc>'], ['xxx', 'f']],
-      \ 'clipboard': [['', 'unnamed', 'autoselect,unnamed'], ['xxx']],
+      \ 'clipboard': [['', 'unnamed', 'autoselect,unnamed', 'html', 'exclude:vimdisplay'], ['xxx', '\ze*']],
       \ 'colorcolumn': [['', '8', '+2'], ['xxx']],
       \ 'comments': [['', 'b:#'], ['xxx']],
       \ 'commentstring': [['', '/*%s*/'], ['xxx']],
new file mode 100644
--- /dev/null
+++ b/src/testdir/mouse.vim
@@ -0,0 +1,172 @@
+" Helper functions for generating mouse events
+
+" xterm2 and sgr always work, urxvt is optional.
+let g:Ttymouse_values = ['xterm2', 'sgr']
+if has('mouse_urxvt')
+  call add(g:Ttymouse_values, 'urxvt')
+endif
+
+" dec doesn't support all the functionality
+if has('mouse_dec')
+  let g:Ttymouse_dec = ['dec']
+else
+  let g:Ttymouse_dec = []
+endif
+
+" netterm only supports left click
+if has('mouse_netterm')
+  let g:Ttymouse_netterm = ['netterm']
+else
+  let g:Ttymouse_netterm = []
+endif
+
+" Helper function to emit a terminal escape code.
+func TerminalEscapeCode(code, row, col, m)
+  if &ttymouse ==# 'xterm2'
+    " need to use byte encoding here.
+    let str = list2str([a:code + 0x20, a:col + 0x20, a:row + 0x20])
+    if has('iconv')
+      let bytes = str->iconv('utf-8', 'latin1')
+    else
+      " Hopefully the numbers are not too big.
+      let bytes = str
+    endif
+    return "\<Esc>[M" .. bytes
+  elseif &ttymouse ==# 'sgr'
+    return printf("\<Esc>[<%d;%d;%d%s", a:code, a:col, a:row, a:m)
+  elseif &ttymouse ==# 'urxvt'
+    return printf("\<Esc>[%d;%d;%dM", a:code + 0x20, a:col, a:row)
+  endif
+endfunc
+
+func DecEscapeCode(code, down, row, col)
+    return printf("\<Esc>[%d;%d;%d;%d&w", a:code, a:down, a:row, a:col)
+endfunc
+
+func NettermEscapeCode(row, col)
+    return printf("\<Esc>}%d,%d\r", a:row, a:col)
+endfunc
+
+func MouseLeftClickCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(2, 4, a:row, a:col)
+  elseif &ttymouse ==# 'netterm'
+    return NettermEscapeCode(a:row, a:col)
+  else
+    return TerminalEscapeCode(0, a:row, a:col, 'M')
+  endif
+endfunc
+
+func MouseLeftClick(row, col)
+  call feedkeys(MouseLeftClickCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseMiddleClickCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(4, 2, a:row, a:col)
+  else
+    return TerminalEscapeCode(1, a:row, a:col, 'M')
+  endif
+endfunc
+
+func MouseMiddleClick(row, col)
+  call feedkeys(MouseMiddleClickCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseRightClickCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(6, 1, a:row, a:col)
+  else
+    return TerminalEscapeCode(2, a:row, a:col, 'M')
+  endif
+endfunc
+
+func MouseRightClick(row, col)
+  call feedkeys(MouseRightClickCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseCtrlLeftClickCode(row, col)
+  let ctrl = 0x10
+  return TerminalEscapeCode(0 + ctrl, a:row, a:col, 'M')
+endfunc
+
+func MouseCtrlLeftClick(row, col)
+  call feedkeys(MouseCtrlLeftClickCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseCtrlRightClickCode(row, col)
+  let ctrl = 0x10
+  return TerminalEscapeCode(2 + ctrl, a:row, a:col, 'M')
+endfunc
+
+func MouseCtrlRightClick(row, col)
+  call feedkeys(MouseCtrlRightClickCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseLeftReleaseCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(3, 0, a:row, a:col)
+  elseif &ttymouse ==# 'netterm'
+    return ''
+  else
+    return TerminalEscapeCode(3, a:row, a:col, 'm')
+  endif
+endfunc
+
+func MouseLeftRelease(row, col)
+  call feedkeys(MouseLeftReleaseCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseMiddleReleaseCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(5, 0, a:row, a:col)
+  else
+    return TerminalEscapeCode(3, a:row, a:col, 'm')
+  endif
+endfunc
+
+func MouseMiddleRelease(row, col)
+  call feedkeys(MouseMiddleReleaseCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseRightReleaseCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(7, 0, a:row, a:col)
+  else
+    return TerminalEscapeCode(3, a:row, a:col, 'm')
+  endif
+endfunc
+
+func MouseRightRelease(row, col)
+  call feedkeys(MouseRightReleaseCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseLeftDragCode(row, col)
+  if &ttymouse ==# 'dec'
+    return DecEscapeCode(1, 4, a:row, a:col)
+  else
+    return TerminalEscapeCode(0x20, a:row, a:col, 'M')
+  endif
+endfunc
+
+func MouseLeftDrag(row, col)
+  call feedkeys(MouseLeftDragCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseWheelUpCode(row, col)
+  return TerminalEscapeCode(0x40, a:row, a:col, 'M')
+endfunc
+
+func MouseWheelUp(row, col)
+  call feedkeys(MouseWheelUpCode(a:row, a:col), 'Lx!')
+endfunc
+
+func MouseWheelDownCode(row, col)
+  return TerminalEscapeCode(0x41, a:row, a:col, 'M')
+endfunc
+
+func MouseWheelDown(row, col)
+  call feedkeys(MouseWheelDownCode(a:row, a:col), 'Lx!')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -257,22 +257,6 @@ func Test_edit_09()
   bw!
 endfunc
 
-func Test_edit_10()
-  " Test for starting selectmode
-  new
-  set selectmode=key keymodel=startsel
-  call setline(1, ['abc', 'def', 'ghi'])
-  call cursor(1, 4)
-  call feedkeys("A\<s-home>start\<esc>", 'txin')
-  call assert_equal(['startdef', 'ghi'], getline(1, '$'))
-  " start select mode again with gv
-  set selectmode=cmd
-  call feedkeys('gvabc', 'xt')
-  call assert_equal('abctdef', getline(1))
-  set selectmode= keymodel=
-  bw!
-endfunc
-
 func Test_edit_11()
   " Test that indenting kicks in
   new
--- a/src/testdir/test_global.vim
+++ b/src/testdir/test_global.vim
@@ -5,7 +5,10 @@ func Test_yank_put_clipboard()
   set clipboard=unnamed
   g/^/normal yyp
   call assert_equal(['a', 'a', 'b', 'b', 'c', 'c'], getline(1, 6))
-
+  set clipboard=unnamed,unnamedplus
+  call setline(1, ['a', 'b', 'c'])
+  g/^/normal yyp
+  call assert_equal(['a', 'a', 'b', 'b', 'c', 'c'], getline(1, 6))
   set clipboard&
   bwipe!
 endfunc
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_modeless.vim
@@ -0,0 +1,397 @@
+" Test for modeless selection
+
+" This only works for Unix in a terminal
+source check.vim
+CheckNotGui
+CheckUnix
+
+source mouse.vim
+
+" Test for modeless characterwise selection (single click)
+func Test_modeless_characterwise_selection()
+  CheckFeature clipboard_working
+  let save_mouse = &mouse
+  let save_term = &term
+  let save_ttymouse = &ttymouse
+  call test_override('no_query_mouse', 1)
+  set mouse=a term=xterm mousetime=200
+  new
+  call setline(1, ['one two three', 'foo bar baz'])
+  redraw!
+
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
+    let msg = 'ttymouse=' .. ttymouse_val
+    exe 'set ttymouse=' .. ttymouse_val
+
+    " select multiple characters within a line
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 6)
+    let keys ..= MouseLeftDragCode(1, 10)
+    let keys ..= MouseLeftReleaseCode(1, 10)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("wo th", @*, msg)
+
+    " select multiple characters including the end of line
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 11)
+    let keys ..= MouseLeftDragCode(1, 16)
+    let keys ..= MouseLeftReleaseCode(1, 16)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("ree\n", @*, msg)
+
+    " extend a selection using right mouse click
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    set mousemodel=extend
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 2)
+    let keys ..= MouseLeftDragCode(1, 5)
+    let keys ..= MouseLeftReleaseCode(1, 5)
+    let keys ..= MouseRightClickCode(1, 10)
+    let keys ..= MouseRightReleaseCode(1, 10)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("ne two th", @*, msg)
+    set mousemodel&
+
+    " extend a selection backwards using right mouse click
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    set mousemodel=extend
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 7)
+    let keys ..= MouseLeftDragCode(1, 11)
+    let keys ..= MouseLeftReleaseCode(1, 11)
+    let keys ..= MouseRightClickCode(1, 3)
+    let keys ..= MouseRightReleaseCode(1, 3)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("e two thr", @*, msg)
+    set mousemodel&
+
+    " select multiple characters within a line backwards
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 9)
+    let keys ..= MouseLeftDragCode(1, 3)
+    let keys ..= MouseLeftReleaseCode(1, 3)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("e two t", @*, msg)
+
+    " select multiple characters across lines with (end row > start row) and
+    " (end column < start column)
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 9)
+    let keys ..= MouseLeftDragCode(2, 3)
+    let keys ..= MouseLeftReleaseCode(2, 3)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("three\nfoo", @*, msg)
+
+    " select multiple characters across lines with (end row > start row) and
+    " (end column > start column)
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 4)
+    let keys ..= MouseLeftDragCode(2, 8)
+    let keys ..= MouseLeftReleaseCode(2, 8)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal(" two three\nfoo bar ", @*, msg)
+
+    " select multiple characters across lines with (end row < start row) and
+    " (end column < start column)
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 7)
+    let keys ..= MouseLeftDragCode(1, 5)
+    let keys ..= MouseLeftReleaseCode(1, 5)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("two three\nfoo bar", @*, msg)
+
+    " select multiple characters across lines with (end row < start row) and
+    " (end column > start column)
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 11)
+    let keys ..= MouseLeftDragCode(1, 13)
+    let keys ..= MouseLeftReleaseCode(1, 13)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("e\nfoo bar baz", @*, msg)
+
+    " select multiple characters across lines with (end row < start row) and
+    " the end column is greater than the line length
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 7)
+    let keys ..= MouseLeftDragCode(1, 16)
+    let keys ..= MouseLeftReleaseCode(1, 16)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("\nfoo bar", @*, msg)
+
+    " select multiple characters across lines with start/end row and start/end
+    " column outside the lines in the buffer
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(4, 3)
+    let keys ..= MouseLeftDragCode(3, 2)
+    let keys ..= MouseLeftReleaseCode(3, 2)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("\n~  ", @*, msg)
+
+    " change selection using right mouse click within the selected text
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    set mousemodel=extend
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 5)
+    let keys ..= MouseLeftDragCode(1, 13)
+    let keys ..= MouseLeftReleaseCode(1, 13)
+    let keys ..= MouseRightClickCode(1, 7)
+    let keys ..= MouseRightReleaseCode(1, 7)
+    let keys ..= MouseRightClickCode(1, 11)
+    let keys ..= MouseRightReleaseCode(1, 11)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("o thr", @*, msg)
+    set mousemodel&
+
+    " select text multiple times at different places
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 3)
+    let keys ..= MouseLeftDragCode(1, 5)
+    let keys ..= MouseLeftReleaseCode(1, 5)
+    let keys ..= MouseLeftClickCode(2, 7)
+    let keys ..= MouseLeftDragCode(2, 9)
+    let keys ..= MouseLeftReleaseCode(2, 9)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("r b", @*, msg)
+
+    " Test for 'clipboard' set to 'autoselectml' to automatically copy the
+    " modeless selection to the clipboard
+    set clipboard=autoselectml
+    let @* = ''
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 5)
+    let keys ..= MouseLeftDragCode(2, 7)
+    let keys ..= MouseLeftReleaseCode(2, 7)
+    let keys ..= "\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("bar", @*)
+    set clipboard&
+
+    " quadruple click should start characterwise selectmode
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 10)
+    let keys ..= MouseLeftReleaseCode(1, 10)
+    let keys ..= MouseLeftClickCode(1, 10)
+    let keys ..= MouseLeftReleaseCode(1, 10)
+    let keys ..= MouseLeftClickCode(1, 10)
+    let keys ..= MouseLeftReleaseCode(1, 10)
+    let keys ..= MouseLeftClickCode(1, 10)
+    let keys ..= MouseLeftDragCode(1, 11)
+    let keys ..= MouseLeftReleaseCode(1, 11)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("hree", @*, msg)
+  endfor
+
+  let &mouse = save_mouse
+  let &term = save_term
+  let &ttymouse = save_ttymouse
+  set mousetime&
+  call test_override('no_query_mouse', 0)
+  close!
+endfunc
+
+" Test for modeless word selection (double click)
+func Test_modeless_word_selection()
+  CheckFeature clipboard_working
+  let save_mouse = &mouse
+  let save_term = &term
+  let save_ttymouse = &ttymouse
+  call test_override('no_query_mouse', 1)
+  set mouse=a term=xterm mousetime=200
+  new
+  call setline(1, ['one two three', 'foo bar baz'])
+  redraw!
+
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
+    let msg = 'ttymouse=' .. ttymouse_val
+    exe 'set ttymouse=' .. ttymouse_val
+
+    " select multiple words within a line
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 6)
+    let keys ..= MouseLeftReleaseCode(1, 6)
+    let keys ..= MouseLeftClickCode(1, 6)
+    let keys ..= MouseLeftDragCode(1, 10)
+    let keys ..= MouseLeftReleaseCode(1, 10)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("two three", @*, msg)
+
+    " select a single word
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 6)
+    let keys ..= MouseLeftReleaseCode(2, 6)
+    let keys ..= MouseLeftClickCode(2, 6)
+    let keys ..= MouseLeftReleaseCode(2, 6)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("bar", @*, msg)
+
+    " select multiple words backwards within a line
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 11)
+    let keys ..= MouseLeftReleaseCode(2, 11)
+    let keys ..= MouseLeftClickCode(2, 11)
+    let keys ..= MouseLeftDragCode(2, 7)
+    let keys ..= MouseLeftReleaseCode(2, 7)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("bar baz", @*, msg)
+
+    " select multiple words backwards across lines
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 7)
+    let keys ..= MouseLeftReleaseCode(2, 7)
+    let keys ..= MouseLeftClickCode(2, 7)
+    let keys ..= MouseLeftDragCode(1, 6)
+    let keys ..= MouseLeftReleaseCode(1, 6)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("two three\nfoo bar", @*, msg)
+  endfor
+
+  let &mouse = save_mouse
+  let &term = save_term
+  let &ttymouse = save_ttymouse
+  set mousetime&
+  call test_override('no_query_mouse', 0)
+  close!
+endfunc
+
+" Test for modeless line selection (triple click)
+func Test_modeless_line_selection()
+  CheckFeature clipboard_working
+  let save_mouse = &mouse
+  let save_term = &term
+  let save_ttymouse = &ttymouse
+  call test_override('no_query_mouse', 1)
+  set mouse=a term=xterm mousetime=200
+  new
+  call setline(1, ['one two three', 'foo bar baz'])
+  redraw!
+
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
+    let msg = 'ttymouse=' .. ttymouse_val
+    exe 'set ttymouse=' .. ttymouse_val
+
+    " select single line
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 6)
+    let keys ..= MouseLeftReleaseCode(2, 6)
+    let keys ..= MouseLeftClickCode(2, 6)
+    let keys ..= MouseLeftReleaseCode(2, 6)
+    let keys ..= MouseLeftClickCode(2, 6)
+    let keys ..= MouseLeftReleaseCode(2, 6)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("foo bar baz\n", @*, msg)
+
+    " select multiple lines
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(1, 6)
+    let keys ..= MouseLeftReleaseCode(1, 6)
+    let keys ..= MouseLeftClickCode(1, 6)
+    let keys ..= MouseLeftReleaseCode(1, 6)
+    let keys ..= MouseLeftClickCode(1, 6)
+    let keys ..= MouseLeftDragCode(2, 12)
+    let keys ..= MouseLeftReleaseCode(2, 12)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("one two three\nfoo bar baz\n", @*, msg)
+
+    " select multiple lines backwards
+    let @* = ''
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+    let keys = ":"
+    let keys ..= MouseLeftClickCode(2, 10)
+    let keys ..= MouseLeftReleaseCode(2, 10)
+    let keys ..= MouseLeftClickCode(2, 10)
+    let keys ..= MouseLeftReleaseCode(2, 10)
+    let keys ..= MouseLeftClickCode(2, 10)
+    let keys ..= MouseLeftDragCode(1, 3)
+    let keys ..= MouseLeftReleaseCode(1, 3)
+    let keys ..= "\<C-Y>\<CR>"
+    call feedkeys(keys, "x")
+    call assert_equal("one two three\nfoo bar baz\n", @*, msg)
+  endfor
+
+  let &mouse = save_mouse
+  let &term = save_term
+  let &ttymouse = save_ttymouse
+  set mousetime&
+  call test_override('no_query_mouse', 0)
+  close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -121,30 +121,6 @@ func Test_normal01_keymodel()
   bw!
 endfunc
 
-" Test for select mode
-func Test_normal02_selectmode()
-  call Setup_NewWindow()
-  50
-  norm! gHy
-  call assert_equal('y51', getline('.'))
-  call setline(1, range(1,100))
-  50
-  exe ":norm! V9jo\<c-g>y"
-  call assert_equal('y60', getline('.'))
-  " clean up
-  bw!
-endfunc
-
-func Test_normal02_selectmode2()
-  " some basic select mode tests
-  call Setup_NewWindow()
-  50
-  call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
-  call assert_equal('c51', getline('.'))
-  " clean up
-  bw!
-endfunc
-
 func Test_normal03_join()
   " basic join test
   call Setup_NewWindow()
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_selectmode.vim
@@ -0,0 +1,255 @@
+" Test for Select-mode
+
+" This only works for Unix in a terminal
+source check.vim
+CheckNotGui
+CheckUnix
+
+source mouse.vim
+
+" Test for select mode
+func Test_selectmode_basic()
+  new
+  call setline(1, range(1,100))
+  50
+  norm! gHy
+  call assert_equal('y51', getline('.'))
+  call setline(1, range(1,100))
+  50
+  exe ":norm! V9jo\<c-g>y"
+  call assert_equal('y60', getline('.'))
+  call setline(1, range(1,100))
+  50
+  call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+  call assert_equal('c51', getline('.'))
+  " clean up
+  bw!
+endfunc
+
+" Test for starting selectmode
+func Test_selectmode_start()
+  new
+  set selectmode=key keymodel=startsel
+  call setline(1, ['abc', 'def', 'ghi'])
+  call cursor(1, 4)
+  call feedkeys("A\<s-home>start\<esc>", 'txin')
+  call assert_equal(['startdef', 'ghi'], getline(1, '$'))
+  " start select mode again with gv
+  set selectmode=cmd
+  call feedkeys('gvabc', 'xt')
+  call assert_equal('abctdef', getline(1))
+  set selectmode= keymodel=
+  bw!
+endfunc
+
+" Test for characterwise select mode
+func Test_characterwise_select_mode()
+  new
+
+  " Select mode maps
+  snoremap <lt>End> <End>
+  snoremap <lt>Down> <Down>
+  snoremap <lt>Del> <Del>
+
+  " characterwise select mode: delete middle line
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal Gkkgh\<End>\<Del>"
+  call assert_equal(['', 'b', 'c'], getline(1, '$'))
+
+  " characterwise select mode: delete middle two lines
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal Gkkgh\<Down>\<End>\<Del>"
+  call assert_equal(['', 'c'], getline(1, '$'))
+
+  " characterwise select mode: delete last line
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal Ggh\<End>\<Del>"
+  call assert_equal(['', 'a', 'b', ''], getline(1, '$'))
+
+  " characterwise select mode: delete last two lines
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal Gkgh\<Down>\<End>\<Del>"
+  call assert_equal(['', 'a', ''], getline(1, '$'))
+
+  " CTRL-H in select mode behaves like 'x'
+  call setline(1, 'abcdef')
+  exe "normal! gggh\<Right>\<Right>\<Right>\<C-H>"
+  call assert_equal('ef', getline(1))
+
+  " CTRL-O in select mode switches to visual mode for one command
+  call setline(1, 'abcdef')
+  exe "normal! gggh\<C-O>3lm"
+  call assert_equal('mef', getline(1))
+
+  sunmap <lt>End>
+  sunmap <lt>Down>
+  sunmap <lt>Del>
+  bwipe!
+endfunc
+
+" Test for linewise select mode
+func Test_linewise_select_mode()
+  new
+
+  " linewise select mode: delete middle line
+  call append('$', ['a', 'b', 'c'])
+  exe "normal GkkgH\<Del>"
+  call assert_equal(['', 'b', 'c'], getline(1, '$'))
+
+  " linewise select mode: delete middle two lines
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal GkkgH\<Down>\<Del>"
+  call assert_equal(['', 'c'], getline(1, '$'))
+
+  " linewise select mode: delete last line
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal GgH\<Del>"
+  call assert_equal(['', 'a', 'b'], getline(1, '$'))
+
+  " linewise select mode: delete last two lines
+  call deletebufline('', 1, '$')
+  call append('$', ['a', 'b', 'c'])
+  exe "normal GkgH\<Down>\<Del>"
+  call assert_equal(['', 'a'], getline(1, '$'))
+
+  bwipe!
+endfunc
+
+" Test for blockwise select mode (g CTRL-H)
+func Test_blockwise_select_mode()
+  new
+  call setline(1, ['foo', 'bar'])
+  call feedkeys("g\<BS>\<Right>\<Down>mm", 'xt')
+  call assert_equal(['mmo', 'mmr'], getline(1, '$'))
+  close!
+endfunc
+
+" Test for using visual mode maps in select mode
+func Test_select_mode_map()
+  new
+  vmap <buffer> <F2> 3l
+  call setline(1, 'Test line')
+  call feedkeys("gh\<F2>map", 'xt')
+  call assert_equal('map line', getline(1))
+
+  vmap <buffer> <F2> ygV
+  call feedkeys("0gh\<Right>\<Right>\<F2>cwabc", 'xt')
+  call assert_equal('abc line', getline(1))
+
+  vmap <buffer> <F2> :<C-U>let v=100<CR>
+  call feedkeys("gggh\<Right>\<Right>\<F2>foo", 'xt')
+  call assert_equal('foo line', getline(1))
+
+  " reselect the select mode using gv from a visual mode map
+  vmap <buffer> <F2> gv
+  set selectmode=cmd
+  call feedkeys("0gh\<F2>map", 'xt')
+  call assert_equal('map line', getline(1))
+  set selectmode&
+
+  close!
+endfunc
+
+" Test double/triple/quadruple click to start 'select' mode
+func Test_term_mouse_multiple_clicks_to_select_mode()
+  let save_mouse = &mouse
+  let save_term = &term
+  let save_ttymouse = &ttymouse
+  call test_override('no_query_mouse', 1)
+  set mouse=a term=xterm mousetime=200
+  set selectmode=mouse
+  new
+
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
+    let msg = 'ttymouse=' .. ttymouse_val
+    exe 'set ttymouse=' .. ttymouse_val
+
+    " Single-click and drag should 'select' the characters
+    call setline(1, ['foo [foo bar] foo', 'foo'])
+    call MouseLeftClick(1, 3)
+    call assert_equal(0, getcharmod(), msg)
+    call MouseLeftDrag(1, 13)
+    call MouseLeftRelease(1, 13)
+    norm! o
+    call assert_equal(['foo foo', 'foo'], getline(1, '$'), msg)
+
+    " Double-click on word should visually 'select' the word.
+    call setline(1, ['foo [foo bar] foo', 'foo'])
+    call MouseLeftClick(1, 2)
+    call assert_equal(0, getcharmod(), msg)
+    call MouseLeftRelease(1, 2)
+    call MouseLeftClick(1, 2)
+    call assert_equal(32, getcharmod(), msg) " double-click
+    call MouseLeftRelease(1, 2)
+    call assert_equal('s', mode(), msg)
+    norm! bar
+    call assert_equal(['bar [foo bar] foo', 'foo'], getline(1, '$'), msg)
+
+    " Double-click on opening square bracket should visually
+    " 'select' the whole [foo bar].
+    call setline(1, ['foo [foo bar] foo', 'foo'])
+    call MouseLeftClick(1, 5)
+    call assert_equal(0, getcharmod(), msg)
+    call MouseLeftRelease(1, 5)
+    call MouseLeftClick(1, 5)
+    call assert_equal(32, getcharmod(), msg) " double-click
+    call MouseLeftRelease(1, 5)
+    call assert_equal('s', mode(), msg)
+    norm! bar
+    call assert_equal(['foo bar foo', 'foo'], getline(1, '$'), msg)
+
+    " To guarantee that the next click is not counted as a triple click
+    call MouseRightClick(1, 1)
+    call MouseRightRelease(1, 1)
+
+    " Triple-click should visually 'select' the whole line.
+    call setline(1, ['foo [foo bar] foo', 'foo'])
+    call MouseLeftClick(1, 3)
+    call assert_equal(0, getcharmod(), msg)
+    call MouseLeftRelease(1, 3)
+    call MouseLeftClick(1, 3)
+    call assert_equal(32, getcharmod(), msg) " double-click
+    call MouseLeftRelease(1, 3)
+    call MouseLeftClick(1, 3)
+    call assert_equal(64, getcharmod(), msg) " triple-click
+    call MouseLeftRelease(1, 3)
+    call assert_equal('S', mode(), msg)
+    norm! baz
+    call assert_equal(['bazfoo'], getline(1, '$'), msg)
+
+    " Quadruple-click should start visual block 'select'.
+    call setline(1, ['aaaaaa', 'bbbbbb'])
+    call MouseLeftClick(1, 2)
+    call assert_equal(0, getcharmod(), msg)
+    call MouseLeftRelease(1, 2)
+    call MouseLeftClick(1, 2)
+    call assert_equal(32, getcharmod(), msg) " double-click
+    call MouseLeftRelease(1, 2)
+    call MouseLeftClick(1, 2)
+    call assert_equal(64, getcharmod(), msg) " triple-click
+    call MouseLeftRelease(1, 2)
+    call MouseLeftClick(1, 2)
+    call assert_equal(96, getcharmod(), msg) " quadruple-click
+    call MouseLeftDrag(2, 4)
+    call MouseLeftRelease(2, 4)
+    call assert_equal("\<c-s>", mode(), msg)
+    norm! x
+    call assert_equal(['axaa', 'bxbb'], getline(1, '$'), msg)
+  endfor
+
+  let &mouse = save_mouse
+  let &term = save_term
+  let &ttymouse = save_ttymouse
+  set mousetime&
+  set selectmode&
+  call test_override('no_query_mouse', 0)
+  bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_termcodes.vim
+++ b/src/testdir/test_termcodes.vim
@@ -6,175 +6,7 @@ CheckNotGui
 CheckUnix
 
 source shared.vim
-
-" xterm2 and sgr always work, urxvt is optional.
-let s:ttymouse_values = ['xterm2', 'sgr']
-if has('mouse_urxvt')
-  call add(s:ttymouse_values, 'urxvt')
-endif
-
-" dec doesn't support all the functionality
-if has('mouse_dec')
-  let s:ttymouse_dec = ['dec']
-else
-  let s:ttymouse_dec = []
-endif
-
-" netterm only supports left click
-if has('mouse_netterm')
-  let s:ttymouse_netterm = ['netterm']
-else
-  let s:ttymouse_netterm = []
-endif
-
-" Helper function to emit a terminal escape code.
-func TerminalEscapeCode(code, row, col, m)
-  if &ttymouse ==# 'xterm2'
-    " need to use byte encoding here.
-    let str = list2str([a:code + 0x20, a:col + 0x20, a:row + 0x20])
-    if has('iconv')
-      let bytes = str->iconv('utf-8', 'latin1')
-    else
-      " Hopefully the numbers are not too big.
-      let bytes = str
-    endif
-    return "\<Esc>[M" .. bytes
-  elseif &ttymouse ==# 'sgr'
-    return printf("\<Esc>[<%d;%d;%d%s", a:code, a:col, a:row, a:m)
-  elseif &ttymouse ==# 'urxvt'
-    return printf("\<Esc>[%d;%d;%dM", a:code + 0x20, a:col, a:row)
-  endif
-endfunc
-
-func DecEscapeCode(code, down, row, col)
-    return printf("\<Esc>[%d;%d;%d;%d&w", a:code, a:down, a:row, a:col)
-endfunc
-
-func NettermEscapeCode(row, col)
-    return printf("\<Esc>}%d,%d\r", a:row, a:col)
-endfunc
-
-func MouseLeftClickCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(2, 4, a:row, a:col)
-  elseif &ttymouse ==# 'netterm'
-    return NettermEscapeCode(a:row, a:col)
-  else
-    return TerminalEscapeCode(0, a:row, a:col, 'M')
-  endif
-endfunc
-
-func MouseLeftClick(row, col)
-  call feedkeys(MouseLeftClickCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseMiddleClickCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(4, 2, a:row, a:col)
-  else
-    return TerminalEscapeCode(1, a:row, a:col, 'M')
-  endif
-endfunc
-
-func MouseMiddleClick(row, col)
-  call feedkeys(MouseMiddleClickCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseRightClickCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(6, 1, a:row, a:col)
-  else
-    return TerminalEscapeCode(2, a:row, a:col, 'M')
-  endif
-endfunc
-
-func MouseRightClick(row, col)
-  call feedkeys(MouseRightClickCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseCtrlLeftClickCode(row, col)
-  let ctrl = 0x10
-  return TerminalEscapeCode(0 + ctrl, a:row, a:col, 'M')
-endfunc
-
-func MouseCtrlLeftClick(row, col)
-  call feedkeys(MouseCtrlLeftClickCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseCtrlRightClickCode(row, col)
-  let ctrl = 0x10
-  return TerminalEscapeCode(2 + ctrl, a:row, a:col, 'M')
-endfunc
-
-func MouseCtrlRightClick(row, col)
-  call feedkeys(MouseCtrlRightClickCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseLeftReleaseCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(3, 0, a:row, a:col)
-  elseif &ttymouse ==# 'netterm'
-    return ''
-  else
-    return TerminalEscapeCode(3, a:row, a:col, 'm')
-  endif
-endfunc
-
-func MouseLeftRelease(row, col)
-  call feedkeys(MouseLeftReleaseCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseMiddleReleaseCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(5, 0, a:row, a:col)
-  else
-    return TerminalEscapeCode(3, a:row, a:col, 'm')
-  endif
-endfunc
-
-func MouseMiddleRelease(row, col)
-  call feedkeys(MouseMiddleReleaseCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseRightReleaseCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(7, 0, a:row, a:col)
-  else
-    return TerminalEscapeCode(3, a:row, a:col, 'm')
-  endif
-endfunc
-
-func MouseRightRelease(row, col)
-  call feedkeys(MouseRightReleaseCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseLeftDragCode(row, col)
-  if &ttymouse ==# 'dec'
-    return DecEscapeCode(1, 4, a:row, a:col)
-  else
-    return TerminalEscapeCode(0x20, a:row, a:col, 'M')
-  endif
-endfunc
-
-func MouseLeftDrag(row, col)
-  call feedkeys(MouseLeftDragCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseWheelUpCode(row, col)
-  return TerminalEscapeCode(0x40, a:row, a:col, 'M')
-endfunc
-
-func MouseWheelUp(row, col)
-  call feedkeys(MouseWheelUpCode(a:row, a:col), 'Lx!')
-endfunc
-
-func MouseWheelDownCode(row, col)
-  return TerminalEscapeCode(0x41, a:row, a:col, 'M')
-endfunc
-
-func MouseWheelDown(row, col)
-  call feedkeys(MouseWheelDownCode(a:row, a:col), 'Lx!')
-endfunc
+source mouse.vim
 
 func Test_term_mouse_left_click()
   new
@@ -185,7 +17,7 @@ func Test_term_mouse_left_click()
   set mouse=a term=xterm
   call setline(1, ['line 1', 'line 2', 'line 3 is a bit longer'])
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec + s:ttymouse_netterm
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     go
@@ -215,7 +47,7 @@ func Test_xterm_mouse_right_click_extend
   set mouse=a term=xterm
 
   for visual_mode in ["v", "V", "\<C-V>"]
-    for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+    for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
       let msg = 'visual=' .. visual_mode .. ' ttymouse=' .. ttymouse_val
       exe 'set ttymouse=' .. ttymouse_val
 
@@ -284,7 +116,7 @@ func Test_xterm_mouse_ctrl_click()
   let save_ttymouse = &ttymouse
   set mouse=a term=xterm
 
-  for ttymouse_val in s:ttymouse_values
+  for ttymouse_val in g:Ttymouse_values
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     help
@@ -322,7 +154,7 @@ func Test_term_mouse_middle_click()
   let @* = 'abc'
   set mouse=a term=xterm
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     call setline(1, ['123456789', '123456789'])
@@ -366,7 +198,7 @@ func Test_1xterm_mouse_wheel()
   set mouse=a term=xterm
   call setline(1, range(1, 100))
 
-  for ttymouse_val in s:ttymouse_values
+  for ttymouse_val in g:Ttymouse_values
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     go
@@ -413,7 +245,7 @@ func Test_term_mouse_drag_beyond_window(
   wincmd j
   2split
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
 
@@ -490,7 +322,7 @@ func Test_term_mouse_drag_window_separat
   call test_override('no_query_mouse', 1)
   set mouse=a term=xterm
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
 
@@ -549,7 +381,7 @@ func Test_term_mouse_drag_statusline()
   let save_laststatus = &laststatus
   set mouse=a term=xterm laststatus=2
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
 
@@ -592,7 +424,7 @@ func Test_term_mouse_click_tab()
   set mouse=a term=xterm
   let row = 1
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec + s:ttymouse_netterm
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     e Xfoo
@@ -642,7 +474,7 @@ func Test_term_mouse_click_X_to_close_ta
   let row = 1
   let col = &columns
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec + s:ttymouse_netterm
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec + g:Ttymouse_netterm
     if ttymouse_val ==# 'xterm2' && col > 223
       " When 'ttymouse' is 'xterm2', row/col bigger than 223 are not supported.
       continue
@@ -690,7 +522,7 @@ func Test_term_mouse_drag_to_move_tab()
   set mouse=a term=xterm mousetime=1
   let row = 1
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     e Xtab1
@@ -744,7 +576,7 @@ func Test_term_mouse_double_click_to_cre
   let row = 1
   let col = 10
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     e Xtab1
@@ -797,7 +629,7 @@ func Test_term_mouse_multiple_clicks_to_
   set mouse=a term=xterm mousetime=200
   new
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
     call setline(1, ['foo [foo bar] foo', 'foo'])
@@ -925,7 +757,7 @@ func Test_term_mouse_click_in_cmdline_to
   set mouse=a term=xterm
   let row = &lines
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
 
@@ -958,7 +790,7 @@ func Test_term_mouse_middle_click_in_cmd
   let col = 1
   let @* = 'paste'
 
-  for ttymouse_val in s:ttymouse_values + s:ttymouse_dec
+  for ttymouse_val in g:Ttymouse_values + g:Ttymouse_dec
     let msg = 'ttymouse=' .. ttymouse_val
     exe 'set ttymouse=' .. ttymouse_val
 
@@ -995,7 +827,7 @@ func Test_mouse_popup_menu()
   menu PopUp.bar :let g:menustr = 'bar'<CR>
   menu PopUp.baz :let g:menustr = 'baz'<CR>
 
-  for ttymouse_val in s:ttymouse_values
+  for ttymouse_val in g:Ttymouse_values
     exe 'set ttymouse=' .. ttymouse_val
     let g:menustr = ''
     call feedkeys(MouseRightClickCode(1, 4)
--- a/src/testdir/test_visual.vim
+++ b/src/testdir/test_visual.vim
@@ -618,92 +618,6 @@ func Test_characterwise_visual_mode()
   bwipe!
 endfunc
 
-func Test_characterwise_select_mode()
-  new
-
-  " Select mode maps
-  snoremap <lt>End> <End>
-  snoremap <lt>Down> <Down>
-  snoremap <lt>Del> <Del>
-
-  " characterwise select mode: delete middle line
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal Gkkgh\<End>\<Del>"
-  call assert_equal(['', 'b', 'c'], getline(1, '$'))
-
-  " characterwise select mode: delete middle two lines
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal Gkkgh\<Down>\<End>\<Del>"
-  call assert_equal(['', 'c'], getline(1, '$'))
-
-  " characterwise select mode: delete last line
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal Ggh\<End>\<Del>"
-  call assert_equal(['', 'a', 'b', ''], getline(1, '$'))
-
-  " characterwise select mode: delete last two lines
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal Gkgh\<Down>\<End>\<Del>"
-  call assert_equal(['', 'a', ''], getline(1, '$'))
-
-  " CTRL-H in select mode behaves like 'x'
-  call setline(1, 'abcdef')
-  exe "normal! gggh\<Right>\<Right>\<Right>\<C-H>"
-  call assert_equal('ef', getline(1))
-
-  " CTRL-O in select mode switches to visual mode for one command
-  call setline(1, 'abcdef')
-  exe "normal! gggh\<C-O>3lm"
-  call assert_equal('mef', getline(1))
-
-  sunmap <lt>End>
-  sunmap <lt>Down>
-  sunmap <lt>Del>
-  bwipe!
-endfunc
-
-func Test_linewise_select_mode()
-  new
-
-  " linewise select mode: delete middle line
-  call append('$', ['a', 'b', 'c'])
-  exe "normal GkkgH\<Del>"
-  call assert_equal(['', 'b', 'c'], getline(1, '$'))
-
-  " linewise select mode: delete middle two lines
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal GkkgH\<Down>\<Del>"
-  call assert_equal(['', 'c'], getline(1, '$'))
-
-  " linewise select mode: delete last line
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal GgH\<Del>"
-  call assert_equal(['', 'a', 'b'], getline(1, '$'))
-
-  " linewise select mode: delete last two lines
-  call deletebufline('', 1, '$')
-  call append('$', ['a', 'b', 'c'])
-  exe "normal GkgH\<Down>\<Del>"
-  call assert_equal(['', 'a'], getline(1, '$'))
-
-  bwipe!
-endfunc
-
-" Test for blockwise select mode (g CTRL-H)
-func Test_blockwise_select_mode()
-  new
-  call setline(1, ['foo', 'bar'])
-  call feedkeys("g\<BS>\<Right>\<Down>mm", 'xt')
-  call assert_equal(['mmo', 'mmr'], getline(1, '$'))
-  close!
-endfunc
-
 func Test_visual_mode_put()
   new
 
@@ -743,16 +657,16 @@ func Test_visual_mode_put()
   bwipe!
 endfunc
 
-func Test_select_mode_gv()
+func Test_gv_with_exclusive_selection()
   new
 
-  " gv in exclusive select mode after operation
+  " gv with exclusive selection after an operation
   call append('$', ['zzz ', 'äà '])
   set selection=exclusive
   normal Gkv3lyjv3lpgvcxxx
   call assert_equal(['', 'zzz ', 'xxx '], getline(1, '$'))
 
-  " gv in exclusive select mode without operation
+  " gv with exclusive selection without an operation
   call deletebufline('', 1, '$')
   call append('$', 'zzz ')
   set selection=exclusive
@@ -940,32 +854,6 @@ func Test_star_register()
   close!
 endfunc
 
-" Test for using visual mode maps in select mode
-func Test_select_mode_map()
-  new
-  vmap <buffer> <F2> 3l
-  call setline(1, 'Test line')
-  call feedkeys("gh\<F2>map", 'xt')
-  call assert_equal('map line', getline(1))
-
-  vmap <buffer> <F2> ygV
-  call feedkeys("0gh\<Right>\<Right>\<F2>cwabc", 'xt')
-  call assert_equal('abc line', getline(1))
-
-  vmap <buffer> <F2> :<C-U>let v=100<CR>
-  call feedkeys("gggh\<Right>\<Right>\<F2>foo", 'xt')
-  call assert_equal('foo line', getline(1))
-
-  " reselect the select mode using gv from a visual mode map
-  vmap <buffer> <F2> gv
-  set selectmode=cmd
-  call feedkeys("0gh\<F2>map", 'xt')
-  call assert_equal('map line', getline(1))
-  set selectmode&
-
-  close!
-endfunc
-
 " Test for changing text in visual mode with 'exclusive' selection
 func Test_exclusive_selection()
   new
--- a/src/ui.c
+++ b/src/ui.c
@@ -1046,7 +1046,7 @@ clip_modeless(int button, int is_click, 
     else if (is_drag)
     {
 	// Don't try extending a selection if there isn't one.  Happens when
-	// button-down is in the cmdline and them moving mouse upwards.
+	// button-down is in the cmdline and then moving mouse upwards.
 	if (clip_star.state != SELECT_CLEARED)
 	    clip_process_selection(button, mouse_col, mouse_row, repeat);
     }
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    425,
+/**/
     424,
 /**/
     423,