mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #14532 from janlazo/vim-8.1.1433
vim-patch:8.0.1394,8.1.1967,8.2.{23,1000,1059,2354,2419,2433,2473,2850}
This commit is contained in:
commit
c57a85d534
@ -477,7 +477,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
|
||||
goto end;
|
||||
}
|
||||
|
||||
inserted_bytes += STRLEN(lines[i]) + 1;
|
||||
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
||||
// Mark lines that haven't been passed to the buffer as they need
|
||||
// to be freed later
|
||||
lines[i] = NULL;
|
||||
@ -497,7 +497,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
|
||||
goto end;
|
||||
}
|
||||
|
||||
inserted_bytes += STRLEN(lines[i]) + 1;
|
||||
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
||||
|
||||
// Same as with replacing, but we also need to free lines
|
||||
xfree(lines[i]);
|
||||
|
@ -407,7 +407,8 @@ bool buf_valid(buf_T *buf)
|
||||
/// there to be only one window with this buffer. e.g. when
|
||||
/// ":quit" is supposed to close the window but autocommands
|
||||
/// close all other windows.
|
||||
void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
/// @returns true when we got to the end and b_nwindows was decremented.
|
||||
bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
{
|
||||
bool unload_buf = (action != 0);
|
||||
bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
|
||||
@ -444,7 +445,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
// halfway a command that relies on it). Unloading is allowed.
|
||||
if (buf->b_locked > 0 && (del_buf || wipe_buf)) {
|
||||
EMSG(_("E937: Attempt to delete a buffer that is in use"));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (win != NULL // Avoid bogus clang warning.
|
||||
@ -471,13 +472,13 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
buf) && !bufref_valid(&bufref)) {
|
||||
// Autocommands deleted the buffer.
|
||||
EMSG(_(e_auabort));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
buf->b_locked--;
|
||||
if (abort_if_last && last_nonfloat(win)) {
|
||||
// Autocommands made this the only window.
|
||||
EMSG(_(e_auabort));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// When the buffer becomes hidden, but is not unloaded, trigger
|
||||
@ -488,17 +489,17 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
buf) && !bufref_valid(&bufref)) {
|
||||
// Autocommands deleted the buffer.
|
||||
EMSG(_(e_auabort));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
buf->b_locked--;
|
||||
if (abort_if_last && last_nonfloat(win)) {
|
||||
// Autocommands made this the only window.
|
||||
EMSG(_(e_auabort));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (aborting()) { // autocmds may abort script processing
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +526,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
/* Return when a window is displaying the buffer or when it's not
|
||||
* unloaded. */
|
||||
if (buf->b_nwindows > 0 || !unload_buf) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buf->terminal) {
|
||||
@ -561,11 +562,11 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
|
||||
if (!bufref_valid(&bufref)) {
|
||||
// Autocommands may have deleted the buffer.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (aborting()) {
|
||||
// Autocmds may abort script processing.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -576,7 +577,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
* deleted buffer.
|
||||
*/
|
||||
if (buf == curbuf && !is_curbuf) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (win != NULL // Avoid bogus clang warning.
|
||||
@ -636,6 +637,8 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
buf->b_p_bl = false;
|
||||
}
|
||||
}
|
||||
// NOTE: at this point "curbuf" may be invalid!
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Make buffer not contain a file.
|
||||
|
@ -3150,9 +3150,7 @@ static void ins_compl_clear(void)
|
||||
XFREE_CLEAR(compl_orig_text);
|
||||
compl_enter_selects = false;
|
||||
// clear v:completed_item
|
||||
dict_T *const d = tv_dict_alloc();
|
||||
d->dv_lock = VAR_FIXED;
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, d);
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
|
||||
}
|
||||
|
||||
/// Check that Insert completion is active.
|
||||
@ -4497,9 +4495,7 @@ static void ins_compl_delete(void)
|
||||
// causes flicker, thus we can't do that.
|
||||
changed_cline_bef_curs();
|
||||
// clear v:completed_item
|
||||
dict_T *const d = tv_dict_alloc();
|
||||
d->dv_lock = VAR_FIXED;
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, d);
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
|
||||
}
|
||||
|
||||
// Insert the new text being completed.
|
||||
@ -4520,8 +4516,7 @@ static void ins_compl_insert(int in_compl_func)
|
||||
static dict_T *ins_compl_dict_alloc(compl_T *match)
|
||||
{
|
||||
// { word, abbr, menu, kind, info }
|
||||
dict_T *dict = tv_dict_alloc();
|
||||
dict->dv_lock = VAR_FIXED;
|
||||
dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
|
||||
tv_dict_add_str(
|
||||
dict, S_LEN("word"),
|
||||
(const char *)EMPTY_IF_NULL(match->cp_str));
|
||||
|
@ -377,11 +377,9 @@ void eval_init(void)
|
||||
msgpack_types_dict->dv_lock = VAR_FIXED;
|
||||
|
||||
set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
|
||||
|
||||
dict_T *v_event = tv_dict_alloc();
|
||||
v_event->dv_lock = VAR_FIXED;
|
||||
set_vim_var_dict(VV_EVENT, v_event);
|
||||
set_vim_var_dict(VV_EVENT, tv_dict_alloc_lock(VAR_FIXED));
|
||||
set_vim_var_list(VV_ERRORS, tv_list_alloc(kListLenUnknown));
|
||||
set_vim_var_nr(VV_STDERR, CHAN_STDERR);
|
||||
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
|
||||
@ -7617,7 +7615,7 @@ char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
|
||||
/// @param[out] ret_fnum Set to fnum for marks.
|
||||
///
|
||||
/// @return Pointer to position or NULL in case of error (e.g. invalid type).
|
||||
pos_T *var2fpos(const typval_T *const tv, const int dollar_lnum,
|
||||
pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum,
|
||||
int *const ret_fnum)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
|
@ -217,7 +217,7 @@ return {
|
||||
len={args=1},
|
||||
libcall={args=3},
|
||||
libcallnr={args=3},
|
||||
line={args=1},
|
||||
line={args={1, 2}},
|
||||
line2byte={args=1},
|
||||
lispindent={args=1},
|
||||
list2str={args={1, 2}},
|
||||
|
@ -5540,18 +5540,36 @@ static void f_libcallnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
libcall_common(argvars, rettv, VAR_NUMBER);
|
||||
}
|
||||
|
||||
/*
|
||||
* "line(string)" function
|
||||
*/
|
||||
// "line(string, [winid])" function
|
||||
static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
{
|
||||
linenr_T lnum = 0;
|
||||
pos_T *fp;
|
||||
pos_T *fp = NULL;
|
||||
int fnum;
|
||||
|
||||
fp = var2fpos(&argvars[0], TRUE, &fnum);
|
||||
if (fp != NULL)
|
||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||
tabpage_T *tp;
|
||||
win_T *save_curwin;
|
||||
tabpage_T *save_curtab;
|
||||
|
||||
// use window specified in the second argument
|
||||
win_T *wp = win_id2wp_tp(&argvars[1], &tp);
|
||||
if (wp != NULL && tp != NULL) {
|
||||
if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true)
|
||||
== OK) {
|
||||
check_cursor();
|
||||
fp = var2fpos(&argvars[0], true, &fnum);
|
||||
}
|
||||
restore_win_noblock(save_curwin, save_curtab, true);
|
||||
}
|
||||
} else {
|
||||
// use current window
|
||||
fp = var2fpos(&argvars[0], true, &fnum);
|
||||
}
|
||||
|
||||
if (fp != NULL) {
|
||||
lnum = fp->lnum;
|
||||
}
|
||||
rettv->vval.v_number = lnum;
|
||||
}
|
||||
|
||||
|
@ -2106,6 +2106,13 @@ list_T *tv_list_alloc_ret(typval_T *const ret_tv, const ptrdiff_t len)
|
||||
return l;
|
||||
}
|
||||
|
||||
dict_T *tv_dict_alloc_lock(VarLockStatus lock)
|
||||
{
|
||||
dict_T *const d = tv_dict_alloc();
|
||||
d->dv_lock = lock;
|
||||
return d;
|
||||
}
|
||||
|
||||
/// Allocate an empty dictionary for a return value
|
||||
///
|
||||
/// Also sets reference count.
|
||||
@ -2114,9 +2121,8 @@ list_T *tv_list_alloc_ret(typval_T *const ret_tv, const ptrdiff_t len)
|
||||
void tv_dict_alloc_ret(typval_T *const ret_tv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
dict_T *const d = tv_dict_alloc();
|
||||
dict_T *const d = tv_dict_alloc_lock(VAR_UNLOCKED);
|
||||
tv_dict_set_ret(ret_tv, d);
|
||||
ret_tv->v_lock = VAR_UNLOCKED;
|
||||
}
|
||||
|
||||
//{{{3 Clear
|
||||
|
@ -2434,21 +2434,25 @@ int do_ecmd(
|
||||
* is returned by buflist_new(), nothing to do here.
|
||||
*/
|
||||
if (buf != curbuf) {
|
||||
/*
|
||||
* Be careful: The autocommands may delete any buffer and change
|
||||
* the current buffer.
|
||||
* - If the buffer we are going to edit is deleted, give up.
|
||||
* - If the current buffer is deleted, prefer to load the new
|
||||
* buffer when loading a buffer is required. This avoids
|
||||
* loading another buffer which then must be closed again.
|
||||
* - If we ended up in the new buffer already, need to skip a few
|
||||
* things, set auto_buf.
|
||||
*/
|
||||
const int save_cmdwin_type = cmdwin_type;
|
||||
|
||||
// BufLeave applies to the old buffer.
|
||||
cmdwin_type = 0;
|
||||
|
||||
// Be careful: The autocommands may delete any buffer and change
|
||||
// the current buffer.
|
||||
// - If the buffer we are going to edit is deleted, give up.
|
||||
// - If the current buffer is deleted, prefer to load the new
|
||||
// buffer when loading a buffer is required. This avoids
|
||||
// loading another buffer which then must be closed again.
|
||||
// - If we ended up in the new buffer already, need to skip a few
|
||||
// things, set auto_buf.
|
||||
if (buf->b_fname != NULL) {
|
||||
new_name = vim_strsave(buf->b_fname);
|
||||
}
|
||||
set_bufref(&au_new_curbuf, buf);
|
||||
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
|
||||
cmdwin_type = save_cmdwin_type;
|
||||
if (!bufref_valid(&au_new_curbuf)) {
|
||||
// New buffer has been deleted.
|
||||
delbuf_msg(new_name); // Frees new_name.
|
||||
@ -2462,6 +2466,7 @@ int do_ecmd(
|
||||
auto_buf = true;
|
||||
} else {
|
||||
win_T *the_curwin = curwin;
|
||||
buf_T *was_curbuf = curbuf;
|
||||
|
||||
// Set w_closing to avoid that autocommands close the window.
|
||||
// Set b_locked for the same reason.
|
||||
@ -2475,9 +2480,10 @@ int do_ecmd(
|
||||
// Close the link to the current buffer. This will set
|
||||
// oldwin->w_buffer to NULL.
|
||||
u_sync(false);
|
||||
close_buffer(oldwin, curbuf,
|
||||
(flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
|
||||
false);
|
||||
const bool did_decrement = close_buffer(
|
||||
oldwin, curbuf,
|
||||
(flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
|
||||
false);
|
||||
|
||||
// Autocommands may have closed the window.
|
||||
if (win_valid(the_curwin)) {
|
||||
@ -2497,6 +2503,14 @@ int do_ecmd(
|
||||
goto theend;
|
||||
}
|
||||
if (buf == curbuf) { // already in new buffer
|
||||
// close_buffer() has decremented the window count,
|
||||
// increment it again here and restore w_buffer.
|
||||
if (did_decrement && buf_valid(was_curbuf)) {
|
||||
was_curbuf->b_nwindows++;
|
||||
}
|
||||
if (win_valid_any_tab(oldwin) && oldwin->w_buffer == NULL) {
|
||||
oldwin->w_buffer = was_curbuf;
|
||||
}
|
||||
auto_buf = true;
|
||||
} else {
|
||||
// <VN> We could instead free the synblock
|
||||
|
@ -212,7 +212,7 @@ void do_exmode(int improved)
|
||||
while (exmode_active) {
|
||||
/* Check for a ":normal" command and no more characters left. */
|
||||
if (ex_normal_busy > 0 && typebuf.tb_len == 0) {
|
||||
exmode_active = FALSE;
|
||||
exmode_active = 0;
|
||||
break;
|
||||
}
|
||||
msg_scroll = true;
|
||||
@ -6520,6 +6520,12 @@ ex_win_close(
|
||||
int need_hide;
|
||||
buf_T *buf = win->w_buffer;
|
||||
|
||||
// Never close the autocommand window.
|
||||
if (win == aucmd_win) {
|
||||
EMSG(_(e_autocmd_close));
|
||||
return;
|
||||
}
|
||||
|
||||
need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1);
|
||||
if (need_hide && !buf_hide(buf) && !forceit) {
|
||||
if ((p_confirm || cmdmod.confirm) && p_write) {
|
||||
@ -6589,9 +6595,6 @@ static void ex_tabonly(exarg_T *eap)
|
||||
// Repeat this up to a 1000 times, because autocommands may
|
||||
// mess up the lists.
|
||||
for (int done = 0; done < 1000; done++) {
|
||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||
assert(wp != aucmd_win);
|
||||
}
|
||||
FOR_ALL_TABS(tp) {
|
||||
if (tp->tp_topframe != topframe) {
|
||||
tabpage_close_other(tp, eap->forceit);
|
||||
@ -7304,7 +7307,8 @@ do_exedit(
|
||||
*/
|
||||
if (exmode_active && (eap->cmdidx == CMD_visual
|
||||
|| eap->cmdidx == CMD_view)) {
|
||||
exmode_active = FALSE;
|
||||
exmode_active = 0;
|
||||
ex_pressedreturn = false;
|
||||
if (*eap->arg == NUL) {
|
||||
/* Special case: ":global/pat/visual\NLvi-commands" */
|
||||
if (global_busy) {
|
||||
|
@ -6635,11 +6635,13 @@ static int open_cmdwin(void)
|
||||
wp = curwin;
|
||||
set_bufref(&bufref, curbuf);
|
||||
win_goto(old_curwin);
|
||||
win_close(wp, true);
|
||||
if (win_valid(wp) && wp != curwin) {
|
||||
win_close(wp, true);
|
||||
}
|
||||
|
||||
// win_close() may have already wiped the buffer when 'bh' is
|
||||
// set to 'wipe'.
|
||||
if (bufref_valid(&bufref)) {
|
||||
// set to 'wipe', autocommands may have closed other windows
|
||||
if (bufref_valid(&bufref) && bufref.br_buf != curbuf) {
|
||||
close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false);
|
||||
}
|
||||
|
||||
|
@ -987,6 +987,8 @@ EXTERN char_u e_dirnotf[] INIT(= N_(
|
||||
"E919: Directory not found in '%s': \"%s\""));
|
||||
EXTERN char_u e_au_recursive[] INIT(= N_(
|
||||
"E952: Autocommand caused recursive behavior"));
|
||||
EXTERN char_u e_autocmd_close[] INIT(= N_(
|
||||
"E813: Cannot close autocmd window"));
|
||||
EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
|
||||
EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long"));
|
||||
EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String"));
|
||||
|
@ -1143,7 +1143,6 @@ static int find_tagfunc_tags(
|
||||
typval_T args[4];
|
||||
typval_T rettv;
|
||||
char_u flagString[4];
|
||||
dict_T *d;
|
||||
taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx];
|
||||
|
||||
if (*curbuf->b_p_tfu == NUL) {
|
||||
@ -1156,7 +1155,7 @@ static int find_tagfunc_tags(
|
||||
args[1].vval.v_string = flagString;
|
||||
|
||||
// create 'info' dict argument
|
||||
d = tv_dict_alloc();
|
||||
dict_T *const d = tv_dict_alloc_lock(VAR_FIXED);
|
||||
if (tag->user_data != NULL) {
|
||||
tv_dict_add_str(d, S_LEN("user_data"), (const char *)tag->user_data);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ source test_cursor_func.vim
|
||||
source test_ex_equal.vim
|
||||
source test_ex_undo.vim
|
||||
source test_ex_z.vim
|
||||
source test_ex_mode.vim
|
||||
source test_execute_func.vim
|
||||
source test_expand_func.vim
|
||||
source test_feedkeys.vim
|
||||
|
@ -190,7 +190,6 @@ func Test_autocmd_bufunload_avoiding_SEGV_02()
|
||||
|
||||
normal! i1
|
||||
call assert_fails('edit a.txt', 'E517:')
|
||||
call feedkeys("\<CR>")
|
||||
|
||||
autocmd! test_autocmd_bufunload
|
||||
augroup! test_autocmd_bufunload
|
||||
@ -452,6 +451,27 @@ func Test_autocmd_bufwipe_in_SessLoadPost()
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
" Using :blast and :ball for many events caused a crash, because b_nwindows was
|
||||
" not incremented correctly.
|
||||
func Test_autocmd_blast_badd()
|
||||
let content =<< trim [CODE]
|
||||
au BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* blast
|
||||
edit foo1
|
||||
au BufNew,BufAdd,BufWinEnter,BufEnter,BufLeave,BufWinLeave,BufUnload,VimEnter foo* ball
|
||||
edit foo2
|
||||
call writefile(['OK'], 'Xerrors')
|
||||
qall
|
||||
[CODE]
|
||||
|
||||
call writefile(content, 'XblastBall')
|
||||
call system(GetVimCommand() .. ' --clean -S XblastBall')
|
||||
" call assert_match('OK', readfile('Xerrors')->join())
|
||||
call assert_match('OK', join(readfile('Xerrors')))
|
||||
|
||||
call delete('XblastBall')
|
||||
call delete('Xerrors')
|
||||
endfunc
|
||||
|
||||
" SEGV occurs in older versions.
|
||||
func Test_autocmd_bufwipe_in_SessLoadPost2()
|
||||
tabnew
|
||||
@ -1949,6 +1969,26 @@ func Test_autocmd_window()
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Test for trying to close the tab that has the temporary window for exeucing
|
||||
" an autocmd.
|
||||
func Test_close_autocmd_tab()
|
||||
edit one.txt
|
||||
tabnew two.txt
|
||||
augroup aucmd_win_test
|
||||
au!
|
||||
au BufEnter * if expand('<afile>') == 'one.txt' | tabfirst | tabonly | endif
|
||||
augroup END
|
||||
|
||||
call assert_fails('doautoall BufEnter', 'E813:')
|
||||
|
||||
tabonly
|
||||
augroup aucmd_win_test
|
||||
au!
|
||||
augroup END
|
||||
augroup! aucmd_win_test
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_closes_window()
|
||||
au BufNew,BufWinLeave * e %e
|
||||
file yyy
|
||||
@ -1960,4 +2000,13 @@ func Test_autocmd_closes_window()
|
||||
au! BufWinLeave
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_closing_cmdwin()
|
||||
au BufWinLeave * nested q
|
||||
call assert_fails("norm 7q?\n", 'E855:')
|
||||
|
||||
au! BufWinLeave
|
||||
new
|
||||
only
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -477,7 +477,7 @@ func Test_expand_star_star()
|
||||
call delete('a', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_paste_in_cmdline()
|
||||
func Test_cmdline_paste()
|
||||
let @a = "def"
|
||||
call feedkeys(":abc \<C-R>a ghi\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc def ghi', @:)
|
||||
@ -517,18 +517,38 @@ func Test_paste_in_cmdline()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_remove_char_in_cmdline()
|
||||
call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc ef', @:)
|
||||
func Test_cmdline_remove_char()
|
||||
let encoding_save = &encoding
|
||||
|
||||
call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abcdef', @:)
|
||||
" for e in ['utf8', 'latin1']
|
||||
for e in ['utf8']
|
||||
exe 'set encoding=' . e
|
||||
|
||||
call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc ghi', @:)
|
||||
call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc ef', @:, e)
|
||||
|
||||
call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"def', @:)
|
||||
call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abcdef', @:)
|
||||
|
||||
call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"abc ghi', @:, e)
|
||||
|
||||
call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"def', @:, e)
|
||||
endfor
|
||||
|
||||
let &encoding = encoding_save
|
||||
endfunc
|
||||
|
||||
func Test_cmdline_keymap_ctrl_hat()
|
||||
if !has('keymap')
|
||||
return
|
||||
endif
|
||||
|
||||
set keymap=esperanto
|
||||
call feedkeys(":\"Jxauxdo \<C-^>Jxauxdo \<C-^>Jxauxdo\<CR>", 'tx')
|
||||
call assert_equal('"Jxauxdo Ĵaŭdo Jxauxdo', @:)
|
||||
set keymap=
|
||||
endfunc
|
||||
|
||||
func Test_illegal_address1()
|
||||
@ -863,20 +883,20 @@ func Test_cmdline_overstrike()
|
||||
|
||||
" Test overstrike in the middle of the command line.
|
||||
call feedkeys(":\"01234\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
|
||||
call assert_equal('"0ab1cd4', @:)
|
||||
call assert_equal('"0ab1cd4', @:, e)
|
||||
|
||||
" Test overstrike going beyond end of command line.
|
||||
call feedkeys(":\"01234\<home>\<right>\<right>ab\<right>\<insert>cdefgh\<enter>", 'xt')
|
||||
call assert_equal('"0ab1cdefgh', @:)
|
||||
call assert_equal('"0ab1cdefgh', @:, e)
|
||||
|
||||
" Test toggling insert/overstrike a few times.
|
||||
call feedkeys(":\"01234\<home>\<right>ab\<right>\<insert>cd\<right>\<insert>ef\<enter>", 'xt')
|
||||
call assert_equal('"ab0cd3ef4', @:)
|
||||
call assert_equal('"ab0cd3ef4', @:, e)
|
||||
endfor
|
||||
|
||||
" Test overstrike with multi-byte characters.
|
||||
call feedkeys(":\"テキストエディタ\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
|
||||
call assert_equal('"テabキcdエディタ', @:)
|
||||
call assert_equal('"テabキcdエディタ', @:, e)
|
||||
|
||||
let &encoding = encoding_save
|
||||
endfunc
|
||||
@ -985,6 +1005,25 @@ func Test_buffers_lastused()
|
||||
bwipeout bufc
|
||||
endfunc
|
||||
|
||||
" Test for CmdwinEnter autocmd
|
||||
func Test_cmdwin_autocmd()
|
||||
CheckFeature cmdwin
|
||||
|
||||
augroup CmdWin
|
||||
au!
|
||||
autocmd BufLeave * if &buftype == '' | update | endif
|
||||
autocmd CmdwinEnter * startinsert
|
||||
augroup END
|
||||
|
||||
call assert_fails('call feedkeys("q:xyz\<CR>", "xt")', 'E492:')
|
||||
call assert_equal('xyz', @:)
|
||||
|
||||
augroup CmdWin
|
||||
au!
|
||||
augroup END
|
||||
augroup! CmdWin
|
||||
endfunc
|
||||
|
||||
func Test_cmdlineclear_tabenter()
|
||||
" See test/functional/legacy/cmdline_spec.lua
|
||||
CheckScreendump
|
||||
@ -1033,4 +1072,52 @@ func Test_read_shellcmd()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Test for recalling newer or older cmdline from history with <Up>, <Down>,
|
||||
" <S-Up>, <S-Down>, <PageUp>, <PageDown>, <C-p>, or <C-n>.
|
||||
func Test_recalling_cmdline()
|
||||
CheckFeature cmdline_hist
|
||||
|
||||
let g:cmdlines = []
|
||||
cnoremap <Plug>(save-cmdline) <Cmd>let g:cmdlines += [getcmdline()]<CR>
|
||||
|
||||
let histories = [
|
||||
\ {'name': 'cmd', 'enter': ':', 'exit': "\<Esc>"},
|
||||
\ {'name': 'search', 'enter': '/', 'exit': "\<Esc>"},
|
||||
\ {'name': 'expr', 'enter': ":\<C-r>=", 'exit': "\<Esc>\<Esc>"},
|
||||
\ {'name': 'input', 'enter': ":call input('')\<CR>", 'exit': "\<CR>"},
|
||||
"\ TODO: {'name': 'debug', ...}
|
||||
\]
|
||||
let keypairs = [
|
||||
\ {'older': "\<Up>", 'newer': "\<Down>", 'prefixmatch': v:true},
|
||||
\ {'older': "\<S-Up>", 'newer': "\<S-Down>", 'prefixmatch': v:false},
|
||||
\ {'older': "\<PageUp>", 'newer': "\<PageDown>", 'prefixmatch': v:false},
|
||||
\ {'older': "\<C-p>", 'newer': "\<C-n>", 'prefixmatch': v:false},
|
||||
\]
|
||||
let prefix = 'vi'
|
||||
for h in histories
|
||||
call histadd(h.name, 'vim')
|
||||
call histadd(h.name, 'virtue')
|
||||
call histadd(h.name, 'Virgo')
|
||||
call histadd(h.name, 'vogue')
|
||||
call histadd(h.name, 'emacs')
|
||||
for k in keypairs
|
||||
let g:cmdlines = []
|
||||
let keyseqs = h.enter
|
||||
\ .. prefix
|
||||
\ .. repeat(k.older .. "\<Plug>(save-cmdline)", 2)
|
||||
\ .. repeat(k.newer .. "\<Plug>(save-cmdline)", 2)
|
||||
\ .. h.exit
|
||||
call feedkeys(keyseqs, 'xt')
|
||||
call histdel(h.name, -1) " delete the history added by feedkeys above
|
||||
let expect = k.prefixmatch
|
||||
\ ? ['virtue', 'vim', 'virtue', prefix]
|
||||
\ : ['emacs', 'vogue', 'emacs', prefix]
|
||||
call assert_equal(expect, g:cmdlines)
|
||||
endfor
|
||||
endfor
|
||||
|
||||
unlet g:cmdlines
|
||||
cunmap <Plug>(save-cmdline)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
82
src/nvim/testdir/test_ex_mode.vim
Normal file
82
src/nvim/testdir/test_ex_mode.vim
Normal file
@ -0,0 +1,82 @@
|
||||
" Test editing line in Ex mode (see :help Q and :help gQ).
|
||||
|
||||
" Helper function to test editing line in Q Ex mode
|
||||
func Ex_Q(cmd)
|
||||
" Is there a simpler way to test editing Ex line?
|
||||
call feedkeys("Q"
|
||||
\ .. "let s:test_ex =<< END\<CR>"
|
||||
\ .. a:cmd .. "\<CR>"
|
||||
\ .. "END\<CR>"
|
||||
\ .. "visual\<CR>", 'tx')
|
||||
return s:test_ex[0]
|
||||
endfunc
|
||||
|
||||
" Helper function to test editing line in gQ Ex mode
|
||||
func Ex_gQ(cmd)
|
||||
call feedkeys("gQ" .. a:cmd .. "\<C-b>\"\<CR>", 'tx')
|
||||
let ret = @:[1:] " Remove leading quote.
|
||||
call feedkeys("visual\<CR>", 'tx')
|
||||
return ret
|
||||
endfunc
|
||||
|
||||
" Helper function to test editing line with both Q and gQ Ex mode.
|
||||
func Ex(cmd)
|
||||
return [Ex_Q(a:cmd), Ex_gQ(a:cmd)]
|
||||
endfunc
|
||||
|
||||
" Test editing line in Ex mode (both Q and gQ)
|
||||
func Test_ex_mode()
|
||||
throw 'skipped: TODO: '
|
||||
let encoding_save = &encoding
|
||||
set sw=2
|
||||
|
||||
" for e in ['utf8', 'latin1']
|
||||
for e in ['utf8']
|
||||
exe 'set encoding=' . e
|
||||
|
||||
call assert_equal(['bar', 'bar'], Ex("foo bar\<C-u>bar"), e)
|
||||
call assert_equal(["1\<C-u>2", "1\<C-u>2"], Ex("1\<C-v>\<C-u>2"), e)
|
||||
call assert_equal(["1\<C-b>2\<C-e>3", '213'], Ex("1\<C-b>2\<C-e>3"), e)
|
||||
call assert_equal(['0123', '2013'], Ex("01\<Home>2\<End>3"), e)
|
||||
call assert_equal(['0123', '0213'], Ex("01\<Left>2\<Right>3"), e)
|
||||
call assert_equal(['01234', '0342'], Ex("012\<Left>\<Left>\<Insert>3\<Insert>4"), e)
|
||||
call assert_equal(["foo bar\<C-w>", 'foo '], Ex("foo bar\<C-w>"), e)
|
||||
call assert_equal(['foo', 'foo'], Ex("fooba\<Del>\<Del>"), e)
|
||||
call assert_equal(["foo\tbar", 'foobar'], Ex("foo\<Tab>bar"), e)
|
||||
call assert_equal(["abbrev\t", 'abbreviate'], Ex("abbrev\<Tab>"), e)
|
||||
call assert_equal([' 1', "1\<C-t>\<C-t>"], Ex("1\<C-t>\<C-t>"), e)
|
||||
call assert_equal([' 1', "1\<C-t>\<C-t>"], Ex("1\<C-t>\<C-t>\<C-d>"), e)
|
||||
call assert_equal([' foo', ' foo'], Ex(" foo\<C-d>"), e)
|
||||
call assert_equal(['foo', ' foo0'], Ex(" foo0\<C-d>"), e)
|
||||
call assert_equal(['foo', ' foo^'], Ex(" foo^\<C-d>"), e)
|
||||
endfor
|
||||
|
||||
set sw&
|
||||
let &encoding = encoding_save
|
||||
endfunc
|
||||
|
||||
func Test_ex_mode_errors()
|
||||
" Not allowed to enter ex mode when text is locked
|
||||
au InsertCharPre <buffer> normal! gQ<CR>
|
||||
let caught_e523 = 0
|
||||
try
|
||||
call feedkeys("ix\<esc>", 'xt')
|
||||
catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
|
||||
let caught_e523 = 1
|
||||
endtry
|
||||
call assert_equal(1, caught_e523)
|
||||
au! InsertCharPre
|
||||
|
||||
new
|
||||
au CmdLineEnter * call ExEnterFunc()
|
||||
func ExEnterFunc()
|
||||
|
||||
endfunc
|
||||
call feedkeys("gQvi\r", 'xt')
|
||||
|
||||
au! CmdLineEnter
|
||||
delfunc ExEnterFunc
|
||||
quit
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
@ -2286,7 +2286,7 @@ int win_close(win_T *win, bool free_buf)
|
||||
return FAIL; // window is already being closed
|
||||
}
|
||||
if (win == aucmd_win) {
|
||||
EMSG(_("E813: Cannot close autocmd window"));
|
||||
EMSG(_(e_autocmd_close));
|
||||
return FAIL;
|
||||
}
|
||||
if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window()) {
|
||||
|
@ -73,6 +73,7 @@ describe('NULL', function()
|
||||
null_expr_test('does not crash col()', 'col(L)', 0, 0)
|
||||
null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
|
||||
null_expr_test('does not crash line()', 'line(L)', 0, 0)
|
||||
null_expr_test('does not crash line() with window id', 'line(L, 1000)', 0, 0)
|
||||
null_expr_test('does not crash count()', 'count(L, 1)', 0, 0)
|
||||
null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1)
|
||||
null_expr_test('does not crash map()', 'map(L, "v:val")', 0, {})
|
||||
|
@ -64,10 +64,13 @@ describe('float window', function()
|
||||
|
||||
it('win_execute() should work' , function()
|
||||
local buf = meths.create_buf(false, false)
|
||||
meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'})
|
||||
meths.buf_set_lines(buf, 0, -1, true, {'the floatwin', 'abc', 'def'})
|
||||
local win = meths.open_win(buf, false, {relative='win', width=16, height=1, row=0, col=10})
|
||||
local line = funcs.win_execute(win, 'echo getline(1)')
|
||||
eq('\nthe floatwin', line)
|
||||
eq('\n1', funcs.win_execute(win, 'echo line(".",'..win.id..')'))
|
||||
eq('\n3', funcs.win_execute(win, 'echo line("$",'..win.id..')'))
|
||||
eq('\n0', funcs.win_execute(win, 'echo line("$", 123456)'))
|
||||
funcs.win_execute(win, 'bwipe!')
|
||||
end)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user