aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.c31
-rw-r--r--src/nvim/api/vim.c7
-rw-r--r--src/nvim/api/window.c32
-rw-r--r--src/nvim/buffer_defs.h4
-rw-r--r--src/nvim/normal.c12
-rw-r--r--src/nvim/ops.c33
-rw-r--r--src/nvim/ops.h15
-rw-r--r--src/nvim/regexp.c6
-rw-r--r--src/nvim/testdir/test_blockedit.vim1
-rw-r--r--src/nvim/testdir/test_normal.vim38
-rw-r--r--src/nvim/testdir/test_search.vim20
-rw-r--r--src/nvim/testdir/test_visual.vim270
-rw-r--r--src/nvim/window.c39
13 files changed, 431 insertions, 77 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 5abdc33709..4b1c2d4baa 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1645,7 +1645,7 @@ bool api_object_to_bool(Object obj, const char *what,
} else if (obj.type == kObjectTypeNil) {
return nil_value; // caller decides what NIL (missing retval in lua) means
} else {
- api_set_error(err, kErrorTypeValidation, "%s is not an boolean", what);
+ api_set_error(err, kErrorTypeValidation, "%s is not a boolean", what);
return false;
}
}
@@ -1868,7 +1868,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
}
bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
- Error *err)
+ bool new_win, Error *err)
{
// TODO(bfredl): use a get/has_key interface instead and get rid of extra
// flags
@@ -1968,24 +1968,15 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
}
has_bufpos = true;
} else if (!strcmp(key, "external")) {
- if (val.type == kObjectTypeInteger) {
- fconfig->external = val.data.integer;
- } else if (val.type == kObjectTypeBoolean) {
- fconfig->external = val.data.boolean;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'external' key must be Boolean");
+ has_external = fconfig->external
+ = api_object_to_bool(val, "'external' key", false, err);
+ if (ERROR_SET(err)) {
return false;
}
- has_external = fconfig->external;
} else if (!strcmp(key, "focusable")) {
- if (val.type == kObjectTypeInteger) {
- fconfig->focusable = val.data.integer;
- } else if (val.type == kObjectTypeBoolean) {
- fconfig->focusable = val.data.boolean;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'focusable' key must be Boolean");
+ fconfig->focusable
+ = api_object_to_bool(val, "'focusable' key", true, err);
+ if (ERROR_SET(err)) {
return false;
}
} else if (strequal(key, "zindex")) {
@@ -2015,6 +2006,12 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
api_set_error(err, kErrorTypeValidation,
"Invalid value of 'style' key");
}
+ } else if (strequal(key, "noautocmd") && new_win) {
+ fconfig->noautocmd
+ = api_object_to_bool(val, "'noautocmd' key", false, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
} else {
api_set_error(err, kErrorTypeValidation,
"Invalid key '%s'", key);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a76cefe294..99a41f4f6f 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1459,6 +1459,9 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// By default `FloatBorder` highlight is used which links to `VertSplit`
/// when not defined. It could also be specified by character:
/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ]
+/// - `noautocmd`: If true then no buffer-related autocommand events such as
+/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from
+/// calling this function.
///
/// @param[out] err Error details, if any
///
@@ -1469,7 +1472,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
FUNC_API_CHECK_TEXTLOCK
{
FloatConfig fconfig = FLOAT_CONFIG_INIT;
- if (!parse_float_config(config, &fconfig, false, err)) {
+ if (!parse_float_config(config, &fconfig, false, true, err)) {
return 0;
}
win_T *wp = win_new_float(NULL, fconfig, err);
@@ -1484,7 +1487,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
return 0;
}
if (buffer > 0) {
- nvim_win_set_buf(wp->handle, buffer, err);
+ win_set_buf(wp->handle, buffer, fconfig.noautocmd, err);
}
if (fconfig.style == kWinStyleMinimal) {
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 158e149628..a26213af98 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -46,35 +46,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
FUNC_API_SINCE(5)
FUNC_API_CHECK_TEXTLOCK
{
- win_T *win = find_window_by_handle(window, err), *save_curwin = curwin;
- buf_T *buf = find_buffer_by_handle(buffer, err);
- tabpage_T *tab = win_find_tabpage(win), *save_curtab = curtab;
-
- if (!win || !buf) {
- return;
- }
-
- if (switch_win_noblock(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
- api_set_error(err,
- kErrorTypeException,
- "Failed to switch to window %d",
- window);
- }
-
- try_start();
- int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
- if (!try_end(err) && result == FAIL) {
- api_set_error(err,
- kErrorTypeException,
- "Failed to set buffer %d",
- buffer);
- }
-
- // If window is not current, state logic will not validate its cursor.
- // So do it now.
- validate_cursor();
-
- restore_win_noblock(save_curwin, save_curtab, false);
+ win_set_buf(window, buffer, false, err);
}
/// Gets the (1,0)-indexed cursor position in the window. |api-indexing|
@@ -423,7 +395,7 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
// reuse old values, if not overriden
FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config;
- if (!parse_float_config(config, &fconfig, !new_float, err)) {
+ if (!parse_float_config(config, &fconfig, !new_float, false, err)) {
return;
}
if (new_float) {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 0c839ba12a..e3e538bd12 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1090,6 +1090,7 @@ typedef struct {
schar_T border_chars[8];
int border_hl_ids[8];
int border_attr[8];
+ bool noautocmd;
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
@@ -1098,7 +1099,8 @@ typedef struct {
.relative = 0, .external = false, \
.focusable = true, \
.zindex = kZIndexFloatDefault, \
- .style = kWinStyleUnused })
+ .style = kWinStyleUnused, \
+ .noautocmd = false })
// Structure to store last cursor position and topline. Used by check_lnums()
// and reset_lnums().
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 13706fb14a..173d8d46d1 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -4384,6 +4384,12 @@ dozet:
}
break;
+ // "zp", "zP" in block mode put without addind trailing spaces
+ case 'P':
+ case 'p':
+ nv_put(cap);
+ break;
+
/* "zF": create fold command */
/* "zf": create fold operator */
case 'F':
@@ -7913,12 +7919,14 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
flags |= PUT_FIXINDENT;
} else {
dir = (cap->cmdchar == 'P'
- || (cap->cmdchar == 'g' && cap->nchar == 'P'))
- ? BACKWARD : FORWARD;
+ || ((cap->cmdchar == 'g' || cap->cmdchar == 'z')
+ && cap->nchar == 'P')) ? BACKWARD : FORWARD;
}
prep_redo_cmd(cap);
if (cap->cmdchar == 'g') {
flags |= PUT_CURSEND;
+ } else if (cap->cmdchar == 'z') {
+ flags |= PUT_BLOCK_INNER;
}
if (VIsual_active) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 0ed116c17f..2c8c7f0567 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -2788,13 +2788,13 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
recursive = false;
}
-/*
- * Put contents of register "regname" into the text.
- * Caller must check "regname" to be valid!
- * "flags": PUT_FIXINDENT make indent look nice
- * PUT_CURSEND leave cursor after end of new text
- * PUT_LINE force linewise put (":put")
- dir: BACKWARD for 'P', FORWARD for 'p' */
+// Put contents of register "regname" into the text.
+// Caller must check "regname" to be valid!
+// "flags": PUT_FIXINDENT make indent look nice
+// PUT_CURSEND leave cursor after end of new text
+// PUT_LINE force linewise put (":put")
+// PUT_BLOCK_INNER in block mode, do not add trailing spaces
+// dir: BACKWARD for 'P', FORWARD for 'p'
void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
{
char_u *ptr;
@@ -3126,7 +3126,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
curwin->w_cursor.coladd = 0;
bd.textcol = 0;
for (i = 0; i < y_size; i++) {
- int spaces;
+ int spaces = 0;
char shortline;
// can just be 0 or 1, needed for blockwise paste beyond the current
// buffer end
@@ -3177,13 +3177,16 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
yanklen = (int)STRLEN(y_array[i]);
- // calculate number of spaces required to fill right side of block
- spaces = y_width + 1;
- for (long j = 0; j < yanklen; j++) {
- spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
- }
- if (spaces < 0) {
- spaces = 0;
+ if ((flags & PUT_BLOCK_INNER) == 0) {
+ // calculate number of spaces required to fill right side of
+ // block
+ spaces = y_width + 1;
+ for (int j = 0; j < yanklen; j++) {
+ spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
+ }
+ if (spaces < 0) {
+ spaces = 0;
+ }
}
// insert the new text
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 77d6b4435f..112ffbeaba 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -14,13 +14,14 @@
typedef int (*Indenter)(void);
-/* flags for do_put() */
-#define PUT_FIXINDENT 1 /* make indent look nice */
-#define PUT_CURSEND 2 /* leave cursor after end of new text */
-#define PUT_CURSLINE 4 /* leave cursor on last line of new text */
-#define PUT_LINE 8 /* put register as lines */
-#define PUT_LINE_SPLIT 16 /* split line for linewise register */
-#define PUT_LINE_FORWARD 32 /* put linewise register below Visual sel. */
+// flags for do_put()
+#define PUT_FIXINDENT 1 // make indent look nice
+#define PUT_CURSEND 2 // leave cursor after end of new text
+#define PUT_CURSLINE 4 // leave cursor on last line of new text
+#define PUT_LINE 8 // put register as lines
+#define PUT_LINE_SPLIT 16 // split line for linewise register
+#define PUT_LINE_FORWARD 32 // put linewise register below Visual sel.
+#define PUT_BLOCK_INNER 64 // in block mode, do not add trailing spaces
/*
* Registers:
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index accf9b0bb5..6b84bb3207 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -3755,6 +3755,7 @@ static bool reg_match_visual(void)
int mode;
colnr_T start, end;
colnr_T start2, end2;
+ colnr_T curswant;
// Check if the buffer is the current buffer.
if (rex.reg_buf != curbuf || VIsual.lnum == 0) {
@@ -3770,6 +3771,7 @@ static bool reg_match_visual(void)
bot = VIsual;
}
mode = VIsual_mode;
+ curswant = wp->w_curswant;
} else {
if (lt(curbuf->b_visual.vi_start, curbuf->b_visual.vi_end)) {
top = curbuf->b_visual.vi_start;
@@ -3779,6 +3781,7 @@ static bool reg_match_visual(void)
bot = curbuf->b_visual.vi_start;
}
mode = curbuf->b_visual.vi_mode;
+ curswant = curbuf->b_visual.vi_curswant;
}
lnum = rex.lnum + rex.reg_firstlnum;
if (lnum < top.lnum || lnum > bot.lnum) {
@@ -3798,8 +3801,9 @@ static bool reg_match_visual(void)
start = start2;
if (end2 > end)
end = end2;
- if (top.col == MAXCOL || bot.col == MAXCOL)
+ if (top.col == MAXCOL || bot.col == MAXCOL || curswant == MAXCOL) {
end = MAXCOL;
+ }
unsigned int cols_u = win_linetabsize(wp, rex.line,
(colnr_T)(rex.input - rex.line));
assert(cols_u <= MAXCOL);
diff --git a/src/nvim/testdir/test_blockedit.vim b/src/nvim/testdir/test_blockedit.vim
index 527224ccd2..180524cd73 100644
--- a/src/nvim/testdir/test_blockedit.vim
+++ b/src/nvim/testdir/test_blockedit.vim
@@ -1,6 +1,5 @@
" Test for block inserting
"
-" TODO: rewrite test39.in into this new style test
func Test_blockinsert_indent()
new
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 7a846e5ea0..4a00999c45 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -512,6 +512,12 @@ func Test_normal14_page_eol()
bw!
endfunc
+" Test for errors with z command
+func Test_normal_z_error()
+ call assert_beeps('normal! z2p')
+ call assert_beeps('normal! zq')
+endfunc
+
func Test_normal15_z_scroll_vert()
" basic test for z commands that scroll the window
call Setup_NewWindow()
@@ -2877,3 +2883,35 @@ func Test_normal_gk()
bw!
set cpoptions& number& numberwidth&
endfunc
+
+" Some commands like yy, cc, dd, >>, << and !! accept a count after
+" typing the first letter of the command.
+func Test_normal_count_after_operator()
+ new
+ setlocal shiftwidth=4 tabstop=8 autoindent
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ let @a = ''
+ normal! j"ay4y
+ call assert_equal("two\nthree\nfour\nfive\n", @a)
+ normal! 3G>2>
+ call assert_equal(['one', 'two', ' three', ' four', 'five'],
+ \ getline(1, '$'))
+ exe "normal! 3G0c2cred\nblue"
+ call assert_equal(['one', 'two', ' red', ' blue', 'five'],
+ \ getline(1, '$'))
+ exe "normal! gg<8<"
+ call assert_equal(['one', 'two', 'red', 'blue', 'five'],
+ \ getline(1, '$'))
+ exe "normal! ggd3d"
+ call assert_equal(['blue', 'five'], getline(1, '$'))
+ call setline(1, range(1, 4))
+ call feedkeys("gg!3!\<C-B>\"\<CR>", 'xt')
+ call assert_equal('".,.+2!', @:)
+ call feedkeys("gg!1!\<C-B>\"\<CR>", 'xt')
+ call assert_equal('".!', @:)
+ call feedkeys("gg!9!\<C-B>\"\<CR>", 'xt')
+ call assert_equal('".,$!', @:)
+ bw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index b391663e0f..5ba24d047c 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -824,6 +824,26 @@ func Test_incsearch_search_dump()
call delete('Xis_search_script')
endfunc
+func Test_hlsearch_block_visual_match()
+ CheckScreendump
+
+ let lines =<< trim END
+ set hlsearch
+ call setline(1, ['aa', 'bbbb', 'cccccc'])
+ END
+ call writefile(lines, 'Xhlsearch_block')
+ let buf = RunVimInTerminal('-S Xhlsearch_block', {'rows': 9, 'cols': 60})
+
+ call term_sendkeys(buf, "G\<C-V>$kk\<Esc>")
+ sleep 100m
+ call term_sendkeys(buf, "/\\%V\<CR>")
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_hlsearch_block_visual_match', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xhlsearch_block')
+endfunc
+
func Test_incsearch_substitute()
CheckFunction test_override
CheckOption incsearch
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 73c7960579..21fd57b791 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -1,4 +1,4 @@
-" Tests for various Visual mode.
+" Tests for various Visual modes.
func Test_block_shift_multibyte()
" Uses double-wide character.
@@ -738,4 +738,272 @@ func Test_select_mode_gv()
bwipe!
endfunc
+" Tests for the visual block mode commands
+func Test_visual_block_mode()
+ new
+ call append(0, '')
+ call setline(1, ['abcdefghijklm', 'abcdefghijklm', 'abcdefghijklm',
+ \ 'abcdefghijklm', 'abcdefghijklm'])
+ call cursor(1, 1)
+
+ " Test shift-right of a block
+ exe "normal jllll\<C-V>jj>wll\<C-V>jlll>"
+ " Test shift-left of a block
+ exe "normal G$hhhh\<C-V>kk<"
+ " Test block-insert
+ exe "normal Gkl\<C-V>kkkIxyz"
+ " Test block-replace
+ exe "normal Gllll\<C-V>kkklllrq"
+ " Test block-change
+ exe "normal G$khhh\<C-V>hhkkcmno"
+ call assert_equal(['axyzbcdefghijklm',
+ \ 'axyzqqqq mno ghijklm',
+ \ 'axyzqqqqef mno ghijklm',
+ \ 'axyzqqqqefgmnoklm',
+ \ 'abcdqqqqijklm'], getline(1, 5))
+
+ " Test from ':help v_b_I_example'
+ %d _
+ setlocal tabstop=8 shiftwidth=4
+ let lines =<< trim END
+ abcdefghijklmnopqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmnopqrstuvwxyz
+ END
+ call setline(1, lines)
+ exe "normal ggfo\<C-V>3jISTRING"
+ let expected =<< trim END
+ abcdefghijklmnSTRINGopqrstuvwxyz
+ abc STRING defghijklmnopqrstuvwxyz
+ abcdef ghi STRING jklmnopqrstuvwxyz
+ abcdefghijklmnSTRINGopqrstuvwxyz
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Test from ':help v_b_A_example'
+ %d _
+ let lines =<< trim END
+ abcdefghijklmnopqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmnopqrstuvwxyz
+ END
+ call setline(1, lines)
+ exe "normal ggfo\<C-V>3j$ASTRING"
+ let expected =<< trim END
+ abcdefghijklmnopqrstuvwxyzSTRING
+ abc defghijklmnopqrstuvwxyzSTRING
+ abcdef ghi jklmnopqrstuvwxyzSTRING
+ abcdefghijklmnopqrstuvwxyzSTRING
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Test from ':help v_b_<_example'
+ %d _
+ let lines =<< trim END
+ abcdefghijklmnopqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmnopqrstuvwxyz
+ END
+ call setline(1, lines)
+ exe "normal ggfo\<C-V>3j3l<.."
+ let expected =<< trim END
+ abcdefghijklmnopqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmnopqrstuvwxyz
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Test from ':help v_b_>_example'
+ %d _
+ let lines =<< trim END
+ abcdefghijklmnopqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmnopqrstuvwxyz
+ END
+ call setline(1, lines)
+ exe "normal ggfo\<C-V>3j>.."
+ let expected =<< trim END
+ abcdefghijklmn opqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmn opqrstuvwxyz
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Test from ':help v_b_r_example'
+ %d _
+ let lines =<< trim END
+ abcdefghijklmnopqrstuvwxyz
+ abc defghijklmnopqrstuvwxyz
+ abcdef ghi jklmnopqrstuvwxyz
+ abcdefghijklmnopqrstuvwxyz
+ END
+ call setline(1, lines)
+ exe "normal ggfo\<C-V>5l3jrX"
+ let expected =<< trim END
+ abcdefghijklmnXXXXXXuvwxyz
+ abc XXXXXXhijklmnopqrstuvwxyz
+ abcdef ghi XXXXXX jklmnopqrstuvwxyz
+ abcdefghijklmnXXXXXXuvwxyz
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ bwipe!
+ set tabstop& shiftwidth&
+endfunc
+
+" Test block-insert using cursor keys for movement
+func Test_visual_block_insert_cursor_keys()
+ new
+ call append(0, ['aaaaaa', 'bbbbbb', 'cccccc', 'dddddd'])
+ call cursor(1, 1)
+
+ exe "norm! l\<C-V>jjjlllI\<Right>\<Right> \<Esc>"
+ call assert_equal(['aaa aaa', 'bbb bbb', 'ccc ccc', 'ddd ddd'],
+ \ getline(1, 4))
+
+ call deletebufline('', 1, '$')
+ call setline(1, ['xaaa', 'bbbb', 'cccc', 'dddd'])
+ call cursor(1, 1)
+ exe "norm! \<C-V>jjjI<>\<Left>p\<Esc>"
+ call assert_equal(['<p>xaaa', '<p>bbbb', '<p>cccc', '<p>dddd'],
+ \ getline(1, 4))
+ bwipe!
+endfunc
+
+func Test_visual_block_create()
+ new
+ call append(0, '')
+ " Test for Visual block was created with the last <C-v>$
+ call setline(1, ['A23', '4567'])
+ call cursor(1, 1)
+ exe "norm! l\<C-V>j$Aab\<Esc>"
+ call assert_equal(['A23ab', '4567ab'], getline(1, 2))
+
+ " Test for Visual block was created with the middle <C-v>$ (1)
+ call deletebufline('', 1, '$')
+ call setline(1, ['B23', '4567'])
+ call cursor(1, 1)
+ exe "norm! l\<C-V>j$hAab\<Esc>"
+ call assert_equal(['B23 ab', '4567ab'], getline(1, 2))
+
+ " Test for Visual block was created with the middle <C-v>$ (2)
+ call deletebufline('', 1, '$')
+ call setline(1, ['C23', '4567'])
+ call cursor(1, 1)
+ exe "norm! l\<C-V>j$hhAab\<Esc>"
+ call assert_equal(['C23ab', '456ab7'], getline(1, 2))
+ bwipe!
+endfunc
+
+" Test for Visual block insert when virtualedit=all
+func Test_virtualedit_visual_block()
+ set ve=all
+ new
+ call append(0, ["\t\tline1", "\t\tline2", "\t\tline3"])
+ call cursor(1, 1)
+ exe "norm! 07l\<C-V>jjIx\<Esc>"
+ call assert_equal([" x \tline1",
+ \ " x \tline2",
+ \ " x \tline3"], getline(1, 3))
+
+ " Test for Visual block append when virtualedit=all
+ exe "norm! 012l\<C-v>jjAx\<Esc>"
+ call assert_equal([' x x line1',
+ \ ' x x line2',
+ \ ' x x line3'], getline(1, 3))
+ set ve=
+ bwipe!
+endfunc
+
+" Test for changing case
+func Test_visual_change_case()
+ new
+ " gUe must uppercase a whole word, also when ß changes to SS
+ exe "normal Gothe youtußeuu end\<Esc>Ypk0wgUe\r"
+ " gUfx must uppercase until x, inclusive.
+ exe "normal O- youßtußexu -\<Esc>0fogUfx\r"
+ " VU must uppercase a whole line
+ exe "normal YpkVU\r"
+ " same, when it's the last line in the buffer
+ exe "normal YPGi111\<Esc>VUddP\r"
+ " Uppercase two lines
+ exe "normal Oblah di\rdoh dut\<Esc>VkUj\r"
+ " Uppercase part of two lines
+ exe "normal ddppi333\<Esc>k0i222\<Esc>fyllvjfuUk"
+ call assert_equal(['the YOUTUSSEUU end', '- yOUSSTUSSEXu -',
+ \ 'THE YOUTUSSEUU END', '111THE YOUTUSSEUU END', 'BLAH DI', 'DOH DUT',
+ \ '222the yoUTUSSEUU END', '333THE YOUTUßeuu end'], getline(2, '$'))
+ bwipe!
+endfunc
+
+" Test for Visual replace using Enter or NL
+func Test_visual_replace_crnl()
+ new
+ exe "normal G3o123456789\e2k05l\<C-V>2jr\r"
+ exe "normal G3o98765\e2k02l\<C-V>2jr\<C-V>\r\n"
+ exe "normal G3o123456789\e2k05l\<C-V>2jr\n"
+ exe "normal G3o98765\e2k02l\<C-V>2jr\<C-V>\n"
+ call assert_equal(['12345', '789', '12345', '789', '12345', '789', "98\r65",
+ \ "98\r65", "98\r65", '12345', '789', '12345', '789', '12345', '789',
+ \ "98\n65", "98\n65", "98\n65"], getline(2, '$'))
+ bwipe!
+endfunc
+
+func Test_ve_block_curpos()
+ new
+ " Test cursor position. When ve=block and Visual block mode and $gj
+ call append(0, ['12345', '789'])
+ call cursor(1, 3)
+ set virtualedit=block
+ exe "norm! \<C-V>$gj\<Esc>"
+ call assert_equal([0, 2, 4, 0], getpos("'>"))
+ set virtualedit=
+ bwipe!
+endfunc
+
+" Test for block_insert when replacing spaces in front of the a with tabs
+func Test_block_insert_replace_tabs()
+ new
+ set ts=8 sts=4 sw=4
+ call append(0, ["#define BO_ALL\t 0x0001",
+ \ "#define BO_BS\t 0x0002",
+ \ "#define BO_CRSR\t 0x0004"])
+ call cursor(1, 1)
+ exe "norm! f0\<C-V>2jI\<tab>\<esc>"
+ call assert_equal([
+ \ "#define BO_ALL\t\t0x0001",
+ \ "#define BO_BS\t \t0x0002",
+ \ "#define BO_CRSR\t \t0x0004", ''], getline(1, '$'))
+ set ts& sts& sw&
+ bwipe!
+endfunc
+
+func Test_visual_put_in_block_using_zp()
+ new
+ " paste using zP
+ call setline(1, ['/path;text', '/path;text', '/path;text', '',
+ \ '/subdir',
+ \ '/longsubdir',
+ \ '/longlongsubdir'])
+ exe "normal! 5G\<c-v>2j$y"
+ norm! 1Gf;zP
+ call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3))
+ %d
+ " paste using zP
+ call setline(1, ['/path;text', '/path;text', '/path;text', '',
+ \ '/subdir',
+ \ '/longsubdir',
+ \ '/longlongsubdir'])
+ exe "normal! 5G\<c-v>2j$y"
+ norm! 1Gf;hzp
+ call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3))
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 936bfa8c5b..cdeae2e294 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -570,6 +570,45 @@ static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize,
}
}
+void win_set_buf(Window window, Buffer buffer, bool noautocmd, Error *err)
+{
+ win_T *win = find_window_by_handle(window, err), *save_curwin = curwin;
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ tabpage_T *tab = win_find_tabpage(win), *save_curtab = curtab;
+
+ if (!win || !buf) {
+ return;
+ }
+
+ if (noautocmd) {
+ block_autocmds();
+ }
+ if (switch_win_noblock(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
+ api_set_error(err,
+ kErrorTypeException,
+ "Failed to switch to window %d",
+ window);
+ }
+
+ try_start();
+ int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0);
+ if (!try_end(err) && result == FAIL) {
+ api_set_error(err,
+ kErrorTypeException,
+ "Failed to set buffer %d",
+ buffer);
+ }
+
+ // If window is not current, state logic will not validate its cursor.
+ // So do it now.
+ validate_cursor();
+
+ restore_win_noblock(save_curwin, save_curtab, false);
+ if (noautocmd) {
+ unblock_autocmds();
+ }
+}
+
/// Create a new float.
///
/// if wp == NULL allocate a new window, otherwise turn existing window into a