summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Kiddle <opk@zsh.org>2022-11-17 20:05:12 +0100
committerOliver Kiddle <opk@zsh.org>2022-11-17 20:05:12 +0100
commitc4d557bb0a9cf6a7241f760ad466e2d91359ceb2 (patch)
tree9441513ef4b6f3fabdeb1a9a31ed1a971c3b63d1
parentb1533066ca7d50c88b37ce72093c12cf19807818 (diff)
downloadzsh-c4d557bb0a9cf6a7241f760ad466e2d91359ceb2.tar.gz
zsh-c4d557bb0a9cf6a7241f760ad466e2d91359ceb2.zip
50934: use OSC 52 escape sequence when copying to "* or "+ vi buffers
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/zle.yo11
-rw-r--r--Src/Zle/zle.h3
-rw-r--r--Src/Zle/zle_utils.c32
-rw-r--r--Src/Zle/zle_vi.c9
5 files changed, 54 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 6478f5480..c42163434 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2022-11-17 Oliver Kiddle <opk@zsh.org>
+
+ * 50934: Doc/Zsh/zle.yo, Src/Zle/zle.h, Src/Zle/zle_utils.c,
+ Src/Zle/zle_vi.c: use OSC 52 escape sequence when copying to
+ "* or "+ vi buffers
+
2022-11-09 Bart Schaefer <schaefer@zsh.org>
* 50929: Src/exec.c: fix handling of ERR_RETURN bent by 50928.
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 2d033a0a1..58700072a 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -2470,10 +2470,11 @@ command. tt(run-help) is normally aliased to tt(man).
tindex(vi-set-buffer)
item(tt(vi-set-buffer) (unbound) (tt(")) (unbound))(
Specify a buffer to be used in the following command.
-There are 37 buffers that can be specified:
+There are 39 buffers that can be specified:
the 26 `named' buffers tt("a) to tt("z), the `yank' buffer tt("0),
-the nine `queued' buffers tt("1) to tt("9) and the `black hole' buffer
-tt("_). The named buffers can also be specified as tt("A) to tt("Z).
+the nine `queued' buffers tt("1) to tt("9), the `black hole' buffer
+tt("_) and the system selection tt("*) and clipboard tt("+).
+The named buffers can also be specified as tt("A) to tt("Z).
When a buffer is specified for a cut, change or yank command, the text
concerned replaces the previous contents of the specified buffer. If
@@ -2482,6 +2483,10 @@ appended to the buffer instead of overwriting it. When using the tt("_)
buffer, nothing happens. This can be useful for deleting text without
affecting any buffers.
+Updating the system clipboard relies on specific support from the terminal.
+Reading it is not possible so a paste command with tt("*) or tt("+) will do
+nothing.
+
If no buffer is specified for a cut or change command, tt("1) is used, and
the contents of tt("1) to tt("8) are each shifted along one buffer;
the contents of tt("9) is lost. If no buffer is specified for a yank
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 391586c4a..f59545397 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -258,6 +258,9 @@ struct modifier {
#define MOD_NULL (1<<5) /* throw away text for the vi cut buffer */
#define MOD_CHAR (1<<6) /* force character-wise movement */
#define MOD_LINE (1<<7) /* force line-wise movement */
+#define MOD_PRI (1<<8) /* OS primary selection for the vi cut buffer */
+#define MOD_CLIP (1<<9) /* OS clipboard for the vi cut buffer */
+#define MOD_OSSEL (MOD_PRI | MOD_CLIP) /* either system selection */
/* current modifier status */
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 526216fa7..3d9017dcf 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -936,6 +936,28 @@ cut(int i, int ct, int flags)
cuttext(zleline + i, ct, flags);
}
+static char*
+base64_encode(const char *src, size_t len) {
+ static const char* base64_table =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ const unsigned char *end = (unsigned char *)src + len;
+ const unsigned char *in = (unsigned char *)src;
+ char *ret = zhalloc(1 + 4 * ((len + 2) / 3)); /* 4 bytes out for 3 in */
+ char *cur = ret;
+
+ for (; end - in > 0; in += 3, cur += 4) {
+ unsigned int n = *in << 16;
+ cur[3] = end - in > 2 ? base64_table[(n |= in[2]) & 0x3f] : '=';
+ cur[2] = end - in > 1 ? base64_table[((n |= in[1]<<8) >> 6) & 0x3f] : '=';
+ cur[1] = base64_table[(n >> 12) & 0x3f];
+ cur[0] = base64_table[n >> 18];
+ }
+ *cur = '\0';
+
+ return ret;
+}
+
/*
* As cut, but explicitly supply the text together with its length.
*/
@@ -948,7 +970,15 @@ cuttext(ZLE_STRING_T line, int ct, int flags)
return;
UNMETACHECK();
- if (zmod.flags & MOD_VIBUF) {
+ if (zmod.flags & MOD_OSSEL) {
+ int cutll;
+ char *mbcut = zlelineasstring(line, ct, 0, &cutll, NULL, 1);
+ unmetafy(mbcut, &cutll);
+ mbcut = base64_encode(mbcut, cutll);
+
+ fprintf(shout, "\e]52;%c;%s\a", zmod.flags & MOD_CLIP ? 'c' : 'p',
+ mbcut);
+ } else if (zmod.flags & MOD_VIBUF) {
struct cutbuffer *b = &vibuf[zmod.vibuf];
if (!(zmod.flags & MOD_VIAPP) || !b->buf) {
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 0f198d0e8..24d9de6ea 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -1014,6 +1014,9 @@ int
visetbuffer(char **args)
{
ZLE_INT_T ch;
+ ZLE_CHAR_T *match = ZWS("_*+");
+ int registermod[] = { MOD_NULL, MOD_PRI, MOD_CLIP };
+ ZLE_CHAR_T *found;
if (*args) {
ch = **args;
@@ -1022,12 +1025,12 @@ visetbuffer(char **args)
} else {
ch = getfullchar(0);
}
- if (ch == ZWC('_')) {
- zmod.flags |= MOD_NULL;
+ if ((found = ZS_strchr(match, ch))) {
+ zmod.flags |= registermod[found - match];
prefixflag = 1;
return 0;
} else
- zmod.flags &= ~MOD_NULL;
+ zmod.flags &= ~(MOD_NULL | MOD_OSSEL);
if ((ch < ZWC('0') || ch > ZWC('9')) &&
(ch < ZWC('a') || ch > ZWC('z')) &&
(ch < ZWC('A') || ch > ZWC('Z')))