To: vim_dev@googlegroups.com Subject: Patch 8.1.2350 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.2350 Problem: Other text for CTRL-V in Insert mode with modifyOtherKeys. Solution: Convert the Escape sequence back to key as if modifyOtherKeys is not set, and use CTRL-SHIFT-V to get the Escape sequence itself. (closes #5254) Files: runtime/doc/insert.txt, runtime/doc/cmdline.txt, src/edit.c, src/proto/edit.pro, src/term.c, src/proto/term.pro, src/getchar.c, src/proto/getchar.pro, src/testdir/test_termcodes.vim, src/ex_getln.c *** ../vim-8.1.2349/runtime/doc/insert.txt 2019-10-20 18:17:08.367431701 +0200 --- runtime/doc/insert.txt 2019-11-26 19:28:14.541539868 +0100 *************** *** 194,202 **** decimal, octal or hexadecimal value of a character |i_CTRL-V_digit|. The characters typed right after CTRL-V are not considered for ! mapping. {Vi: no decimal byte entry} Note: When CTRL-V is mapped (e.g., to paste text) you can often use CTRL-Q instead |i_CTRL-Q|. *i_CTRL-Q* CTRL-Q Same as CTRL-V. --- 193,208 ---- decimal, octal or hexadecimal value of a character |i_CTRL-V_digit|. The characters typed right after CTRL-V are not considered for ! mapping. Note: When CTRL-V is mapped (e.g., to paste text) you can often use CTRL-Q instead |i_CTRL-Q|. + When |modifyOtherKeys| is enabled then special Escape sequence + is converted back to what it was without |modifyOtherKeys|, + unless the Shift key is also pressed. + + *i_CTRL-SHIFT-V* + CTRL-SHIFT-V Works just like CTRL-V, unless |modifyOtherKeys| is active, + then it inserts the Escape sequence for a key with modifiers. *i_CTRL-Q* CTRL-Q Same as CTRL-V. *** ../vim-8.1.2349/runtime/doc/cmdline.txt 2019-09-09 18:35:28.119252725 +0200 --- runtime/doc/cmdline.txt 2019-11-26 19:27:57.641739370 +0100 *************** *** 77,86 **** --- 77,93 ---- way as in Insert mode (see above, |i_CTRL-V|). Note: Under Windows CTRL-V is often mapped to paste text. Use CTRL-Q instead then. + When |modifyOtherKeys| is enabled then special Escape sequence + is converted back to what it was without |modifyOtherKeys|, + unless the Shift key is also pressed. *c_CTRL-Q* CTRL-Q Same as CTRL-V. But with some terminals it is used for control flow, it doesn't work then. + CTRL-SHIFT-V *c_CTRL-SHIFT-V* *c_CTRL-SHIFT-Q* + CTRL-SHIFT-Q Works just like CTRL-V, unless |modifyOtherKeys| is active, + then it inserts the Escape sequence for a key with modifiers. + *c_* *c_Left* cursor left *c_* *c_Right* *** ../vim-8.1.2349/src/edit.c 2019-11-26 14:28:11.781313275 +0100 --- src/edit.c 2019-11-26 19:02:23.741606074 +0100 *************** *** 1531,1536 **** --- 1531,1537 ---- { int c; int did_putchar = FALSE; + int prev_mod_mask = mod_mask; /* may need to redraw when no more chars available now */ ins_redraw(FALSE); *************** *** 1554,1559 **** --- 1555,1566 ---- #ifdef FEAT_CMDL_INFO clear_showcmd(); #endif + + if ((c == ESC || c == CSI) && !(prev_mod_mask & MOD_MASK_SHIFT)) + // Using CTRL-V: Change any modifyOtherKeys ESC sequence to a normal + // key. Don't do this for CTRL-SHIFT-V. + c = decodeModifyOtherKeys(c); + insert_special(c, FALSE, TRUE); #ifdef FEAT_RIGHTLEFT revins_chars++; *************** *** 1562,1567 **** --- 1569,1627 ---- } /* + * After getting an ESC or CSI for a literal key: If the typeahead buffer + * contains a modifyOtherKeys sequence then decode it and return the result. + * Otherwise return "c". + * Note that this doesn't wait for characters, they must be in the typeahead + * buffer already. + */ + int + decodeModifyOtherKeys(int c) + { + char_u *p = typebuf.tb_buf + typebuf.tb_off; + int idx; + int form = 0; + int argidx = 0; + int arg[2] = {0, 0}; + + // Recognize: + // form 0: {lead}{key};{modifier}u + // form 1: {lead}27;{modifier};{key}~ + if ((c == CSI || (c == ESC && *p == '[')) && typebuf.tb_len >= 4) + { + idx = (*p == '['); + if (p[idx] == '2' && p[idx + 1] == '7' && p[idx + 2] == ';') + { + form = 1; + idx += 3; + } + while (idx < typebuf.tb_len && argidx < 2) + { + if (p[idx] == ';') + ++argidx; + else if (VIM_ISDIGIT(p[idx])) + arg[argidx] = arg[argidx] * 10 + (p[idx] - '0'); + else + break; + ++idx; + } + if (idx < typebuf.tb_len + && p[idx] == (form == 1 ? '~' : 'u') + && argidx == 1) + { + // Match, consume the code. + typebuf.tb_off += idx + 1; + typebuf.tb_len -= idx + 1; + + mod_mask = decode_modifiers(arg[!form]); + c = merge_modifyOtherKeys(arg[form]); + } + } + + return c; + } + + /* * Put a character directly onto the screen. It's not stored in a buffer. * Used while handling CTRL-K, CTRL-V, etc. in Insert mode. */ *** ../vim-8.1.2349/src/proto/edit.pro 2019-10-09 22:52:49.000043746 +0200 --- src/proto/edit.pro 2019-11-26 18:46:12.734060440 +0100 *************** *** 2,7 **** --- 2,8 ---- int edit(int cmdchar, int startln, long count); int ins_need_undo_get(void); void ins_redraw(int ready); + int decodeModifyOtherKeys(int c); void edit_putchar(int c, int highlight); char_u *prompt_text(void); int prompt_curpos_editable(void); *** ../vim-8.1.2349/src/term.c 2019-11-21 22:14:14.357810945 +0100 --- src/term.c 2019-11-26 18:57:34.625375262 +0100 *************** *** 4277,4283 **** /* * Decode a modifier number as xterm provides it into MOD_MASK bits. */ ! static int decode_modifiers(int n) { int code = n - 1; --- 4277,4283 ---- /* * Decode a modifier number as xterm provides it into MOD_MASK bits. */ ! int decode_modifiers(int n) { int code = n - 1; *** ../vim-8.1.2349/src/proto/term.pro 2019-11-21 22:14:14.357810945 +0100 --- src/proto/term.pro 2019-11-26 18:54:58.233056654 +0100 *************** *** 65,70 **** --- 65,71 ---- void del_termcode(char_u *name); void set_mouse_topline(win_T *wp); int is_mouse_topline(win_T *wp); + int decode_modifiers(int n); int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen); void term_get_fg_color(char_u *r, char_u *g, char_u *b); void term_get_bg_color(char_u *r, char_u *g, char_u *b); *** ../vim-8.1.2349/src/getchar.c 2019-11-22 20:55:22.403621863 +0100 --- src/getchar.c 2019-11-26 19:00:05.013542417 +0100 *************** *** 1525,1530 **** --- 1525,1562 ---- } /* + * Convert "c" plus "mod_mask" to merge the effect of modifyOtherKeys into the + * character. + */ + int + merge_modifyOtherKeys(int c_arg) + { + int c = c_arg; + + if (mod_mask & MOD_MASK_CTRL) + { + if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) + { + c &= 0x1f; + mod_mask &= ~MOD_MASK_CTRL; + } + else if (c == '6') + { + // CTRL-6 is equivalent to CTRL-^ + c = 0x1e; + mod_mask &= ~MOD_MASK_CTRL; + } + } + if ((mod_mask & (MOD_MASK_META | MOD_MASK_ALT)) + && c >= 0 && c <= 127) + { + c += 0x80; + mod_mask &= ~(MOD_MASK_META|MOD_MASK_ALT); + } + return c; + } + + /* * Get the next input character. * Can return a special key or a multi-byte character. * Can return NUL when called recursively, use safe_vgetc() if that's not *************** *** 1765,1794 **** } if (!no_reduce_keys) - { // A modifier was not used for a mapping, apply it to ASCII // keys. Shift would already have been applied. ! if (mod_mask & MOD_MASK_CTRL) ! { ! if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) ! { ! c &= 0x1f; ! mod_mask &= ~MOD_MASK_CTRL; ! } ! else if (c == '6') ! { ! // CTRL-6 is equivalent to CTRL-^ ! c = 0x1e; ! mod_mask &= ~MOD_MASK_CTRL; ! } ! } ! if ((mod_mask & (MOD_MASK_META | MOD_MASK_ALT)) ! && c >= 0 && c <= 127) ! { ! c += 0x80; ! mod_mask &= ~(MOD_MASK_META|MOD_MASK_ALT); ! } ! } break; } --- 1797,1805 ---- } if (!no_reduce_keys) // A modifier was not used for a mapping, apply it to ASCII // keys. Shift would already have been applied. ! c = merge_modifyOtherKeys(c); break; } *** ../vim-8.1.2349/src/proto/getchar.pro 2019-09-15 21:00:51.362604284 +0200 --- src/proto/getchar.pro 2019-11-26 18:59:10.113494756 +0100 *************** *** 37,42 **** --- 37,43 ---- void close_all_scripts(void); int using_script(void); void before_blocking(void); + int merge_modifyOtherKeys(int c_arg); int vgetc(void); int safe_vgetc(void); int plain_vgetc(void); *** ../vim-8.1.2349/src/testdir/test_termcodes.vim 2019-11-26 14:28:11.785313279 +0100 --- src/testdir/test_termcodes.vim 2019-11-26 19:21:32.395606616 +0100 *************** *** 1349,1351 **** --- 1349,1396 ---- call RunTest_mapping_works_with_mods(function('GetEscCodeCSI27'), 'C-S-A', 8) call RunTest_mapping_works_with_mods(function('GetEscCodeCSIu'), 'C-S-A', 8) endfunc + + func Test_insert_literal() + set timeoutlen=10 + new + " CTRL-V CTRL-X inserts a ^X + call feedkeys('a' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('X', '5') .. "\", 'Lx!') + call assert_equal("\", getline(1)) + + call setline(1, '') + call feedkeys('a' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('X', '5') .. "\", 'Lx!') + call assert_equal("\", getline(1)) + + " CTRL-SHIFT-V CTRL-X inserts escape sequencd + call setline(1, '') + call feedkeys('a' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('X', '5') .. "\", 'Lx!') + call assert_equal("\[88;5u", getline(1)) + + call setline(1, '') + call feedkeys('a' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('X', '5') .. "\", 'Lx!') + call assert_equal("\[27;5;88~", getline(1)) + + bwipe! + set timeoutlen& + endfunc + + func Test_cmdline_literal() + set timeoutlen=10 + + " CTRL-V CTRL-Y inserts a ^Y + call feedkeys(':' .. GetEscCodeCSIu('V', '5') .. GetEscCodeCSIu('Y', '5') .. "\\"\", 'Lx!') + call assert_equal("\"\", @:) + + call feedkeys(':' .. GetEscCodeCSI27('V', '5') .. GetEscCodeCSI27('Y', '5') .. "\\"\", 'Lx!') + call assert_equal("\"\", @:) + + " CTRL-SHIFT-V CTRL-Y inserts escape sequencd + call feedkeys(':' .. GetEscCodeCSIu('V', '6') .. GetEscCodeCSIu('Y', '5') .. "\\"\", 'Lx!') + call assert_equal("\"\[89;5u", @:) + + call setline(1, '') + call feedkeys(':' .. GetEscCodeCSI27('V', '6') .. GetEscCodeCSI27('Y', '5') .. "\\"\", 'Lx!') + call assert_equal("\"\[27;5;89~", @:) + + set timeoutlen& + endfunc *** ../vim-8.1.2349/src/ex_getln.c 2019-11-26 14:28:11.781313275 +0100 --- src/ex_getln.c 2019-11-26 19:13:29.857230642 +0100 *************** *** 2208,2225 **** case Ctrl_V: case Ctrl_Q: - ignore_drag_release = TRUE; - putcmdline('^', TRUE); - c = get_literal(); /* get next (two) character(s) */ - do_abbr = FALSE; /* don't do abbreviation now */ - extra_char = NUL; - /* may need to remove ^ when composing char was typed */ - if (enc_utf8 && utf_iscomposing(c) && !cmd_silent) { ! draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos); ! msg_putchar(' '); ! cursorcmd(); } break; #ifdef FEAT_DIGRAPHS --- 2208,2238 ---- case Ctrl_V: case Ctrl_Q: { ! int prev_mod_mask = mod_mask; ! ! ignore_drag_release = TRUE; ! putcmdline('^', TRUE); ! c = get_literal(); // get next (two) character(s) ! do_abbr = FALSE; // don't do abbreviation now ! extra_char = NUL; ! // may need to remove ^ when composing char was typed ! if (enc_utf8 && utf_iscomposing(c) && !cmd_silent) ! { ! draw_cmdline(ccline.cmdpos, ! ccline.cmdlen - ccline.cmdpos); ! msg_putchar(' '); ! cursorcmd(); ! } ! ! if ((c == ESC || c == CSI) ! && !(prev_mod_mask & MOD_MASK_SHIFT)) ! // Using CTRL-V: Change any modifyOtherKeys ESC ! // sequence to a normal key. Don't do this for ! // CTRL-SHIFT-V. ! c = decodeModifyOtherKeys(c); } + break; #ifdef FEAT_DIGRAPHS *** ../vim-8.1.2349/src/version.c 2019-11-26 17:04:53.445152907 +0100 --- src/version.c 2019-11-26 19:28:26.545400388 +0100 *************** *** 739,740 **** --- 739,742 ---- { /* Add new patch number below this line */ + /**/ + 2350, /**/ -- hundred-and-one symptoms of being an internet addict: 126. You brag to all of your friends about your date Saturday night...but you don't tell them it was only in a chat room. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///