clipboard: remove start_batch_changes() in redir_write()

start_batch_changes() doesn't avoid invoking the clipboard
once-per-line, because the loop is actually in ex_echo(), which calls
redir_write() for each message. But we've already entered
start_batch_changes() by then, so that was never the problem.

    redir_write at /home/vagrant/old.neovim/build/../src/nvim/message.c:2523
    msg_puts_attr_len at /home/vagrant/old.neovim/build/../src/nvim/message.c:1600
    msg_outtrans_len_attr at /home/vagrant/old.neovim/build/../src/nvim/message.c:1221
    ex_echo at /home/vagrant/old.neovim/build/../src/nvim/eval.c:19433
    do_one_cmd at /home/vagrant/old.neovim/build/../src/nvim/ex_docmd.c:2242

Trying to defer _explicit_ clipboard updates is difficult.
    :redir @+ | silent echo system('cat foo') | redir END
is essentially equivalent to:
    for l in readfile('foo')
        let @+ .= l
    endfor
We cannot make judgements about when to ignore a script's bad decisions.
start_batch_changes() only works around the case of clipboard=unnamed,
i.e. _implicit_ clipboard updates (`:g/foo/d`).  Not explicit
assignment.
This commit is contained in:
Justin M. Keyes 2017-08-20 18:53:58 +02:00
parent 9882e25dc4
commit cc7e344f83
4 changed files with 37 additions and 12 deletions

View File

@ -2519,7 +2519,6 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
if (redirecting()) {
/* If the string doesn't start with CR or NL, go to msg_col */
if (*s != '\n' && *s != '\r') {
start_batch_changes();
while (cur_col < msg_col) {
if (capture_ga) {
ga_concat_len(capture_ga, " ", 1);
@ -2536,7 +2535,6 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
}
cur_col++;
}
end_batch_changes();
}
size_t len = maxlen == -1 ? STRLEN(s) : (size_t)maxlen;

View File

@ -5558,7 +5558,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
msg((char_u *)MSG_NO_CLIP);
clipboard_didwarn_unnamed = true;
}
// ... else, be silent (avoid a flood of messages).
// ... else, be silent (don't flood during :while, :redir, etc.).
goto end;
}
@ -5567,10 +5567,12 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
goto end;
} else { // unnamed register: "implicit" clipboard
if (writing && clipboard_delay_update) {
// For "set" (copy), defer the clipboard call.
clipboard_needs_update = true;
goto end;
} else if (!writing && clipboard_needs_update) {
goto end; // use the internal value
// For "get" (paste), use the internal value.
goto end;
}
if (cb_flags & CB_UNNAMEDPLUS) {
@ -5772,6 +5774,7 @@ void end_batch_changes(void)
}
clipboard_delay_update = false;
if (clipboard_needs_update) {
// unnamed ("implicit" clipboard)
set_clipboard(NUL, y_previous);
clipboard_needs_update = false;
}

View File

@ -93,17 +93,16 @@ describe('clipboard', function()
local screen = Screen.new(72, 8)
screen:attach()
command("let g:clipboard = 'bogus'")
feed_command('redir @+> | :call system("cat CONTRIBUTING.md") | redir END')
-- it is made empty
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
screen:expect([[
^ |
~ |
~ |
~ |
~ |
~ |
~ |
Error detected while processing function provider#clipboard#Executable: |
line 5: |
clipboard: invalid g:clipboard |
clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
Press ENTER or type command to continue^ |
]], nil, {{bold = true, foreground = Screen.colors.Blue}})
end)
end)
@ -118,7 +117,23 @@ describe('clipboard', function()
feed_command('call getreg("*")') -- force load of provider
end)
it('has independent "* and unnamed registers per default', function()
it('`:redir @+>` invokes clipboard once-per-message', function()
eq(0, eval("g:clip_called_set"))
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
-- Assuming CONTRIBUTING.md has >100 lines.
assert(eval("g:clip_called_set") > 100)
end)
it('`:redir @">` does not invoke clipboard', function()
-- :redir to a non-clipboard register, with `:set clipboard=unnamed`.
-- Does _not_ propagate to the clipboard (complies with Vim behavior).
command("set clipboard=unnamedplus")
eq(0, eval("g:clip_called_set"))
feed_command('redir @"> | :silent echo system("cat CONTRIBUTING.md") | redir END')
eq(0, eval("g:clip_called_set"))
end)
it('has independent "* and unnamed registers per default', function()
insert("some words")
feed('^"*dwdw"*P')
expect('some ')
@ -325,7 +340,7 @@ describe('clipboard', function()
end)
describe('with clipboard=unnamedplus', function()
describe('clipboard=unnamedplus', function()
before_each(function()
feed_command('set clipboard=unnamedplus')
end)
@ -369,6 +384,7 @@ describe('clipboard', function()
really unnamed
the plus]])
end)
it('is updated on global changes', function()
insert([[
text

View File

@ -5,7 +5,13 @@ let s:methods = {}
let g:cliplossy = 0
let g:cliperror = 0
" Count how many times the clipboard was invoked.
let g:clip_called_get = 0
let g:clip_called_set = 0
function! s:methods.get(reg)
let g:clip_called_get += 1
if g:cliperror
return 0
end
@ -19,6 +25,8 @@ function! s:methods.get(reg)
endfunction
function! s:methods.set(lines, regtype, reg)
let g:clip_called_set += 1
if a:reg == '"'
call s:methods.set(a:lines,a:regtype,'+')
call s:methods.set(a:lines,a:regtype,'*')