]> granicus.if.org Git - vim/commitdiff
patch 8.0.0210: no support for bracketed paste v8.0.0210
authorBram Moolenaar <Bram@vim.org>
Sat, 21 Jan 2017 19:04:22 +0000 (20:04 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 21 Jan 2017 19:04:22 +0000 (20:04 +0100)
Problem:    Vim does not support bracketed paste, as implemented by xterm and
            other terminals.
Solution:   Add t_BE, t_BD, t_PS and t_PE.

13 files changed:
runtime/doc/term.txt
src/edit.c
src/evalfunc.c
src/getchar.c
src/keymap.h
src/misc2.c
src/normal.c
src/option.c
src/proto/edit.pro
src/term.c
src/term.h
src/version.c
src/vim.h

index 7e8b3ccc92047f3705782bb7d339b3e62d772283..228853f0249a6cdd864185b41cc9abdbd93629e4 100644 (file)
@@ -89,6 +89,18 @@ an external command (e.g., "!!"), the terminal will be put into Normal mode
 for a moment.  This means that you can stop the output to the screen by
 hitting a printing key.  Output resumes when you hit <BS>.
 
+                                               *xterm-bracketed-paste*
+When the 't_BE' option is set then 't_BE' will be sent to the
+terminal when entering "raw" mode and 't_BD' when leaving "raw" mode.  The
+terminal is then expected to put 't_PS' before pasted text and 't_PE' after
+pasted text.  This way Vim can separate text that is pasted from characters
+that are typed.  The pasted text is handled like when the middle mouse button
+is used.
+
+Note that in some situations Vim will not recognize the bracketed paste and
+you will get the raw text.  In other situations Vim will only get the first
+pasted character and drop the rest, e.g. when using the "r" command.
+
                                                        *cs7-problem*
 Note: If the terminal settings are changed after running Vim, you might have
 an illegal combination of settings.  This has been reported on Solaris 2.5
@@ -306,6 +318,10 @@ Added by Vim (there are no standard codes for these):
                |xterm-true-color|
        t_8b    set background color (R, G, B)                  *t_8b* *'t_8b'*
                |xterm-true-color|
+       t_BE    enable bracketed paste mode                     *t_BE* *'t_BE'*
+               |xterm-bracketed-paste|
+       t_BD    disable bracketed paste mode                    *t_BD* *'t_BD'*
+               |xterm-bracketed-paste|
 
 KEY CODES
 Note: Use the <> form if possible
@@ -398,6 +414,8 @@ Note: Use the <> form if possible
        t_KK    <k8>            keypad 8                 *<k8>* *t_KK* *'t_KK'*
        t_KL    <k9>            keypad 9                 *<k9>* *t_KL* *'t_KL'*
                <Mouse>         leader of mouse code            *<Mouse>*
+       t_PS    start of brackted paste |xterm-bracketed-paste|   *t_PS* 't_PS'
+       t_PE    end of bracketed paste |xterm-bracketed-paste|    *t_PE* 't_PE'
 
 Note about t_so and t_mr: When the termcap entry "so" is not present the
 entry for "mr" is used.  And vice versa.  The same is done for "se" and "me".
index 8e6ca5da9d549faf78bdda89122a229ffd787fcc..61d92170f4be3c366d43118e33fc384e8db7d563 100644 (file)
@@ -309,6 +309,7 @@ static int  dont_sync_undo = FALSE; /* CTRL-G U prevents syncing undo for
  * "cmdchar" can be:
  * 'i' normal insert command
  * 'a' normal append command
+ * K_PS bracketed paste
  * 'R' replace command
  * 'r' "r<CR>" command: insert one <CR>.  Note: count can be > 1, for redo,
  *     but still only one <CR> is inserted.  The <Esc> is not used for redo.
@@ -782,10 +783,14 @@ edit(
            dont_sync_undo = TRUE;
        else
            dont_sync_undo = FALSE;
-       do
-       {
-           c = safe_vgetc();
-       } while (c == K_IGNORE);
+       if (cmdchar == K_PS)
+           /* Got here from normal mode when bracketed paste started. */
+           c = K_PS;
+       else
+           do
+           {
+               c = safe_vgetc();
+           } while (c == K_IGNORE);
 
 #ifdef FEAT_AUTOCMD
        /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
@@ -1193,6 +1198,16 @@ doESCkey:
            ins_mousescroll(MSCR_RIGHT);
            break;
 #endif
+       case K_PS:
+           bracketed_paste(PASTE_INSERT, FALSE, NULL);
+           if (cmdchar == K_PS)
+               /* invoked from normal mode, bail out */
+               goto doESCkey;
+           break;
+       case K_PE:
+           /* Got K_PE without K_PS, ignore. */
+           break;
+
 #ifdef FEAT_GUI_TABLINE
        case K_TABLINE:
        case K_TABMENU:
@@ -9424,6 +9439,91 @@ ins_mousescroll(int dir)
 }
 #endif
 
+/*
+ * Handle receiving P_PS: start paste mode.  Inserts the following text up to
+ * P_PE literally.
+ * When "drop" is TRUE then consume the text and drop it.
+ */
+    int
+bracketed_paste(paste_mode_T mode, int drop, garray_T *gap)
+{
+    int                c;
+    char_u     buf[NUMBUFLEN + MB_MAXBYTES];
+    int                idx = 0;
+    char_u     *end = find_termcode((char_u *)"PE");
+    int                ret_char = -1;
+    int                save_allow_keys = allow_keys;
+
+    /* If the end code is too long we can't detect it, read everything. */
+    if (STRLEN(end) >= NUMBUFLEN)
+       end = NULL;
+    ++no_mapping;
+    allow_keys = 0;
+    for (;;)
+    {
+       /* When the end is not defined read everything. */
+       if (end == NULL && vpeekc() == NUL)
+           break;
+       c = plain_vgetc();
+#ifdef FEAT_MBYTE
+       if (has_mbyte)
+           idx += (*mb_char2bytes)(c, buf + idx);
+       else
+#endif
+           buf[idx++] = c;
+       buf[idx] = NUL;
+       if (end != NUL && STRNCMP(buf, end, idx) == 0)
+       {
+           if (end[idx] == NUL)
+               break; /* Found the end of paste code. */
+           continue;
+       }
+       if (!drop)
+       {
+           switch (mode)
+           {
+               case PASTE_CMDLINE:
+                   put_on_cmdline(buf, idx, TRUE);
+                   break;
+
+               case PASTE_EX:
+                   if (gap != NULL && ga_grow(gap, idx) == OK)
+                   {
+                       mch_memmove((char *)gap->ga_data + gap->ga_len,
+                                                            buf, (size_t)idx);
+                       gap->ga_len += idx;
+                   }
+                   break;
+
+               case PASTE_INSERT:
+                   if (stop_arrow() == OK)
+                   {
+                       ins_char_bytes(buf, idx);
+                       AppendToRedobuffLit(buf, idx);
+                   }
+                   break;
+
+               case PASTE_ONE_CHAR:
+                   if (ret_char == -1)
+                   {
+#ifdef FEAT_MBYTE
+                       if (has_mbyte)
+                           ret_char = (*mb_ptr2char)(buf);
+                       else
+#endif
+                           ret_char = buf[0];
+                   }
+                   break;
+           }
+       }
+       idx = 0;
+    }
+    --no_mapping;
+    allow_keys = save_allow_keys;
+
+    return ret_char;
+}
+
 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
     static void
 ins_tabline(int c)
index c7be082fafbddbd30a47dafcf609e005889d076e..da2235455e01d0b7f50e4c7ad9a0c7869a28be46 100644 (file)
@@ -4231,7 +4231,7 @@ f_getchar(typval_T *argvars, typval_T *rettv)
     {
        if (argvars[0].v_type == VAR_UNKNOWN)
            /* getchar(): blocking wait. */
-           n = safe_vgetc();
+           n = plain_vgetc();
        else if (get_tv_number_chk(&argvars[0], &error) == 1)
            /* getchar(1): only check if char avail */
            n = vpeekc_any();
@@ -4240,7 +4240,7 @@ f_getchar(typval_T *argvars, typval_T *rettv)
            n = 0;
        else
            /* getchar(0) and char avail: return char */
-           n = safe_vgetc();
+           n = plain_vgetc();
 
        if (n == K_IGNORE)
            continue;
index 9adeafa5ba931d7faa700eb24a91ffda59c818aa..9583d9a8f91fb43b429569d80775134e99d2d24b 100644 (file)
@@ -1817,6 +1817,12 @@ plain_vgetc(void)
     {
        c = safe_vgetc();
     } while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
+
+    if (c == K_PS)
+       /* Only handle the first pasted character.  Drop the rest, since we
+        * don't know what to do with it. */
+       c = bracketed_paste(PASTE_ONE_CHAR, FALSE, NULL);
+
     return c;
 }
 
@@ -1906,7 +1912,7 @@ vungetc(int c)
 }
 
 /*
- * get a character:
+ * Get a character:
  * 1. from the stuffbuffer
  *     This is used for abbreviated commands like "D" -> "d$".
  *     Also used to redo a command for ".".
index 1957e9874ac99f1d8b065ddcd27130c9f9357528..9efecfbefd308ea5f69a6d07fda0694c52e1c11c 100644 (file)
@@ -391,6 +391,8 @@ enum key_extra
 #define K_KMULTIPLY    TERMCAP2KEY('K', '9')   /* keypad * */
 #define K_KENTER       TERMCAP2KEY('K', 'A')   /* keypad Enter */
 #define K_KPOINT       TERMCAP2KEY('K', 'B')   /* keypad . or ,*/
+#define K_PS           TERMCAP2KEY('P', 'S')   /* paste start */
+#define K_PE           TERMCAP2KEY('P', 'E')   /* paste end */
 
 #define K_K0           TERMCAP2KEY('K', 'C')   /* keypad 0 */
 #define K_K1           TERMCAP2KEY('K', 'D')   /* keypad 1 */
index c26f90075b449d6f2926b98f94686ea08f0e2ee7..bf98a646c85f9f1ea6880de449af81ecefb1e557 100644 (file)
@@ -2294,6 +2294,8 @@ static struct key_name_entry
     {K_XDOWN,          (char_u *)"xDown"},
     {K_XLEFT,          (char_u *)"xLeft"},
     {K_XRIGHT,         (char_u *)"xRight"},
+    {K_PS,             (char_u *)"PasteStart"},
+    {K_PE,             (char_u *)"PasteEnd"},
 
     {K_F1,             (char_u *)"F1"},
     {K_F2,             (char_u *)"F2"},
index 8724553a9a3d4c20655ebb167cab8891db6bc32e..2b867bb19831d901fd5bf9d9c15c4ee271dc9d12 100644 (file)
@@ -426,6 +426,7 @@ static const struct nv_cmd
 #ifdef FEAT_AUTOCMD
     {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG,          0},
 #endif
+    {K_PS,     nv_edit,        0,                      0},
 };
 
 /* Number of commands in nv_cmds[]. */
@@ -3858,7 +3859,7 @@ add_to_showcmd(int c)
        K_VER_SCROLLBAR, K_HOR_SCROLLBAR,
        K_LEFTMOUSE_NM, K_LEFTRELEASE_NM,
 # endif
-       K_IGNORE,
+       K_IGNORE, K_PS,
        K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE,
        K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE,
        K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
@@ -9015,6 +9016,7 @@ nv_esc(cmdarg_T *cap)
 
 /*
  * Handle "A", "a", "I", "i" and <Insert> commands.
+ * Also handle K_PS, start bracketed paste.
  */
     static void
 nv_edit(cmdarg_T *cap)
@@ -9042,6 +9044,9 @@ nv_edit(cmdarg_T *cap)
        /* Only give this error when 'insertmode' is off. */
        EMSG(_(e_modifiable));
        clearop(cap->oap);
+       if (cap->cmdchar == K_PS)
+           /* drop the pasted text */
+           bracketed_paste(PASTE_INSERT, TRUE, NULL);
     }
     else if (!checkclearopq(cap->oap))
     {
@@ -9073,6 +9078,7 @@ nv_edit(cmdarg_T *cap)
                break;
 
            case 'a':   /* "a"ppend is like "i"nsert on the next character. */
+           case K_PS:  /* bracketed paste works like "a"ppend */
 #ifdef FEAT_VIRTUALEDIT
                /* increment coladd when in virtual space, increment the
                 * column otherwise, also to append after an unprintable char */
@@ -9103,6 +9109,9 @@ nv_edit(cmdarg_T *cap)
 
        invoke_edit(cap, FALSE, cap->cmdchar, FALSE);
     }
+    else if (cap->cmdchar == K_PS)
+       /* drop the pasted text */
+       bracketed_paste(PASTE_INSERT, TRUE, NULL);
 }
 
 /*
index 6f9610dd0f8866b48d44c6ff4d030d09d4204d4b..cc68cdfd5b8c11f2651e1053ac42cda77a3cf8b5 100644 (file)
@@ -3040,6 +3040,8 @@ static struct vimoption options[] =
     p_term("t_ZR", T_CZR)
     p_term("t_8f", T_8F)
     p_term("t_8b", T_8B)
+    p_term("t_BE", T_BE)
+    p_term("t_BD", T_BD)
 
 /* terminal key codes are not in here */
 
index 7a399c0e6e39e717f3e9c7a9697ea2543454700b..f6d645ccfbdf8430f496f2dad7499cd7c601cd68 100644 (file)
@@ -38,6 +38,7 @@ void fixthisline(int (*get_the_indent)(void));
 void fix_indent(void);
 int in_cinkeys(int keytyped, int when, int line_is_empty);
 int hkmap(int c);
+int bracketed_paste(paste_mode_T mode, int drop, garray_T *gap);
 void ins_scroll(void);
 void ins_horscroll(void);
 int ins_copychar(linenr_T lnum);
index 65b86b2842e426960bc4cb55f6d4a6c14b451bc7..8cb92dc478e30a2120e53dc28e1fee020ecebf21 100644 (file)
@@ -857,6 +857,8 @@ static struct builtin_term builtin_termcaps[] =
     {(int)KS_8F,       IF_EB("\033[38;2;%lu;%lu;%lum", ESC_STR "[38;2;%lu;%lu;%lum")},
     {(int)KS_8B,       IF_EB("\033[48;2;%lu;%lu;%lum", ESC_STR "[48;2;%lu;%lu;%lum")},
 #  endif
+    {(int)KS_CBE,      IF_EB("\033[?2004h", ESC_STR "[?2004h")},
+    {(int)KS_CBD,      IF_EB("\033[?2004l", ESC_STR "[?2004l")},
 
     {K_UP,             IF_EB("\033O*A", ESC_STR "O*A")},
     {K_DOWN,           IF_EB("\033O*B", ESC_STR "O*B")},
@@ -902,13 +904,15 @@ static struct builtin_term builtin_termcaps[] =
     {K_ZEND,           IF_EB("\033[8;*~", ESC_STR "[8;*~")},
     {K_PAGEUP,         IF_EB("\033[5;*~", ESC_STR "[5;*~")},
     {K_PAGEDOWN,       IF_EB("\033[6;*~", ESC_STR "[6;*~")},
-    {K_KPLUS,          IF_EB("\033O*k", ESC_STR "O*k")},       /* keypad plus */
-    {K_KMINUS,         IF_EB("\033O*m", ESC_STR "O*m")},       /* keypad minus */
-    {K_KDIVIDE,                IF_EB("\033O*o", ESC_STR "O*o")},       /* keypad / */
-    {K_KMULTIPLY,      IF_EB("\033O*j", ESC_STR "O*j")},       /* keypad * */
-    {K_KENTER,         IF_EB("\033O*M", ESC_STR "O*M")},       /* keypad Enter */
-    {K_KPOINT,         IF_EB("\033O*n", ESC_STR "O*n")},       /* keypad . */
-    {K_KDEL,           IF_EB("\033[3;*~", ESC_STR "[3;*~")},   /* keypad Del */
+    {K_KPLUS,          IF_EB("\033O*k", ESC_STR "O*k")},     /* keypad plus */
+    {K_KMINUS,         IF_EB("\033O*m", ESC_STR "O*m")},     /* keypad minus */
+    {K_KDIVIDE,                IF_EB("\033O*o", ESC_STR "O*o")},     /* keypad / */
+    {K_KMULTIPLY,      IF_EB("\033O*j", ESC_STR "O*j")},     /* keypad * */
+    {K_KENTER,         IF_EB("\033O*M", ESC_STR "O*M")},     /* keypad Enter */
+    {K_KPOINT,         IF_EB("\033O*n", ESC_STR "O*n")},     /* keypad . */
+    {K_KDEL,           IF_EB("\033[3;*~", ESC_STR "[3;*~")}, /* keypad Del */
+    {K_PS,             IF_EB("\033[200~", ESC_STR "[200~")}, /* paste start */
+    {K_PE,             IF_EB("\033[201~", ESC_STR "[201~")}, /* paste end */
 
     {BT_EXTRA_KEYS,   ""},
     {TERMCAP2KEY('k', '0'), IF_EB("\033[10;*~", ESC_STR "[10;*~")}, /* F0 */
@@ -1224,6 +1228,8 @@ static struct builtin_term builtin_termcaps[] =
     {K_KMULTIPLY,      "[KMULTIPLY]"},
     {K_KENTER,         "[KENTER]"},
     {K_KPOINT,         "[KPOINT]"},
+    {K_PS,             "[PASTE-START]"},
+    {K_PE,             "[PASTE-END]"},
     {K_K0,             "[K0]"},
     {K_K1,             "[K1]"},
     {K_K2,             "[K2]"},
@@ -1538,6 +1544,8 @@ set_termname(char_u *term)
                                {KS_CSI, "SI"}, {KS_CEI, "EI"},
                                {KS_U7, "u7"}, {KS_RBG, "RB"},
                                {KS_8F, "8f"}, {KS_8B, "8b"},
+                               {KS_CBE, "BE"}, {KS_CBD, "BD"},
+                               {KS_CPS, "PS"}, {KS_CPE, "PE"},
                                {(enum SpecialKey)0, NULL}
                            };
 
@@ -3140,6 +3148,7 @@ starttermcap(void)
     {
        out_str(T_TI);                  /* start termcap mode */
        out_str(T_KS);                  /* start "keypad transmit" mode */
+       out_str(T_BE);                  /* enable bracketed paste moe */
        out_flush();
        termcap_active = TRUE;
        screen_start();                 /* don't know where cursor is now */
@@ -3189,6 +3198,7 @@ stoptermcap(void)
            check_for_codes_from_term();
        }
 #endif
+       out_str(T_BD);                  /* disable bracketed paste moe */
        out_str(T_KE);                  /* stop "keypad transmit" mode */
        out_flush();
        termcap_active = FALSE;
index 3064cefb72a1c67aaf46443e9277e02b95e2afd6..251b475f61ff10cddc860afab094fc0c30646038 100644 (file)
@@ -89,10 +89,14 @@ enum SpecialKey
     KS_OP,     /* original color pair */
     KS_U7,     /* request cursor position */
     KS_8F,     /* set foreground color (RGB) */
-    KS_8B      /* set background color (RGB) */
+    KS_8B,     /* set background color (RGB) */
+    KS_CBE,    /* enable bracketed paste mode */
+    KS_CBD,    /* disable bracketed paste mode */
+    KS_CPS,    /* start of brackted paste */
+    KS_CPE     /* end of brackted paste */
 };
 
-#define KS_LAST            KS_8B
+#define KS_LAST            KS_CPE
 
 /*
  * the terminal capabilities are stored in this array
@@ -170,6 +174,10 @@ extern char_u *(term_strings[]);    /* current terminal strings */
 #define T_U7   (term_str(KS_U7))       /* request cursor position */
 #define T_8F   (term_str(KS_8F))       /* set foreground color (RGB) */
 #define T_8B   (term_str(KS_8B))       /* set background color (RGB) */
+#define T_BE   (term_str(KS_CBE))      /* enable bracketed paste mode */
+#define T_BD   (term_str(KS_CBD))      /* disable bracketed paste mode */
+#define T_PS   (term_str(KS_CPS))      /* start of bracketed paste */
+#define T_PE   (term_str(KS_CPE))      /* end of bracketed paste */
 
 #define TMODE_COOK  0  /* terminal mode for external cmds and Ex mode */
 #define TMODE_SLEEP 1  /* terminal mode for sleeping (cooked but no echo) */
index e74aa5f4bcb22dd1666df7c0542aeb4337cc9ad5..927825cf77fa901cac30e1df3046b1209f49530b 100644 (file)
@@ -764,6 +764,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    210,
 /**/
     209,
 /**/
index 3273409d6126247034627cb4cf3dbe376937a8da..4ebf348044eee7b8ac727774dcfd5bd5e13df501 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2108,6 +2108,14 @@ typedef enum
     ASSERT_OTHER
 } assert_type_T;
 
+/* Mode for bracketed_paste(). */
+typedef enum {
+    PASTE_INSERT,      /* insert mode */
+    PASTE_CMDLINE,     /* command line */
+    PASTE_EX,          /* ex mode line */
+    PASTE_ONE_CHAR     /* return first character */
+} paste_mode_T;
+
 #include "ex_cmds.h"       /* Ex command defines */
 #include "spell.h"         /* spell checking stuff */