aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2021-10-30 04:18:52 +0200
committerPřemysl Eric Janouch <p@janouch.name>2021-10-30 09:27:32 +0200
commit5165f76b7cbcc6db541b0c76f3e07cfe52ca71b7 (patch)
tree0170fcdf776909fa869eacd243a6e193750ec0f7
parent92ac13f3c679b8d1261a33e7dbe4baf9e4dc3107 (diff)
downloadxK-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.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/xC.c b/xC.c
index 3de9f26..a5a8070 100644
--- a/xC.c
+++ b/xC.c
@@ -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: