From 4cffaa1b3f1a78805977db1565111b8e894d3c17 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 10 Apr 2021 12:12:06 +0200 Subject: Fix bracketed paste support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- libterminput.c | 94 +++++++++++++++++++++++++++++++++++-------------- libterminput.h | 7 ++-- libterminput_is_ready.3 | 6 +++- test.c | 37 ++++++++++++++++--- 4 files changed, 109 insertions(+), 35 deletions(-) diff --git a/libterminput.c b/libterminput.c index 54016fe..0b2b22d 100644 --- a/libterminput.c +++ b/libterminput.c @@ -656,40 +656,82 @@ read_bracketed_paste(int fd, union libterminput_input *input, struct libterminpu * would stop the paste at the ~ in ESC [201~, send ~ as normal, and * then continue the brackated paste mode. */ - if (ctx->stored_head - ctx->stored_tail) { /* TODO test */ - for (n = ctx->stored_tail; n + 6 < ctx->stored_head; n++) { - if (ctx->stored[n + 0] == '\033' && ctx->stored[n + 1] == '[' && ctx->stored[n + 2] == '2' && - ctx->stored[n + 3] == '0' && ctx->stored[n + 4] == '0' && ctx->stored[n + 5] == '~') - break; - } - if (n == ctx->stored_tail && ctx->stored_head - ctx->stored_tail >= 6) { - ctx->stored_tail += 6; - if (ctx->stored_tail == ctx->stored_head) - ctx->stored_tail = ctx->stored_head = 0; - ctx->bracketed_paste = 0; - input->type = LIBTERMINPUT_BRACKETED_PASTE_END; - return 0; + if (ctx->stored_head - ctx->stored_tail) { + ctx->paused = 0; + n = ctx->stored_head - ctx->stored_tail; + if (!strncmp(&ctx->stored[ctx->stored_tail], "\033[201~", n < 6 ? n : 6)) { + if (n >= 6) { + ctx->stored_tail += 6; + if (ctx->stored_tail == ctx->stored_head) + ctx->stored_tail = ctx->stored_head = 0; + ctx->bracketed_paste = 0; + input->type = LIBTERMINPUT_BRACKETED_PASTE_END; + return 1; + } + input->text.nbytes = ctx->stored_head - ctx->stored_tail; + memcpy(input->text.bytes, &ctx->stored[ctx->stored_tail], input->text.nbytes); + r = read(fd, &input->text.bytes[input->text.nbytes], sizeof(input->text.bytes) - input->text.nbytes); + if (r <= 0) + return (int)r; + input->text.nbytes += (size_t)r; + ctx->stored_head = ctx->stored_tail = 0; + goto normal; } input->text.nbytes = ctx->stored_head - ctx->stored_tail; - input->text.type = LIBTERMINPUT_TEXT; - memcpy(input->text.bytes, &ctx->stored[ctx->stored_tail], n - ctx->stored_tail); - ctx->stored_tail = n; - if (ctx->stored_tail == ctx->stored_head) - ctx->stored_tail = ctx->stored_head = 0; - return 0; + memcpy(input->text.bytes, &ctx->stored[ctx->stored_tail], input->text.nbytes); + ctx->stored_head = ctx->stored_tail = 0; + goto normal; } r = read(fd, input->text.bytes, sizeof(input->text.bytes)); if (r <= 0) return (int)r; - input->text.nbytes = (size_t)r; - for (n = 0; n + 6 < input->text.nbytes; n++) { + +normal: + for (n = 0; n + 5 < input->text.nbytes; n++) { if (input->text.bytes[n + 0] == '\033' && input->text.bytes[n + 1] == '[' && input->text.bytes[n + 2] == '2' && - input->text.bytes[n + 3] == '0' && input->text.bytes[n + 4] == '0' && input->text.bytes[n + 5] == '~') + input->text.bytes[n + 3] == '0' && input->text.bytes[n + 4] == '1' && input->text.bytes[n + 5] == '~') break; } - if (!n && input->text.nbytes >= 6) { + do { + if (n + 4 < input->text.nbytes) { + if (input->text.bytes[n + 0] == '\033' && input->text.bytes[n + 1] == '[' && input->text.bytes[n + 2] == '2' && + input->text.bytes[n + 3] == '0' && input->text.bytes[n + 4] == '1') + break; + n += 1; + } + if (n + 3 < input->text.nbytes) { + if (input->text.bytes[n + 0] == '\033' && input->text.bytes[n + 1] == '[' && input->text.bytes[n + 2] == '2' && + input->text.bytes[n + 3] == '0') + break; + n += 1; + } + if (n + 2 < input->text.nbytes) { + if (input->text.bytes[n + 0] == '\033' && input->text.bytes[n + 1] == '[' && input->text.bytes[n + 2] == '2') + break; + n += 1; + } + if (n + 1 < input->text.nbytes) { + if (input->text.bytes[n + 0] == '\033' && input->text.bytes[n + 1] == '[') + break; + n += 1; + } + if (n + 0 < input->text.nbytes) { + if (input->text.bytes[n + 0] == '\033') + break; + n += 1; + } + } while (0); + if (!n) { + if (input->text.nbytes < 6) { + input->text.type = LIBTERMINPUT_NONE; + memcpy(ctx->stored, input->text.bytes, input->text.nbytes); + ctx->stored_tail = 0; + ctx->stored_head = input->text.nbytes; + ctx->paused = 1; + return 1; + } ctx->stored_tail = 0; ctx->stored_head = input->text.nbytes - 6; memcpy(ctx->stored, &input->text.bytes[6], ctx->stored_head); @@ -697,14 +739,14 @@ read_bracketed_paste(int fd, union libterminput_input *input, struct libterminpu ctx->stored_tail = ctx->stored_head = 0; ctx->bracketed_paste = 0; input->type = LIBTERMINPUT_BRACKETED_PASTE_END; - return 0; + return 1; } - /* TODO test */ ctx->stored_tail = 0; ctx->stored_head = input->text.nbytes - n; + memcpy(ctx->stored, &input->text.bytes[n], ctx->stored_head); input->text.nbytes = n; input->text.type = LIBTERMINPUT_TEXT; - return 0; + return 1; } diff --git a/libterminput.h b/libterminput.h index 95eea11..6029305 100644 --- a/libterminput.h +++ b/libterminput.h @@ -172,12 +172,13 @@ struct libterminput_state { int inited; /* whether the input in initialised, not this struct */ enum libterminput_mod mods; enum libterminput_flags flags; - size_t stored_head; - size_t stored_tail; char bracketed_paste; char mouse_tracking; char meta; char n; + size_t stored_head; + size_t stored_tail; + char paused; char npartial; char partial[7]; char key[44]; @@ -198,7 +199,7 @@ int libterminput_read(int fd, union libterminput_input *input, struct libterminp inline int libterminput_is_ready(union libterminput_input *input, struct libterminput_state *ctx) { - if (!ctx->inited) + if (!ctx->inited || ctx->paused) return 0; if (input->type == LIBTERMINPUT_KEYPRESS && input->keypress.times > 1) return 1; diff --git a/libterminput_is_ready.3 b/libterminput_is_ready.3 index 293d60e..0739e11 100644 --- a/libterminput_is_ready.3 +++ b/libterminput_is_ready.3 @@ -19,7 +19,11 @@ function check if a call to the .BR libterminput_read (3) function will skip reading from the file descriptor passed to it because it already -has read data buffered. +has read data buffered. However, if there +is buffered data but the library knows it +it not enough to return something they, +it will also return that there is nothing +buffered. .SH RETURN VALUE The diff --git a/test.c b/test.c index 76a4654..86d9bfa 100644 --- a/test.c +++ b/test.c @@ -128,7 +128,9 @@ main(void) #define TYPE(STR, T)\ do {\ - TEST(write(fds[1], STR, strlen(STR)) == (ssize_t)strlen(STR));\ + alarm(5);\ + if ((STR) && *(const char *)(STR))\ + TEST(write(fds[1], STR, strlen(STR)) == (ssize_t)strlen(STR));\ do {\ TEST(libterminput_read(fds[0], &input, &ctx) == 1);\ } while (input.type == LIBTERMINPUT_NONE && libterminput_is_ready(&input, &ctx));\ @@ -138,8 +140,10 @@ main(void) #define KEYPRESS_(STR1, STR2, STR3, STR4, KEY, MODS, TIMES)\ do {\ int times__ = (TIMES);\ + alarm(5);\ stpcpy(stpcpy(stpcpy(stpcpy(buffer, STR1), STR2), STR3), STR4);\ - TEST(write(fds[1], buffer, strlen(buffer)) == (ssize_t)strlen(buffer));\ + if (*buffer)\ + TEST(write(fds[1], buffer, strlen(buffer)) == (ssize_t)strlen(buffer));\ for (; times__; times__--) {\ do {\ TEST(libterminput_read(fds[0], &input, &ctx) == 1);\ @@ -229,11 +233,34 @@ main(void) TYPE("\033[201~", LIBTERMINPUT_BRACKETED_PASTE_END); TYPE("x", LIBTERMINPUT_KEYPRESS); -#ifdef TODO TYPE("\033[200~", LIBTERMINPUT_BRACKETED_PASTE_START); - TYPE("x", LIBTERMINPUT_TEXT); -#endif + TYPE("x\033[201~", LIBTERMINPUT_TEXT); + TEST(input.text.nbytes == strlen("x")); + TEST(!memcmp(input.text.bytes, "x", strlen("x"))); + TYPE(NULL, LIBTERMINPUT_BRACKETED_PASTE_END); + TYPE("\033[200~x", LIBTERMINPUT_BRACKETED_PASTE_START); + TYPE(NULL, LIBTERMINPUT_TEXT); + TEST(input.text.nbytes == strlen("x")); + TEST(!memcmp(input.text.bytes, "x", strlen("x"))); + TYPE("\033[201x~x\033[201~x", LIBTERMINPUT_TEXT); + TEST(input.text.nbytes == strlen("\033[201x~x")); + TEST(!memcmp(input.text.bytes, "\033[201x~x", strlen("\033[201x~x"))); + TYPE(NULL, LIBTERMINPUT_BRACKETED_PASTE_END); + TYPE(NULL, LIBTERMINPUT_KEYPRESS); + TYPE("\033[200~", LIBTERMINPUT_BRACKETED_PASTE_START); TYPE("\033[201~", LIBTERMINPUT_BRACKETED_PASTE_END); + TYPE("\033[200~", LIBTERMINPUT_BRACKETED_PASTE_START); + TYPE("\033[201", LIBTERMINPUT_NONE); + TYPE("x\033[20", LIBTERMINPUT_TEXT); + TEST(input.text.nbytes == strlen("\033[201x")); + TEST(!memcmp(input.text.bytes, "\033[201x", strlen("\033[201x"))); + TYPE("1", LIBTERMINPUT_NONE); + TYPE("~", LIBTERMINPUT_BRACKETED_PASTE_END); + TYPE("\033[200~\033[201~", LIBTERMINPUT_BRACKETED_PASTE_START); + TYPE(NULL, LIBTERMINPUT_BRACKETED_PASTE_END); + TYPE("\033[200~\033[201", LIBTERMINPUT_BRACKETED_PASTE_START); + TYPE("~", LIBTERMINPUT_BRACKETED_PASTE_END); + TYPE("\033[200^", LIBTERMINPUT_NONE); TYPE("\033[200$", LIBTERMINPUT_NONE); TYPE("\033[200@", LIBTERMINPUT_NONE); -- cgit v1.2.3-70-g09d2