bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] bracketed paste support


From: Daniel Colascione
Subject: [PATCH] bracketed paste support
Date: Mon, 27 Oct 2014 22:35:00 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0

This patch adds support for "bracketed paste mode" to readline. In
this mode, readline instructs the terminal to wrap pasted strings in
special control sequences so that programs can distinguish them from
typed input. This patch makes readline insert each pasted string as
one big literal into the edit buffer; as there is no termcap
capability for bracketed paste support, the patch detects capable
terminals automatically by looking for support for similar escape
sequences.

diff --git a/lib/readline/bind.c b/lib/readline/bind.c
index 8acf4ac..7173552 100644
--- a/lib/readline/bind.c
+++ b/lib/readline/bind.c
@@ -1486,6 +1486,7 @@ static const struct {
   { "convert-meta",            &_rl_convert_meta_chars_to_ascii, 0 },
   { "disable-completion",      &rl_inhibit_completion,         0 },
   { "echo-control-characters", &_rl_echo_control_chars,        0 },
+  { "enable-bracketed-paste",   &_rl_enable_bracketed_paste,    0 },
   { "enable-keypad",           &_rl_enable_keypad,             0 },
   { "enable-meta-key",         &_rl_enable_meta,               0 },
   { "expand-tilde",            &rl_complete_with_tilde_expansion, 0 },
diff --git a/lib/readline/doc/readline.3 b/lib/readline/doc/readline.3
index ca0a81a..808b4b7 100644
--- a/lib/readline/doc/readline.3
+++ b/lib/readline/doc/readline.3
@@ -578,6 +578,13 @@ following the cursor are not duplicated.
 If set to \fBOn\fP, a character denoting a file's type as reported  
 by \fIstat\fP(2) is appended to the filename when listing possible
 completions.
+.TP
+.B enable\-bracketed\-paste (On)
+If set to \fBOn\fP and the terminal supports bracketed
+paste mode, configure it to insert each paste into the
+editing buffer as a string instead of treating
+the characters pasted as normal input, preventing inadvertent
+execution of pasted commands.
 .PD
 .SS Conditional Constructs
 .PP
diff --git a/lib/readline/doc/rluser.texi b/lib/readline/doc/rluser.texi
index 0000577..0a26444 100644
--- a/lib/readline/doc/rluser.texi
+++ b/lib/readline/doc/rluser.texi
@@ -703,6 +703,13 @@ If set to @samp{on}, a character denoting a file's type
 is appended to the filename when listing possible
 completions.  The default is @samp{off}.
 
address@hidden enable-bracketed-paste
address@hidden enable-bracketed-paste
+If set to @samp{on} and the terminal supports bracketed paste mode,
+configure it to insert each paste into the editing buffer as a string
+instead of treating the characters pasted as normal input, preventing
+inadvertent execution of pasted commands.  The default is @samp{on}.
+
 @end table
 
 @item Key Bindings
diff --git a/lib/readline/funmap.c b/lib/readline/funmap.c
index 363507b..29f089b 100644
--- a/lib/readline/funmap.c
+++ b/lib/readline/funmap.c
@@ -101,6 +101,7 @@ static const FUNMAP default_funmap[] = {
   { "history-substring-search-backward", rl_history_substr_search_backward },
   { "history-substring-search-forward", rl_history_substr_search_forward },
   { "insert-comment", rl_insert_comment },
+  { "bracketed-paste-begin", rl_bracketed_paste_begin },
   { "insert-completions", rl_insert_completions },
   { "kill-whole-line", rl_kill_full_line },
   { "kill-line", rl_kill_line },
diff --git a/lib/readline/kill.c b/lib/readline/kill.c
index 3d23745..79de79f 100644
--- a/lib/readline/kill.c
+++ b/lib/readline/kill.c
@@ -656,6 +656,61 @@ rl_yank_last_arg (count, key)
   return retval;
 }
 
+/* We've recognized a terminal control sequence telling us to expected
+ * pasted content.  Read characters from the terminal until we read a
+ * bracketed paste end sequence, treating the characters read as
+ * literal text to insert.  */
+int
+rl_bracketed_paste_begin (count, key)
+     int count, key;
+{
+  static const char endseq[] = "\033[201~";
+  static const int endseqlen = sizeof (endseq) - 1;
+
+  int rv = -1;
+  int c;
+  size_t len = 0;
+  size_t cap = 16;
+  char *buf = xmalloc (cap);
+
+  RL_SETSTATE(RL_STATE_MOREINPUT);
+  while (0 <= (c = rl_read_key ()))
+    {
+      if (RL_ISSTATE (RL_STATE_MACRODEF))
+        _rl_add_macro_char (c);
+
+      if (c == '\r')
+        c = '\n';
+
+      if (len == cap)
+        buf = xrealloc (buf, (cap *= 2));
+
+      buf[len++] = c;
+      if (len >= endseqlen &&
+          !strncmp (&buf[len - endseqlen],
+                    endseq,
+                    endseqlen))
+        {
+          len -= endseqlen;
+          break;
+        }
+    }
+  RL_UNSETSTATE(RL_STATE_MOREINPUT);
+
+  if (c >= 0)
+    {
+      if (len == cap)
+        buf = xrealloc (buf, (cap += 1));
+
+      buf[len++] = '\0';
+      rl_insert_text (buf);
+      rv = 0;
+    }
+
+  xfree (buf);
+  return rv;
+}
+
 /* A special paste command for users of Cygnus's cygwin32. */
 #if defined (__CYGWIN__)
 #include <windows.h>
diff --git a/lib/readline/readline.c b/lib/readline/readline.c
index f8211e7..d6e9775 100644
--- a/lib/readline/readline.c
+++ b/lib/readline/readline.c
@@ -302,6 +302,11 @@ int _rl_revert_all_at_newline = 0;
    characters corresponding to keyboard-generated signals. */
 int _rl_echo_control_chars = 1;
 
+/* Non-zero means to instruct the terminal to use "bracketed paste"
+   mode to quote characters pasted from the clipboard if we
+   believe the terminal supports the facility. */
+int _rl_enable_bracketed_paste = 1;
+
 /* Non-zero means to prefix the displayed prompt with a character indicating
    the editing mode: @ for emacs, : for vi-command, + for vi-insert. */
 int _rl_show_mode_in_prompt = 0;
@@ -1247,6 +1252,8 @@ bind_arrow_keys_internal (map)
   rl_bind_keyseq_if_unbound ("\033OH", rl_beg_of_line);
   rl_bind_keyseq_if_unbound ("\033OF", rl_end_of_line);
 
+  rl_bind_keyseq_if_unbound ("\033[200~", rl_bracketed_paste_begin);
+
 #if defined (__MINGW32__)
   rl_bind_keyseq_if_unbound ("\340H", rl_get_previous_history);
   rl_bind_keyseq_if_unbound ("\340P", rl_get_next_history);
diff --git a/lib/readline/readline.h b/lib/readline/readline.h
index 08dcd2b..712747f 100644
--- a/lib/readline/readline.h
+++ b/lib/readline/readline.h
@@ -110,6 +110,7 @@ extern int rl_rubout_or_delete PARAMS((int, int));
 extern int rl_delete_horizontal_space PARAMS((int, int));
 extern int rl_delete_or_show_completions PARAMS((int, int));
 extern int rl_insert_comment PARAMS((int, int));
+extern int rl_bracketed_paste_begin PARAMS((int, int));
 
 /* Bindable commands for changing case. */
 extern int rl_upcase_word PARAMS((int, int));
diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h
index b486e7b..ba07129 100644
--- a/lib/readline/rlprivate.h
+++ b/lib/readline/rlprivate.h
@@ -524,6 +524,7 @@ extern int _rl_screenwidth;
 extern int _rl_screenchars;
 extern int _rl_terminal_can_insert;
 extern int _rl_term_autowrap;
+extern int _rl_enable_bracketed_paste;
 
 /* undo.c */
 extern int _rl_doing_an_undo;
diff --git a/lib/readline/rltty.c b/lib/readline/rltty.c
index 908bae1..837381b 100644
--- a/lib/readline/rltty.c
+++ b/lib/readline/rltty.c
@@ -4,7 +4,7 @@
 /* Copyright (C) 1992-2005 Free Software Foundation, Inc.
 
    This file is part of the GNU Readline Library (Readline), a library
-   for reading lines of text with interactive input and history editing.      
+   for reading lines of text with interactive input and history editing.
 
    Readline is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -60,7 +60,12 @@ static void set_winsize PARAMS((int));
 /*                                                                 */
 /* **************************************************************** */
 
-/* Non-zero means that the terminal is in a prepped state. */
+/* Non-zero means that the terminal is in a prepped state.  If
+ * TERMINAL_PREPPED_BRACKETED_PASTE set, we sent the bracketed paste
+ * enable sequence, so we should disable the sequence when we
+ * deprep.  */
+#define TERMINAL_PREPPED 1
+#define TERMINAL_PREPPED_BRACKETED_PASTE 3
 static int terminal_prepped;
 
 static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars;
@@ -489,7 +494,7 @@ set_tty_settings (tty, tiop)
 {
   if (_set_tty_settings (tty, tiop) < 0)
     return -1;
-    
+
 #if 0
 
 #if defined (TERMIOS_TTY_DRIVER)
@@ -591,12 +596,26 @@ rl_deprep_terminal ()
 }
 
 #else /* ! NO_TTY_DRIVER */
+
+static int
+rl_bracketed_paste_probably_supported_p ()
+{
+  /* There is no termcap entry for bracketed paste support, so look
+     for a termcap entry that all terminals that support bracketed
+     paste also support.  If that capability is ANSI-ish, the
+     bracketed paste sequence will either work or be harmless. */
+  static const char pat[] = "\033[?1049l";
+  const char *te = rl_get_termcap ("te");
+  return te && strstr (te, pat);
+}
+
 void
 rl_prep_terminal (meta_flag)
      int meta_flag;
 {
   int tty;
   TIOTYPE tio;
+  int new_prep;
 
   if (terminal_prepped)
     return;
@@ -642,7 +661,7 @@ rl_prep_terminal (meta_flag)
       /* If editing in vi mode, make sure we set the bindings in the
         insertion keymap no matter what keymap we ended up in. */
       if (rl_editing_mode == vi_mode)
-       _rl_bind_tty_special_chars (vi_insertion_keymap, tio);  
+       _rl_bind_tty_special_chars (vi_insertion_keymap, tio);
       else
 #endif
        _rl_bind_tty_special_chars (_rl_keymap, tio);
@@ -659,8 +678,17 @@ rl_prep_terminal (meta_flag)
   if (_rl_enable_keypad)
     _rl_control_keypad (1);
 
+  new_prep = TERMINAL_PREPPED;
+
+  if (_rl_enable_bracketed_paste &&
+      rl_bracketed_paste_probably_supported_p ())
+    {
+      fprintf (rl_outstream, "\033[?2004h");
+      new_prep |= TERMINAL_PREPPED_BRACKETED_PASTE;
+    }
+
   fflush (rl_outstream);
-  terminal_prepped = 1;
+  terminal_prepped = new_prep;
   RL_SETSTATE(RL_STATE_TERMPREPPED);
 
   _rl_release_sigint ();
@@ -678,6 +706,9 @@ rl_deprep_terminal ()
   /* Try to keep this function from being interrupted. */
   _rl_block_sigint ();
 
+  if (terminal_prepped & TERMINAL_PREPPED_BRACKETED_PASTE)
+    fprintf (rl_outstream, "\033[?2004l");
+
   tty = rl_instream ? fileno (rl_instream) : fileno (stdin);
 
   if (_rl_enable_keypad)
diff --git a/lib/readline/terminal.c b/lib/readline/terminal.c
index 1212ec4..d00362e 100644
--- a/lib/readline/terminal.c
+++ b/lib/readline/terminal.c
@@ -137,6 +137,9 @@ char *_rl_term_forward_char;
 /* How to go up a line. */
 char *_rl_term_up;
 
+/* Proxy for bracketed paste support. */
+char *_rl_term_te;
+
 /* A visible bell; char if the terminal can be made to flash the screen. */
 static char *_rl_visible_bell;
 
@@ -414,6 +417,7 @@ static const struct _tc_string tc_strings[] =
   { "mo", &_rl_term_mo },
   { "nd", &_rl_term_forward_char },
   { "pc", &_rl_term_pc },
+  { "te", &_rl_term_te },
   { "up", &_rl_term_up },
   { "vb", &_rl_visible_bell },
   { "vs", &_rl_term_vs },


Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]