mirror of
https://github.com/neovim/neovim.git
synced 2024-12-31 17:13:26 -07:00
feat(edit): insert an unsimplified key using CTRL-SHIFT-V
This marks the following Vim patches as ported: vim-patch:8.1.2333: with modifyOtherKeys CTRL-^ doesn't work Problem: With modifyOtherKeys CTRL-^ doesn't work. Solution: Handle the exception.828ffd5963
vim-patch:8.1.2350: other text for CTRL-V in Insert mode with modifyOtherKeys 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 vim/vim#5254)fc4ea2a72d
vim-patch:8.2.2084: CTRL-V U doesn't work to enter a Unicode character Problem: CTRL-V U doesn't work to enter a Unicode character when modifyOtherKeys is effective. (Ken Takata) Solution: Add a flag to get_literal() for the shift key. (closes vim/vim#7413)0684e36a7e
Omit getcmdkeycmd() change as it depends on Vim patch 8.2.2062, which may introduce a potential breakage.
This commit is contained in:
parent
44269c73a3
commit
212349c100
@ -67,12 +67,19 @@ CTRL-V Insert next non-digit literally. Up to three digits form the
|
|||||||
decimal value of a single byte. The non-digit and the three
|
decimal value of a single byte. The non-digit and the three
|
||||||
digits are not considered for mapping. This works the same
|
digits are not considered for mapping. This works the same
|
||||||
way as in Insert mode (see above, |i_CTRL-V|).
|
way as in Insert mode (see above, |i_CTRL-V|).
|
||||||
|
For special keys, the CTRL modifier may be included into the
|
||||||
|
key to produce a control character. If there is no control
|
||||||
|
character for the key then its |key-notation| is inserted.
|
||||||
Note: Under Windows CTRL-V is often mapped to paste text.
|
Note: Under Windows CTRL-V is often mapped to paste text.
|
||||||
Use CTRL-Q instead then.
|
Use CTRL-Q instead then.
|
||||||
*c_CTRL-Q*
|
*c_CTRL-Q*
|
||||||
CTRL-Q Same as CTRL-V. But with some terminals it is used for
|
CTRL-Q Same as CTRL-V. But with some terminals it is used for
|
||||||
control flow, it doesn't work then.
|
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, but do not try to include the CTRL
|
||||||
|
modifier into the key.
|
||||||
|
|
||||||
*c_<Left>* *c_Left*
|
*c_<Left>* *c_Left*
|
||||||
<Left> cursor left
|
<Left> cursor left
|
||||||
*c_<Right>* *c_Right*
|
*c_<Right>* *c_Right*
|
||||||
|
@ -192,12 +192,14 @@ CTRL-D Delete one shiftwidth of indent at the start of the current
|
|||||||
label.
|
label.
|
||||||
|
|
||||||
*i_CTRL-V*
|
*i_CTRL-V*
|
||||||
CTRL-V Insert next non-digit literally. For special keys, the
|
CTRL-V Insert next non-digit literally. It's also possible to enter
|
||||||
terminal code is inserted. It's also possible to enter the
|
the decimal, octal or hexadecimal value of a character
|
||||||
decimal, octal or hexadecimal value of a character
|
|
||||||
|i_CTRL-V_digit|.
|
|i_CTRL-V_digit|.
|
||||||
The characters typed right after CTRL-V are not considered for
|
The characters typed right after CTRL-V are not considered for
|
||||||
mapping.
|
mapping.
|
||||||
|
For special keys, the CTRL modifier may be included into the
|
||||||
|
key to produce a control character. If there is no control
|
||||||
|
character for the key then its |key-notation| is inserted.
|
||||||
Note: When CTRL-V is mapped (e.g., to paste text) you can
|
Note: When CTRL-V is mapped (e.g., to paste text) you can
|
||||||
often use CTRL-Q instead |i_CTRL-Q|.
|
often use CTRL-Q instead |i_CTRL-Q|.
|
||||||
|
|
||||||
@ -206,6 +208,10 @@ CTRL-Q Same as CTRL-V.
|
|||||||
Note: Some terminal connections may eat CTRL-Q, it doesn't
|
Note: Some terminal connections may eat CTRL-Q, it doesn't
|
||||||
work then. It does work in the GUI.
|
work then. It does work in the GUI.
|
||||||
|
|
||||||
|
CTRL-SHIFT-V *i_CTRL-SHIFT-V* *i_CTRL-SHIFT-Q*
|
||||||
|
CTRL-SHIFT-Q Works just like CTRL-V, but do not try to include the CTRL
|
||||||
|
modifier into the key.
|
||||||
|
|
||||||
CTRL-X Enter CTRL-X mode. This is a sub-mode where commands can
|
CTRL-X Enter CTRL-X mode. This is a sub-mode where commands can
|
||||||
be given to complete words or scroll the window. See
|
be given to complete words or scroll the window. See
|
||||||
|i_CTRL-X| and |ins-completion|.
|
|i_CTRL-X| and |ins-completion|.
|
||||||
|
@ -1587,7 +1587,8 @@ static void ins_ctrl_v(void)
|
|||||||
|
|
||||||
add_to_showcmd_c(Ctrl_V);
|
add_to_showcmd_c(Ctrl_V);
|
||||||
|
|
||||||
c = get_literal();
|
// Do not include modifiers into the key for CTRL-SHIFT-V.
|
||||||
|
c = get_literal(mod_mask & MOD_MASK_SHIFT);
|
||||||
if (did_putchar) {
|
if (did_putchar) {
|
||||||
// when the line fits in 'columns' the '^' is at the start of the next
|
// when the line fits in 'columns' the '^' is at the start of the next
|
||||||
// line and will not removed by the redraw
|
// line and will not removed by the redraw
|
||||||
@ -5612,13 +5613,13 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// Next character is interpreted literally.
|
||||||
* Next character is interpreted literally.
|
/// A one, two or three digit decimal number is interpreted as its byte value.
|
||||||
* A one, two or three digit decimal number is interpreted as its byte value.
|
/// If one or two digits are entered, the next character is given to vungetc().
|
||||||
* If one or two digits are entered, the next character is given to vungetc().
|
/// For Unicode a character > 255 may be returned.
|
||||||
* For Unicode a character > 255 may be returned.
|
///
|
||||||
*/
|
/// @param no_simplify do not include modifiers into the key
|
||||||
int get_literal(void)
|
int get_literal(bool no_simplify)
|
||||||
{
|
{
|
||||||
int cc;
|
int cc;
|
||||||
int nc;
|
int nc;
|
||||||
@ -5636,6 +5637,9 @@ int get_literal(void)
|
|||||||
i = 0;
|
i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nc = plain_vgetc();
|
nc = plain_vgetc();
|
||||||
|
if (!no_simplify) {
|
||||||
|
nc = merge_modifiers(nc);
|
||||||
|
}
|
||||||
if ((mod_mask & ~MOD_MASK_SHIFT) != 0) {
|
if ((mod_mask & ~MOD_MASK_SHIFT) != 0) {
|
||||||
// A character with non-Shift modifiers should not be a valid
|
// A character with non-Shift modifiers should not be a valid
|
||||||
// character for i_CTRL-V_digit.
|
// character for i_CTRL-V_digit.
|
||||||
|
@ -2208,7 +2208,11 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
case Ctrl_Q:
|
case Ctrl_Q:
|
||||||
s->ignore_drag_release = true;
|
s->ignore_drag_release = true;
|
||||||
putcmdline('^', true);
|
putcmdline('^', true);
|
||||||
s->c = get_literal(); // get next (two) character(s)
|
|
||||||
|
// Get next (two) characters.
|
||||||
|
// Do not include modifiers into the key for CTRL-SHIFT-V.
|
||||||
|
s->c = get_literal(mod_mask & MOD_MASK_SHIFT);
|
||||||
|
|
||||||
s->do_abbr = false; // don't do abbreviation now
|
s->do_abbr = false; // don't do abbreviation now
|
||||||
ccline.special_char = NUL;
|
ccline.special_char = NUL;
|
||||||
// may need to remove ^ when composing char was typed
|
// may need to remove ^ when composing char was typed
|
||||||
|
@ -1442,6 +1442,27 @@ static void updatescript(int c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Merge "mod_mask" into "c_arg"
|
||||||
|
int merge_modifiers(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;
|
||||||
|
if (c == 0) {
|
||||||
|
c = K_ZERO;
|
||||||
|
}
|
||||||
|
} else if (c == '6') {
|
||||||
|
// CTRL-6 is equivalent to CTRL-^
|
||||||
|
c = 0x1e;
|
||||||
|
mod_mask &= ~MOD_MASK_CTRL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next input character.
|
/// Get the next input character.
|
||||||
/// Can return a special key or a multi-byte character.
|
/// Can return a special key or a multi-byte character.
|
||||||
/// Can return NUL when called recursively, use safe_vgetc() if that's not
|
/// Can return NUL when called recursively, use safe_vgetc() if that's not
|
||||||
@ -1603,19 +1624,7 @@ int vgetc(void)
|
|||||||
|
|
||||||
// A modifier was not used for a mapping, apply it to ASCII
|
// A modifier was not used for a mapping, apply it to ASCII
|
||||||
// keys. Shift would already have been applied.
|
// keys. Shift would already have been applied.
|
||||||
if (mod_mask & MOD_MASK_CTRL) {
|
c = merge_modifiers(c);
|
||||||
if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) {
|
|
||||||
c &= 0x1f;
|
|
||||||
mod_mask &= ~MOD_MASK_CTRL;
|
|
||||||
if (c == 0) {
|
|
||||||
c = K_ZERO;
|
|
||||||
}
|
|
||||||
} else if (c == '6') {
|
|
||||||
// CTRL-6 is equivalent to CTRL-^
|
|
||||||
c = 0x1e;
|
|
||||||
mod_mask &= ~MOD_MASK_CTRL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If mappings are enabled (i.e., not Ctrl-v) and the user directly typed
|
// If mappings are enabled (i.e., not Ctrl-v) and the user directly typed
|
||||||
// something with a meta- or alt- modifier that was not mapped, interpret
|
// something with a meta- or alt- modifier that was not mapped, interpret
|
||||||
|
@ -5154,7 +5154,7 @@ static void nv_replace(cmdarg_T *cap)
|
|||||||
// get another character
|
// get another character
|
||||||
if (cap->nchar == Ctrl_V) {
|
if (cap->nchar == Ctrl_V) {
|
||||||
had_ctrl_v = Ctrl_V;
|
had_ctrl_v = Ctrl_V;
|
||||||
cap->nchar = get_literal();
|
cap->nchar = get_literal(false);
|
||||||
// Don't redo a multibyte character with CTRL-V.
|
// Don't redo a multibyte character with CTRL-V.
|
||||||
if (cap->nchar > DEL) {
|
if (cap->nchar > DEL) {
|
||||||
had_ctrl_v = NUL;
|
had_ctrl_v = NUL;
|
||||||
@ -5369,7 +5369,7 @@ static void nv_vreplace(cmdarg_T *cap)
|
|||||||
emsg(_(e_modifiable));
|
emsg(_(e_modifiable));
|
||||||
} else {
|
} else {
|
||||||
if (cap->extra_char == Ctrl_V) { // get another character
|
if (cap->extra_char == Ctrl_V) { // get another character
|
||||||
cap->extra_char = get_literal();
|
cap->extra_char = get_literal(false);
|
||||||
}
|
}
|
||||||
stuffcharReadbuff(cap->extra_char);
|
stuffcharReadbuff(cap->extra_char);
|
||||||
stuffcharReadbuff(ESC);
|
stuffcharReadbuff(ESC);
|
||||||
|
@ -3,67 +3,74 @@
|
|||||||
local helpers = require('test.functional.helpers')(after_each)
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
local clear, insert, funcs, eq, feed =
|
local clear, insert, funcs, eq, feed =
|
||||||
helpers.clear, helpers.insert, helpers.funcs, helpers.eq, helpers.feed
|
helpers.clear, helpers.insert, helpers.funcs, helpers.eq, helpers.feed
|
||||||
|
local eval = helpers.eval
|
||||||
local meths = helpers.meths
|
local meths = helpers.meths
|
||||||
|
|
||||||
describe('cmdline CTRL-R', function()
|
describe('cmdline', function()
|
||||||
before_each(clear)
|
before_each(clear)
|
||||||
|
|
||||||
it('pasting non-special register inserts <CR> *between* lines', function()
|
describe('Ctrl-R', function()
|
||||||
insert([[
|
it('pasting non-special register inserts <CR> *between* lines', function()
|
||||||
line1abc
|
insert([[
|
||||||
line2somemoretext
|
line1abc
|
||||||
]])
|
line2somemoretext
|
||||||
-- Yank 2 lines linewise, then paste to cmdline.
|
]])
|
||||||
feed([[<C-\><C-N>gg0yj:<C-R>0]])
|
-- Yank 2 lines linewise, then paste to cmdline.
|
||||||
-- <CR> inserted between lines, NOT after the final line.
|
feed([[<C-\><C-N>gg0yj:<C-R>0]])
|
||||||
eq('line1abc\rline2somemoretext', funcs.getcmdline())
|
-- <CR> inserted between lines, NOT after the final line.
|
||||||
|
eq('line1abc\rline2somemoretext', funcs.getcmdline())
|
||||||
|
|
||||||
-- Yank 2 lines charwise, then paste to cmdline.
|
-- Yank 2 lines charwise, then paste to cmdline.
|
||||||
feed([[<C-\><C-N>gg05lyvj:<C-R>0]])
|
feed([[<C-\><C-N>gg05lyvj:<C-R>0]])
|
||||||
-- <CR> inserted between lines, NOT after the final line.
|
-- <CR> inserted between lines, NOT after the final line.
|
||||||
eq('abc\rline2', funcs.getcmdline())
|
eq('abc\rline2', funcs.getcmdline())
|
||||||
|
|
||||||
-- Yank 1 line linewise, then paste to cmdline.
|
-- Yank 1 line linewise, then paste to cmdline.
|
||||||
feed([[<C-\><C-N>ggyy:<C-R>0]])
|
feed([[<C-\><C-N>ggyy:<C-R>0]])
|
||||||
-- No <CR> inserted.
|
-- No <CR> inserted.
|
||||||
eq('line1abc', funcs.getcmdline())
|
eq('line1abc', funcs.getcmdline())
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('pasting special register inserts <CR>, <NL>', function()
|
||||||
|
feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
|
||||||
|
eq('foo\nbar\rbaz', funcs.getcmdline())
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('pasting special register inserts <CR>, <NL>', function()
|
it('Ctrl-Shift-V supports entering unsimplified key notations', function()
|
||||||
feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
|
feed(':"<C-S-V><C-J><C-S-V><C-@><C-S-V><C-[><C-S-V><C-S-M><C-S-V><M-C-I><C-S-V><C-D-J><CR>')
|
||||||
eq('foo\nbar\rbaz', funcs.getcmdline())
|
|
||||||
end)
|
eq('"<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>', eval('@:'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('cmdline history', function()
|
describe('history', function()
|
||||||
before_each(clear)
|
it('correctly clears start of the history', function()
|
||||||
|
-- Regression test: check absence of the memory leak when clearing start of
|
||||||
it('correctly clears start of the history', function()
|
-- the history using ex_getln.c/clr_history().
|
||||||
-- Regression test: check absence of the memory leak when clearing start of
|
eq(1, funcs.histadd(':', 'foo'))
|
||||||
-- the history using ex_getln.c/clr_history().
|
eq(1, funcs.histdel(':'))
|
||||||
eq(1, funcs.histadd(':', 'foo'))
|
eq('', funcs.histget(':', -1))
|
||||||
eq(1, funcs.histdel(':'))
|
end)
|
||||||
eq('', funcs.histget(':', -1))
|
|
||||||
end)
|
it('correctly clears end of the history', function()
|
||||||
|
-- Regression test: check absence of the memory leak when clearing end of
|
||||||
it('correctly clears end of the history', function()
|
-- the history using ex_getln.c/clr_history().
|
||||||
-- Regression test: check absence of the memory leak when clearing end of
|
meths.set_option('history', 1)
|
||||||
-- the history using ex_getln.c/clr_history().
|
eq(1, funcs.histadd(':', 'foo'))
|
||||||
meths.set_option('history', 1)
|
eq(1, funcs.histdel(':'))
|
||||||
eq(1, funcs.histadd(':', 'foo'))
|
eq('', funcs.histget(':', -1))
|
||||||
eq(1, funcs.histdel(':'))
|
end)
|
||||||
eq('', funcs.histget(':', -1))
|
|
||||||
end)
|
it('correctly removes item from history', function()
|
||||||
|
-- Regression test: check that ex_getln.c/del_history_idx() correctly clears
|
||||||
it('correctly removes item from history', function()
|
-- history index after removing history entry. If it does not then deleting
|
||||||
-- Regression test: check that ex_getln.c/del_history_idx() correctly clears
|
-- history will result in a double free.
|
||||||
-- history index after removing history entry. If it does not then deleting
|
eq(1, funcs.histadd(':', 'foo'))
|
||||||
-- history will result in a double free.
|
eq(1, funcs.histadd(':', 'bar'))
|
||||||
eq(1, funcs.histadd(':', 'foo'))
|
eq(1, funcs.histadd(':', 'baz'))
|
||||||
eq(1, funcs.histadd(':', 'bar'))
|
eq(1, funcs.histdel(':', -2))
|
||||||
eq(1, funcs.histadd(':', 'baz'))
|
eq(1, funcs.histdel(':'))
|
||||||
eq(1, funcs.histdel(':', -2))
|
eq('', funcs.histget(':', -1))
|
||||||
eq(1, funcs.histdel(':'))
|
end)
|
||||||
eq('', funcs.histget(':', -1))
|
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -131,6 +131,11 @@ describe('insert-mode', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('Ctrl-Shift-V supports entering unsimplified key notations', function()
|
||||||
|
feed('i<C-S-V><C-J><C-S-V><C-@><C-S-V><C-[><C-S-V><C-S-M><C-S-V><M-C-I><C-S-V><C-D-J><Esc>')
|
||||||
|
expect('<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>')
|
||||||
|
end)
|
||||||
|
|
||||||
describe([[With 'insertmode', Insert mode is not re-entered immediately after <C-L>]], function()
|
describe([[With 'insertmode', Insert mode is not re-entered immediately after <C-L>]], function()
|
||||||
before_each(function()
|
before_each(function()
|
||||||
command('set insertmode')
|
command('set insertmode')
|
||||||
|
Loading…
Reference in New Issue
Block a user