mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #16421 from seandewar/vim-8.1.0035
vim-patch:8.1.{35,42,64},8.2.{1781,1783,1976,2014,3671}
This commit is contained in:
commit
5abd7c2c14
@ -210,6 +210,11 @@ effective prompt text for a buffer, with |prompt_getprompt()|.
|
||||
The user can go to Normal mode and navigate through the buffer. This can be
|
||||
useful to see older output or copy text.
|
||||
|
||||
The CTRL-W key can be used to start a window command, such as CTRL-W w to
|
||||
switch to the next window. This also works in Insert mode (use Shift-CTRL-W
|
||||
to delete a word). When leaving the window Insert mode will be stopped. When
|
||||
coming back to the prompt window Insert mode will be restored.
|
||||
|
||||
Any command that starts Insert mode, such as "a", "i", "A" and "I", will move
|
||||
the cursor to the last line. "A" will move to the end of the line, "I" to the
|
||||
start of the line.
|
||||
|
@ -1213,10 +1213,13 @@ win_found:
|
||||
// Hmm, original window disappeared. Just use the first one.
|
||||
curwin = firstwin;
|
||||
}
|
||||
curbuf = curwin->w_buffer;
|
||||
// May need to restore insert mode for a prompt buffer.
|
||||
entering_window(curwin);
|
||||
|
||||
prevwin = win_find_by_handle(aco->save_prevwin_handle);
|
||||
vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
|
||||
hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
|
||||
curbuf = curwin->w_buffer;
|
||||
|
||||
xfree(globaldir);
|
||||
globaldir = aco->globaldir;
|
||||
|
@ -227,6 +227,7 @@ typedef struct insert_state {
|
||||
cmdarg_T *ca;
|
||||
int mincol;
|
||||
int cmdchar;
|
||||
int cmdchar_todo; // cmdchar to handle once in init_prompt
|
||||
int startln;
|
||||
long count;
|
||||
int c;
|
||||
@ -290,6 +291,7 @@ static void insert_enter(InsertState *s)
|
||||
s->did_backspace = true;
|
||||
s->old_topfill = -1;
|
||||
s->replaceState = REPLACE;
|
||||
s->cmdchar_todo = s->cmdchar;
|
||||
// Remember whether editing was restarted after CTRL-O
|
||||
did_restart_edit = restart_edit;
|
||||
// sleep before redrawing, needed for "CTRL-O :" that results in an
|
||||
@ -585,7 +587,8 @@ static int insert_check(VimState *state)
|
||||
}
|
||||
|
||||
if (bt_prompt(curbuf)) {
|
||||
init_prompt(s->cmdchar);
|
||||
init_prompt(s->cmdchar_todo);
|
||||
s->cmdchar_todo = NUL;
|
||||
}
|
||||
|
||||
// If we inserted a character at the last position of the last line in the
|
||||
@ -655,10 +658,17 @@ static int insert_check(VimState *state)
|
||||
|
||||
static int insert_execute(VimState *state, int key)
|
||||
{
|
||||
InsertState *const s = (InsertState *)state;
|
||||
if (stop_insert_mode) {
|
||||
// Insert mode ended, possibly from a callback.
|
||||
s->count = 0;
|
||||
s->nomove = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (key == K_IGNORE || key == K_NOP) {
|
||||
return -1; // get another key
|
||||
}
|
||||
InsertState *s = (InsertState *)state;
|
||||
s->c = key;
|
||||
|
||||
// Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
|
||||
@ -984,6 +994,15 @@ static int insert_handle_key(InsertState *s)
|
||||
break;
|
||||
|
||||
case Ctrl_W: // delete word before the cursor
|
||||
if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0) {
|
||||
// In a prompt window CTRL-W is used for window commands.
|
||||
// Use Shift-CTRL-W to delete a word.
|
||||
stuffcharReadbuff(Ctrl_W);
|
||||
restart_edit = 'A';
|
||||
s->nomove = true;
|
||||
s->count = 0;
|
||||
return 0;
|
||||
}
|
||||
s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space);
|
||||
auto_format(false, true);
|
||||
break;
|
||||
@ -1653,10 +1672,21 @@ static void init_prompt(int cmdchar_todo)
|
||||
coladvance(MAXCOL);
|
||||
changed_bytes(curbuf->b_ml.ml_line_count, 0);
|
||||
}
|
||||
|
||||
// Insert always starts after the prompt, allow editing text after it.
|
||||
if (Insstart_orig.lnum != curwin->w_cursor.lnum || Insstart_orig.col != (colnr_T)STRLEN(prompt)) {
|
||||
Insstart.lnum = curwin->w_cursor.lnum;
|
||||
Insstart.col = STRLEN(prompt);
|
||||
Insstart_orig = Insstart;
|
||||
Insstart_textlen = Insstart.col;
|
||||
Insstart_blank_vcol = MAXCOL;
|
||||
arrow_used = false;
|
||||
}
|
||||
|
||||
if (cmdchar_todo == 'A') {
|
||||
coladvance(MAXCOL);
|
||||
}
|
||||
if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) {
|
||||
if (curwin->w_cursor.col < (colnr_T)STRLEN(prompt)) {
|
||||
curwin->w_cursor.col = STRLEN(prompt);
|
||||
}
|
||||
// Make sure the cursor is in a valid position.
|
||||
@ -8241,7 +8271,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
|
||||
|| (!revins_on
|
||||
&& ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
|
||||
|| (!can_bs(BS_START)
|
||||
&& (arrow_used
|
||||
&& ((arrow_used && !bt_prompt(curbuf))
|
||||
|| (curwin->w_cursor.lnum == Insstart_orig.lnum
|
||||
&& curwin->w_cursor.col <= Insstart_orig.col)))
|
||||
|| (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
|
||||
|
@ -6932,7 +6932,7 @@ int showmode(void)
|
||||
do_mode = ((p_smd && msg_silent == 0)
|
||||
&& ((State & TERM_FOCUS)
|
||||
|| (State & INSERT)
|
||||
|| restart_edit
|
||||
|| restart_edit != NUL
|
||||
|| VIsual_active));
|
||||
if (do_mode || reg_recording != 0) {
|
||||
// Don't show mode right now, when not redrawing or inside a mapping.
|
||||
@ -7012,7 +7012,7 @@ int showmode(void)
|
||||
}
|
||||
msg_puts_attr(_(" INSERT"), attr);
|
||||
} else if (restart_edit == 'I' || restart_edit == 'i'
|
||||
|| restart_edit == 'a') {
|
||||
|| restart_edit == 'a' || restart_edit == 'A') {
|
||||
msg_puts_attr(_(" (insert)"), attr);
|
||||
} else if (restart_edit == 'R') {
|
||||
msg_puts_attr(_(" (replace)"), attr);
|
||||
|
@ -197,7 +197,12 @@ func RunTheTest(test)
|
||||
|
||||
" Close any extra tab pages and windows and make the current one not modified.
|
||||
while tabpagenr('$') > 1
|
||||
let winid = win_getid()
|
||||
quit!
|
||||
if winid == win_getid()
|
||||
echoerr 'Could not quit window'
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
|
||||
while 1
|
||||
|
@ -41,6 +41,10 @@ func WriteScript(name)
|
||||
\ ' set nomodified',
|
||||
\ 'endfunc',
|
||||
\ '',
|
||||
\ 'func SwitchWindows()',
|
||||
\ ' call timer_start(0, {-> execute("wincmd p|wincmd p", "")})',
|
||||
\ 'endfunc',
|
||||
\ '',
|
||||
\ 'call setline(1, "other buffer")',
|
||||
\ 'set nomodified',
|
||||
\ 'new',
|
||||
@ -89,9 +93,12 @@ func Test_prompt_editing()
|
||||
call term_sendkeys(buf, left . left . left . bs . '-')
|
||||
call WaitForAssert({-> assert_equal('cmd: -hel', term_getline(buf, 1))})
|
||||
|
||||
call term_sendkeys(buf, "\<C-O>lz")
|
||||
call WaitForAssert({-> assert_equal('cmd: -hzel', term_getline(buf, 1))})
|
||||
|
||||
let end = "\<End>"
|
||||
call term_sendkeys(buf, end . "x")
|
||||
call WaitForAssert({-> assert_equal('cmd: -helx', term_getline(buf, 1))})
|
||||
call WaitForAssert({-> assert_equal('cmd: -hzelx', term_getline(buf, 1))})
|
||||
|
||||
call term_sendkeys(buf, "\<C-U>exit\<CR>")
|
||||
call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))})
|
||||
@ -100,6 +107,28 @@ func Test_prompt_editing()
|
||||
call delete(scriptName)
|
||||
endfunc
|
||||
|
||||
func Test_prompt_switch_windows()
|
||||
throw 'skipped: TODO'
|
||||
call CanTestPromptBuffer()
|
||||
let scriptName = 'XpromptSwitchWindows'
|
||||
call WriteScript(scriptName)
|
||||
|
||||
let buf = RunVimInTerminal('-S ' . scriptName, {'rows': 12})
|
||||
call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))})
|
||||
call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))})
|
||||
|
||||
call term_sendkeys(buf, "\<C-O>:call SwitchWindows()\<CR>")
|
||||
call term_wait(buf, 50)
|
||||
call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))})
|
||||
|
||||
call term_sendkeys(buf, "\<Esc>")
|
||||
call term_wait(buf, 50)
|
||||
call WaitForAssert({-> assert_match('^ *$', term_getline(buf, 12))})
|
||||
|
||||
call StopVimInTerminal(buf)
|
||||
call delete(scriptName)
|
||||
endfunc
|
||||
|
||||
func Test_prompt_garbage_collect()
|
||||
func MyPromptCallback(x, text)
|
||||
" NOP
|
||||
@ -126,6 +155,14 @@ func Test_prompt_garbage_collect()
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_prompt_backspace()
|
||||
new
|
||||
set buftype=prompt
|
||||
call feedkeys("A123456\<Left>\<BS>\<Esc>", 'xt')
|
||||
call assert_equal('% 12346', getline(1))
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" Test for editing the prompt buffer
|
||||
func Test_prompt_buffer_edit()
|
||||
new
|
||||
@ -145,10 +182,9 @@ func Test_prompt_buffer_edit()
|
||||
call assert_beeps("normal! \<C-X>")
|
||||
" pressing CTRL-W in the prompt buffer should trigger the window commands
|
||||
call assert_equal(1, winnr())
|
||||
" In Nvim, CTRL-W commands aren't usable from insert mode in a prompt buffer
|
||||
" exe "normal A\<C-W>\<C-W>"
|
||||
" call assert_equal(2, winnr())
|
||||
" wincmd w
|
||||
exe "normal A\<C-W>\<C-W>"
|
||||
call assert_equal(2, winnr())
|
||||
wincmd w
|
||||
close!
|
||||
call assert_equal(0, prompt_setprompt([], ''))
|
||||
endfunc
|
||||
@ -187,4 +223,38 @@ func Test_prompt_buffer_getbufinfo()
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
function! Test_prompt_while_writing_to_hidden_buffer()
|
||||
throw 'skipped: TODO'
|
||||
call CanTestPromptBuffer()
|
||||
CheckUnix
|
||||
|
||||
" Make a job continuously write to a hidden buffer, check that the prompt
|
||||
" buffer is not affected.
|
||||
let scriptName = 'XpromptscriptHiddenBuf'
|
||||
let script =<< trim END
|
||||
set buftype=prompt
|
||||
call prompt_setprompt( bufnr(), 'cmd:' )
|
||||
let job = job_start(['/bin/sh', '-c',
|
||||
\ 'while true;
|
||||
\ do echo line;
|
||||
\ sleep 0.1;
|
||||
\ done'], #{out_io: 'buffer', out_name: ''})
|
||||
startinsert
|
||||
END
|
||||
eval script->writefile(scriptName)
|
||||
|
||||
let buf = RunVimInTerminal('-S ' .. scriptName, {})
|
||||
call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))})
|
||||
|
||||
call term_sendkeys(buf, 'test')
|
||||
call WaitForAssert({-> assert_equal('cmd:test', term_getline(buf, 1))})
|
||||
call term_sendkeys(buf, 'test')
|
||||
call WaitForAssert({-> assert_equal('cmd:testtest', term_getline(buf, 1))})
|
||||
call term_sendkeys(buf, 'test')
|
||||
call WaitForAssert({-> assert_equal('cmd:testtesttest', term_getline(buf, 1))})
|
||||
|
||||
call StopVimInTerminal(buf)
|
||||
call delete(scriptName)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -2229,6 +2229,54 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
|
||||
}
|
||||
}
|
||||
|
||||
static void leaving_window(win_T *const win)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// Only matters for a prompt window.
|
||||
if (!bt_prompt(win->w_buffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When leaving a prompt window stop Insert mode and perhaps restart
|
||||
// it when entering that window again.
|
||||
win->w_buffer->b_prompt_insert = restart_edit;
|
||||
if (restart_edit != NUL && mode_displayed) {
|
||||
clear_cmdline = true; // unshow mode later
|
||||
}
|
||||
restart_edit = NUL;
|
||||
|
||||
// When leaving the window (or closing the window) was done from a
|
||||
// callback we need to break out of the Insert mode loop and restart Insert
|
||||
// mode when entering the window again.
|
||||
if (State & INSERT) {
|
||||
stop_insert_mode = true;
|
||||
if (win->w_buffer->b_prompt_insert == NUL) {
|
||||
win->w_buffer->b_prompt_insert = 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void entering_window(win_T *const win)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// Only matters for a prompt window.
|
||||
if (!bt_prompt(win->w_buffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When switching to a prompt buffer that was in Insert mode, don't stop
|
||||
// Insert mode, it may have been set in leaving_window().
|
||||
if (win->w_buffer->b_prompt_insert != NUL) {
|
||||
stop_insert_mode = false;
|
||||
}
|
||||
|
||||
// When entering the prompt window restart Insert mode if we were in Insert
|
||||
// mode when we left it and not already in Insert mode.
|
||||
if ((State & INSERT) == 0) {
|
||||
restart_edit = win->w_buffer->b_prompt_insert;
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes all windows for buffer `buf`.
|
||||
///
|
||||
/// @param keep_curwin don't close `curwin`
|
||||
@ -2367,6 +2415,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
|
||||
shell_new_rows();
|
||||
}
|
||||
}
|
||||
entering_window(curwin);
|
||||
|
||||
// Since goto_tabpage_tp above did not trigger *Enter autocommands, do
|
||||
// that now.
|
||||
@ -2434,10 +2483,10 @@ int win_close(win_T *win, bool free_buf)
|
||||
}
|
||||
|
||||
if (win == curwin) {
|
||||
/*
|
||||
* Guess which window is going to be the new current window.
|
||||
* This may change because of the autocommands (sigh).
|
||||
*/
|
||||
leaving_window(curwin);
|
||||
|
||||
// Guess which window is going to be the new current window.
|
||||
// This may change because of the autocommands (sigh).
|
||||
if (!win->w_floating) {
|
||||
wp = frame2win(win_altframe(win, NULL));
|
||||
} else {
|
||||
@ -3801,6 +3850,8 @@ int win_new_tabpage(int after, char_u *filename)
|
||||
|
||||
lastused_tabpage = old_curtab;
|
||||
|
||||
entering_window(curwin);
|
||||
|
||||
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
|
||||
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
|
||||
apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
|
||||
@ -3956,6 +4007,7 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds)
|
||||
{
|
||||
tabpage_T *tp = curtab;
|
||||
|
||||
leaving_window(curwin);
|
||||
reset_VIsual_and_resel(); // stop Visual mode
|
||||
if (trigger_leave_autocmds) {
|
||||
if (new_curbuf != curbuf) {
|
||||
@ -4478,6 +4530,10 @@ static void win_enter_ext(win_T *const wp, const int flags)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!curwin_invalid) {
|
||||
leaving_window(curwin);
|
||||
}
|
||||
|
||||
if (!curwin_invalid && (flags & WEE_TRIGGER_LEAVE_AUTOCMDS)) {
|
||||
// Be careful: If autocommands delete the window, return now.
|
||||
if (wp->w_buffer != curbuf) {
|
||||
@ -4525,6 +4581,7 @@ static void win_enter_ext(win_T *const wp, const int flags)
|
||||
|
||||
fix_current_dir();
|
||||
|
||||
entering_window(curwin);
|
||||
// Careful: autocommands may close the window and make "wp" invalid
|
||||
if (flags & WEE_TRIGGER_NEW_AUTOCMDS) {
|
||||
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
|
||||
|
@ -1,9 +1,12 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local feed= helpers.feed
|
||||
local feed = helpers.feed
|
||||
local source = helpers.source
|
||||
local clear = helpers.clear
|
||||
local feed_command = helpers.feed_command
|
||||
local poke_eventloop = helpers.poke_eventloop
|
||||
local meths = helpers.meths
|
||||
local eq = helpers.eq
|
||||
|
||||
describe('prompt buffer', function()
|
||||
local screen
|
||||
@ -28,12 +31,17 @@ describe('prompt buffer', function()
|
||||
func TimerFunc(text)
|
||||
call append(line("$") - 1, 'Result: "' . a:text .'"')
|
||||
endfunc
|
||||
|
||||
func SwitchWindows()
|
||||
call timer_start(0, {-> execute("wincmd p|wincmd p", "")})
|
||||
endfunc
|
||||
]])
|
||||
feed_command("set noshowmode | set laststatus=0")
|
||||
feed_command("call setline(1, 'other buffer')")
|
||||
feed_command("new")
|
||||
feed_command("set buftype=prompt")
|
||||
feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))")
|
||||
feed_command("eval bufnr('')->prompt_setprompt('cmd: ')")
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
@ -56,10 +64,10 @@ describe('prompt buffer', function()
|
||||
feed("i")
|
||||
feed("hello\n")
|
||||
screen:expect([[
|
||||
% hello |
|
||||
cmd: hello |
|
||||
Command: "hello" |
|
||||
Result: "hello" |
|
||||
% ^ |
|
||||
cmd: ^ |
|
||||
[Prompt] [+] |
|
||||
other buffer |
|
||||
~ |
|
||||
@ -98,7 +106,7 @@ describe('prompt buffer', function()
|
||||
feed("i")
|
||||
feed("hello<BS><BS>")
|
||||
screen:expect([[
|
||||
% hel^ |
|
||||
cmd: hel^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
@ -111,7 +119,20 @@ describe('prompt buffer', function()
|
||||
]])
|
||||
feed("<Left><Left><Left><BS>-")
|
||||
screen:expect([[
|
||||
% -^hel |
|
||||
cmd: -^hel |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
[Prompt] [+] |
|
||||
other buffer |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
|
|
||||
]])
|
||||
feed("<C-O>lz")
|
||||
screen:expect([[
|
||||
cmd: -hz^el |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
@ -124,7 +145,7 @@ describe('prompt buffer', function()
|
||||
]])
|
||||
feed("<End>x")
|
||||
screen:expect([[
|
||||
% -helx^ |
|
||||
cmd: -hzelx^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
@ -150,4 +171,58 @@ describe('prompt buffer', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
it('switch windows', function()
|
||||
feed_command("set showmode")
|
||||
feed("i")
|
||||
screen:expect([[
|
||||
cmd: ^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
[Prompt] [+] |
|
||||
other buffer |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
-- INSERT -- |
|
||||
]])
|
||||
feed("<C-O>:call SwitchWindows()<CR>")
|
||||
poke_eventloop()
|
||||
screen:expect([[
|
||||
cmd: ^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
[Prompt] [+] |
|
||||
other buffer |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
-- INSERT -- |
|
||||
]])
|
||||
feed("<Esc>")
|
||||
poke_eventloop()
|
||||
screen:expect([[
|
||||
cmd:^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
[Prompt] [+] |
|
||||
other buffer |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('keeps insert mode after aucmd_restbuf in callback', function()
|
||||
source [[
|
||||
let s:buf = nvim_create_buf(1, 1)
|
||||
call timer_start(0, {-> nvim_buf_set_lines(s:buf, -1, -1, 0, ['walrus'])})
|
||||
startinsert
|
||||
]]
|
||||
poke_eventloop()
|
||||
eq({ mode = "i", blocking = false }, meths.get_mode())
|
||||
end)
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user