Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vt: bracketed paste support

This is comprised of 3 aspects:

- Take note of when applications advertise bracketed paste support via
"\e[?2004h" and "\e[?2004l".

- Insert bracketed paste markers ("\e[200~" and "\e[201~") around pasted
content in paste_selection() when bracketed paste is active.

- Add TIOCL_GETBRACKETEDPASTE to return bracketed paste status so user
space daemons implementing cut-and-paste functionality (e.g. gpm,
BRLTTY) may know when to insert bracketed paste markers.

Link: https://en.wikipedia.org/wiki/Bracketed-paste

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20250520171851.1219676-2-nico@fluxnic.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Nicolas Pitre and committed by
Greg Kroah-Hartman
80fa7a03 c4c7ead7

+44 -4
+27 -4
drivers/tty/vt/selection.c
··· 403 403 DECLARE_WAITQUEUE(wait, current); 404 404 int ret = 0; 405 405 406 + bool bp = vc->vc_bracketed_paste; 407 + static const char bracketed_paste_start[] = "\033[200~"; 408 + static const char bracketed_paste_end[] = "\033[201~"; 409 + const char *bps = bp ? bracketed_paste_start : NULL; 410 + const char *bpe = bp ? bracketed_paste_end : NULL; 411 + 406 412 console_lock(); 407 413 poke_blanked_console(); 408 414 console_unlock(); ··· 420 414 421 415 add_wait_queue(&vc->paste_wait, &wait); 422 416 mutex_lock(&vc_sel.lock); 423 - while (vc_sel.buffer && vc_sel.buf_len > pasted) { 417 + while (vc_sel.buffer && (vc_sel.buf_len > pasted || bpe)) { 424 418 set_current_state(TASK_INTERRUPTIBLE); 425 419 if (signal_pending(current)) { 426 420 ret = -EINTR; ··· 433 427 continue; 434 428 } 435 429 __set_current_state(TASK_RUNNING); 430 + 431 + if (bps) { 432 + bps += tty_ldisc_receive_buf(ld, bps, NULL, strlen(bps)); 433 + if (*bps != '\0') 434 + continue; 435 + bps = NULL; 436 + } 437 + 436 438 count = vc_sel.buf_len - pasted; 437 - count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL, 438 - count); 439 - pasted += count; 439 + if (count) { 440 + pasted += tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, 441 + NULL, count); 442 + if (vc_sel.buf_len > pasted) 443 + continue; 444 + } 445 + 446 + if (bpe) { 447 + bpe += tty_ldisc_receive_buf(ld, bpe, NULL, strlen(bpe)); 448 + if (*bpe == '\0') 449 + bpe = NULL; 450 + } 440 451 } 441 452 mutex_unlock(&vc_sel.lock); 442 453 remove_wait_queue(&vc->paste_wait, &wait);
+15
drivers/tty/vt/vt.c
··· 1870 1870 return vc_cons[fg_console].d->vc_report_mouse; 1871 1871 } 1872 1872 1873 + /* invoked via ioctl(TIOCLINUX) */ 1874 + static int get_bracketed_paste(struct tty_struct *tty) 1875 + { 1876 + struct vc_data *vc = tty->driver_data; 1877 + 1878 + return vc->vc_bracketed_paste; 1879 + } 1880 + 1873 1881 enum { 1874 1882 CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */ 1875 1883 CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */ ··· 1888 1880 CSI_DEC_hl_MOUSE_X10 = 9, 1889 1881 CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */ 1890 1882 CSI_DEC_hl_MOUSE_VT200 = 1000, 1883 + CSI_DEC_hl_BRACKETED_PASTE = 2004, 1891 1884 }; 1892 1885 1893 1886 /* console_lock is held */ ··· 1940 1931 break; 1941 1932 case CSI_DEC_hl_MOUSE_VT200: 1942 1933 vc->vc_report_mouse = on_off ? 2 : 0; 1934 + break; 1935 + case CSI_DEC_hl_BRACKETED_PASTE: 1936 + vc->vc_bracketed_paste = on_off; 1943 1937 break; 1944 1938 } 1945 1939 } ··· 2169 2157 vc->state.charset = 0; 2170 2158 vc->vc_need_wrap = 0; 2171 2159 vc->vc_report_mouse = 0; 2160 + vc->vc_bracketed_paste = 0; 2172 2161 vc->vc_utf = default_utf8; 2173 2162 vc->vc_utf_count = 0; 2174 2163 ··· 3496 3483 break; 3497 3484 case TIOCL_BLANKEDSCREEN: 3498 3485 return console_blanked; 3486 + case TIOCL_GETBRACKETEDPASTE: 3487 + return get_bracketed_paste(tty); 3499 3488 default: 3500 3489 return -EINVAL; 3501 3490 }
+1
include/linux/console_struct.h
··· 145 145 unsigned int vc_need_wrap : 1; 146 146 unsigned int vc_can_do_color : 1; 147 147 unsigned int vc_report_mouse : 2; 148 + unsigned int vc_bracketed_paste : 1; 148 149 unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */ 149 150 unsigned char vc_utf_count; 150 151 int vc_utf_char;
+1
include/uapi/linux/tiocl.h
··· 36 36 #define TIOCL_BLANKSCREEN 14 /* keep screen blank even if a key is pressed */ 37 37 #define TIOCL_BLANKEDSCREEN 15 /* return which vt was blanked */ 38 38 #define TIOCL_GETKMSGREDIRECT 17 /* get the vt the kernel messages are restricted to */ 39 + #define TIOCL_GETBRACKETEDPASTE 18 /* get whether paste may be bracketed */ 39 40 40 41 #endif /* _LINUX_TIOCL_H */