mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:9.1.0433: Wrong yanking with exclusive selection and ve=all (#28933)
Problem: Wrong yanking with exclusive selection and virtualedit=all,
and integer overflow when using getregion() on it.
Solution: Set coladd when decreasing column and 'virtualedit' is active.
Add more tests for getregion() with 'virtualedit' (zeertzjq).
closes: vim/vim#14830
701ad50a9e
This commit is contained in:
parent
cd48b72b60
commit
bdf15dbe69
@ -2913,24 +2913,13 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2
|
||||
}
|
||||
|
||||
if (*region_type == kMTCharWise) {
|
||||
// handle 'selection' == "exclusive"
|
||||
// Handle 'selection' == "exclusive".
|
||||
if (is_select_exclusive && !equalpos(*p1, *p2)) {
|
||||
if (p2->coladd > 0) {
|
||||
p2->coladd--;
|
||||
} else if (p2->col > 0) {
|
||||
p2->col--;
|
||||
mark_mb_adjustpos(curbuf, p2);
|
||||
} else if (p2->lnum > 1) {
|
||||
p2->lnum--;
|
||||
p2->col = ml_get_len(p2->lnum);
|
||||
if (p2->col > 0) {
|
||||
p2->col--;
|
||||
mark_mb_adjustpos(curbuf, p2);
|
||||
}
|
||||
}
|
||||
// When backing up to previous line, inclusive becomes false.
|
||||
*inclusive = !unadjust_for_sel_inner(p2);
|
||||
}
|
||||
// if fp2 is on NUL (empty line) inclusive becomes false
|
||||
if (*ml_get_pos(p2) == NUL && !virtual_op) {
|
||||
// If p2 is on NUL (end of line), inclusive becomes false.
|
||||
if (*inclusive && !virtual_op && *ml_get_pos(p2) == NUL) {
|
||||
*inclusive = false;
|
||||
}
|
||||
} else if (*region_type == kMTBlockWise) {
|
||||
|
@ -6014,26 +6014,37 @@ static void adjust_for_sel(cmdarg_T *cap)
|
||||
bool unadjust_for_sel(void)
|
||||
{
|
||||
if (*p_sel == 'e' && !equalpos(VIsual, curwin->w_cursor)) {
|
||||
pos_T *pp;
|
||||
if (lt(VIsual, curwin->w_cursor)) {
|
||||
pp = &curwin->w_cursor;
|
||||
} else {
|
||||
pp = &VIsual;
|
||||
}
|
||||
if (pp->coladd > 0) {
|
||||
pp->coladd--;
|
||||
} else if (pp->col > 0) {
|
||||
pp->col--;
|
||||
mark_mb_adjustpos(curbuf, pp);
|
||||
} else if (pp->lnum > 1) {
|
||||
pp->lnum--;
|
||||
pp->col = ml_get_len(pp->lnum);
|
||||
return true;
|
||||
}
|
||||
return unadjust_for_sel_inner(lt(VIsual, curwin->w_cursor)
|
||||
? &curwin->w_cursor : &VIsual);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Move position "*pp" back one character for 'selection' == "exclusive".
|
||||
///
|
||||
/// @return true when backed up to the previous line.
|
||||
bool unadjust_for_sel_inner(pos_T *pp)
|
||||
{
|
||||
colnr_T cs, ce;
|
||||
|
||||
if (pp->coladd > 0) {
|
||||
pp->coladd--;
|
||||
} else if (pp->col > 0) {
|
||||
pp->col--;
|
||||
mark_mb_adjustpos(curbuf, pp);
|
||||
if (virtual_active(curwin)) {
|
||||
getvcol(curwin, pp, &cs, NULL, &ce);
|
||||
pp->coladd = ce - cs;
|
||||
}
|
||||
} else if (pp->lnum > 1) {
|
||||
pp->lnum--;
|
||||
pp->col = ml_get_len(pp->lnum);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SELECT key in Normal or Visual mode: end of Select mode mapping.
|
||||
static void nv_select(cmdarg_T *cap)
|
||||
{
|
||||
|
@ -1635,6 +1635,22 @@ func Test_visual_substitute_visual()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_virtualedit_exclusive_selection()
|
||||
new
|
||||
set virtualedit=all selection=exclusive
|
||||
|
||||
call setline(1, "a\tb")
|
||||
normal! 0v8ly
|
||||
call assert_equal("a\t", getreg('"'))
|
||||
normal! 0v6ly
|
||||
call assert_equal('a ', getreg('"'))
|
||||
normal! 06lv2ly
|
||||
call assert_equal(' ', getreg('"'))
|
||||
|
||||
set virtualedit& selection&
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_visual_getregion()
|
||||
let lines =<< trim END
|
||||
new
|
||||
@ -2016,37 +2032,113 @@ func Test_visual_getregion()
|
||||
#" Exclusive selection 2
|
||||
new
|
||||
call setline(1, ["a\tc", "x\tz", '', ''])
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v2l", 'xt')
|
||||
call assert_equal(["a\t"],
|
||||
\ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v$G", 'xt')
|
||||
call assert_equal(["a\tc", "x\tz", ''],
|
||||
\ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
|
||||
\ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v$j", 'xt')
|
||||
call assert_equal(["a\tc", "x\tz"],
|
||||
\ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>\<C-v>$j", 'xt')
|
||||
call assert_equal(["a\tc", "x\tz"],
|
||||
\ getregion(getpos('v'), getpos('.'),
|
||||
\ {'exclusive': v:true, 'type': "\<C-v>" }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'),
|
||||
\ {'exclusive': v:true, 'type': "\<C-v>" }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>\<C-v>$G", 'xt')
|
||||
call assert_equal(["a", "x", '', ''],
|
||||
\ getregion(getpos('v'), getpos('.'),
|
||||
\ {'exclusive': v:true, 'type': "\<C-v>" }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 1, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 1, 0]],
|
||||
\ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 0]],
|
||||
\ [[bufnr('%'), 4, 0, 0], [bufnr('%'), 4, 0, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'),
|
||||
\ {'exclusive': v:true, 'type': "\<C-v>" }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>wv2j", 'xt')
|
||||
call assert_equal(["c", "x\tz"],
|
||||
\ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
|
||||
|
||||
#" virtualedit
|
||||
#" 'virtualedit' with exclusive selection
|
||||
set selection=exclusive
|
||||
set virtualedit=all
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>vj", 'xt')
|
||||
call assert_equal(["a\tc"],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v8l", 'xt')
|
||||
call assert_equal(["a\t"],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v6l", 'xt')
|
||||
call assert_equal(['a '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 5]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>6lv2l", 'xt')
|
||||
call assert_equal([' '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 2, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>lv2l", 'xt')
|
||||
call assert_equal([' '],
|
||||
@ -2106,9 +2198,106 @@ func Test_visual_getregion()
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
|
||||
set virtualedit&
|
||||
#" 'virtualedit' with inclusive selection
|
||||
set selection&
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>vj", 'xt')
|
||||
call assert_equal(["a\tc", 'x'],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 1, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v8l", 'xt')
|
||||
call assert_equal(["a\tc"],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>v6l", 'xt')
|
||||
call assert_equal(['a '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 6]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>6lv2l", 'xt')
|
||||
call assert_equal([' c'],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>lv2l", 'xt')
|
||||
call assert_equal([' '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 3]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>2lv2l", 'xt')
|
||||
call assert_equal([' '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 4]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call feedkeys('j', 'xt')
|
||||
call assert_equal([' c', 'x '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 4]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>6l\<C-v>2lj", 'xt')
|
||||
call assert_equal([' c', ' z'],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 3, 0]],
|
||||
\ [[bufnr('%'), 2, 2, 5], [bufnr('%'), 2, 3, 0]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>l\<C-v>2l2j", 'xt')
|
||||
call assert_equal([' ', ' ', ' '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 3]],
|
||||
\ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 3]],
|
||||
\ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 3]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
|
||||
call cursor(1, 1)
|
||||
call feedkeys("\<Esc>2l\<C-v>2l2j", 'xt')
|
||||
call assert_equal([' ', ' ', ' '],
|
||||
\ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
call assert_equal([
|
||||
\ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 4]],
|
||||
\ [[bufnr('%'), 2, 2, 1], [bufnr('%'), 2, 2, 4]],
|
||||
\ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 3]],
|
||||
\ ],
|
||||
\ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
|
||||
|
||||
set virtualedit&
|
||||
bwipe!
|
||||
END
|
||||
call CheckLegacyAndVim9Success(lines)
|
||||
|
Loading…
Reference in New Issue
Block a user