mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 11:28:22 +00:00
paste: phases, dots
- Send `phase` parameter to the paste handler. - Redraw at intervals and when paste terminates. - Show "..." throbber during paste to indicate activity.
This commit is contained in:
@@ -94,19 +94,39 @@ local function _os_proc_children(ppid)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Default paste function.
|
-- Default paste function.
|
||||||
local function _paste(lines)
|
local _paste = (function()
|
||||||
-- local eof = (lines == {''})
|
local tdots = 0
|
||||||
|
local tredraw = 0
|
||||||
|
local tick = 0
|
||||||
|
return function(lines, phase)
|
||||||
local call = vim.api.nvim_call_function
|
local call = vim.api.nvim_call_function
|
||||||
local mode = call('mode', {})
|
local now = vim.loop.now()
|
||||||
local curline = call('line', {'.'})
|
if phase == 1 then
|
||||||
-- vim.api.nvim_set_option('paste', true)
|
tdots = now
|
||||||
|
tredraw = now
|
||||||
|
tick = 0
|
||||||
|
if (call('mode', {})):find('[vV]') then
|
||||||
|
vim.api.nvim_feedkeys('', 'n', false)
|
||||||
|
end
|
||||||
|
end
|
||||||
vim.api.nvim_put(lines, 'c', true, true)
|
vim.api.nvim_put(lines, 'c', true, true)
|
||||||
-- vim.api.nvim_set_option('paste', false)
|
if (now - tredraw >= 1000) or phase == 1 or phase == 3 then
|
||||||
-- TODO: do not redraw (slow!) until paste is finished.
|
tredraw = now
|
||||||
-- if eof then
|
|
||||||
vim.api.nvim_command('redraw')
|
vim.api.nvim_command('redraw')
|
||||||
|
vim.api.nvim_command('redrawstatus')
|
||||||
|
end
|
||||||
|
if (now - tdots >= 100) then
|
||||||
|
local dots = ('.'):rep(tick % 4)
|
||||||
|
tdots = now
|
||||||
|
tick = tick + 1
|
||||||
|
vim.api.nvim_command(('echo "%s"'):format(dots))
|
||||||
|
end
|
||||||
|
if phase == 3 then
|
||||||
|
vim.api.nvim_command('echo ""')
|
||||||
|
end
|
||||||
return true -- Paste will not continue if not returning `true`.
|
return true -- Paste will not continue if not returning `true`.
|
||||||
end
|
end
|
||||||
|
end)()
|
||||||
|
|
||||||
-- TODO(ZyX-I): Create compatibility layer.
|
-- TODO(ZyX-I): Create compatibility layer.
|
||||||
--{{{1 package.path updater function
|
--{{{1 package.path updater function
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
void tinput_init(TermInput *input, Loop *loop)
|
void tinput_init(TermInput *input, Loop *loop)
|
||||||
{
|
{
|
||||||
input->loop = loop;
|
input->loop = loop;
|
||||||
input->paste_enabled = false;
|
input->paste = 0;
|
||||||
input->in_fd = 0;
|
input->in_fd = 0;
|
||||||
input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE);
|
input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE);
|
||||||
uv_mutex_init(&input->key_buffer_mutex);
|
uv_mutex_init(&input->key_buffer_mutex);
|
||||||
@@ -130,19 +130,20 @@ static void tinput_wait_enqueue(void **argv)
|
|||||||
TermInput *input = argv[0];
|
TermInput *input = argv[0];
|
||||||
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
|
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
|
||||||
const String keys = { .data = buf, .size = len };
|
const String keys = { .data = buf, .size = len };
|
||||||
if (input->paste_enabled) {
|
if (input->paste) {
|
||||||
Object keys_array = ARRAY_OBJ(string_to_array(keys));
|
|
||||||
Array args = { .capacity = 1, .size = 1, .items = &keys_array };
|
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
Object fret
|
Array args = ARRAY_DICT_INIT;
|
||||||
|
ADD(args, ARRAY_OBJ(string_to_array(keys)));
|
||||||
|
ADD(args, INTEGER_OBJ(input->paste));
|
||||||
|
Object rv
|
||||||
= nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim._paste(...)"),
|
= nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim._paste(...)"),
|
||||||
args, &err);
|
args, &err);
|
||||||
if (fret.type != kObjectTypeBoolean || !fret.data.boolean) {
|
input->paste = (rv.type == kObjectTypeBoolean && rv.data.boolean)
|
||||||
// Abort paste if handler does not return true.
|
? 2 // Paste phase: "continue".
|
||||||
input->paste_enabled = false;
|
: 0; // Abort paste if handler does not return true.
|
||||||
}
|
|
||||||
api_free_object(fret);
|
api_free_object(rv);
|
||||||
api_free_object(keys_array);
|
api_free_array(args);
|
||||||
rbuffer_consumed(input->key_buffer, len);
|
rbuffer_consumed(input->key_buffer, len);
|
||||||
rbuffer_reset(input->key_buffer);
|
rbuffer_reset(input->key_buffer);
|
||||||
if (ERROR_SET(&err)) {
|
if (ERROR_SET(&err)) {
|
||||||
@@ -392,18 +393,27 @@ static bool handle_bracketed_paste(TermInput *input)
|
|||||||
&& (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6)
|
&& (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6)
|
||||||
|| !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) {
|
|| !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) {
|
||||||
bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
|
bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
|
||||||
if (input->paste_enabled && enable) {
|
if (input->paste && enable) {
|
||||||
// Pasting "enable paste" code literally.
|
return false; // Pasting "start paste" code literally.
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// Advance past the sequence
|
// Advance past the sequence
|
||||||
rbuffer_consumed(input->read_stream.buffer, 6);
|
rbuffer_consumed(input->read_stream.buffer, 6);
|
||||||
if (input->paste_enabled == enable) {
|
if (!!input->paste == enable) {
|
||||||
return true;
|
return true; // Spurious "disable paste" code.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
// Flush before starting paste.
|
||||||
tinput_flush(input, true);
|
tinput_flush(input, true);
|
||||||
input->paste_enabled = enable;
|
// Paste phase: "first-chunk".
|
||||||
|
input->paste = 1;
|
||||||
|
} else {
|
||||||
|
// Paste phase: "last-chunk".
|
||||||
|
input->paste = 3;
|
||||||
|
tinput_flush(input, true);
|
||||||
|
// Paste phase: "disabled".
|
||||||
|
input->paste = 0;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -548,7 +558,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Push bytes directly (paste).
|
// Push bytes directly (paste).
|
||||||
if (input->paste_enabled) {
|
if (input->paste) {
|
||||||
RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
|
RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
|
||||||
size_t consumed = MIN(count, len);
|
size_t consumed = MIN(count, len);
|
||||||
assert(consumed <= input->read_stream.buffer->size);
|
assert(consumed <= input->read_stream.buffer->size);
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
typedef struct term_input {
|
typedef struct term_input {
|
||||||
int in_fd;
|
int in_fd;
|
||||||
bool paste_enabled;
|
uint8_t paste; // Phases: 0=disabled 1=first-chunk 2=continue 3=last-chunk
|
||||||
bool waiting;
|
bool waiting;
|
||||||
TermKey *tk;
|
TermKey *tk;
|
||||||
#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18
|
#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18
|
||||||
|
Reference in New Issue
Block a user