mirror of
https://github.com/neovim/neovim.git
synced 2025-09-22 19:18:34 +00:00
paste: WIP #4448
This commit is contained in:
@@ -4215,11 +4215,11 @@ getchar([expr]) *getchar()*
|
|||||||
:endfunction
|
:endfunction
|
||||||
<
|
<
|
||||||
You may also receive synthetic characters, such as
|
You may also receive synthetic characters, such as
|
||||||
|<CursorHold>|. Often you will want to ignore this and get
|
|<LeftMouse>|. Often you will want to ignore this and get
|
||||||
another character: >
|
another character: >
|
||||||
:function GetKey()
|
:function GetKey()
|
||||||
: let c = getchar()
|
: let c = getchar()
|
||||||
: while c == "\<CursorHold>"
|
: while c == "\<LeftMouse>"
|
||||||
: let c = getchar()
|
: let c = getchar()
|
||||||
: endwhile
|
: endwhile
|
||||||
: return c
|
: return c
|
||||||
|
@@ -36,6 +36,10 @@ void loop_init(Loop *loop, void *data)
|
|||||||
/// Processes all `Loop.fast_events` events.
|
/// Processes all `Loop.fast_events` events.
|
||||||
/// Does NOT process `Loop.events`, that is an application-specific decision.
|
/// Does NOT process `Loop.events`, that is an application-specific decision.
|
||||||
///
|
///
|
||||||
|
/// @param loop
|
||||||
|
/// @param ms 0: non-blocking poll.
|
||||||
|
/// >0: timeout after `ms`.
|
||||||
|
/// <0: wait forever.
|
||||||
/// @returns true if `ms` timeout was reached
|
/// @returns true if `ms` timeout was reached
|
||||||
bool loop_poll_events(Loop *loop, int ms)
|
bool loop_poll_events(Loop *loop, int ms)
|
||||||
{
|
{
|
||||||
@@ -104,10 +108,10 @@ static void loop_deferred_event(void **argv)
|
|||||||
void loop_on_put(MultiQueue *queue, void *data)
|
void loop_on_put(MultiQueue *queue, void *data)
|
||||||
{
|
{
|
||||||
Loop *loop = data;
|
Loop *loop = data;
|
||||||
// Sometimes libuv will run pending callbacks(timer for example) before
|
// Sometimes libuv will run pending callbacks (timer for example) before
|
||||||
// blocking for a poll. If this happens and the callback pushes a event to one
|
// blocking for a poll. If this happens and the callback pushes a event to one
|
||||||
// of the queues, the event would only be processed after the poll
|
// of the queues, the event would only be processed after the poll
|
||||||
// returns(user hits a key for example). To avoid this scenario, we call
|
// returns (user hits a key for example). To avoid this scenario, we call
|
||||||
// uv_stop when a event is enqueued.
|
// uv_stop when a event is enqueued.
|
||||||
uv_stop(&loop->uv);
|
uv_stop(&loop->uv);
|
||||||
}
|
}
|
||||||
@@ -162,6 +166,7 @@ static void async_cb(uv_async_t *handle)
|
|||||||
{
|
{
|
||||||
Loop *l = handle->loop->data;
|
Loop *l = handle->loop->data;
|
||||||
uv_mutex_lock(&l->mutex);
|
uv_mutex_lock(&l->mutex);
|
||||||
|
// Flush thread_events to fast_events for processing on main loop.
|
||||||
while (!multiqueue_empty(l->thread_events)) {
|
while (!multiqueue_empty(l->thread_events)) {
|
||||||
Event ev = multiqueue_get(l->thread_events);
|
Event ev = multiqueue_get(l->thread_events);
|
||||||
multiqueue_put_event(l->fast_events, ev);
|
multiqueue_put_event(l->fast_events, ev);
|
||||||
|
@@ -532,7 +532,7 @@ static int command_line_check(VimState *state)
|
|||||||
|
|
||||||
static int command_line_execute(VimState *state, int key)
|
static int command_line_execute(VimState *state, int key)
|
||||||
{
|
{
|
||||||
if (key == K_IGNORE || key == K_PASTE) {
|
if (key == K_IGNORE) {
|
||||||
return -1; // get another key
|
return -1; // get another key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -151,7 +151,6 @@ static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */
|
|||||||
static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
|
static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
|
||||||
|
|
||||||
static size_t last_recorded_len = 0; // number of last recorded chars
|
static size_t last_recorded_len = 0; // number of last recorded chars
|
||||||
static const uint8_t ui_toggle[] = { K_SPECIAL, KS_EXTRA, KE_PASTE, 0 };
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "getchar.c.generated.h"
|
# include "getchar.c.generated.h"
|
||||||
@@ -1902,14 +1901,8 @@ static int vgetorpeek(int advance)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a key that can toggle the 'paste' option
|
if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) {
|
||||||
if (mp == NULL && (State & (INSERT|NORMAL))) {
|
bool match = typebuf_match_len(p_pt, &mlen);
|
||||||
bool match = typebuf_match_len(ui_toggle, &mlen);
|
|
||||||
if (!match && mlen != typebuf.tb_len && *p_pt != NUL) {
|
|
||||||
// didn't match ui_toggle_key and didn't try the whole typebuf,
|
|
||||||
// check the 'pastetoggle'
|
|
||||||
match = typebuf_match_len(p_pt, &mlen);
|
|
||||||
}
|
|
||||||
if (match) {
|
if (match) {
|
||||||
// write chars to script file(s)
|
// write chars to script file(s)
|
||||||
if (mlen > typebuf.tb_maplen) {
|
if (mlen > typebuf.tb_maplen) {
|
||||||
@@ -1940,8 +1933,7 @@ static int vgetorpeek(int advance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((mp == NULL || max_mlen >= mp_match_len)
|
if ((mp == NULL || max_mlen >= mp_match_len)
|
||||||
&& keylen != KEYLEN_PART_MAP
|
&& keylen != KEYLEN_PART_MAP) {
|
||||||
&& !(keylen == KEYLEN_PART_KEY && c1 == ui_toggle[0])) {
|
|
||||||
// No matching mapping found or found a non-matching mapping that
|
// No matching mapping found or found a non-matching mapping that
|
||||||
// matches at least what the matching mapping matched
|
// matches at least what the matching mapping matched
|
||||||
keylen = 0;
|
keylen = 0;
|
||||||
|
@@ -72,12 +72,6 @@
|
|||||||
# define VIMRC_FILE ".nvimrc"
|
# define VIMRC_FILE ".nvimrc"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
kNone = -1,
|
|
||||||
kFalse = 0,
|
|
||||||
kTrue = 1,
|
|
||||||
} TriState;
|
|
||||||
|
|
||||||
EXTERN struct nvim_stats_s {
|
EXTERN struct nvim_stats_s {
|
||||||
int64_t fsync;
|
int64_t fsync;
|
||||||
int64_t redraw;
|
int64_t redraw;
|
||||||
|
@@ -309,7 +309,6 @@ static const struct key_name_entry {
|
|||||||
{ K_ZERO, "Nul" },
|
{ K_ZERO, "Nul" },
|
||||||
{ K_SNR, "SNR" },
|
{ K_SNR, "SNR" },
|
||||||
{ K_PLUG, "Plug" },
|
{ K_PLUG, "Plug" },
|
||||||
{ K_PASTE, "Paste" },
|
|
||||||
{ K_COMMAND, "Cmd" },
|
{ K_COMMAND, "Cmd" },
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
|
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
|
||||||
|
@@ -239,14 +239,12 @@ enum key_extra {
|
|||||||
|
|
||||||
, KE_DROP = 95 // DnD data is available
|
, KE_DROP = 95 // DnD data is available
|
||||||
// , KE_CURSORHOLD = 96 // CursorHold event
|
// , KE_CURSORHOLD = 96 // CursorHold event
|
||||||
, KE_NOP = 97 // doesn't do something
|
, KE_NOP = 97 // no-op: does nothing
|
||||||
, KE_FOCUSGAINED = 98 // focus gained
|
, KE_FOCUSGAINED = 98 // focus gained
|
||||||
, KE_FOCUSLOST = 99 // focus lost
|
, KE_FOCUSLOST = 99 // focus lost
|
||||||
// , KE_MOUSEMOVE = 100 // mouse moved with no button down
|
// , KE_MOUSEMOVE = 100 // mouse moved with no button down
|
||||||
// , KE_CANCEL = 101 // return from vgetc
|
// , KE_CANCEL = 101 // return from vgetc
|
||||||
, KE_EVENT = 102 // event
|
, KE_EVENT = 102 // event
|
||||||
, KE_PASTE = 103 // special key to toggle the 'paste' option.
|
|
||||||
// sent only by UIs
|
|
||||||
, KE_COMMAND = 104 // <Cmd> special key
|
, KE_COMMAND = 104 // <Cmd> special key
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -443,7 +441,6 @@ enum key_extra {
|
|||||||
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
|
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
|
||||||
|
|
||||||
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
|
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
|
||||||
#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)
|
|
||||||
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
|
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
|
||||||
|
|
||||||
/* Bits for modifier mask */
|
/* Bits for modifier mask */
|
||||||
|
@@ -448,7 +448,7 @@ static void process_interrupts(void)
|
|||||||
|
|
||||||
size_t consume_count = 0;
|
size_t consume_count = 0;
|
||||||
RBUFFER_EACH_REVERSE(input_buffer, c, i) {
|
RBUFFER_EACH_REVERSE(input_buffer, c, i) {
|
||||||
if ((uint8_t)c == 3) {
|
if ((uint8_t)c == Ctrl_C) {
|
||||||
got_int = true;
|
got_int = true;
|
||||||
consume_count = i;
|
consume_count = i;
|
||||||
break;
|
break;
|
||||||
@@ -456,7 +456,7 @@ static void process_interrupts(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (got_int && consume_count) {
|
if (got_int && consume_count) {
|
||||||
// Remove everything typed before the CTRL-C
|
// Remove all unprocessed input (typeahead) before the CTRL-C.
|
||||||
rbuffer_consumed(input_buffer, consume_count);
|
rbuffer_consumed(input_buffer, consume_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -475,10 +475,6 @@ static int terminal_execute(VimState *state, int key)
|
|||||||
TerminalState *s = (TerminalState *)state;
|
TerminalState *s = (TerminalState *)state;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
// Temporary fix until paste events gets implemented
|
|
||||||
case K_PASTE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case K_LEFTMOUSE:
|
case K_LEFTMOUSE:
|
||||||
case K_LEFTDRAG:
|
case K_LEFTDRAG:
|
||||||
case K_LEFTRELEASE:
|
case K_LEFTRELEASE:
|
||||||
|
@@ -16,7 +16,8 @@
|
|||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/event/rstream.h"
|
#include "nvim/event/rstream.h"
|
||||||
|
|
||||||
#define PASTETOGGLE_KEY "<Paste>"
|
#define PASTE_KEY "<Paste>"
|
||||||
|
#define PASTEPOST_KEY "<PastePost>"
|
||||||
#define KEY_BUFFER_SIZE 0xfff
|
#define KEY_BUFFER_SIZE 0xfff
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
@@ -292,9 +293,12 @@ static void tk_getkeys(TermInput *input, bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != TERMKEY_RES_AGAIN || input->paste_enabled) {
|
if (result != TERMKEY_RES_AGAIN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// else: Partial keypress event was found in the buffer, but it does not
|
||||||
|
// yet contain all the bytes required. `key` structure indicates what
|
||||||
|
// termkey_getkey_force() would return.
|
||||||
|
|
||||||
int ms = get_key_code_timeout();
|
int ms = get_key_code_timeout();
|
||||||
|
|
||||||
@@ -326,8 +330,8 @@ static bool handle_focus_event(TermInput *input)
|
|||||||
if (rbuffer_size(input->read_stream.buffer) > 2
|
if (rbuffer_size(input->read_stream.buffer) > 2
|
||||||
&& (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3)
|
&& (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3)
|
||||||
|| !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) {
|
|| !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) {
|
||||||
// Advance past the sequence
|
|
||||||
bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
|
bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
|
||||||
|
// Advance past the sequence
|
||||||
rbuffer_consumed(input->read_stream.buffer, 3);
|
rbuffer_consumed(input->read_stream.buffer, 3);
|
||||||
aucmd_schedule_focusgained(focus_gained);
|
aucmd_schedule_focusgained(focus_gained);
|
||||||
return true;
|
return true;
|
||||||
@@ -343,16 +347,31 @@ static bool handle_bracketed_paste(TermInput *input)
|
|||||||
bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
|
bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
|
||||||
// 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 (enable && input->paste_enabled) {
|
||||||
|
// Bogus "paste start"; forward it.
|
||||||
|
tinput_enqueue(input, "<C-v><Esc>200~", sizeof("<C-v><Esc>200~") - 1);
|
||||||
|
return true;
|
||||||
|
} else if (!enable && !input->paste_enabled) {
|
||||||
|
// Bogus "paste stop"; ignore it.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
tinput_enqueue(input, PASTETOGGLE_KEY, sizeof(PASTETOGGLE_KEY) - 1);
|
|
||||||
input->paste_enabled = enable;
|
input->paste_enabled = enable;
|
||||||
|
if (enable) {
|
||||||
|
loop_schedule(&main_loop, event_create(apply_pastepre, 0));
|
||||||
|
} else {
|
||||||
|
tinput_enqueue(input, PASTEPOST_KEY, sizeof(PASTEPOST_KEY) - 1);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void apply_pastepre(void **argv) // MAIN thread
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
static bool handle_forced_escape(TermInput *input)
|
static bool handle_forced_escape(TermInput *input)
|
||||||
{
|
{
|
||||||
if (rbuffer_size(input->read_stream.buffer) > 1
|
if (rbuffer_size(input->read_stream.buffer) > 1
|
||||||
@@ -477,9 +496,11 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the next 'esc' and push everything up to it(excluding). This is done
|
//
|
||||||
// so the `handle_bracketed_paste`/`handle_forced_escape` calls above work
|
// Find the next ESC and push everything up to it (excluding), so it will
|
||||||
// as expected.
|
// be the first thing encountered on the next iteration. The `handle_*`
|
||||||
|
// calls (above) depend on this.
|
||||||
|
//
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
RBUFFER_EACH(input->read_stream.buffer, c, i) {
|
RBUFFER_EACH(input->read_stream.buffer, c, i) {
|
||||||
count = i + 1;
|
count = i + 1;
|
||||||
@@ -488,7 +509,6 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
|
RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
|
||||||
size_t consumed = termkey_push_bytes(input->tk, ptr, MIN(count, len));
|
size_t consumed = termkey_push_bytes(input->tk, ptr, MIN(count, len));
|
||||||
// termkey_push_bytes can return (size_t)-1, so it is possible that
|
// termkey_push_bytes can return (size_t)-1, so it is possible that
|
||||||
@@ -505,7 +525,8 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
|
|||||||
}
|
}
|
||||||
} while (rbuffer_size(input->read_stream.buffer));
|
} while (rbuffer_size(input->read_stream.buffer));
|
||||||
tinput_flush(input, true);
|
tinput_flush(input, true);
|
||||||
// Make sure the next input escape sequence fits into the ring buffer
|
// Make sure the next input escape sequence fits into the ring buffer without
|
||||||
// without wrap around, otherwise it could be misinterpreted.
|
// wraparound, else it could be misinterpreted (because rbuffer_read_ptr()
|
||||||
|
// exposes the underlying buffer to callers unaware of the wraparound).
|
||||||
rbuffer_reset(input->read_stream.buffer);
|
rbuffer_reset(input->read_stream.buffer);
|
||||||
}
|
}
|
||||||
|
@@ -23,4 +23,10 @@ typedef int LuaRef;
|
|||||||
|
|
||||||
typedef struct expand expand_T;
|
typedef struct expand expand_T;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kNone = -1,
|
||||||
|
kFalse = 0,
|
||||||
|
kTrue = 1,
|
||||||
|
} TriState;
|
||||||
|
|
||||||
#endif // NVIM_TYPES_H
|
#endif // NVIM_TYPES_H
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
|
-- To test tui/input.c, this module spawns `nvim` inside :terminal and sends
|
||||||
|
-- bytes via jobsend(). Note: the functional/helpers.lua test-session methods
|
||||||
|
-- operate on the _host_ session, _not_ the child session.
|
||||||
local helpers = require('test.functional.helpers')(nil)
|
local helpers = require('test.functional.helpers')(nil)
|
||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
local nvim_dir = helpers.nvim_dir
|
local nvim_dir = helpers.nvim_dir
|
||||||
|
204
test/functional/terminal/paste_spec.lua
Normal file
204
test/functional/terminal/paste_spec.lua
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
-- TUI tests for "bracketed paste" mode.
|
||||||
|
-- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
|
||||||
|
local helpers = require('test.functional.helpers')
|
||||||
|
local child_tui = require('test.functional.tui.child_session')
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
local execute = helpers.execute
|
||||||
|
local nvim_dir = helpers.nvim_dir
|
||||||
|
local eval = helpers.eval
|
||||||
|
local eq = helpers.eq
|
||||||
|
local feed_tui = child_tui.feed_data
|
||||||
|
|
||||||
|
describe('tui paste', function()
|
||||||
|
local screen
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
helpers.clear()
|
||||||
|
screen = child_tui.screen_setup(0, '["'..helpers.nvim_prog..
|
||||||
|
'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]')
|
||||||
|
|
||||||
|
-- Pasting can be really slow in the TUI, especially in ASAN.
|
||||||
|
screen.timeout = 5000
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
{1: } |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
[No Name] |
|
||||||
|
|
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
screen:detach()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function setup_harness()
|
||||||
|
-- Delete the default PastePre/PastePost autocmds.
|
||||||
|
feed_tui(":autocmd! PastePre,PastePost\n")
|
||||||
|
|
||||||
|
-- Set up test handlers.
|
||||||
|
feed_tui(":autocmd PastePre * "..
|
||||||
|
"call feedkeys('iPastePre mode:'.mode(),'n')\n")
|
||||||
|
feed_tui(":autocmd PastePost * "..
|
||||||
|
"call feedkeys('PastePost mode:'.mode(),'n')\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
it('handles long bursts of input', function()
|
||||||
|
execute('set ruler')
|
||||||
|
local t = {}
|
||||||
|
for i = 1, 3000 do
|
||||||
|
t[i] = 'item ' .. tostring(i)
|
||||||
|
end
|
||||||
|
feed_tui('i\027[200~')
|
||||||
|
feed_tui(table.concat(t, '\n'))
|
||||||
|
feed_tui('\027[201~')
|
||||||
|
screen:expect([[
|
||||||
|
item 2997 |
|
||||||
|
item 2998 |
|
||||||
|
item 2999 |
|
||||||
|
item 3000{1: } |
|
||||||
|
[No Name] [+] 3000,10 Bot|
|
||||||
|
-- INSERT -- |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('raises PastePre, PastePost in normal-mode', function()
|
||||||
|
setup_harness()
|
||||||
|
|
||||||
|
-- Send the "start paste" sequence.
|
||||||
|
feed_tui("\027[200~")
|
||||||
|
feed_tui("\npasted from terminal (1)\npasted from terminal (2)\n")
|
||||||
|
-- Send the "stop paste" sequence.
|
||||||
|
feed_tui("\027[201~")
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
PastePre mode:n |
|
||||||
|
pasted from terminal (1) |
|
||||||
|
pasted from terminal (2) |
|
||||||
|
PastePost mode:i{1: } |
|
||||||
|
[No Name] [+] |
|
||||||
|
-- INSERT -- |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('forwards spurious "start paste" sequence', function()
|
||||||
|
setup_harness()
|
||||||
|
-- If multiple "start paste" sequences are sent without a corresponding
|
||||||
|
-- "stop paste" sequence, only the first occurrence should be consumed.
|
||||||
|
|
||||||
|
-- Send the "start paste" sequence.
|
||||||
|
feed_tui("\027[200~")
|
||||||
|
feed_tui("\npasted from terminal (1)\n")
|
||||||
|
-- Send spurious "start paste" sequence.
|
||||||
|
feed_tui("\027[200~")
|
||||||
|
feed_tui("\n")
|
||||||
|
-- Send the "stop paste" sequence.
|
||||||
|
feed_tui("\027[201~")
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
PastePre mode:n |
|
||||||
|
pasted from terminal (1) |
|
||||||
|
{1:^[}200~ |
|
||||||
|
PastePost mode:i{2: } |
|
||||||
|
[No Name] [+] |
|
||||||
|
-- INSERT -- |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]], {
|
||||||
|
[1] = {foreground = 4},
|
||||||
|
[2] = {reverse = true},
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('ignores spurious "stop paste" sequence', function()
|
||||||
|
setup_harness()
|
||||||
|
-- If "stop paste" sequence is received without a preceding "start paste"
|
||||||
|
-- sequence, it should be ignored.
|
||||||
|
|
||||||
|
feed_tui("i")
|
||||||
|
-- Send "stop paste" sequence.
|
||||||
|
feed_tui("\027[201~")
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
{1: } |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
[No Name] |
|
||||||
|
-- INSERT -- |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('raises PastePre, PastePost in command-mode', function()
|
||||||
|
-- The default PastePre/PastePost handlers set the 'paste' option. To test,
|
||||||
|
-- we define a command-mode map, then assert that the mapping was ignored
|
||||||
|
-- during paste.
|
||||||
|
feed_tui(":cnoremap st XXX\n")
|
||||||
|
|
||||||
|
feed_tui(":not pasted")
|
||||||
|
|
||||||
|
-- Paste did not start, so the mapping _should_ apply.
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
[No Name] |
|
||||||
|
:not paXXXed{1: } |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed_tui("\003") -- CTRL-C
|
||||||
|
feed_tui(":")
|
||||||
|
feed_tui("\027[200~") -- Send the "start paste" sequence.
|
||||||
|
feed_tui("pasted")
|
||||||
|
|
||||||
|
-- Paste started, so the mapping should _not_ apply.
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
[No Name] |
|
||||||
|
:pasted{1: } |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed_tui("\003") -- CTRL-C
|
||||||
|
feed_tui(":")
|
||||||
|
feed_tui("\027[201~") -- Send the "stop paste" sequence.
|
||||||
|
feed_tui("not pasted")
|
||||||
|
|
||||||
|
-- Paste stopped, so the mapping _should_ apply.
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
[No Name] |
|
||||||
|
:not paXXXed{1: } |
|
||||||
|
-- TERMINAL -- |
|
||||||
|
]])
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO
|
||||||
|
it('sets undo-point after consecutive pastes', function()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO
|
||||||
|
it('handles missing "stop paste" sequence', function()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- TODO: error when pasting into 'nomodifiable' buffer:
|
||||||
|
-- [error @ do_put:2656] 17043 - Failed to save undo information
|
||||||
|
it("handles 'nomodifiable' buffer gracefully", function()
|
||||||
|
end)
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
@@ -127,7 +127,7 @@ describe('feeding large chunks of input with <Paste>', function()
|
|||||||
for i = 1, 20000 do
|
for i = 1, 20000 do
|
||||||
t[i] = 'item ' .. tostring(i)
|
t[i] = 'item ' .. tostring(i)
|
||||||
end
|
end
|
||||||
feed('i<Paste>')
|
command('doautocmd PastePre')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
^ |
|
^ |
|
||||||
~ |
|
~ |
|
||||||
@@ -161,7 +161,7 @@ describe('feeding large chunks of input with <Paste>', function()
|
|||||||
item 20000^ |
|
item 20000^ |
|
||||||
-- INSERT (paste) -- |
|
-- INSERT (paste) -- |
|
||||||
]])
|
]])
|
||||||
feed('<Paste>')
|
command('doautocmd PastePost')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
item 19988 |
|
item 19988 |
|
||||||
item 19989 |
|
item 19989 |
|
||||||
@@ -175,8 +175,8 @@ describe('feeding large chunks of input with <Paste>', function()
|
|||||||
item 19997 |
|
item 19997 |
|
||||||
item 19998 |
|
item 19998 |
|
||||||
item 19999 |
|
item 19999 |
|
||||||
item 20000^ |
|
item 2000^0 |
|
||||||
-- INSERT -- 20000,11 Bot |
|
20000,10 Bot |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user