xC: quote text coming from a bracketed paste

Not having this has caused me much annoyance over the years.
This commit is contained in:
Přemysl Eric Janouch 2021-10-30 04:18:52 +02:00
parent 92ac13f3c6
commit 5165f76b7c
Signed by: p
GPG Key ID: A0420B94F92B9493

42
xC.c
View File

@ -2445,6 +2445,10 @@ static struct config_schema g_config_behaviour[] =
{ .name = "editor_command", { .name = "editor_command",
.comment = "VIM: \"vim +%Bgo %F\", Emacs: \"emacs -nw +%L:%C %F\"", .comment = "VIM: \"vim +%Bgo %F\", Emacs: \"emacs -nw +%L:%C %F\"",
.type = CONFIG_ITEM_STRING }, .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", { .name = "date_change_line",
.comment = "Input to strftime(3) for the date change line", .comment = "Input to strftime(3) for the date change line",
.type = CONFIG_ITEM_STRING, .type = CONFIG_ITEM_STRING,
@ -12624,8 +12628,6 @@ process_input (struct app_context *ctx, char *user_input)
else else
{ {
struct strv lines = strv_make (); struct strv lines = strv_make ();
// XXX: this interprets commands in pasted text
cstr_split (input, "\r\n", false, &lines); cstr_split (input, "\r\n", false, &lines);
for (size_t i = 0; i < lines.len; i++) for (size_t i = 0; i < lines.len; i++)
(void) process_input_utf8 (ctx, (void) process_input_utf8 (ctx,
@ -14234,6 +14236,40 @@ done:
#define BRACKETED_PASTE_LIMIT 102400 ///< How much text can be pasted #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 static void
process_bracketed_paste (const struct pollfd *fd, struct app_context *ctx) 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)); (int) (text_len = BRACKETED_PASTE_LIMIT));
buf->str[text_len] = '\0'; buf->str[text_len] = '\0';
if (CALL_ (ctx->input, insert, buf->str)) if (insert_paste (ctx, buf->str, text_len))
goto done; goto done;
error: error: