Skip to content

Commit ec2da36

Browse files
committed
patch 8.0.0210: no support for bracketed paste
Problem: Vim does not support bracketed paste, as implemented by xterm and other terminals. Solution: Add t_BE, t_BD, t_PS and t_PE.
1 parent 41baa79 commit ec2da36

File tree

13 files changed

+185
-17
lines changed

13 files changed

+185
-17
lines changed

runtime/doc/term.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ an external command (e.g., "!!"), the terminal will be put into Normal mode
8989
for a moment. This means that you can stop the output to the screen by
9090
hitting a printing key. Output resumes when you hit <BS>.
9191

92+
*xterm-bracketed-paste*
93+
When the 't_BE' option is set then 't_BE' will be sent to the
94+
terminal when entering "raw" mode and 't_BD' when leaving "raw" mode. The
95+
terminal is then expected to put 't_PS' before pasted text and 't_PE' after
96+
pasted text. This way Vim can separate text that is pasted from characters
97+
that are typed. The pasted text is handled like when the middle mouse button
98+
is used.
99+
100+
Note that in some situations Vim will not recognize the bracketed paste and
101+
you will get the raw text. In other situations Vim will only get the first
102+
pasted character and drop the rest, e.g. when using the "r" command.
103+
92104
*cs7-problem*
93105
Note: If the terminal settings are changed after running Vim, you might have
94106
an illegal combination of settings. This has been reported on Solaris 2.5
@@ -306,6 +318,10 @@ Added by Vim (there are no standard codes for these):
306318
|xterm-true-color|
307319
t_8b set background color (R, G, B) *t_8b* *'t_8b'*
308320
|xterm-true-color|
321+
t_BE enable bracketed paste mode *t_BE* *'t_BE'*
322+
|xterm-bracketed-paste|
323+
t_BD disable bracketed paste mode *t_BD* *'t_BD'*
324+
|xterm-bracketed-paste|
309325

310326
KEY CODES
311327
Note: Use the <> form if possible
@@ -398,6 +414,8 @@ Note: Use the <> form if possible
398414
t_KK <k8> keypad 8 *<k8>* *t_KK* *'t_KK'*
399415
t_KL <k9> keypad 9 *<k9>* *t_KL* *'t_KL'*
400416
<Mouse> leader of mouse code *<Mouse>*
417+
t_PS start of brackted paste |xterm-bracketed-paste| *t_PS* 't_PS'
418+
t_PE end of bracketed paste |xterm-bracketed-paste| *t_PE* 't_PE'
401419

402420
Note about t_so and t_mr: When the termcap entry "so" is not present the
403421
entry for "mr" is used. And vice versa. The same is done for "se" and "me".

src/edit.c

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ static int dont_sync_undo = FALSE; /* CTRL-G U prevents syncing undo for
309309
* "cmdchar" can be:
310310
* 'i' normal insert command
311311
* 'a' normal append command
312+
* K_PS bracketed paste
312313
* 'R' replace command
313314
* 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
314315
* but still only one <CR> is inserted. The <Esc> is not used for redo.
@@ -782,10 +783,14 @@ edit(
782783
dont_sync_undo = TRUE;
783784
else
784785
dont_sync_undo = FALSE;
785-
do
786-
{
787-
c = safe_vgetc();
788-
} while (c == K_IGNORE);
786+
if (cmdchar == K_PS)
787+
/* Got here from normal mode when bracketed paste started. */
788+
c = K_PS;
789+
else
790+
do
791+
{
792+
c = safe_vgetc();
793+
} while (c == K_IGNORE);
789794

790795
#ifdef FEAT_AUTOCMD
791796
/* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
@@ -1193,6 +1198,16 @@ edit(
11931198
ins_mousescroll(MSCR_RIGHT);
11941199
break;
11951200
#endif
1201+
case K_PS:
1202+
bracketed_paste(PASTE_INSERT, FALSE, NULL);
1203+
if (cmdchar == K_PS)
1204+
/* invoked from normal mode, bail out */
1205+
goto doESCkey;
1206+
break;
1207+
case K_PE:
1208+
/* Got K_PE without K_PS, ignore. */
1209+
break;
1210+
11961211
#ifdef FEAT_GUI_TABLINE
11971212
case K_TABLINE:
11981213
case K_TABMENU:
@@ -9424,6 +9439,91 @@ ins_mousescroll(int dir)
94249439
}
94259440
#endif
94269441

9442+
/*
9443+
* Handle receiving P_PS: start paste mode. Inserts the following text up to
9444+
* P_PE literally.
9445+
* When "drop" is TRUE then consume the text and drop it.
9446+
*/
9447+
int
9448+
bracketed_paste(paste_mode_T mode, int drop, garray_T *gap)
9449+
{
9450+
int c;
9451+
char_u buf[NUMBUFLEN + MB_MAXBYTES];
9452+
int idx = 0;
9453+
char_u *end = find_termcode((char_u *)"PE");
9454+
int ret_char = -1;
9455+
int save_allow_keys = allow_keys;
9456+
9457+
/* If the end code is too long we can't detect it, read everything. */
9458+
if (STRLEN(end) >= NUMBUFLEN)
9459+
end = NULL;
9460+
++no_mapping;
9461+
allow_keys = 0;
9462+
for (;;)
9463+
{
9464+
/* When the end is not defined read everything. */
9465+
if (end == NULL && vpeekc() == NUL)
9466+
break;
9467+
c = plain_vgetc();
9468+
#ifdef FEAT_MBYTE
9469+
if (has_mbyte)
9470+
idx += (*mb_char2bytes)(c, buf + idx);
9471+
else
9472+
#endif
9473+
buf[idx++] = c;
9474+
buf[idx] = NUL;
9475+
if (end != NUL && STRNCMP(buf, end, idx) == 0)
9476+
{
9477+
if (end[idx] == NUL)
9478+
break; /* Found the end of paste code. */
9479+
continue;
9480+
}
9481+
if (!drop)
9482+
{
9483+
switch (mode)
9484+
{
9485+
case PASTE_CMDLINE:
9486+
put_on_cmdline(buf, idx, TRUE);
9487+
break;
9488+
9489+
case PASTE_EX:
9490+
if (gap != NULL && ga_grow(gap, idx) == OK)
9491+
{
9492+
mch_memmove((char *)gap->ga_data + gap->ga_len,
9493+
buf, (size_t)idx);
9494+
gap->ga_len += idx;
9495+
}
9496+
break;
9497+
9498+
case PASTE_INSERT:
9499+
if (stop_arrow() == OK)
9500+
{
9501+
ins_char_bytes(buf, idx);
9502+
AppendToRedobuffLit(buf, idx);
9503+
}
9504+
break;
9505+
9506+
case PASTE_ONE_CHAR:
9507+
if (ret_char == -1)
9508+
{
9509+
#ifdef FEAT_MBYTE
9510+
if (has_mbyte)
9511+
ret_char = (*mb_ptr2char)(buf);
9512+
else
9513+
#endif
9514+
ret_char = buf[0];
9515+
}
9516+
break;
9517+
}
9518+
}
9519+
idx = 0;
9520+
}
9521+
--no_mapping;
9522+
allow_keys = save_allow_keys;
9523+
9524+
return ret_char;
9525+
}
9526+
94279527
#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
94289528
static void
94299529
ins_tabline(int c)

src/evalfunc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4231,7 +4231,7 @@ f_getchar(typval_T *argvars, typval_T *rettv)
42314231
{
42324232
if (argvars[0].v_type == VAR_UNKNOWN)
42334233
/* getchar(): blocking wait. */
4234-
n = safe_vgetc();
4234+
n = plain_vgetc();
42354235
else if (get_tv_number_chk(&argvars[0], &error) == 1)
42364236
/* getchar(1): only check if char avail */
42374237
n = vpeekc_any();
@@ -4240,7 +4240,7 @@ f_getchar(typval_T *argvars, typval_T *rettv)
42404240
n = 0;
42414241
else
42424242
/* getchar(0) and char avail: return char */
4243-
n = safe_vgetc();
4243+
n = plain_vgetc();
42444244

42454245
if (n == K_IGNORE)
42464246
continue;

src/getchar.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,12 @@ plain_vgetc(void)
18171817
{
18181818
c = safe_vgetc();
18191819
} while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
1820+
1821+
if (c == K_PS)
1822+
/* Only handle the first pasted character. Drop the rest, since we
1823+
* don't know what to do with it. */
1824+
c = bracketed_paste(PASTE_ONE_CHAR, FALSE, NULL);
1825+
18201826
return c;
18211827
}
18221828

@@ -1906,7 +1912,7 @@ vungetc(int c)
19061912
}
19071913

19081914
/*
1909-
* get a character:
1915+
* Get a character:
19101916
* 1. from the stuffbuffer
19111917
* This is used for abbreviated commands like "D" -> "d$".
19121918
* Also used to redo a command for ".".

src/keymap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ enum key_extra
391391
#define K_KMULTIPLY TERMCAP2KEY('K', '9') /* keypad * */
392392
#define K_KENTER TERMCAP2KEY('K', 'A') /* keypad Enter */
393393
#define K_KPOINT TERMCAP2KEY('K', 'B') /* keypad . or ,*/
394+
#define K_PS TERMCAP2KEY('P', 'S') /* paste start */
395+
#define K_PE TERMCAP2KEY('P', 'E') /* paste end */
394396

395397
#define K_K0 TERMCAP2KEY('K', 'C') /* keypad 0 */
396398
#define K_K1 TERMCAP2KEY('K', 'D') /* keypad 1 */

src/misc2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,8 @@ static struct key_name_entry
22942294
{K_XDOWN, (char_u *)"xDown"},
22952295
{K_XLEFT, (char_u *)"xLeft"},
22962296
{K_XRIGHT, (char_u *)"xRight"},
2297+
{K_PS, (char_u *)"PasteStart"},
2298+
{K_PE, (char_u *)"PasteEnd"},
22972299

22982300
{K_F1, (char_u *)"F1"},
22992301
{K_F2, (char_u *)"F2"},

src/normal.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ static const struct nv_cmd
426426
#ifdef FEAT_AUTOCMD
427427
{K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0},
428428
#endif
429+
{K_PS, nv_edit, 0, 0},
429430
};
430431

431432
/* Number of commands in nv_cmds[]. */
@@ -3858,7 +3859,7 @@ add_to_showcmd(int c)
38583859
K_VER_SCROLLBAR, K_HOR_SCROLLBAR,
38593860
K_LEFTMOUSE_NM, K_LEFTRELEASE_NM,
38603861
# endif
3861-
K_IGNORE,
3862+
K_IGNORE, K_PS,
38623863
K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE,
38633864
K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE,
38643865
K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
@@ -9015,6 +9016,7 @@ nv_esc(cmdarg_T *cap)
90159016

90169017
/*
90179018
* Handle "A", "a", "I", "i" and <Insert> commands.
9019+
* Also handle K_PS, start bracketed paste.
90189020
*/
90199021
static void
90209022
nv_edit(cmdarg_T *cap)
@@ -9042,6 +9044,9 @@ nv_edit(cmdarg_T *cap)
90429044
/* Only give this error when 'insertmode' is off. */
90439045
EMSG(_(e_modifiable));
90449046
clearop(cap->oap);
9047+
if (cap->cmdchar == K_PS)
9048+
/* drop the pasted text */
9049+
bracketed_paste(PASTE_INSERT, TRUE, NULL);
90459050
}
90469051
else if (!checkclearopq(cap->oap))
90479052
{
@@ -9073,6 +9078,7 @@ nv_edit(cmdarg_T *cap)
90739078
break;
90749079

90759080
case 'a': /* "a"ppend is like "i"nsert on the next character. */
9081+
case K_PS: /* bracketed paste works like "a"ppend */
90769082
#ifdef FEAT_VIRTUALEDIT
90779083
/* increment coladd when in virtual space, increment the
90789084
* column otherwise, also to append after an unprintable char */
@@ -9103,6 +9109,9 @@ nv_edit(cmdarg_T *cap)
91039109

91049110
invoke_edit(cap, FALSE, cap->cmdchar, FALSE);
91059111
}
9112+
else if (cap->cmdchar == K_PS)
9113+
/* drop the pasted text */
9114+
bracketed_paste(PASTE_INSERT, TRUE, NULL);
91069115
}
91079116

91089117
/*

src/option.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3040,6 +3040,8 @@ static struct vimoption options[] =
30403040
p_term("t_ZR", T_CZR)
30413041
p_term("t_8f", T_8F)
30423042
p_term("t_8b", T_8B)
3043+
p_term("t_BE", T_BE)
3044+
p_term("t_BD", T_BD)
30433045

30443046
/* terminal key codes are not in here */
30453047

src/proto/edit.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ void fixthisline(int (*get_the_indent)(void));
3838
void fix_indent(void);
3939
int in_cinkeys(int keytyped, int when, int line_is_empty);
4040
int hkmap(int c);
41+
int bracketed_paste(paste_mode_T mode, int drop, garray_T *gap);
4142
void ins_scroll(void);
4243
void ins_horscroll(void);
4344
int ins_copychar(linenr_T lnum);

src/term.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,8 @@ static struct builtin_term builtin_termcaps[] =
857857
{(int)KS_8F, IF_EB("\033[38;2;%lu;%lu;%lum", ESC_STR "[38;2;%lu;%lu;%lum")},
858858
{(int)KS_8B, IF_EB("\033[48;2;%lu;%lu;%lum", ESC_STR "[48;2;%lu;%lu;%lum")},
859859
# endif
860+
{(int)KS_CBE, IF_EB("\033[?2004h", ESC_STR "[?2004h")},
861+
{(int)KS_CBD, IF_EB("\033[?2004l", ESC_STR "[?2004l")},
860862

861863
{K_UP, IF_EB("\033O*A", ESC_STR "O*A")},
862864
{K_DOWN, IF_EB("\033O*B", ESC_STR "O*B")},
@@ -902,13 +904,15 @@ static struct builtin_term builtin_termcaps[] =
902904
{K_ZEND, IF_EB("\033[8;*~", ESC_STR "[8;*~")},
903905
{K_PAGEUP, IF_EB("\033[5;*~", ESC_STR "[5;*~")},
904906
{K_PAGEDOWN, IF_EB("\033[6;*~", ESC_STR "[6;*~")},
905-
{K_KPLUS, IF_EB("\033O*k", ESC_STR "O*k")}, /* keypad plus */
906-
{K_KMINUS, IF_EB("\033O*m", ESC_STR "O*m")}, /* keypad minus */
907-
{K_KDIVIDE, IF_EB("\033O*o", ESC_STR "O*o")}, /* keypad / */
908-
{K_KMULTIPLY, IF_EB("\033O*j", ESC_STR "O*j")}, /* keypad * */
909-
{K_KENTER, IF_EB("\033O*M", ESC_STR "O*M")}, /* keypad Enter */
910-
{K_KPOINT, IF_EB("\033O*n", ESC_STR "O*n")}, /* keypad . */
911-
{K_KDEL, IF_EB("\033[3;*~", ESC_STR "[3;*~")}, /* keypad Del */
907+
{K_KPLUS, IF_EB("\033O*k", ESC_STR "O*k")}, /* keypad plus */
908+
{K_KMINUS, IF_EB("\033O*m", ESC_STR "O*m")}, /* keypad minus */
909+
{K_KDIVIDE, IF_EB("\033O*o", ESC_STR "O*o")}, /* keypad / */
910+
{K_KMULTIPLY, IF_EB("\033O*j", ESC_STR "O*j")}, /* keypad * */
911+
{K_KENTER, IF_EB("\033O*M", ESC_STR "O*M")}, /* keypad Enter */
912+
{K_KPOINT, IF_EB("\033O*n", ESC_STR "O*n")}, /* keypad . */
913+
{K_KDEL, IF_EB("\033[3;*~", ESC_STR "[3;*~")}, /* keypad Del */
914+
{K_PS, IF_EB("\033[200~", ESC_STR "[200~")}, /* paste start */
915+
{K_PE, IF_EB("\033[201~", ESC_STR "[201~")}, /* paste end */
912916

913917
{BT_EXTRA_KEYS, ""},
914918
{TERMCAP2KEY('k', '0'), IF_EB("\033[10;*~", ESC_STR "[10;*~")}, /* F0 */
@@ -1224,6 +1228,8 @@ static struct builtin_term builtin_termcaps[] =
12241228
{K_KMULTIPLY, "[KMULTIPLY]"},
12251229
{K_KENTER, "[KENTER]"},
12261230
{K_KPOINT, "[KPOINT]"},
1231+
{K_PS, "[PASTE-START]"},
1232+
{K_PE, "[PASTE-END]"},
12271233
{K_K0, "[K0]"},
12281234
{K_K1, "[K1]"},
12291235
{K_K2, "[K2]"},
@@ -1538,6 +1544,8 @@ set_termname(char_u *term)
15381544
{KS_CSI, "SI"}, {KS_CEI, "EI"},
15391545
{KS_U7, "u7"}, {KS_RBG, "RB"},
15401546
{KS_8F, "8f"}, {KS_8B, "8b"},
1547+
{KS_CBE, "BE"}, {KS_CBD, "BD"},
1548+
{KS_CPS, "PS"}, {KS_CPE, "PE"},
15411549
{(enum SpecialKey)0, NULL}
15421550
};
15431551

@@ -3140,6 +3148,7 @@ starttermcap(void)
31403148
{
31413149
out_str(T_TI); /* start termcap mode */
31423150
out_str(T_KS); /* start "keypad transmit" mode */
3151+
out_str(T_BE); /* enable bracketed paste moe */
31433152
out_flush();
31443153
termcap_active = TRUE;
31453154
screen_start(); /* don't know where cursor is now */
@@ -3189,6 +3198,7 @@ stoptermcap(void)
31893198
check_for_codes_from_term();
31903199
}
31913200
#endif
3201+
out_str(T_BD); /* disable bracketed paste moe */
31923202
out_str(T_KE); /* stop "keypad transmit" mode */
31933203
out_flush();
31943204
termcap_active = FALSE;

0 commit comments

Comments
 (0)