mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
Merge #5546 from justinmk/global-ctrlc
ex_global: Catch CTRL-C even if it is mapped.
This commit is contained in:
commit
ed198737fd
@ -4074,61 +4074,66 @@ void ex_global(exarg_T *eap)
|
|||||||
vim_regfree(regmatch.regprog);
|
vim_regfree(regmatch.regprog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// Execute `cmd` on lines marked with ml_setmarked().
|
||||||
* Execute "cmd" on lines marked with ml_setmarked().
|
|
||||||
*/
|
|
||||||
void global_exe(char_u *cmd)
|
void global_exe(char_u *cmd)
|
||||||
{
|
{
|
||||||
linenr_T old_lcount; /* b_ml.ml_line_count before the command */
|
linenr_T old_lcount; // b_ml.ml_line_count before the command
|
||||||
buf_T *old_buf = curbuf; /* remember what buffer we started in */
|
buf_T *old_buf = curbuf; // remember what buffer we started in
|
||||||
linenr_T lnum; /* line number according to old situation */
|
linenr_T lnum; // line number according to old situation
|
||||||
|
int save_mapped_ctrl_c = mapped_ctrl_c;
|
||||||
|
|
||||||
/*
|
// Set current position only once for a global command.
|
||||||
* Set current position only once for a global command.
|
// If global_busy is set, setpcmark() will not do anything.
|
||||||
* If global_busy is set, setpcmark() will not do anything.
|
// If there is an error, global_busy will be incremented.
|
||||||
* If there is an error, global_busy will be incremented.
|
|
||||||
*/
|
|
||||||
setpcmark();
|
setpcmark();
|
||||||
|
|
||||||
/* When the command writes a message, don't overwrite the command. */
|
// When the command writes a message, don't overwrite the command.
|
||||||
msg_didout = TRUE;
|
msg_didout = true;
|
||||||
|
// Disable CTRL-C mapping, let it interrupt (potentially long output).
|
||||||
|
mapped_ctrl_c = 0;
|
||||||
|
|
||||||
sub_nsubs = 0;
|
sub_nsubs = 0;
|
||||||
sub_nlines = 0;
|
sub_nlines = 0;
|
||||||
global_need_beginline = FALSE;
|
global_need_beginline = false;
|
||||||
global_busy = 1;
|
global_busy = 1;
|
||||||
old_lcount = curbuf->b_ml.ml_line_count;
|
old_lcount = curbuf->b_ml.ml_line_count;
|
||||||
|
|
||||||
while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) {
|
while (!got_int && (lnum = ml_firstmarked()) != 0 && global_busy == 1) {
|
||||||
curwin->w_cursor.lnum = lnum;
|
curwin->w_cursor.lnum = lnum;
|
||||||
curwin->w_cursor.col = 0;
|
curwin->w_cursor.col = 0;
|
||||||
if (*cmd == NUL || *cmd == '\n')
|
if (*cmd == NUL || *cmd == '\n') {
|
||||||
do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT);
|
do_cmdline((char_u *)"p", NULL, NULL, DOCMD_NOWAIT);
|
||||||
else
|
} else {
|
||||||
do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT);
|
do_cmdline(cmd, NULL, NULL, DOCMD_NOWAIT);
|
||||||
|
}
|
||||||
os_breakcheck();
|
os_breakcheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapped_ctrl_c = save_mapped_ctrl_c;
|
||||||
global_busy = 0;
|
global_busy = 0;
|
||||||
if (global_need_beginline)
|
if (global_need_beginline) {
|
||||||
beginline(BL_WHITE | BL_FIX);
|
beginline(BL_WHITE | BL_FIX);
|
||||||
else
|
} else {
|
||||||
check_cursor(); /* cursor may be beyond the end of the line */
|
check_cursor(); // cursor may be beyond the end of the line
|
||||||
|
}
|
||||||
|
|
||||||
/* the cursor may not have moved in the text but a change in a previous
|
// the cursor may not have moved in the text but a change in a previous
|
||||||
* line may move it on the screen */
|
// line may move it on the screen
|
||||||
changed_line_abv_curs();
|
changed_line_abv_curs();
|
||||||
|
|
||||||
/* If it looks like no message was written, allow overwriting the
|
// If it looks like no message was written, allow overwriting the
|
||||||
* command with the report for number of changes. */
|
// command with the report for number of changes.
|
||||||
if (msg_col == 0 && msg_scrolled == 0)
|
if (msg_col == 0 && msg_scrolled == 0) {
|
||||||
msg_didout = FALSE;
|
msg_didout = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* If substitutes done, report number of substitutes, otherwise report
|
// If substitutes done, report number of substitutes, otherwise report
|
||||||
* number of extra or deleted lines.
|
// number of extra or deleted lines.
|
||||||
* Don't report extra or deleted lines in the edge case where the buffer
|
// Don't report extra or deleted lines in the edge case where the buffer
|
||||||
* we are in after execution is different from the buffer we started in. */
|
// we are in after execution is different from the buffer we started in.
|
||||||
if (!do_sub_msg(false) && curbuf == old_buf)
|
if (!do_sub_msg(false) && curbuf == old_buf) {
|
||||||
msgmore(curbuf->b_ml.ml_line_count - old_lcount);
|
msgmore(curbuf->b_ml.ml_line_count - old_lcount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE)
|
#if defined(EXITFREE)
|
||||||
|
74
test/functional/ex_cmds/global_spec.lua
Normal file
74
test/functional/ex_cmds/global_spec.lua
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
local clear, feed, source = helpers.clear, helpers.feed, helpers.source
|
||||||
|
|
||||||
|
if helpers.pending_win32(pending) then return end
|
||||||
|
|
||||||
|
describe(':global', function()
|
||||||
|
before_each(function()
|
||||||
|
clear()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('is interrupted by mapped CTRL-C', function()
|
||||||
|
if os.getenv("TRAVIS") and os.getenv("CLANG_SANITIZER") == "ASAN_UBSAN" then
|
||||||
|
-- XXX: ASAN_UBSAN is too slow to react to the CTRL-C.
|
||||||
|
pending("", function() end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
source([[
|
||||||
|
set nomore
|
||||||
|
set undolevels=-1
|
||||||
|
nnoremap <C-C> <NOP>
|
||||||
|
for i in range(0, 99999)
|
||||||
|
put ='XXX'
|
||||||
|
endfor
|
||||||
|
put ='ZZZ'
|
||||||
|
1
|
||||||
|
.delete
|
||||||
|
]])
|
||||||
|
|
||||||
|
local screen = Screen.new(52, 6)
|
||||||
|
screen:attach()
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
[0] = {foreground = Screen.colors.White,
|
||||||
|
background = Screen.colors.Red},
|
||||||
|
[1] = {bold = true,
|
||||||
|
foreground = Screen.colors.SeaGreen}
|
||||||
|
})
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
^XXX |
|
||||||
|
XXX |
|
||||||
|
XXX |
|
||||||
|
XXX |
|
||||||
|
XXX |
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
local function test_ctrl_c(ms)
|
||||||
|
feed(":global/^/p<CR>")
|
||||||
|
helpers.sleep(ms)
|
||||||
|
feed("<C-C>")
|
||||||
|
screen:expect([[
|
||||||
|
XXX |
|
||||||
|
XXX |
|
||||||
|
XXX |
|
||||||
|
XXX |
|
||||||
|
{0:Interrupted} |
|
||||||
|
Interrupt: {1:Press ENTER or type command to continue}^ |
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The test is time-sensitive. Try with different sleep values.
|
||||||
|
local ms_values = {10, 50, 100}
|
||||||
|
for i, ms in ipairs(ms_values) do
|
||||||
|
if i < #ms_values then
|
||||||
|
local status, _ = pcall(test_ctrl_c, ms)
|
||||||
|
if status then break end
|
||||||
|
else -- Call the last attempt directly.
|
||||||
|
test_ctrl_c(ms)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue
Block a user