mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.0916: mapping with partly modifyOtherKeys code does not work
Problem: Mapping with partly modifyOtherKeys code does not work. Solution: If there is no mapping with a separate modifier include the modifier in the key and then try mapping again. (closes vim/vim#6200)975a880a13
Cherry-pick applicable part of put_string_in_typebuf(). Revert related changes from10a5825
. Use KEYLEN_PART_KEY for incomplete modifier sequence. Omit test as it sends terminal codes. Use a Lua test instead.
This commit is contained in:
parent
f6afc7c324
commit
32da3e56cd
@ -5640,7 +5640,7 @@ int get_literal(bool no_simplify)
|
||||
for (;;) {
|
||||
nc = plain_vgetc();
|
||||
if (!no_simplify) {
|
||||
nc = merge_modifiers(nc);
|
||||
nc = merge_modifiers(nc, &mod_mask);
|
||||
}
|
||||
if ((mod_mask & ~MOD_MASK_SHIFT) != 0) {
|
||||
// A character with non-Shift modifiers should not be a valid
|
||||
|
@ -1442,12 +1442,12 @@ static void updatescript(int c)
|
||||
}
|
||||
}
|
||||
|
||||
/// Merge "mod_mask" into "c_arg"
|
||||
int merge_modifiers(int c_arg)
|
||||
/// Merge "modifiers" into "c_arg".
|
||||
int merge_modifiers(int c_arg, int *modifiers)
|
||||
{
|
||||
int c = c_arg;
|
||||
|
||||
if (mod_mask & MOD_MASK_CTRL) {
|
||||
if (*modifiers & MOD_MASK_CTRL) {
|
||||
if ((c >= '`' && c <= 0x7f) || (c >= '@' && c <= '_')) {
|
||||
c &= 0x1f;
|
||||
if (c == 0) {
|
||||
@ -1458,7 +1458,7 @@ int merge_modifiers(int c_arg)
|
||||
c = 0x1e;
|
||||
}
|
||||
if (c != c_arg) {
|
||||
mod_mask &= ~MOD_MASK_CTRL;
|
||||
*modifiers &= ~MOD_MASK_CTRL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
@ -1636,7 +1636,7 @@ int vgetc(void)
|
||||
// cases they are put back in the typeahead buffer.
|
||||
vgetc_mod_mask = mod_mask;
|
||||
vgetc_char = c;
|
||||
c = merge_modifiers(c);
|
||||
c = merge_modifiers(c, &mod_mask);
|
||||
|
||||
// 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
|
||||
@ -1752,6 +1752,55 @@ typedef enum {
|
||||
map_result_nomatch, // no matching mapping, get char
|
||||
} map_result_T;
|
||||
|
||||
/// Put "string[new_slen]" in typebuf.
|
||||
/// Remove "slen" bytes.
|
||||
/// @return FAIL for error, OK otherwise.
|
||||
static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_slen)
|
||||
{
|
||||
int extra = new_slen - slen;
|
||||
string[new_slen] = NUL;
|
||||
if (extra < 0) {
|
||||
// remove matched chars, taking care of noremap
|
||||
del_typebuf(-extra, offset);
|
||||
} else if (extra > 0) {
|
||||
// insert the extra space we need
|
||||
ins_typebuf(string + slen, REMAP_YES, offset, false, false);
|
||||
}
|
||||
// Careful: del_typebuf() and ins_typebuf() may have reallocated
|
||||
// typebuf.tb_buf[]!
|
||||
memmove(typebuf.tb_buf + typebuf.tb_off + offset, string, (size_t)new_slen);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Check if typebuf.tb_buf[] contains a modifer plus key that can be changed
|
||||
/// into just a key, apply that.
|
||||
/// Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off + "max_offset"].
|
||||
/// @return the length of the replaced bytes, zero if nothing changed.
|
||||
static int check_simplify_modifier(int max_offset)
|
||||
{
|
||||
for (int offset = 0; offset < max_offset; offset++) {
|
||||
if (offset + 3 >= typebuf.tb_len) {
|
||||
break;
|
||||
}
|
||||
char_u *tp = typebuf.tb_buf + typebuf.tb_off + offset;
|
||||
if (tp[0] == K_SPECIAL && tp[1] == KS_MODIFIER) {
|
||||
int modifier = tp[2];
|
||||
int new_c = merge_modifiers(tp[3], &modifier);
|
||||
|
||||
if (new_c != tp[3] && modifier == 0) {
|
||||
char_u new_string[MB_MAXBYTES];
|
||||
int len = utf_char2bytes(new_c, new_string);
|
||||
|
||||
if (put_string_in_typebuf(offset, 4, new_string, len) == FAIL) {
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Handle mappings in the typeahead buffer.
|
||||
/// - When something was mapped, return map_result_retry for recursive mappings.
|
||||
/// - When nothing mapped and typeahead has a character: return map_result_get.
|
||||
@ -1950,16 +1999,51 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
|
||||
}
|
||||
|
||||
if ((mp == NULL || max_mlen >= mp_match_len) && keylen != KEYLEN_PART_MAP) {
|
||||
// No matching mapping found or found a non-matching mapping that
|
||||
// matches at least what the matching mapping matched
|
||||
keylen = 0;
|
||||
(void)keylen; // suppress clang/dead assignment
|
||||
// If there was no mapping, use the character from the typeahead
|
||||
// buffer right here. Otherwise, use the mapping (loop around).
|
||||
if (mp == NULL) {
|
||||
*keylenp = keylen;
|
||||
return map_result_get; // get character from typeahead
|
||||
// When no matching mapping found or found a non-matching mapping that
|
||||
// matches at least what the matching mapping matched:
|
||||
// Try to include the modifier into the key, when:
|
||||
// - mapping is allowed,
|
||||
// - keys have not been mapped,
|
||||
// - and when not timed out,
|
||||
if ((no_mapping == 0 || allow_keys != 0)
|
||||
&& (typebuf.tb_maplen == 0
|
||||
|| (p_remap && typebuf.tb_noremap[typebuf.tb_off] == RM_YES))
|
||||
&& !*timedout) {
|
||||
if (tb_c1 == K_SPECIAL
|
||||
&& (typebuf.tb_len < 2
|
||||
|| (typebuf.tb_buf[typebuf.tb_off + 1] == KS_MODIFIER
|
||||
&& typebuf.tb_len < 4))) {
|
||||
// Incomplete modifier sequence: cannot decide whether to simplify yet.
|
||||
keylen = KEYLEN_PART_KEY;
|
||||
// Don't simplify if 'pastetoggle' matched partially.
|
||||
} else if (keylen != KEYLEN_PART_KEY) {
|
||||
// Try to include the modifier into the key.
|
||||
keylen = check_simplify_modifier(max_mlen + 1);
|
||||
assert(keylen >= 0);
|
||||
}
|
||||
} else {
|
||||
keylen = 0;
|
||||
}
|
||||
if (keylen == 0) { // no simplication has been done
|
||||
// If there was no mapping at all use the character from the
|
||||
// typeahead buffer right here.
|
||||
if (mp == NULL) {
|
||||
*keylenp = keylen;
|
||||
return map_result_get; // get character from typeahead
|
||||
}
|
||||
}
|
||||
|
||||
if (keylen > 0) { // keys have been simplified
|
||||
*keylenp = keylen;
|
||||
return map_result_retry; // try mapping again
|
||||
}
|
||||
|
||||
if (keylen < 0) {
|
||||
// Incomplete key sequence: get some more characters.
|
||||
assert(keylen == KEYLEN_PART_KEY);
|
||||
} else {
|
||||
assert(mp != NULL);
|
||||
// When a matching mapping was found use that one.
|
||||
keylen = mp_match_len;
|
||||
}
|
||||
}
|
||||
|
@ -249,6 +249,14 @@ it('typing a simplifiable key at hit-enter prompt triggers mapping vim-patch:8.2
|
||||
]])
|
||||
end)
|
||||
|
||||
it('mixing simplified and unsimplified keys can trigger mapping vim-patch:8.2.0916', function()
|
||||
command('set timeoutlen=10')
|
||||
command([[imap ' <C-W>]])
|
||||
command('imap <C-W><C-A> c-a')
|
||||
feed([[a'<C-A>]])
|
||||
expect('c-a')
|
||||
end)
|
||||
|
||||
describe('input non-printable chars', function()
|
||||
after_each(function()
|
||||
os.remove('Xtest-overwrite')
|
||||
|
Loading…
Reference in New Issue
Block a user