diff options
Diffstat (limited to 'src/nvim/keymap.c')
-rw-r--r-- | src/nvim/keymap.c | 194 |
1 files changed, 167 insertions, 27 deletions
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 67f342fd37..25a8457aba 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -10,8 +10,12 @@ #include "nvim/ascii.h" #include "nvim/keymap.h" #include "nvim/charset.h" +#include "nvim/memory.h" #include "nvim/edit.h" -#include "nvim/term.h" +#include "nvim/eval.h" +#include "nvim/message.h" +#include "nvim/strings.h" +#include "nvim/mouse.h" /* @@ -709,35 +713,18 @@ int find_special_key_in_table(int c) int get_special_key_code(char_u *name) { char_u *table_name; - char_u string[3]; int i, j; - /* - * If it's <t_xx> we get the code for xx from the termcap - */ - if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL) { - string[0] = name[2]; - string[1] = name[3]; - string[2] = NUL; - if (add_termcap_entry(string, FALSE) == OK) - return TERMCAP2KEY(name[2], name[3]); - } else - for (i = 0; key_names_table[i].name != NULL; i++) { - table_name = key_names_table[i].name; - for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++) - if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) - break; - if (!vim_isIDc(name[j]) && table_name[j] == NUL) - return key_names_table[i].key; - } - return 0; -} + for (i = 0; key_names_table[i].name != NULL; i++) { + table_name = key_names_table[i].name; + for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++) + if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) + break; + if (!vim_isIDc(name[j]) && table_name[j] == NUL) + return key_names_table[i].key; + } -char_u *get_key_name(size_t i) -{ - if (i >= KEY_NAMES_TABLE_LEN) - return NULL; - return key_names_table[i].name; + return 0; } /* @@ -756,3 +743,156 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag) } return 0; /* Shouldn't get here */ } + +// Replace any terminal code strings in from[] with the equivalent internal +// vim representation. This is used for the "from" and "to" part of a +// mapping, and the "to" part of a menu command. +// Any strings like "<C-UP>" are also replaced, unless 'cpoptions' contains +// '<'. +// K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER. +// +// The replacement is done in result[] and finally copied into allocated +// memory. If this all works well *bufp is set to the allocated memory and a +// pointer to it is returned. If something fails *bufp is set to NULL and from +// is returned. +// +// CTRL-V characters are removed. When "from_part" is TRUE, a trailing CTRL-V +// is included, otherwise it is removed (for ":map xx ^V", maps xx to +// nothing). When 'cpoptions' does not contain 'B', a backslash can be used +// instead of a CTRL-V. +char_u * replace_termcodes ( + char_u *from, + char_u **bufp, + int from_part, + int do_lt, // also translate <lt> + int special // always accept <key> notation +) +{ + ssize_t i; + size_t slen; + char_u key; + size_t dlen = 0; + char_u *src; + int do_backslash; // backslash is a special character + int do_special; // recognize <> key codes + char_u *result; // buffer for resulting string + + do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL); + do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special; + + // Allocate space for the translation. Worst case a single character is + // replaced by 6 bytes (shifted special key), plus a NUL at the end. + result = xmalloc(STRLEN(from) * 6 + 1); + + src = from; + + // Check for #n at start only: function key n + if (from_part && src[0] == '#' && VIM_ISDIGIT(src[1])) { // function key + result[dlen++] = K_SPECIAL; + result[dlen++] = 'k'; + if (src[1] == '0') { + result[dlen++] = ';'; // #0 is F10 is "k;" + } else { + result[dlen++] = src[1]; // #3 is F3 is "k3" + } + src += 2; + } + + // Copy each byte from *from to result[dlen] + while (*src != NUL) { + // If 'cpoptions' does not contain '<', check for special key codes, + // like "<C-S-LeftMouse>" + if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0)) { + // Replace <SID> by K_SNR <script-nr> _. + // (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14) + if (STRNICMP(src, "<SID>", 5) == 0) { + if (current_SID <= 0) { + EMSG(_(e_usingsid)); + } else { + src += 5; + result[dlen++] = K_SPECIAL; + result[dlen++] = (int)KS_EXTRA; + result[dlen++] = (int)KE_SNR; + sprintf((char *)result + dlen, "%" PRId64, (int64_t)current_SID); + dlen += STRLEN(result + dlen); + result[dlen++] = '_'; + continue; + } + } + + slen = trans_special(&src, result + dlen, TRUE); + if (slen) { + dlen += slen; + continue; + } + } + + if (do_special) { + char_u *p, *s, len; + + // Replace <Leader> by the value of "mapleader". + // Replace <LocalLeader> by the value of "maplocalleader". + // If "mapleader" or "maplocalleader" isn't set use a backslash. + if (STRNICMP(src, "<Leader>", 8) == 0) { + len = 8; + p = get_var_value((char_u *)"g:mapleader"); + } else if (STRNICMP(src, "<LocalLeader>", 13) == 0) { + len = 13; + p = get_var_value((char_u *)"g:maplocalleader"); + } else { + len = 0; + p = NULL; + } + + if (len != 0) { + // Allow up to 8 * 6 characters for "mapleader". + if (p == NULL || *p == NUL || STRLEN(p) > 8 * 6) { + s = (char_u *)"\\"; + } else { + s = p; + } + while (*s != NUL) { + result[dlen++] = *s++; + } + src += len; + continue; + } + } + + // Remove CTRL-V and ignore the next character. + // For "from" side the CTRL-V at the end is included, for the "to" + // part it is removed. + // If 'cpoptions' does not contain 'B', also accept a backslash. + key = *src; + if (key == Ctrl_V || (do_backslash && key == '\\')) { + ++src; // skip CTRL-V or backslash + if (*src == NUL) { + if (from_part) { + result[dlen++] = key; + } + break; + } + } + + // skip multibyte char correctly + for (i = (*mb_ptr2len)(src); i > 0; --i) { + // If the character is K_SPECIAL, replace it with K_SPECIAL + // KS_SPECIAL KE_FILLER. + // If compiled with the GUI replace CSI with K_CSI. + if (*src == K_SPECIAL) { + result[dlen++] = K_SPECIAL; + result[dlen++] = KS_SPECIAL; + result[dlen++] = KE_FILLER; + } else { + result[dlen++] = *src; + } + ++src; + } + } + result[dlen] = NUL; + + *bufp = xrealloc(result, dlen + 1); + + return *bufp; +} + |