1https://marc.info/?l=openbsd-tech&m=161737611015124&w=2
2
3diff -upr a/edit.c b/edit.c
4--- a/edit.c 2021-05-01 11:37:53.000000000 +0200
5+++ b/edit.c 2021-09-04 15:22:54.365095598 +0200
6@@ -150,12 +150,28 @@ x_puts(const char *s)
7 shf_putc(*s++, shl_out);
8 }
9
10+#ifdef EMACS
11+static void
12+x_paste_mode(bool onoff)
13+{
14+ if (!Flag(FBBRACKETPASTE))
15+ return;
16+
17+ printf((onoff) ? BRPASTE_INT : BRPASTE_DEINT);
18+ fflush(stdout);
19+}
20+#endif
21+
22 bool
23 x_mode(bool onoff)
24 {
25 static bool x_cur_mode;
26 bool prev;
27
28+#ifdef EMACS
29+ x_paste_mode(onoff);
30+#endif
31+
32 if (x_cur_mode == onoff)
33 return x_cur_mode;
34 prev = x_cur_mode;
35diff -upr a/edit.h b/edit.h
36--- a/edit.h 2021-05-01 11:37:53.000000000 +0200
37+++ b/edit.h 2021-09-04 15:22:27.475021303 +0200
38@@ -34,6 +34,12 @@ extern X_chars edchars;
39 #define XCF_FULLPATH BIT(2) /* command completion: store full path */
40 #define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
41
42+/* https://www.xfree86.org/4.7.0/ctlseqs.html#Bracketed%20Paste%20Mode */
43+#define BRPASTE_INT "\033[?2004h"
44+#define BRPASTE_DEINT "\033[?2004l"
45+#define BRPASTE_PRE kb_encode("^[[200~")
46+#define BRPASTE_POST kb_encode("^[[201~")
47+
48 /* edit.c */
49 int x_getc(void);
50 void x_flush(void);
51diff -upr a/emacs.c b/emacs.c
52--- a/emacs.c 2021-05-01 11:37:53.000000000 +0200
53+++ b/emacs.c 2021-09-04 15:22:27.478354645 +0200
54@@ -118,6 +118,7 @@ static char *xmp; /* mark pointer */
55 static char *killstack[KILLSIZE];
56 static int killsp, killtp;
57 static int x_literal_set;
58+static int x_brack_paste;
59 static int x_arg_set;
60 static char *macro_args;
61 static int prompt_skip;
62@@ -203,6 +204,8 @@ static int x_fold_lower(int);
63 static int x_fold_upper(int);
64 static int x_set_arg(int);
65 static int x_comment(int);
66+static int x_brack_paste_start(int);
67+static int x_brack_paste_end(int);
68 #ifdef DEBUG
69 static int x_debug_info(int);
70 #endif
71@@ -260,6 +263,8 @@ static const struct x_ftab x_ftab[] = {
72 { x_fold_upper, "upcase-word", XF_ARG },
73 { x_set_arg, "set-arg", XF_NOBIND },
74 { x_comment, "comment", 0 },
75+ { x_brack_paste_start, "bracketed-paste-start", 0 },
76+ { x_brack_paste_end, "bracketed-paste-end", 0 },
77 { 0, 0, 0 },
78 #ifdef DEBUG
79 { x_debug_info, "debug-info", 0 },
80@@ -316,6 +321,8 @@ x_emacs(char *buf, size_t len)
81 }
82
83 x_literal_set = 0;
84+ x_brack_paste = 0;
85+
86 x_arg = -1;
87 x_last_command = NULL;
88 while (1) {
89@@ -353,6 +360,13 @@ x_emacs(char *buf, size_t len)
90 }
91 }
92
93+ /* In bracketed paste mode only allow x_brack_paste_end,
94+ * to quit this mode, for all other commands insert a literal. */
95+ if (x_brack_paste && (submatch == 1 && kmatch)) {
96+ if (kmatch->ftab->xf_func != x_brack_paste_end)
97+ submatch = 0;
98+ }
99+
100 if (submatch == 1 && kmatch) {
101 if (kmatch->ftab->xf_func == x_ins_string &&
102 kmatch->args && !macro_args) {
103@@ -1479,6 +1493,10 @@ x_init_emacs(void)
104
105 TAILQ_INIT(&kblist);
106
107+ /* bracketed paste mode */
108+ kb_add_string(x_brack_paste_start, NULL, BRPASTE_PRE);
109+ kb_add_string(x_brack_paste_end, NULL, BRPASTE_POST);
110+
111 /* man page order */
112 kb_add(x_abort, CTRL('G'), 0);
113 kb_add(x_mv_back, CTRL('B'), 0);
114@@ -1984,6 +2002,21 @@ x_comment(int c)
115 return KSTD;
116 }
117
118+int
119+x_brack_paste_start(int c)
120+{
121+ if (Flag(FBBRACKETPASTE))
122+ x_brack_paste = 1;
123+ return KSTD;
124+}
125+
126+int
127+x_brack_paste_end(int c)
128+{
129+ if (Flag(FBBRACKETPASTE))
130+ x_brack_paste = 0;
131+ return KSTD;
132+}
133
134 /* NAME:
135 * x_prev_histword - recover word from prev command
136diff -upr a/ksh.1 b/ksh.1
137--- a/ksh.1 2021-05-01 11:37:53.000000000 +0200
138+++ b/ksh.1 2021-09-04 15:23:21.358503517 +0200
139@@ -3595,6 +3595,9 @@ during file name generation.
140 Print commands and parameter assignments when they are executed, preceded by
141 the value of
142 .Ev PS4 .
143+.It Ic bracket-paste
144+Enables bracketed paste mode, requires the associated escape sequences to be
145+supported by the utilized terminal emulator.
146 .It Ic bgnice
147 Background jobs are run with lower priority.
148 .It Ic braceexpand
149diff -upr a/misc.c b/misc.c
150--- a/misc.c 2021-05-01 11:37:53.000000000 +0200
151+++ b/misc.c 2021-09-04 15:22:27.478354645 +0200
152@@ -123,6 +123,9 @@ const struct option sh_options[] = {
153 */
154 { "allexport", 'a', OF_ANY },
155 { "braceexpand", 0, OF_ANY }, /* non-standard */
156+#ifdef EMACS
157+ { "bracket-paste", 0, OF_ANY }, /* non-standard */
158+#endif
159 { "bgnice", 0, OF_ANY },
160 { NULL, 'c', OF_CMDLINE },
161 { "csh-history", 0, OF_ANY }, /* non-standard */
162diff -upr a/sh.h b/sh.h
163--- a/sh.h 2021-05-01 11:37:53.000000000 +0200
164+++ b/sh.h 2021-09-04 15:22:27.481687988 +0200
165@@ -134,6 +134,9 @@ extern const struct option sh_options[];
166 enum sh_flag {
167 FEXPORT = 0, /* -a: export all */
168 FBRACEEXPAND, /* enable {} globbing */
169+#ifdef EMACS
170+ FBBRACKETPASTE, /* bracketed paste mode */
171+#endif
172 FBGNICE, /* bgnice */
173 FCOMMAND, /* -c: (invocation) execute specified command */
174 FCSHHISTORY, /* csh-style history enabled */