diff options
author | Přemysl Eric Janouch <p@janouch.name> | 2021-10-30 04:18:52 +0200 |
---|---|---|
committer | Přemysl Eric Janouch <p@janouch.name> | 2021-10-30 09:27:32 +0200 |
commit | 5165f76b7cbcc6db541b0c76f3e07cfe52ca71b7 (patch) | |
tree | 0170fcdf776909fa869eacd243a6e193750ec0f7 | |
parent | 92ac13f3c679b8d1261a33e7dbe4baf9e4dc3107 (diff) | |
download | xK-5165f76b7cbcc6db541b0c76f3e07cfe52ca71b7.tar.gz xK-5165f76b7cbcc6db541b0c76f3e07cfe52ca71b7.tar.xz xK-5165f76b7cbcc6db541b0c76f3e07cfe52ca71b7.zip |
xC: quote text coming from a bracketed paste
Not having this has caused me much annoyance over the years.
-rw-r--r-- | xC.c | 42 |
1 files changed, 39 insertions, 3 deletions
@@ -2445,6 +2445,10 @@ static struct config_schema g_config_behaviour[] = { .name = "editor_command", .comment = "VIM: \"vim +%Bgo %F\", Emacs: \"emacs -nw +%L:%C %F\"", .type = CONFIG_ITEM_STRING }, + { .name = "process_pasted_text", + .comment = "Normalize newlines and quote the command prefix in pastes", + .type = CONFIG_ITEM_BOOLEAN, + .default_ = "on" }, { .name = "date_change_line", .comment = "Input to strftime(3) for the date change line", .type = CONFIG_ITEM_STRING, @@ -12624,8 +12628,6 @@ process_input (struct app_context *ctx, char *user_input) else { struct strv lines = strv_make (); - - // XXX: this interprets commands in pasted text cstr_split (input, "\r\n", false, &lines); for (size_t i = 0; i < lines.len; i++) (void) process_input_utf8 (ctx, @@ -14234,6 +14236,40 @@ done: #define BRACKETED_PASTE_LIMIT 102400 ///< How much text can be pasted +static bool +insert_paste (struct app_context *ctx, char *paste, size_t len) +{ + if (!get_config_boolean (ctx->config.root, "behaviour.process_pasted_text")) + return CALL_ (ctx->input, insert, paste); + + // Without ICRNL, which Editline keeps but Readline doesn't, + // the terminal sends newlines as carriage returns (seen on urxvt) + for (size_t i = 0; i < len; i++) + if (paste[i] == '\r') + paste[i] = '\n'; + + int position = 0; + char *input = CALL_ (ctx->input, get_line, &position); + bool quote_first_slash = !position || strchr ("\r\n", input[position - 1]); + free (input); + + // Executing commands by accident is much more common than pasting them + // intentionally, although the latter may also have security consequences + struct str processed = str_make (); + str_reserve (&processed, len); + for (size_t i = 0; i < len; i++) + { + if (paste[i] == '/' + && ((!i && quote_first_slash) || (i && paste[i - 1] == '\n'))) + str_append_c (&processed, paste[i]); + str_append_c (&processed, paste[i]); + } + + bool success = CALL_ (ctx->input, insert, processed.str); + str_free (&processed); + return success; +} + static void process_bracketed_paste (const struct pollfd *fd, struct app_context *ctx) { @@ -14258,7 +14294,7 @@ process_bracketed_paste (const struct pollfd *fd, struct app_context *ctx) (int) (text_len = BRACKETED_PASTE_LIMIT)); buf->str[text_len] = '\0'; - if (CALL_ (ctx->input, insert, buf->str)) + if (insert_paste (ctx, buf->str, text_len)) goto done; error: |