Commit 80fa7a03 authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Greg Kroah-Hartman
Browse files

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: default avatarNicolas Pitre <npitre@baylibre.com>
Reviewed-by: default avatarJiri Slaby <jirislaby@kernel.org>
Link: https://lore.kernel.org/r/20250520171851.1219676-2-nico@fluxnic.net


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c4c7ead7
Loading
Loading
Loading
Loading
+27 −4
Original line number Diff line number Diff line
@@ -403,6 +403,12 @@ int paste_selection(struct tty_struct *tty)
	DECLARE_WAITQUEUE(wait, current);
	int ret = 0;

	bool bp = vc->vc_bracketed_paste;
	static const char bracketed_paste_start[] = "\033[200~";
	static const char bracketed_paste_end[]   = "\033[201~";
	const char *bps = bp ? bracketed_paste_start : NULL;
	const char *bpe = bp ? bracketed_paste_end : NULL;

	console_lock();
	poke_blanked_console();
	console_unlock();
@@ -414,7 +420,7 @@ int paste_selection(struct tty_struct *tty)

	add_wait_queue(&vc->paste_wait, &wait);
	mutex_lock(&vc_sel.lock);
	while (vc_sel.buffer && vc_sel.buf_len > pasted) {
	while (vc_sel.buffer && (vc_sel.buf_len > pasted || bpe)) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (signal_pending(current)) {
			ret = -EINTR;
@@ -427,10 +433,27 @@ int paste_selection(struct tty_struct *tty)
			continue;
		}
		__set_current_state(TASK_RUNNING);

		if (bps) {
			bps += tty_ldisc_receive_buf(ld, bps, NULL, strlen(bps));
			if (*bps != '\0')
				continue;
			bps = NULL;
		}

		count = vc_sel.buf_len - pasted;
		count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL,
					      count);
		pasted += count;
		if (count) {
			pasted += tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted,
							NULL, count);
			if (vc_sel.buf_len > pasted)
				continue;
		}

		if (bpe) {
			bpe += tty_ldisc_receive_buf(ld, bpe, NULL, strlen(bpe));
			if (*bpe == '\0')
				bpe = NULL;
		}
	}
	mutex_unlock(&vc_sel.lock);
	remove_wait_queue(&vc->paste_wait, &wait);
+15 −0
Original line number Diff line number Diff line
@@ -1870,6 +1870,14 @@ int mouse_reporting(void)
	return vc_cons[fg_console].d->vc_report_mouse;
}

/* invoked via ioctl(TIOCLINUX) */
static int get_bracketed_paste(struct tty_struct *tty)
{
	struct vc_data *vc = tty->driver_data;

	return vc->vc_bracketed_paste;
}

enum {
	CSI_DEC_hl_CURSOR_KEYS	= 1,	/* CKM: cursor keys send ^[Ox/^[[x */
	CSI_DEC_hl_132_COLUMNS	= 3,	/* COLM: 80/132 mode switch */
@@ -1880,6 +1888,7 @@ enum {
	CSI_DEC_hl_MOUSE_X10	= 9,
	CSI_DEC_hl_SHOW_CURSOR	= 25,	/* TCEM */
	CSI_DEC_hl_MOUSE_VT200	= 1000,
	CSI_DEC_hl_BRACKETED_PASTE = 2004,
};

/* console_lock is held */
@@ -1932,6 +1941,9 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
		case CSI_DEC_hl_MOUSE_VT200:
			vc->vc_report_mouse = on_off ? 2 : 0;
			break;
		case CSI_DEC_hl_BRACKETED_PASTE:
			vc->vc_bracketed_paste = on_off;
			break;
		}
}

@@ -2157,6 +2169,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
	vc->state.charset	= 0;
	vc->vc_need_wrap	= 0;
	vc->vc_report_mouse	= 0;
	vc->vc_bracketed_paste	= 0;
	vc->vc_utf              = default_utf8;
	vc->vc_utf_count	= 0;

@@ -3483,6 +3496,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
		break;
	case TIOCL_BLANKEDSCREEN:
		return console_blanked;
	case TIOCL_GETBRACKETEDPASTE:
		return get_bracketed_paste(tty);
	default:
		return -EINVAL;
	}
+1 −0
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ struct vc_data {
	unsigned int	vc_need_wrap	: 1;
	unsigned int	vc_can_do_color	: 1;
	unsigned int	vc_report_mouse : 2;
	unsigned int	vc_bracketed_paste : 1;
	unsigned char	vc_utf		: 1;	/* Unicode UTF-8 encoding */
	unsigned char	vc_utf_count;
		 int	vc_utf_char;
+1 −0
Original line number Diff line number Diff line
@@ -36,5 +36,6 @@ struct tiocl_selection {
#define TIOCL_BLANKSCREEN	14	/* keep screen blank even if a key is pressed */
#define TIOCL_BLANKEDSCREEN	15	/* return which vt was blanked */
#define TIOCL_GETKMSGREDIRECT	17	/* get the vt the kernel messages are restricted to */
#define TIOCL_GETBRACKETEDPASTE	18	/* get whether paste may be bracketed */

#endif /* _LINUX_TIOCL_H */