aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/if_lua.txt19
-rw-r--r--runtime/doc/provider.txt20
-rw-r--r--src/nvim/api/vim.c2
-rw-r--r--src/nvim/lua/vim.lua96
-rw-r--r--test/functional/api/vim_spec.lua2
-rw-r--r--test/functional/terminal/tui_spec.lua6
6 files changed, 89 insertions, 56 deletions
diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt
index a9b8c5fae8..1837e14623 100644
--- a/runtime/doc/if_lua.txt
+++ b/runtime/doc/if_lua.txt
@@ -533,6 +533,25 @@ inspect({object}, {options}) *vim.inspect()*
See also: ~
https://github.com/kikito/inspect.lua
+paste({lines}, {phase}) *vim.paste()*
+ Paste handler, invoked by |nvim_paste()| when a conforming UI
+ (such as the |TUI|) pastes text into the editor.
+
+ Parameters: ~
+ {lines} |readfile()|-style list of lines to paste.
+ |channel-lines|
+ {phase} -1: "non-streaming" paste: the call contains all
+ lines. If paste is "streamed", `phase` indicates the stream state:
+ • 1: starts the paste (exactly once)
+ • 2: continues the paste (zero or more times)
+ • 3: ends the paste (exactly once)
+
+ Return: ~
+ false if client should cancel the paste.
+
+ See also: ~
+ |paste|
+
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index eb6d562e18..833be8a103 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -222,11 +222,11 @@ a list of lines and `regtype` is a register type conforming to |setreg()|.
Paste *provider-paste* *paste*
"Paste" is a separate concept from |clipboard|: paste means "dump a bunch of
-text to the editor", whereas clipboard adds features like |quote-+| to get and
-set the OS clipboard buffer directly. When you middle-click or CTRL-SHIFT-v
-(macOS: CMD-v) to paste text into your terminal, this is "paste", not
-"clipboard": the terminal application (Nvim) just gets a stream of text, it
-does not interact with the clipboard directly.
+text to the editor", whereas clipboard provides features like |quote-+| to get
+and set the OS clipboard directly. For example, middle-click or CTRL-SHIFT-v
+(macOS: CMD-v) in your terminal is "paste", not "clipboard": the terminal
+application (Nvim) just gets a stream of text, it does not interact with the
+clipboard directly.
*bracketed-paste-mode*
Pasting in the |TUI| depends on the "bracketed paste" terminal capability,
@@ -235,19 +235,21 @@ pasted text. https://cirw.in/blog/bracketed-paste
This works automatically if your terminal supports it.
*ui-paste*
-GUIs can opt-into Nvim's amazing paste-handling by calling |nvim_paste()|.
+GUIs can paste by calling |nvim_paste()|.
PASTE BEHAVIOR ~
Paste always inserts text after the cursor. In cmdline-mode only the first
-line is pasted, to avoid accidentally executing many commands.
+line is pasted, to avoid accidentally executing many commands. Use the
+|cmdline-window| if you really want to paste multiple lines to the cmdline.
When pasting a huge amount of text, screen updates are throttled and the
message area shows a "..." pulse.
-You can implement a custom paste handler. Example: >
+You can implement a custom paste handler by redefining |vim.paste()|.
+Example: >
- vim._paste = (function(lines, phase)
+ vim.paste = (function(lines, phase)
vim.api.nvim_put(lines, 'c', true, true)
end)
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 910b76d02d..4f132ddbae 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1243,7 +1243,7 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
Array lines = string_to_array(data);
ADD(args, ARRAY_OBJ(lines));
ADD(args, INTEGER_OBJ(phase));
- rv = nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim._paste(...)"), args,
+ rv = nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim.paste(...)"), args,
err);
if (ERROR_SET(err)) {
draining = true;
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index 05951fbd0f..fd34b8545d 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -93,47 +93,6 @@ local function _os_proc_children(ppid)
return children
end
--- Default nvim_paste() handler.
-local _paste = (function()
- local tdots, tredraw, tick, got_line1 = 0, 0, 0, false
- return function(lines, phase)
- local call = vim.api.nvim_call_function
- local now = vim.loop.now()
- local mode = call('mode', {}):sub(1,1)
- if phase < 2 then -- Reset flags.
- tdots, tredraw, tick, got_line1 = now, now, 0, false
- end
- if mode == 'c' and not got_line1 then -- cmdline-mode: paste only 1 line.
- got_line1 = (#lines > 1)
- vim.api.nvim_set_option('paste', true) -- For nvim_input().
- local line1, _ = string.gsub(lines[1], '[\r\n\012\027]', ' ')
- vim.api.nvim_input(line1) -- Scrub "\r".
- elseif mode == 'i' or mode == 'R' then
- vim.api.nvim_put(lines, 'c', false, true)
- else
- vim.api.nvim_put(lines, 'c', true, true)
- end
- if (now - tredraw >= 1000) or phase == -1 or phase > 2 then
- tredraw = now
- vim.api.nvim_command('redraw')
- vim.api.nvim_command('redrawstatus')
- end
- if phase ~= -1 and (now - tdots >= 100) then
- local dots = ('.'):rep(tick % 4)
- tdots = now
- tick = tick + 1
- -- Use :echo because Lua print('') is a no-op, and we want to clear the
- -- message when there are zero dots.
- vim.api.nvim_command(('echo "%s"'):format(dots))
- end
- if phase == -1 or phase == 3 then
- vim.api.nvim_command('echo ""')
- vim.api.nvim_set_option('paste', false)
- end
- return true -- Paste will not continue if not returning `true`.
- end
-end)()
-
-- TODO(ZyX-I): Create compatibility layer.
--{{{1 package.path updater function
-- Last inserted paths. Used to clear out items from package.[c]path when they
@@ -202,6 +161,59 @@ local function inspect(object, options) -- luacheck: no unused
error(object, options) -- Stub for gen_vimdoc.py
end
+--- Paste handler, invoked by |nvim_paste()| when a conforming UI
+--- (such as the |TUI|) pastes text into the editor.
+---
+--@see |paste|
+---
+--@param lines |readfile()|-style list of lines to paste. |channel-lines|
+--@param phase -1: "non-streaming" paste: the call contains all lines.
+--- If paste is "streamed", `phase` indicates the stream state:
+--- - 1: starts the paste (exactly once)
+--- - 2: continues the paste (zero or more times)
+--- - 3: ends the paste (exactly once)
+--@returns false if client should cancel the paste.
+local function paste(lines, phase) end -- luacheck: no unused
+paste = (function()
+ local tdots, tredraw, tick, got_line1 = 0, 0, 0, false
+ return function(lines, phase)
+ local call = vim.api.nvim_call_function
+ local now = vim.loop.now()
+ local mode = call('mode', {}):sub(1,1)
+ if phase < 2 then -- Reset flags.
+ tdots, tredraw, tick, got_line1 = now, now, 0, false
+ end
+ if mode == 'c' and not got_line1 then -- cmdline-mode: paste only 1 line.
+ got_line1 = (#lines > 1)
+ vim.api.nvim_set_option('paste', true) -- For nvim_input().
+ local line1, _ = string.gsub(lines[1], '[\r\n\012\027]', ' ')
+ vim.api.nvim_input(line1) -- Scrub "\r".
+ elseif mode == 'i' or mode == 'R' then
+ vim.api.nvim_put(lines, 'c', false, true)
+ else
+ vim.api.nvim_put(lines, 'c', true, true)
+ end
+ if (now - tredraw >= 1000) or phase == -1 or phase > 2 then
+ tredraw = now
+ vim.api.nvim_command('redraw')
+ vim.api.nvim_command('redrawstatus')
+ end
+ if phase ~= -1 and (now - tdots >= 100) then
+ local dots = ('.'):rep(tick % 4)
+ tdots = now
+ tick = tick + 1
+ -- Use :echo because Lua print('') is a no-op, and we want to clear the
+ -- message when there are zero dots.
+ vim.api.nvim_command(('echo "%s"'):format(dots))
+ end
+ if phase == -1 or phase == 3 then
+ vim.api.nvim_command('echo ""')
+ vim.api.nvim_set_option('paste', false)
+ end
+ return true -- Paste will not continue if not returning `true`.
+ end
+end)()
+
--- Defers the wrapped callback until the Nvim API is safe to call.
---
--@see |vim-loop-callbacks|
@@ -227,8 +239,8 @@ local module = {
_update_package_paths = _update_package_paths,
_os_proc_children = _os_proc_children,
_os_proc_info = _os_proc_info,
- _paste = _paste,
_system = _system,
+ paste = paste,
schedule_wrap = schedule_wrap,
}
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 01e4a3a1a0..47a04795f8 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -396,7 +396,7 @@ describe('API', function()
eq(false, nvim('get_option', 'paste'))
end)
it('vim.paste() failure', function()
- nvim('execute_lua', 'vim._paste = (function(lines, phase) error("fake fail") end)', {})
+ nvim('execute_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {})
expect_err([[Error executing lua: %[string "%<nvim>"]:1: fake fail]],
request, 'nvim_paste', 'line 1\nline 2\nline 3', 1)
end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index e7db39b5d0..aafbbc04b1 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -326,8 +326,8 @@ describe('TUI', function()
it('paste: recovers from vim.paste() failure', function()
child_session:request('nvim_execute_lua', [[
- _G.save_paste_fn = vim._paste
- vim._paste = function(lines, phase) error("fake fail") end
+ _G.save_paste_fn = vim.paste
+ vim.paste = function(lines, phase) error("fake fail") end
]], {})
-- Start pasting...
feed_data('\027[200~line 1\nline 2\n')
@@ -360,7 +360,7 @@ describe('TUI', function()
]]}
-- Paste works if vim.paste() succeeds.
child_session:request('nvim_execute_lua', [[
- vim._paste = _G.save_paste_fn
+ vim.paste = _G.save_paste_fn
]], {})
feed_data('\027[200~line A\nline B\n\027[201~')
feed_data('\n') -- <Enter>