mapping.c (91612B)
1 // mapping.c: Code for mappings and abbreviations. 2 3 #include <assert.h> 4 #include <lauxlib.h> 5 #include <limits.h> 6 #include <stdbool.h> 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include "klib/kvec.h" 13 #include "nvim/api/keysets_defs.h" 14 #include "nvim/api/private/converter.h" 15 #include "nvim/api/private/defs.h" 16 #include "nvim/api/private/dispatch.h" 17 #include "nvim/api/private/helpers.h" 18 #include "nvim/ascii_defs.h" 19 #include "nvim/buffer_defs.h" 20 #include "nvim/charset.h" 21 #include "nvim/cmdexpand.h" 22 #include "nvim/cmdexpand_defs.h" 23 #include "nvim/errors.h" 24 #include "nvim/eval.h" 25 #include "nvim/eval/typval.h" 26 #include "nvim/eval/typval_defs.h" 27 #include "nvim/eval/userfunc.h" 28 #include "nvim/eval/vars.h" 29 #include "nvim/ex_cmds_defs.h" 30 #include "nvim/ex_session.h" 31 #include "nvim/fuzzy.h" 32 #include "nvim/garray.h" 33 #include "nvim/garray_defs.h" 34 #include "nvim/getchar.h" 35 #include "nvim/getchar_defs.h" 36 #include "nvim/gettext_defs.h" 37 #include "nvim/globals.h" 38 #include "nvim/highlight_defs.h" 39 #include "nvim/keycodes.h" 40 #include "nvim/lua/executor.h" 41 #include "nvim/macros_defs.h" 42 #include "nvim/mapping.h" 43 #include "nvim/mapping_defs.h" 44 #include "nvim/mbyte.h" 45 #include "nvim/mbyte_defs.h" 46 #include "nvim/memory.h" 47 #include "nvim/memory_defs.h" 48 #include "nvim/message.h" 49 #include "nvim/option_defs.h" 50 #include "nvim/option_vars.h" 51 #include "nvim/pos_defs.h" 52 #include "nvim/regexp.h" 53 #include "nvim/regexp_defs.h" 54 #include "nvim/runtime.h" 55 #include "nvim/state_defs.h" 56 #include "nvim/strings.h" 57 #include "nvim/types_defs.h" 58 #include "nvim/ui.h" 59 #include "nvim/ui_defs.h" 60 #include "nvim/vim_defs.h" 61 62 /// List used for abbreviations. 63 static mapblock_T *first_abbr = NULL; // first entry in abbrlist 64 65 // Each mapping is put in one of the MAX_MAPHASH hash lists, 66 // to speed up finding it. 67 static mapblock_T *(maphash[MAX_MAPHASH]) = { 0 }; 68 69 // Make a hash value for a mapping. 70 // "mode" is the lower 4 bits of the State for the mapping. 71 // "c1" is the first character of the "lhs". 72 // Returns a value between 0 and 255, index in maphash. 73 // Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode. 74 #define MAP_HASH(mode, \ 75 c1) (((mode) & \ 76 (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | \ 77 MODE_OP_PENDING | MODE_TERMINAL)) ? (c1) : ((c1) ^ 0x80)) 78 79 /// All possible |:map-arguments| usable in a |:map| command. 80 /// 81 /// The <special> argument has no effect on mappings and is excluded from this 82 /// struct declaration. |:noremap| is included, since it behaves like a map 83 /// argument when used in a mapping. 84 /// 85 /// @see mapblock_T 86 struct map_arguments { 87 bool buffer; 88 bool expr; 89 bool noremap; 90 bool nowait; 91 bool script; 92 bool silent; 93 bool unique; 94 bool replace_keycodes; 95 96 /// The {lhs} of the mapping. 97 /// 98 /// vim limits this to MAXMAPLEN characters, allowing us to use a static 99 /// buffer. Setting lhs_len to a value larger than MAXMAPLEN can signal 100 /// that {lhs} was too long and truncated. 101 char lhs[MAXMAPLEN + 1]; 102 size_t lhs_len; 103 104 /// Unsimplifed {lhs} of the mapping. If no simplification has been done then alt_lhs_len is 0. 105 char alt_lhs[MAXMAPLEN + 1]; 106 size_t alt_lhs_len; 107 108 char *rhs; ///< The {rhs} of the mapping. 109 size_t rhs_len; 110 LuaRef rhs_lua; ///< lua function as {rhs} 111 bool rhs_is_noop; ///< True when the {rhs} should be <Nop>. 112 113 char *orig_rhs; ///< The original text of the {rhs}. 114 size_t orig_rhs_len; 115 char *desc; ///< map description 116 }; 117 typedef struct map_arguments MapArguments; 118 #define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, false, \ 119 { 0 }, 0, { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL } 120 121 #include "mapping.c.generated.h" 122 123 static const char e_global_abbreviation_already_exists_for_str[] 124 = N_("E224: Global abbreviation already exists for %s"); 125 static const char e_global_mapping_already_exists_for_str[] 126 = N_("E225: Global mapping already exists for %s"); 127 static const char e_abbreviation_already_exists_for_str[] 128 = N_("E226: Abbreviation already exists for %s"); 129 static const char e_mapping_already_exists_for_str[] 130 = N_("E227: Mapping already exists for %s"); 131 static const char e_entries_missing_in_mapset_dict_argument[] 132 = N_("E460: Entries missing in mapset() dict argument"); 133 static const char e_illegal_map_mode_string_str[] 134 = N_("E1276: Illegal map mode string: '%s'"); 135 136 /// Get the start of the hashed map list for "state" and first character "c". 137 mapblock_T *get_maphash_list(int state, int c) 138 { 139 return maphash[MAP_HASH(state, c)]; 140 } 141 142 /// Get the buffer-local hashed map list for "state" and first character "c". 143 mapblock_T *get_buf_maphash_list(int state, int c) 144 { 145 return curbuf->b_maphash[MAP_HASH(state, c)]; 146 } 147 148 /// Delete one entry from the abbrlist or maphash[]. 149 /// "mpp" is a pointer to the m_next field of the PREVIOUS entry! 150 static void mapblock_free(mapblock_T **mpp) 151 { 152 mapblock_T *mp = *mpp; 153 xfree(mp->m_keys); 154 if (mp->m_alt != NULL) { 155 mp->m_alt->m_alt = NULL; 156 } else { 157 NLUA_CLEAR_REF(mp->m_luaref); 158 xfree(mp->m_str); 159 xfree(mp->m_orig_str); 160 xfree(mp->m_desc); 161 } 162 *mpp = mp->m_next; 163 xfree(mp); 164 } 165 166 /// put characters to represent the map mode in a string buffer 167 /// 168 /// @param[out] buf must be at least 7 bytes (including NUL) 169 void map_mode_to_chars(int mode, char *buf) 170 FUNC_ATTR_NONNULL_ALL 171 { 172 char *p = buf; 173 if ((mode & (MODE_INSERT | MODE_CMDLINE)) == (MODE_INSERT | MODE_CMDLINE)) { 174 *p++ = '!'; // :map! 175 } else if (mode & MODE_INSERT) { 176 *p++ = 'i'; // :imap 177 } else if (mode & MODE_LANGMAP) { 178 *p++ = 'l'; // :lmap 179 } else if (mode & MODE_CMDLINE) { 180 *p++ = 'c'; // :cmap 181 } else if ((mode & (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING)) 182 == (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING)) { 183 *p++ = ' '; // :map 184 } else { 185 if (mode & MODE_NORMAL) { 186 *p++ = 'n'; // :nmap 187 } 188 if (mode & MODE_OP_PENDING) { 189 *p++ = 'o'; // :omap 190 } 191 if (mode & MODE_TERMINAL) { 192 *p++ = 't'; // :tmap 193 } 194 if ((mode & (MODE_VISUAL | MODE_SELECT)) == (MODE_VISUAL | MODE_SELECT)) { 195 *p++ = 'v'; // :vmap 196 } else { 197 if (mode & MODE_VISUAL) { 198 *p++ = 'x'; // :xmap 199 } 200 if (mode & MODE_SELECT) { 201 *p++ = 's'; // :smap 202 } 203 } 204 } 205 206 *p = NUL; 207 } 208 209 /// @param local true for buffer-local map 210 static void showmap(mapblock_T *mp, bool local) 211 { 212 if (message_filtered(mp->m_keys) && message_filtered(mp->m_str) 213 && (mp->m_desc == NULL || message_filtered(mp->m_desc))) { 214 return; 215 } 216 217 if (msg_col > 0 || msg_silent != 0) { 218 msg_putchar('\n'); 219 if (got_int) { // 'q' typed at MORE prompt 220 return; 221 } 222 } 223 224 char mapchars[7]; 225 map_mode_to_chars(mp->m_mode, mapchars); 226 msg_puts(mapchars); 227 size_t len = strlen(mapchars); 228 229 while (++len <= 3) { 230 msg_putchar(' '); 231 } 232 233 // Display the LHS. Get length of what we write. 234 len = (size_t)msg_outtrans_special(mp->m_keys, true, 0); 235 do { 236 msg_putchar(' '); // pad with blanks 237 len++; 238 } while (len < 12); 239 240 if (mp->m_noremap == REMAP_NONE) { 241 msg_puts_hl("*", HLF_8, false); 242 } else if (mp->m_noremap == REMAP_SCRIPT) { 243 msg_puts_hl("&", HLF_8, false); 244 } else { 245 msg_putchar(' '); 246 } 247 248 if (local) { 249 msg_putchar('@'); 250 } else { 251 msg_putchar(' '); 252 } 253 254 // Use false below if we only want things like <Up> to show up as such on 255 // the rhs, and not M-x etc, true gets both -- webb 256 if (mp->m_luaref != LUA_NOREF) { 257 char *str = nlua_funcref_str(mp->m_luaref, NULL); 258 msg_puts_hl(str, HLF_8, false); 259 xfree(str); 260 } else if (mp->m_str[0] == NUL) { 261 msg_puts_hl("<Nop>", HLF_8, false); 262 } else { 263 msg_outtrans_special(mp->m_str, false, 0); 264 } 265 266 if (mp->m_desc != NULL) { 267 msg_puts("\n "); // Shift line to same level as rhs. 268 msg_puts(mp->m_desc); 269 } 270 if (p_verbose > 0) { 271 last_set_msg(mp->m_script_ctx); 272 } 273 msg_clr_eos(); 274 } 275 276 /// Replace termcodes in the given LHS and RHS and store the results into the 277 /// `lhs` and `rhs` of the given @ref MapArguments struct. 278 /// 279 /// `rhs` and `orig_rhs` will both point to new allocated buffers. `orig_rhs` 280 /// will hold a copy of the given `orig_rhs`. 281 /// 282 /// The `*_len` variables will be set appropriately. If the length of 283 /// the final `lhs` exceeds `MAXMAPLEN`, `lhs_len` will be set equal to the 284 /// original larger length and `lhs` will be truncated. 285 /// 286 /// If RHS should be <Nop>, `rhs` will be an empty string, `rhs_len` will be 287 /// zero, and `rhs_is_noop` will be set to true. 288 /// 289 /// Any memory allocated by @ref replace_termcodes is freed before this function 290 /// returns. 291 /// 292 /// @param[in] orig_lhs Original mapping LHS, with characters to replace. 293 /// @param[in] orig_lhs_len `strlen` of orig_lhs. 294 /// @param[in] orig_rhs Original mapping RHS, with characters to replace. 295 /// @param[in] rhs_lua Lua reference for Lua mappings. 296 /// @param[in] orig_rhs_len `strlen` of orig_rhs. 297 /// @param[in] cpo_val See param docs for @ref replace_termcodes. 298 /// @param[out] mapargs MapArguments struct holding the replaced strings. 299 static bool set_maparg_lhs_rhs(const char *const orig_lhs, const size_t orig_lhs_len, 300 const char *const orig_rhs, const size_t orig_rhs_len, 301 const LuaRef rhs_lua, const char *const cpo_val, 302 MapArguments *const mapargs) 303 { 304 char lhs_buf[128]; 305 306 // If mapping has been given as ^V<C_UP> say, then replace the term codes 307 // with the appropriate two bytes. If it is a shifted special key, unshift 308 // it too, giving another two bytes. 309 // 310 // replace_termcodes() may move the result to allocated memory, which 311 // needs to be freed later (*lhs_buf and *rhs_buf). 312 // replace_termcodes() also removes CTRL-Vs and sometimes backslashes. 313 // If something like <C-H> is simplified to 0x08 then mark it as simplified 314 // and also add en entry with a modifier. 315 bool did_simplify = false; 316 const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; 317 char *bufarg = lhs_buf; 318 char *replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, 0, 319 flags, &did_simplify, cpo_val); 320 if (replaced == NULL) { 321 return false; 322 } 323 mapargs->lhs_len = strlen(replaced); 324 xstrlcpy(mapargs->lhs, replaced, sizeof(mapargs->lhs)); 325 if (did_simplify) { 326 replaced = replace_termcodes(orig_lhs, orig_lhs_len, &bufarg, 0, 327 flags | REPTERM_NO_SIMPLIFY, NULL, cpo_val); 328 if (replaced == NULL) { 329 return false; 330 } 331 mapargs->alt_lhs_len = strlen(replaced); 332 xstrlcpy(mapargs->alt_lhs, replaced, sizeof(mapargs->alt_lhs)); 333 } else { 334 mapargs->alt_lhs_len = 0; 335 } 336 337 set_maparg_rhs(orig_rhs, orig_rhs_len, rhs_lua, 0, cpo_val, mapargs); 338 339 return true; 340 } 341 342 /// @see set_maparg_lhs_rhs 343 static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len, 344 const LuaRef rhs_lua, const scid_T sid, const char *const cpo_val, 345 MapArguments *const mapargs) 346 { 347 mapargs->rhs_lua = rhs_lua; 348 349 if (rhs_lua == LUA_NOREF) { 350 mapargs->orig_rhs_len = orig_rhs_len; 351 mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char)); 352 xmemcpyz(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len); 353 if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing 354 mapargs->rhs = xcalloc(1, sizeof(char)); // single NUL-char 355 mapargs->rhs_len = 0; 356 mapargs->rhs_is_noop = true; 357 } else { 358 char *rhs_buf = NULL; 359 char *replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf, sid, 360 REPTERM_DO_LT, NULL, cpo_val); 361 mapargs->rhs_len = strlen(replaced); 362 // NB: replace_termcodes may produce an empty string even if orig_rhs is non-empty 363 // (e.g. a single ^V, see :h map-empty-rhs) 364 mapargs->rhs_is_noop = orig_rhs_len != 0 && mapargs->rhs_len == 0; 365 mapargs->rhs = replaced; 366 } 367 } else { 368 char tmp_buf[64]; 369 // orig_rhs is not used for Lua mappings, but still needs to be a string. 370 mapargs->orig_rhs = xcalloc(1, sizeof(char)); 371 mapargs->orig_rhs_len = 0; 372 // stores <lua>ref_no<cr> in map_str 373 mapargs->rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "%c%c%c%d\r", K_SPECIAL, 374 KS_EXTRA, KE_LUA, rhs_lua); 375 mapargs->rhs = xstrdup(tmp_buf); 376 } 377 } 378 379 /// Parse a string of |:map-arguments| into a @ref MapArguments struct. 380 /// 381 /// Termcodes, backslashes, CTRL-V's, etc. inside the extracted {lhs} and 382 /// {rhs} are replaced by @ref set_maparg_lhs_rhs. 383 /// 384 /// rhs and orig_rhs in the returned mapargs will be set to null or a pointer 385 /// to allocated memory and should be freed even on error. 386 /// 387 /// @param[in] strargs String of map args, e.g. "<buffer> <expr><silent>". 388 /// May contain leading or trailing whitespace. 389 /// @param[in] is_unmap True, if strargs should be parsed like an |:unmap| 390 /// command. |:unmap| commands interpret *all* text to the 391 /// right of the last map argument as the {lhs} of the 392 /// mapping, i.e. a literal ' ' character is treated like 393 /// a "<space>", rather than separating the {lhs} from the 394 /// {rhs}. 395 /// @param[out] mapargs MapArguments struct holding all extracted argument 396 /// values. 397 /// @return 0 on success, 1 if invalid arguments are detected. 398 static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapargs) 399 { 400 const char *to_parse = strargs; 401 to_parse = skipwhite(to_parse); 402 CLEAR_POINTER(mapargs); 403 404 // Accept <buffer>, <nowait>, <silent>, <expr>, <script>, and <unique> in 405 // any order. 406 while (true) { 407 if (strncmp(to_parse, "<buffer>", 8) == 0) { 408 to_parse = skipwhite(to_parse + 8); 409 mapargs->buffer = true; 410 continue; 411 } 412 413 if (strncmp(to_parse, "<nowait>", 8) == 0) { 414 to_parse = skipwhite(to_parse + 8); 415 mapargs->nowait = true; 416 continue; 417 } 418 419 if (strncmp(to_parse, "<silent>", 8) == 0) { 420 to_parse = skipwhite(to_parse + 8); 421 mapargs->silent = true; 422 continue; 423 } 424 425 // Ignore obsolete "<special>" modifier. 426 if (strncmp(to_parse, "<special>", 9) == 0) { 427 to_parse = skipwhite(to_parse + 9); 428 continue; 429 } 430 431 if (strncmp(to_parse, "<script>", 8) == 0) { 432 to_parse = skipwhite(to_parse + 8); 433 mapargs->script = true; 434 continue; 435 } 436 437 if (strncmp(to_parse, "<expr>", 6) == 0) { 438 to_parse = skipwhite(to_parse + 6); 439 mapargs->expr = true; 440 continue; 441 } 442 443 if (strncmp(to_parse, "<unique>", 8) == 0) { 444 to_parse = skipwhite(to_parse + 8); 445 mapargs->unique = true; 446 continue; 447 } 448 break; 449 } 450 451 // Find the next whitespace character, call that the end of {lhs}. 452 // 453 // If a character (e.g. whitespace) is immediately preceded by a CTRL-V, 454 // "scan past" that character, i.e. don't "terminate" LHS with that character 455 // if it's whitespace. 456 // 457 // Treat backslash like CTRL-V when 'cpoptions' does not contain 'B'. 458 // 459 // With :unmap, literal white space is included in the {lhs}; there is no 460 // separate {rhs}. 461 const char *lhs_end = to_parse; 462 bool do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL); 463 while (*lhs_end && (is_unmap || !ascii_iswhite(*lhs_end))) { 464 if ((lhs_end[0] == Ctrl_V || (do_backslash && lhs_end[0] == '\\')) 465 && lhs_end[1] != NUL) { 466 lhs_end++; // skip CTRL-V or backslash 467 } 468 lhs_end++; 469 } 470 471 // {lhs_end} is a pointer to the "terminating whitespace" after {lhs}. 472 // Use that to initialize {rhs_start}. 473 const char *rhs_start = skipwhite(lhs_end); 474 475 // Given {lhs} might be larger than MAXMAPLEN before replace_termcodes 476 // (e.g. "<Space>" is longer than ' '), so first copy into a buffer. 477 size_t orig_lhs_len = (size_t)(lhs_end - to_parse); 478 if (orig_lhs_len >= 256) { 479 return 1; 480 } 481 char lhs_to_replace[256]; 482 xmemcpyz(lhs_to_replace, to_parse, orig_lhs_len); 483 484 size_t orig_rhs_len = strlen(rhs_start); 485 if (!set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len, 486 rhs_start, orig_rhs_len, LUA_NOREF, 487 p_cpo, mapargs)) { 488 return 1; 489 } 490 491 if (mapargs->lhs_len > MAXMAPLEN) { 492 return 1; 493 } 494 return 0; 495 } 496 497 /// @param args "rhs", "rhs_lua", "orig_rhs", "expr", "silent", "nowait", 498 /// "replace_keycodes" and "desc" fields are used. 499 /// @param sid 0 to use current_sctx 500 static mapblock_T *map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, 501 const char *keys, MapArguments *args, int noremap, int mode, 502 bool is_abbr, scid_T sid, linenr_T lnum, bool simplified) 503 FUNC_ATTR_NONNULL_RET 504 { 505 mapblock_T *mp = xcalloc(1, sizeof(mapblock_T)); 506 507 // If CTRL-C has been mapped, don't always use it for Interrupting. 508 if (*keys == Ctrl_C) { 509 if (map_table == buf->b_maphash) { 510 buf->b_mapped_ctrl_c |= mode; 511 } else { 512 mapped_ctrl_c |= mode; 513 } 514 } 515 516 mp->m_keys = xstrdup(keys); 517 mp->m_str = args->rhs; 518 mp->m_orig_str = args->orig_rhs; 519 mp->m_luaref = args->rhs_lua; 520 mp->m_keylen = (int)strlen(mp->m_keys); 521 mp->m_noremap = noremap; 522 mp->m_nowait = args->nowait; 523 mp->m_silent = args->silent; 524 mp->m_mode = mode; 525 mp->m_simplified = simplified; 526 mp->m_expr = args->expr; 527 mp->m_replace_keycodes = args->replace_keycodes; 528 if (sid != 0) { 529 mp->m_script_ctx.sc_sid = sid; 530 mp->m_script_ctx.sc_lnum = lnum; 531 } else { 532 mp->m_script_ctx = current_sctx; 533 mp->m_script_ctx.sc_lnum += SOURCING_LNUM; 534 nlua_set_sctx(&mp->m_script_ctx); 535 } 536 mp->m_desc = args->desc; 537 538 // add the new entry in front of the abbrlist or maphash[] list 539 if (is_abbr) { 540 mp->m_next = *abbr_table; 541 *abbr_table = mp; 542 } else { 543 const int n = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]); 544 mp->m_next = map_table[n]; 545 map_table[n] = mp; 546 } 547 return mp; 548 } 549 550 /// Sets or removes a mapping or abbreviation in buffer `buf`. 551 /// 552 /// @param maptype @see do_map 553 /// @param args Fully parsed and "preprocessed" arguments for the 554 /// (un)map/abbrev command. Termcodes should have already been 555 /// replaced; whitespace, `<` and `>` signs, etc. in {lhs} and 556 /// {rhs} are assumed to be literal components of the mapping. 557 /// @param mode @see do_map 558 /// @param is_abbrev @see do_map 559 /// @param buf Target Buffer 560 static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T *buf) 561 { 562 int retval = 0; 563 564 // If <buffer> was given, we'll be searching through the buffer's 565 // mappings/abbreviations, not the globals. 566 mapblock_T **map_table = args->buffer ? buf->b_maphash : maphash; 567 mapblock_T **abbr_table = args->buffer ? &buf->b_first_abbr : &first_abbr; 568 mapblock_T *mp_result[2] = { NULL, NULL }; 569 570 bool unmap_lhs_only = false; 571 if (maptype == MAPTYPE_UNMAP_LHS) { 572 unmap_lhs_only = true; 573 maptype = MAPTYPE_UNMAP; 574 } 575 576 // For ":noremap" don't remap, otherwise do remap. 577 int noremap = args->script ? REMAP_SCRIPT 578 : maptype == MAPTYPE_NOREMAP ? REMAP_NONE : REMAP_YES; 579 580 const bool has_lhs = (args->lhs[0] != NUL); 581 const bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop; 582 const bool do_print = !has_lhs || (maptype != MAPTYPE_UNMAP && !has_rhs); 583 if (do_print) { 584 msg_ext_set_kind("list_cmd"); 585 } 586 587 // check for :unmap without argument 588 if (maptype == MAPTYPE_UNMAP && !has_lhs) { 589 retval = 1; 590 goto theend; 591 } 592 593 const char *lhs = (char *)&args->lhs; 594 const bool did_simplify = args->alt_lhs_len != 0; 595 596 // The following is done twice if we have two versions of keys 597 for (int keyround = 1; keyround <= 2; keyround++) { 598 bool did_it = false; 599 bool did_local = false; 600 bool keyround1_simplified = keyround == 1 && did_simplify; 601 int len = (int)args->lhs_len; 602 603 if (keyround == 2) { 604 if (!did_simplify) { 605 break; 606 } 607 lhs = (char *)&args->alt_lhs; 608 len = (int)args->alt_lhs_len; 609 } else if (did_simplify && do_print) { 610 // when printing always use the not-simplified map 611 lhs = (char *)&args->alt_lhs; 612 len = (int)args->alt_lhs_len; 613 } 614 615 // check arguments and translate function keys 616 if (has_lhs) { 617 if (len > MAXMAPLEN) { 618 retval = 1; 619 goto theend; 620 } 621 622 if (is_abbrev && maptype != MAPTYPE_UNMAP) { 623 // If an abbreviation ends in a keyword character, the 624 // rest must be all keyword-char or all non-keyword-char. 625 // Otherwise we won't be able to find the start of it in a 626 // vi-compatible way. 627 int same = -1; 628 629 const int first = vim_iswordp(lhs); 630 int last = first; 631 const char *p = lhs + utfc_ptr2len(lhs); 632 int n = 1; 633 while (p < lhs + len) { 634 n++; // nr of (multi-byte) chars 635 last = vim_iswordp(p); // type of last char 636 if (same == -1 && last != first) { 637 same = n - 1; // count of same char type 638 } 639 p += utfc_ptr2len(p); 640 } 641 if (last && n > 2 && same >= 0 && same < n - 1) { 642 retval = 1; 643 goto theend; 644 } 645 // An abbreviation cannot contain white space. 646 for (n = 0; n < len; n++) { 647 if (ascii_iswhite(lhs[n])) { 648 retval = 1; 649 goto theend; 650 } 651 } // for 652 } 653 } 654 655 if (has_lhs && has_rhs && is_abbrev) { // if we will add an abbreviation, 656 no_abbr = false; // reset flag that indicates there are no abbreviations 657 } 658 659 if (do_print) { 660 msg_start(); 661 } 662 663 // Check if a new local mapping wasn't already defined globally. 664 if (args->unique && map_table == buf->b_maphash && has_lhs && has_rhs 665 && maptype != MAPTYPE_UNMAP) { 666 // need to loop over all global hash lists 667 for (int hash = 0; hash < 256 && !got_int; hash++) { 668 mapblock_T *mp; 669 if (is_abbrev) { 670 if (hash != 0) { // there is only one abbreviation list 671 break; 672 } 673 mp = first_abbr; 674 } else { 675 mp = maphash[hash]; 676 } 677 for (; mp != NULL && !got_int; mp = mp->m_next) { 678 // check entries with the same mode 679 if ((mp->m_mode & mode) != 0 680 && mp->m_keylen == len 681 && strncmp(mp->m_keys, lhs, (size_t)len) == 0) { 682 retval = 6; 683 goto theend; 684 } 685 } 686 } 687 } 688 689 // When listing global mappings, also list buffer-local ones here. 690 if (map_table != buf->b_maphash && !has_rhs && maptype != MAPTYPE_UNMAP) { 691 // need to loop over all global hash lists 692 for (int hash = 0; hash < 256 && !got_int; hash++) { 693 mapblock_T *mp; 694 if (is_abbrev) { 695 if (hash != 0) { // there is only one abbreviation list 696 break; 697 } 698 mp = buf->b_first_abbr; 699 } else { 700 mp = buf->b_maphash[hash]; 701 } 702 for (; mp != NULL && !got_int; mp = mp->m_next) { 703 // check entries with the same mode 704 if (!mp->m_simplified && (mp->m_mode & mode) != 0) { 705 if (!has_lhs) { // show all entries 706 showmap(mp, true); 707 did_local = true; 708 } else { 709 int n = mp->m_keylen; 710 if (strncmp(mp->m_keys, lhs, (size_t)(n < len ? n : len)) == 0) { 711 showmap(mp, true); 712 did_local = true; 713 } 714 } 715 } 716 } 717 } 718 } 719 720 // Find an entry in the maphash[] list that matches. 721 // For :unmap we may loop two times: once to try to unmap an entry with a 722 // matching 'from' part, a second time, if the first fails, to unmap an 723 // entry with a matching 'to' part. This was done to allow ":ab foo bar" 724 // to be unmapped by typing ":unab foo", where "foo" will be replaced by 725 // "bar" because of the abbreviation. 726 const int num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1; 727 for (int round = 0; round < num_rounds && !did_it && !got_int; round++) { 728 int hash_start, hash_end; 729 if ((round == 0 && has_lhs) || is_abbrev) { 730 // just use one hash 731 hash_start = is_abbrev ? 0 : MAP_HASH(mode, (uint8_t)lhs[0]); 732 hash_end = hash_start + 1; 733 } else { 734 // need to loop over all hash lists 735 hash_start = 0; 736 hash_end = 256; 737 } 738 for (int hash = hash_start; hash < hash_end && !got_int; hash++) { 739 mapblock_T **mpp = is_abbrev ? abbr_table : &(map_table[hash]); 740 for (mapblock_T *mp = *mpp; mp != NULL && !got_int; mp = *mpp) { 741 if ((mp->m_mode & mode) == 0) { 742 // skip entries with wrong mode 743 mpp = &(mp->m_next); 744 continue; 745 } 746 if (!has_lhs) { // show all entries 747 if (!mp->m_simplified) { 748 showmap(mp, map_table != maphash); 749 did_it = true; 750 } 751 } else { // do we have a match? 752 int n; 753 const char *p; 754 if (round) { // second round: Try unmap "rhs" string 755 n = (int)strlen(mp->m_str); 756 p = mp->m_str; 757 } else { 758 n = mp->m_keylen; 759 p = mp->m_keys; 760 } 761 if (strncmp(p, lhs, (size_t)(n < len ? n : len)) == 0) { 762 if (maptype == MAPTYPE_UNMAP) { 763 // Delete entry. 764 // Only accept a full match. For abbreviations 765 // we ignore trailing space when matching with 766 // the "lhs", since an abbreviation can't have 767 // trailing space. 768 if (n != len && (!is_abbrev || round || n > len || *skipwhite(lhs + n) != NUL)) { 769 mpp = &(mp->m_next); 770 continue; 771 } 772 // In keyround for simplified keys, don't unmap 773 // a mapping without m_simplified flag. 774 if (keyround1_simplified && !mp->m_simplified) { 775 break; 776 } 777 // We reset the indicated mode bits. If nothing 778 // is left the entry is deleted below. 779 mp->m_mode &= ~mode; 780 did_it = true; // remember we did something 781 } else if (!has_rhs) { // show matching entry 782 if (!mp->m_simplified) { 783 showmap(mp, map_table != maphash); 784 did_it = true; 785 } 786 } else if (n != len) { // new entry is ambiguous 787 mpp = &(mp->m_next); 788 continue; 789 } else if (keyround1_simplified && !mp->m_simplified) { 790 // In keyround for simplified keys, don't replace 791 // a mapping without m_simplified flag. 792 did_it = true; 793 break; 794 } else if (args->unique) { 795 retval = 5; 796 goto theend; 797 } else { 798 // new rhs for existing entry 799 mp->m_mode &= ~mode; // remove mode bits 800 if (mp->m_mode == 0 && !did_it) { // reuse entry 801 if (mp->m_alt != NULL) { 802 mp->m_alt = mp->m_alt->m_alt = NULL; 803 } else { 804 NLUA_CLEAR_REF(mp->m_luaref); 805 xfree(mp->m_str); 806 xfree(mp->m_orig_str); 807 xfree(mp->m_desc); 808 } 809 mp->m_str = args->rhs; 810 mp->m_orig_str = args->orig_rhs; 811 mp->m_luaref = args->rhs_lua; 812 mp->m_noremap = noremap; 813 mp->m_nowait = args->nowait; 814 mp->m_silent = args->silent; 815 mp->m_mode = mode; 816 mp->m_simplified = keyround1_simplified; 817 mp->m_expr = args->expr; 818 mp->m_replace_keycodes = args->replace_keycodes; 819 mp->m_script_ctx = current_sctx; 820 mp->m_script_ctx.sc_lnum += SOURCING_LNUM; 821 nlua_set_sctx(&mp->m_script_ctx); 822 mp->m_desc = args->desc; 823 mp_result[keyround - 1] = mp; 824 did_it = true; 825 } 826 } 827 if (mp->m_mode == 0) { // entry can be deleted 828 mapblock_free(mpp); 829 continue; // continue with *mpp 830 } 831 832 // May need to put this entry into another hash list. 833 int new_hash = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]); 834 if (!is_abbrev && new_hash != hash) { 835 *mpp = mp->m_next; 836 mp->m_next = map_table[new_hash]; 837 map_table[new_hash] = mp; 838 839 continue; // continue with *mpp 840 } 841 } 842 } 843 mpp = &(mp->m_next); 844 } 845 } 846 } 847 848 if (maptype == MAPTYPE_UNMAP) { 849 // delete entry 850 if (!did_it) { 851 if (!keyround1_simplified) { 852 retval = 2; // no match 853 } 854 } else if (*lhs == Ctrl_C) { 855 // If CTRL-C has been unmapped, reuse it for Interrupting. 856 if (map_table == buf->b_maphash) { 857 buf->b_mapped_ctrl_c &= ~mode; 858 } else { 859 mapped_ctrl_c &= ~mode; 860 } 861 } 862 continue; 863 } 864 865 if (!has_lhs || !has_rhs) { 866 // print entries 867 if (!did_it && !did_local) { 868 if (is_abbrev) { 869 msg(_("No abbreviation found"), 0); 870 } else { 871 msg(_("No mapping found"), 0); 872 } 873 } 874 goto theend; // listing finished 875 } 876 877 if (did_it) { 878 continue; // have added the new entry already 879 } 880 881 // Get here when adding a new entry to the maphash[] list or abbrlist. 882 mp_result[keyround - 1] = map_add(buf, map_table, abbr_table, lhs, 883 args, noremap, mode, is_abbrev, 884 0, // sid 885 0, // lnum 886 keyround1_simplified); 887 } 888 889 if (mp_result[0] != NULL && mp_result[1] != NULL) { 890 mp_result[0]->m_alt = mp_result[1]; 891 mp_result[1]->m_alt = mp_result[0]; 892 } 893 894 theend: 895 if (mp_result[0] != NULL || mp_result[1] != NULL) { 896 args->rhs = NULL; 897 args->orig_rhs = NULL; 898 args->rhs_lua = LUA_NOREF; 899 args->desc = NULL; 900 } 901 return retval; 902 } 903 904 /// Set or remove a mapping or an abbreviation in the current buffer, OR 905 /// display (matching) mappings/abbreviations. 906 /// 907 /// ```vim 908 /// map[!] " show all key mappings 909 /// map[!] {lhs} " show key mapping for {lhs} 910 /// map[!] {lhs} {rhs} " set key mapping for {lhs} to {rhs} 911 /// noremap[!] {lhs} {rhs} " same, but no remapping for {rhs} 912 /// unmap[!] {lhs} " remove key mapping for {lhs} 913 /// abbr " show all abbreviations 914 /// abbr {lhs} " show abbreviations for {lhs} 915 /// abbr {lhs} {rhs} " set abbreviation for {lhs} to {rhs} 916 /// noreabbr {lhs} {rhs} " same, but no remapping for {rhs} 917 /// unabbr {lhs} " remove abbreviation for {lhs} 918 /// 919 /// for :map mode is MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING 920 /// for :map! mode is MODE_INSERT | MODE_CMDLINE 921 /// for :cmap mode is MODE_CMDLINE 922 /// for :imap mode is MODE_INSERT 923 /// for :lmap mode is MODE_LANGMAP 924 /// for :nmap mode is MODE_NORMAL 925 /// for :vmap mode is MODE_VISUAL | MODE_SELECT 926 /// for :xmap mode is MODE_VISUAL 927 /// for :smap mode is MODE_SELECT 928 /// for :omap mode is MODE_OP_PENDING 929 /// for :tmap mode is MODE_TERMINAL 930 /// 931 /// for :abbr mode is MODE_INSERT | MODE_CMDLINE 932 /// for :iabbr mode is MODE_INSERT 933 /// for :cabbr mode is MODE_CMDLINE 934 /// ``` 935 /// 936 /// @param maptype MAPTYPE_MAP for |:map| or |:abbr| 937 /// MAPTYPE_UNMAP for |:unmap| or |:unabbr| 938 /// MAPTYPE_NOREMAP for |:noremap| or |:noreabbr| 939 /// MAPTYPE_UNMAP_LHS is like MAPTYPE_UNMAP, but doesn't try to match 940 /// with {rhs} if there is no match with {lhs}. 941 /// @param arg C-string containing the arguments of the map/abbrev 942 /// command, i.e. everything except the initial `:[X][nore]map`. 943 /// - Cannot be a read-only string; it will be modified. 944 /// @param mode Bitflags representing the mode in which to set the mapping. 945 /// See @ref get_map_mode. 946 /// @param is_abbrev True if setting an abbreviation, false otherwise. 947 /// 948 /// @return 0 on success. On failure, will return one of the following: 949 /// - 1 for invalid arguments 950 /// - 2 for no match 951 /// - 4 for out of mem (deprecated, WON'T HAPPEN) 952 /// - 5 for entry not unique 953 /// - 6 for buflocal unique entry conflicts with global entry 954 /// 955 int do_map(int maptype, char *arg, int mode, bool is_abbrev) 956 { 957 MapArguments parsed_args; 958 int result = str_to_mapargs(arg, maptype == MAPTYPE_UNMAP, &parsed_args); 959 switch (result) { 960 case 0: 961 break; 962 case 1: 963 // invalid arguments 964 goto free_and_return; 965 default: 966 assert(false && "Unknown return code from str_to_mapargs!"); 967 result = -1; 968 goto free_and_return; 969 } // switch 970 971 result = buf_do_map(maptype, &parsed_args, mode, is_abbrev, curbuf); 972 973 free_and_return: 974 xfree(parsed_args.rhs); 975 xfree(parsed_args.orig_rhs); 976 return result; 977 } 978 979 /// Get the mapping mode from the command name. 980 static int get_map_mode(char **cmdp, bool forceit) 981 { 982 int mode; 983 984 char *p = *cmdp; 985 int modec = (uint8_t)(*p++); 986 if (modec == 'i') { 987 mode = MODE_INSERT; // :imap 988 } else if (modec == 'l') { 989 mode = MODE_LANGMAP; // :lmap 990 } else if (modec == 'c') { 991 mode = MODE_CMDLINE; // :cmap 992 } else if (modec == 'n' && *p != 'o') { // avoid :noremap 993 mode = MODE_NORMAL; // :nmap 994 } else if (modec == 'v') { 995 mode = MODE_VISUAL | MODE_SELECT; // :vmap 996 } else if (modec == 'x') { 997 mode = MODE_VISUAL; // :xmap 998 } else if (modec == 's') { 999 mode = MODE_SELECT; // :smap 1000 } else if (modec == 'o') { 1001 mode = MODE_OP_PENDING; // :omap 1002 } else if (modec == 't') { 1003 mode = MODE_TERMINAL; // :tmap 1004 } else { 1005 p--; 1006 if (forceit) { 1007 mode = MODE_INSERT | MODE_CMDLINE; // :map ! 1008 } else { 1009 mode = MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING; // :map 1010 } 1011 } 1012 1013 *cmdp = p; 1014 return mode; 1015 } 1016 1017 /// Clear all mappings (":mapclear") or abbreviations (":abclear"). 1018 /// "abbr" should be false for mappings, true for abbreviations. 1019 /// This function used to be called map_clear(). 1020 static void do_mapclear(char *cmdp, char *arg, int forceit, int abbr) 1021 { 1022 bool local = strcmp(arg, "<buffer>") == 0; 1023 if (!local && *arg != NUL) { 1024 emsg(_(e_invarg)); 1025 return; 1026 } 1027 1028 int mode = get_map_mode(&cmdp, forceit); 1029 map_clear_mode(curbuf, mode, local, abbr); 1030 } 1031 1032 /// Clear all mappings in "mode". 1033 /// 1034 /// @param buf, buffer for local mappings 1035 /// @param mode mode in which to delete 1036 /// @param local true for buffer-local mappings 1037 /// @param abbr true for abbreviations 1038 void map_clear_mode(buf_T *buf, int mode, bool local, bool abbr) 1039 { 1040 for (int hash = 0; hash < 256; hash++) { 1041 mapblock_T **mpp; 1042 if (abbr) { 1043 if (hash > 0) { // there is only one abbrlist 1044 break; 1045 } 1046 if (local) { 1047 mpp = &buf->b_first_abbr; 1048 } else { 1049 mpp = &first_abbr; 1050 } 1051 } else { 1052 if (local) { 1053 mpp = &buf->b_maphash[hash]; 1054 } else { 1055 mpp = &maphash[hash]; 1056 } 1057 } 1058 while (*mpp != NULL) { 1059 mapblock_T *mp = *mpp; 1060 if (mp->m_mode & mode) { 1061 mp->m_mode &= ~mode; 1062 if (mp->m_mode == 0) { // entry can be deleted 1063 mapblock_free(mpp); 1064 continue; 1065 } 1066 // May need to put this entry into another hash list. 1067 int new_hash = MAP_HASH(mp->m_mode, (uint8_t)mp->m_keys[0]); 1068 if (!abbr && new_hash != hash) { 1069 *mpp = mp->m_next; 1070 if (local) { 1071 mp->m_next = buf->b_maphash[new_hash]; 1072 buf->b_maphash[new_hash] = mp; 1073 } else { 1074 mp->m_next = maphash[new_hash]; 1075 maphash[new_hash] = mp; 1076 } 1077 continue; // continue with *mpp 1078 } 1079 } 1080 mpp = &(mp->m_next); 1081 } 1082 } 1083 } 1084 1085 /// Check if a map exists that has given string in the rhs 1086 /// 1087 /// Also checks mappings local to the current buffer. 1088 /// 1089 /// @param[in] str String which mapping must have in the rhs. Termcap codes 1090 /// are recognized in this argument. 1091 /// @param[in] modechars Mode(s) in which mappings are checked. 1092 /// @param[in] abbr true if checking abbreviations in place of mappings. 1093 /// 1094 /// @return true if there is at least one mapping with given parameters. 1095 bool map_to_exists(const char *const str, const char *const modechars, const bool abbr) 1096 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 1097 { 1098 int mode = 0; 1099 1100 char *buf = NULL; 1101 const char *const rhs = replace_termcodes(str, strlen(str), &buf, 0, 1102 REPTERM_DO_LT, NULL, p_cpo); 1103 1104 #define MAPMODE(mode, modechars, chr, modeflags) \ 1105 do { \ 1106 if (strchr(modechars, chr) != NULL) { \ 1107 (mode) |= (modeflags); \ 1108 } \ 1109 } while (0) 1110 MAPMODE(mode, modechars, 'n', MODE_NORMAL); 1111 MAPMODE(mode, modechars, 'v', MODE_VISUAL | MODE_SELECT); 1112 MAPMODE(mode, modechars, 'x', MODE_VISUAL); 1113 MAPMODE(mode, modechars, 's', MODE_SELECT); 1114 MAPMODE(mode, modechars, 'o', MODE_OP_PENDING); 1115 MAPMODE(mode, modechars, 'i', MODE_INSERT); 1116 MAPMODE(mode, modechars, 'l', MODE_LANGMAP); 1117 MAPMODE(mode, modechars, 'c', MODE_CMDLINE); 1118 #undef MAPMODE 1119 1120 bool retval = map_to_exists_mode(rhs, mode, abbr); 1121 xfree(buf); 1122 1123 return retval; 1124 } 1125 1126 /// Check if a map exists that has given string in the rhs 1127 /// 1128 /// Also checks mappings local to the current buffer. 1129 /// 1130 /// @param[in] rhs String which mapping must have in the rhs. Termcap codes 1131 /// are recognized in this argument. 1132 /// @param[in] mode Mode(s) in which mappings are checked. 1133 /// @param[in] abbr true if checking abbreviations in place of mappings. 1134 /// 1135 /// @return true if there is at least one mapping with given parameters. 1136 bool map_to_exists_mode(const char *const rhs, const int mode, const bool abbr) 1137 { 1138 bool exp_buffer = false; 1139 1140 // Do it twice: once for global maps and once for local maps. 1141 while (true) { 1142 for (int hash = 0; hash < 256; hash++) { 1143 mapblock_T *mp; 1144 if (abbr) { 1145 if (hash > 0) { // There is only one abbr list. 1146 break; 1147 } 1148 if (exp_buffer) { 1149 mp = curbuf->b_first_abbr; 1150 } else { 1151 mp = first_abbr; 1152 } 1153 } else if (exp_buffer) { 1154 mp = curbuf->b_maphash[hash]; 1155 } else { 1156 mp = maphash[hash]; 1157 } 1158 for (; mp; mp = mp->m_next) { 1159 if ((mp->m_mode & mode) && strstr(mp->m_str, rhs) != NULL) { 1160 return true; 1161 } 1162 } 1163 } 1164 if (exp_buffer) { 1165 break; 1166 } 1167 exp_buffer = true; 1168 } 1169 1170 return false; 1171 } 1172 1173 /// Used below when expanding mapping/abbreviation names. 1174 static int expand_mapmodes = 0; 1175 static bool expand_isabbrev = false; 1176 static bool expand_buffer = false; 1177 1178 /// Translate an internal mapping/abbreviation representation into the 1179 /// corresponding external one recognized by :map/:abbrev commands. 1180 /// 1181 /// This function is called when expanding mappings/abbreviations on the 1182 /// command-line. 1183 /// 1184 /// It uses a growarray to build the translation string since the latter can be 1185 /// wider than the original description. The caller has to free the string 1186 /// afterwards. 1187 /// 1188 /// @param[in] cpo_val See param docs for @ref replace_termcodes. 1189 /// 1190 /// @return NULL when there is a problem. 1191 static char *translate_mapping(const char *const str_in, const char *const cpo_val) 1192 { 1193 const uint8_t *str = (const uint8_t *)str_in; 1194 garray_T ga; 1195 ga_init(&ga, 1, 40); 1196 1197 const bool cpo_bslash = (vim_strchr(cpo_val, CPO_BSLASH) != NULL); 1198 1199 for (; *str; str++) { 1200 int c = *str; 1201 if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) { 1202 int modifiers = 0; 1203 if (str[1] == KS_MODIFIER) { 1204 str++; 1205 modifiers = *++str; 1206 c = *++str; 1207 } 1208 1209 if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) { 1210 c = TO_SPECIAL(str[1], str[2]); 1211 if (c == K_ZERO) { 1212 // display <Nul> as ^@ 1213 c = NUL; 1214 } 1215 str += 2; 1216 } 1217 if (IS_SPECIAL(c) || modifiers) { // special key 1218 ga_concat(&ga, get_special_key_name(c, modifiers)); 1219 continue; // for (str) 1220 } 1221 } 1222 1223 if (c == ' ' || c == '\t' || c == Ctrl_J || c == Ctrl_V 1224 || c == '<' || (c == '\\' && !cpo_bslash)) { 1225 ga_append(&ga, cpo_bslash ? Ctrl_V : '\\'); 1226 } 1227 1228 if (c) { 1229 ga_append(&ga, (uint8_t)c); 1230 } 1231 } 1232 ga_append(&ga, NUL); 1233 return (char *)ga.ga_data; 1234 } 1235 1236 /// Work out what to complete when doing command line completion of mapping 1237 /// or abbreviation names. 1238 /// 1239 /// @param forceit true if '!' given 1240 /// @param isabbrev true if abbreviation 1241 /// @param isunmap true if unmap/unabbrev command 1242 char *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, bool isabbrev, 1243 bool isunmap, cmdidx_T cmdidx) 1244 { 1245 if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap) { 1246 xp->xp_context = EXPAND_NOTHING; 1247 } else { 1248 if (isunmap) { 1249 expand_mapmodes = get_map_mode(&cmd, forceit || isabbrev); 1250 } else { 1251 expand_mapmodes = MODE_INSERT | MODE_CMDLINE; 1252 if (!isabbrev) { 1253 expand_mapmodes |= MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING; 1254 } 1255 } 1256 expand_isabbrev = isabbrev; 1257 xp->xp_context = EXPAND_MAPPINGS; 1258 expand_buffer = false; 1259 while (true) { 1260 if (strncmp(arg, "<buffer>", 8) == 0) { 1261 expand_buffer = true; 1262 arg = skipwhite(arg + 8); 1263 continue; 1264 } 1265 if (strncmp(arg, "<unique>", 8) == 0) { 1266 arg = skipwhite(arg + 8); 1267 continue; 1268 } 1269 if (strncmp(arg, "<nowait>", 8) == 0) { 1270 arg = skipwhite(arg + 8); 1271 continue; 1272 } 1273 if (strncmp(arg, "<silent>", 8) == 0) { 1274 arg = skipwhite(arg + 8); 1275 continue; 1276 } 1277 if (strncmp(arg, "<special>", 9) == 0) { 1278 arg = skipwhite(arg + 9); 1279 continue; 1280 } 1281 if (strncmp(arg, "<script>", 8) == 0) { 1282 arg = skipwhite(arg + 8); 1283 continue; 1284 } 1285 if (strncmp(arg, "<expr>", 6) == 0) { 1286 arg = skipwhite(arg + 6); 1287 continue; 1288 } 1289 break; 1290 } 1291 xp->xp_pattern = arg; 1292 } 1293 1294 return NULL; 1295 } 1296 1297 /// Find all mapping/abbreviation names that match regexp "regmatch". 1298 /// For command line expansion of ":[un]map" and ":[un]abbrev" in all modes. 1299 /// @return OK if matches found, FAIL otherwise. 1300 int ExpandMappings(char *pat, regmatch_T *regmatch, int *numMatches, char ***matches) 1301 { 1302 const bool fuzzy = cmdline_fuzzy_complete(pat); 1303 1304 *numMatches = 0; // return values in case of FAIL 1305 *matches = NULL; 1306 1307 garray_T ga; 1308 if (!fuzzy) { 1309 ga_init(&ga, sizeof(char *), 3); 1310 } else { 1311 ga_init(&ga, sizeof(fuzmatch_str_T), 3); 1312 } 1313 1314 // First search in map modifier arguments 1315 for (int i = 0; i < 7; i++) { 1316 char *p; 1317 if (i == 0) { 1318 p = "<silent>"; 1319 } else if (i == 1) { 1320 p = "<unique>"; 1321 } else if (i == 2) { 1322 p = "<script>"; 1323 } else if (i == 3) { 1324 p = "<expr>"; 1325 } else if (i == 4 && !expand_buffer) { 1326 p = "<buffer>"; 1327 } else if (i == 5) { 1328 p = "<nowait>"; 1329 } else if (i == 6) { 1330 p = "<special>"; 1331 } else { 1332 continue; 1333 } 1334 1335 bool match; 1336 int score = 0; 1337 if (!fuzzy) { 1338 match = vim_regexec(regmatch, p, 0); 1339 } else { 1340 score = fuzzy_match_str(p, pat); 1341 match = (score != FUZZY_SCORE_NONE); 1342 } 1343 1344 if (!match) { 1345 continue; 1346 } 1347 1348 if (fuzzy) { 1349 GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){ 1350 .idx = ga.ga_len, 1351 .str = xstrdup(p), 1352 .score = score, 1353 })); 1354 } else { 1355 GA_APPEND(char *, &ga, xstrdup(p)); 1356 } 1357 } 1358 1359 for (int hash = 0; hash < 256; hash++) { 1360 mapblock_T *mp; 1361 if (expand_isabbrev) { 1362 if (hash > 0) { // only one abbrev list 1363 break; // for (hash) 1364 } 1365 mp = first_abbr; 1366 } else if (expand_buffer) { 1367 mp = curbuf->b_maphash[hash]; 1368 } else { 1369 mp = maphash[hash]; 1370 } 1371 for (; mp; mp = mp->m_next) { 1372 if (mp->m_simplified || !(mp->m_mode & expand_mapmodes)) { 1373 continue; 1374 } 1375 1376 char *p = translate_mapping(mp->m_keys, p_cpo); 1377 if (p == NULL) { 1378 continue; 1379 } 1380 1381 bool match; 1382 int score = 0; 1383 if (!fuzzy) { 1384 match = vim_regexec(regmatch, p, 0); 1385 } else { 1386 score = fuzzy_match_str(p, pat); 1387 match = (score != FUZZY_SCORE_NONE); 1388 } 1389 1390 if (!match) { 1391 xfree(p); 1392 continue; 1393 } 1394 1395 if (fuzzy) { 1396 GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){ 1397 .idx = ga.ga_len, 1398 .str = p, 1399 .score = score, 1400 })); 1401 } else { 1402 GA_APPEND(char *, &ga, p); 1403 } 1404 } // for (mp) 1405 } // for (hash) 1406 1407 if (ga.ga_len == 0) { 1408 return FAIL; 1409 } 1410 1411 if (!fuzzy) { 1412 *matches = ga.ga_data; 1413 *numMatches = ga.ga_len; 1414 } else { 1415 fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, false); 1416 *numMatches = ga.ga_len; 1417 } 1418 1419 int count = *numMatches; 1420 if (count > 1) { 1421 // Sort the matches 1422 // Fuzzy matching already sorts the matches 1423 if (!fuzzy) { 1424 sort_strings(*matches, count); 1425 } 1426 1427 // Remove multiple entries 1428 char **ptr1 = *matches; 1429 char **ptr2 = ptr1 + 1; 1430 char **ptr3 = ptr1 + count; 1431 1432 while (ptr2 < ptr3) { 1433 if (strcmp(*ptr1, *ptr2) != 0) { 1434 *++ptr1 = *ptr2++; 1435 } else { 1436 xfree(*ptr2++); 1437 count--; 1438 } 1439 } 1440 } 1441 1442 *numMatches = count; 1443 return count == 0 ? FAIL : OK; 1444 } 1445 1446 // Check for an abbreviation. 1447 // Cursor is at ptr[col]. 1448 // When inserting, mincol is where insert started. 1449 // For the command line, mincol is what is to be skipped over. 1450 // "c" is the character typed before check_abbr was called. It may have 1451 // ABBR_OFF added to avoid prepending a CTRL-V to it. 1452 // 1453 // Historic vi practice: The last character of an abbreviation must be an id 1454 // character ([a-zA-Z0-9_]). The characters in front of it must be all id 1455 // characters or all non-id characters. This allows for abbr. "#i" to 1456 // "#include". 1457 // 1458 // Vim addition: Allow for abbreviations that end in a non-keyword character. 1459 // Then there must be white space before the abbr. 1460 // 1461 // Return true if there is an abbreviation, false if not. 1462 bool check_abbr(int c, char *ptr, int col, int mincol) 1463 { 1464 uint8_t tb[MB_MAXBYTES + 4]; 1465 int clen = 0; // length in characters 1466 1467 if (typebuf.tb_no_abbr_cnt) { // abbrev. are not recursive 1468 return false; 1469 } 1470 1471 // no remapping implies no abbreviation, except for CTRL-] 1472 if (noremap_keys() && c != Ctrl_RSB) { 1473 return false; 1474 } 1475 1476 // Check for word before the cursor: If it ends in a keyword char all 1477 // chars before it must be keyword chars or non-keyword chars, but not 1478 // white space. If it ends in a non-keyword char we accept any characters 1479 // before it except white space. 1480 if (col == 0) { // cannot be an abbr. 1481 return false; 1482 } 1483 1484 int scol; // starting column of the abbr. 1485 1486 { 1487 bool is_id = true; 1488 bool vim_abbr; 1489 char *p = mb_prevptr(ptr, ptr + col); 1490 if (!vim_iswordp(p)) { 1491 vim_abbr = true; // Vim added abbr. 1492 } else { 1493 vim_abbr = false; // vi compatible abbr. 1494 if (p > ptr) { 1495 is_id = vim_iswordp(mb_prevptr(ptr, p)); 1496 } 1497 } 1498 clen = 1; 1499 while (p > ptr + mincol) { 1500 p = mb_prevptr(ptr, p); 1501 if (ascii_isspace(*p) || (!vim_abbr && is_id != vim_iswordp(p))) { 1502 p += utfc_ptr2len(p); 1503 break; 1504 } 1505 clen++; 1506 } 1507 scol = (int)(p - ptr); 1508 } 1509 1510 if (scol < mincol) { 1511 scol = mincol; 1512 } 1513 if (scol < col) { // there is a word in front of the cursor 1514 ptr += scol; 1515 int len = col - scol; 1516 mapblock_T *mp = curbuf->b_first_abbr; 1517 mapblock_T *mp2 = first_abbr; 1518 if (mp == NULL) { 1519 mp = mp2; 1520 mp2 = NULL; 1521 } 1522 for (; mp; 1523 mp->m_next == NULL ? (mp = mp2, mp2 = NULL) 1524 : (mp = mp->m_next)) { 1525 int qlen = mp->m_keylen; 1526 char *q = mp->m_keys; 1527 1528 if (strchr(mp->m_keys, K_SPECIAL) != NULL) { 1529 // Might have K_SPECIAL escaped mp->m_keys. 1530 q = xstrdup(mp->m_keys); 1531 vim_unescape_ks(q); 1532 qlen = (int)strlen(q); 1533 } 1534 // find entries with right mode and keys 1535 int match = (mp->m_mode & State) 1536 && qlen == len 1537 && !strncmp(q, ptr, (size_t)len); 1538 if (q != mp->m_keys) { 1539 xfree(q); 1540 } 1541 if (match) { 1542 break; 1543 } 1544 } 1545 if (mp != NULL) { 1546 // Found a match: 1547 // Insert the rest of the abbreviation in typebuf.tb_buf[]. 1548 // This goes from end to start. 1549 // 1550 // Characters 0x000 - 0x100: normal chars, may need CTRL-V, 1551 // except K_SPECIAL: Becomes K_SPECIAL KS_SPECIAL KE_FILLER 1552 // Characters where IS_SPECIAL() == true: key codes, need 1553 // K_SPECIAL. Other characters (with ABBR_OFF): don't use CTRL-V. 1554 // 1555 // Character CTRL-] is treated specially - it completes the 1556 // abbreviation, but is not inserted into the input stream. 1557 int j = 0; 1558 if (c != Ctrl_RSB) { 1559 // special key code, split up 1560 if (IS_SPECIAL(c) || c == K_SPECIAL) { 1561 tb[j++] = K_SPECIAL; 1562 tb[j++] = (uint8_t)K_SECOND(c); 1563 tb[j++] = (uint8_t)K_THIRD(c); 1564 } else { 1565 if (c < ABBR_OFF && (c < ' ' || c > '~')) { 1566 tb[j++] = Ctrl_V; // special char needs CTRL-V 1567 } 1568 // if ABBR_OFF has been added, remove it here. 1569 if (c >= ABBR_OFF) { 1570 c -= ABBR_OFF; 1571 } 1572 int newlen = utf_char2bytes(c, (char *)tb + j); 1573 tb[j + newlen] = NUL; 1574 // Need to escape K_SPECIAL. 1575 char *escaped = vim_strsave_escape_ks((char *)tb + j); 1576 if (escaped != NULL) { 1577 newlen = (int)strlen(escaped); 1578 memmove(tb + j, escaped, (size_t)newlen); 1579 j += newlen; 1580 xfree(escaped); 1581 } 1582 } 1583 tb[j] = NUL; 1584 // insert the last typed char 1585 ins_typebuf((char *)tb, 1, 0, true, mp->m_silent); 1586 } 1587 1588 // copy values here, calling eval_map_expr() may make "mp" invalid! 1589 const int noremap = mp->m_noremap; 1590 const bool silent = mp->m_silent; 1591 const bool expr = mp->m_expr; 1592 1593 char *s; 1594 if (expr) { 1595 s = eval_map_expr(mp, c); 1596 } else { 1597 s = mp->m_str; 1598 } 1599 if (s != NULL) { 1600 // insert the to string 1601 ins_typebuf(s, noremap, 0, true, silent); 1602 // no abbrev. for these chars 1603 typebuf.tb_no_abbr_cnt += (int)strlen(s) + j + 1; 1604 if (expr) { 1605 xfree(s); 1606 } 1607 } 1608 1609 tb[0] = Ctrl_H; 1610 tb[1] = NUL; 1611 len = clen; // Delete characters instead of bytes 1612 while (len-- > 0) { // delete the from string 1613 ins_typebuf((char *)tb, 1, 0, true, silent); 1614 } 1615 return true; 1616 } 1617 } 1618 return false; 1619 } 1620 1621 /// Evaluate the RHS of a mapping or abbreviations and take care of escaping 1622 /// special characters. 1623 /// Careful: after this "mp" will be invalid if the mapping was deleted. 1624 /// 1625 /// @param c NUL or typed character for abbreviation 1626 char *eval_map_expr(mapblock_T *mp, int c) 1627 { 1628 char *p = NULL; 1629 char *expr = NULL; 1630 1631 // Remove escaping of K_SPECIAL, because "str" is in a format to be used as 1632 // typeahead. 1633 if (mp->m_luaref == LUA_NOREF) { 1634 expr = xstrdup(mp->m_str); 1635 vim_unescape_ks(expr); 1636 } 1637 1638 const bool replace_keycodes = mp->m_replace_keycodes; 1639 1640 // Forbid changing text or using ":normal" to avoid most of the bad side 1641 // effects. Also restore the cursor position. 1642 expr_map_lock++; 1643 set_vim_var_char(c); // set v:char to the typed character 1644 const pos_T save_cursor = curwin->w_cursor; 1645 const int save_msg_col = msg_col; 1646 const int save_msg_row = msg_row; 1647 if (mp->m_luaref != LUA_NOREF) { 1648 Error err = ERROR_INIT; 1649 Array args = ARRAY_DICT_INIT; 1650 Object ret = nlua_call_ref(mp->m_luaref, NULL, args, kRetObject, NULL, &err); 1651 if (ret.type == kObjectTypeString) { 1652 p = string_to_cstr(ret.data.string); 1653 } 1654 api_free_object(ret); 1655 if (ERROR_SET(&err)) { 1656 semsg_multiline("emsg", "E5108: %s", err.msg); 1657 api_clear_error(&err); 1658 } 1659 } else { 1660 p = eval_to_string(expr, false, false); 1661 xfree(expr); 1662 } 1663 expr_map_lock--; 1664 curwin->w_cursor = save_cursor; 1665 msg_col = save_msg_col; 1666 msg_row = save_msg_row; 1667 1668 if (p == NULL) { 1669 return NULL; 1670 } 1671 1672 char *res = NULL; 1673 1674 if (replace_keycodes) { 1675 replace_termcodes(p, strlen(p), &res, 0, REPTERM_DO_LT, NULL, p_cpo); 1676 } else { 1677 // Escape K_SPECIAL in the result to be able to use the string as typeahead. 1678 res = vim_strsave_escape_ks(p); 1679 } 1680 xfree(p); 1681 1682 return res; 1683 } 1684 1685 /// Write map commands for the current mappings to an .exrc file. 1686 /// Return FAIL on error, OK otherwise. 1687 /// 1688 /// @param buf buffer for local mappings or NULL 1689 int makemap(FILE *fd, buf_T *buf) 1690 { 1691 bool did_cpo = false; 1692 1693 // Do the loop twice: Once for mappings, once for abbreviations. 1694 // Then loop over all map hash lists. 1695 for (int abbr = 0; abbr < 2; abbr++) { 1696 for (int hash = 0; hash < 256; hash++) { 1697 mapblock_T *mp; 1698 if (abbr) { 1699 if (hash > 0) { // there is only one abbr list 1700 break; 1701 } 1702 if (buf != NULL) { 1703 mp = buf->b_first_abbr; 1704 } else { 1705 mp = first_abbr; 1706 } 1707 } else { 1708 if (buf != NULL) { 1709 mp = buf->b_maphash[hash]; 1710 } else { 1711 mp = maphash[hash]; 1712 } 1713 } 1714 1715 for (; mp; mp = mp->m_next) { 1716 // skip script-local mappings 1717 if (mp->m_noremap == REMAP_SCRIPT) { 1718 continue; 1719 } 1720 1721 // skip Lua mappings and mappings that contain a <SNR> (script-local thing), 1722 // they probably don't work when loaded again 1723 if (mp->m_luaref != LUA_NOREF) { 1724 continue; 1725 } 1726 char *p; 1727 for (p = mp->m_str; *p != NUL; p++) { 1728 if ((uint8_t)p[0] == K_SPECIAL && (uint8_t)p[1] == KS_EXTRA 1729 && p[2] == KE_SNR) { 1730 break; 1731 } 1732 } 1733 if (*p != NUL) { 1734 continue; 1735 } 1736 1737 // It's possible to create a mapping and then ":unmap" certain 1738 // modes. We recreate this here by mapping the individual 1739 // modes, which requires up to three of them. 1740 char c1 = NUL; 1741 char c2 = NUL; 1742 char c3 = NUL; 1743 char *cmd = abbr ? "abbr" : "map"; 1744 switch (mp->m_mode) { 1745 case MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING: 1746 break; 1747 case MODE_NORMAL: 1748 c1 = 'n'; 1749 break; 1750 case MODE_VISUAL: 1751 c1 = 'x'; 1752 break; 1753 case MODE_SELECT: 1754 c1 = 's'; 1755 break; 1756 case MODE_OP_PENDING: 1757 c1 = 'o'; 1758 break; 1759 case MODE_NORMAL | MODE_VISUAL: 1760 c1 = 'n'; 1761 c2 = 'x'; 1762 break; 1763 case MODE_NORMAL | MODE_SELECT: 1764 c1 = 'n'; 1765 c2 = 's'; 1766 break; 1767 case MODE_NORMAL | MODE_OP_PENDING: 1768 c1 = 'n'; 1769 c2 = 'o'; 1770 break; 1771 case MODE_VISUAL | MODE_SELECT: 1772 c1 = 'v'; 1773 break; 1774 case MODE_VISUAL | MODE_OP_PENDING: 1775 c1 = 'x'; 1776 c2 = 'o'; 1777 break; 1778 case MODE_SELECT | MODE_OP_PENDING: 1779 c1 = 's'; 1780 c2 = 'o'; 1781 break; 1782 case MODE_NORMAL | MODE_VISUAL | MODE_SELECT: 1783 c1 = 'n'; 1784 c2 = 'v'; 1785 break; 1786 case MODE_NORMAL | MODE_VISUAL | MODE_OP_PENDING: 1787 c1 = 'n'; 1788 c2 = 'x'; 1789 c3 = 'o'; 1790 break; 1791 case MODE_NORMAL | MODE_SELECT | MODE_OP_PENDING: 1792 c1 = 'n'; 1793 c2 = 's'; 1794 c3 = 'o'; 1795 break; 1796 case MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING: 1797 c1 = 'v'; 1798 c2 = 'o'; 1799 break; 1800 case MODE_CMDLINE | MODE_INSERT: 1801 if (!abbr) { 1802 cmd = "map!"; 1803 } 1804 break; 1805 case MODE_CMDLINE: 1806 c1 = 'c'; 1807 break; 1808 case MODE_INSERT: 1809 c1 = 'i'; 1810 break; 1811 case MODE_LANGMAP: 1812 c1 = 'l'; 1813 break; 1814 case MODE_TERMINAL: 1815 c1 = 't'; 1816 break; 1817 default: 1818 iemsg(_("E228: makemap: Illegal mode")); 1819 return FAIL; 1820 } 1821 do { // do this twice if c2 is set, 3 times with c3 1822 // When outputting <> form, need to make sure that 'cpo' 1823 // is set to the Vim default. 1824 if (!did_cpo) { 1825 if (*mp->m_str == NUL) { // Will use <Nop>. 1826 did_cpo = true; 1827 } else { 1828 const char specials[] = { (char)(uint8_t)K_SPECIAL, NL, NUL }; 1829 if (strpbrk(mp->m_str, specials) != NULL || strpbrk(mp->m_keys, specials) != NULL) { 1830 did_cpo = true; 1831 } 1832 } 1833 if (did_cpo) { 1834 if (fprintf(fd, "let s:cpo_save=&cpo") < 0 1835 || put_eol(fd) < 0 1836 || fprintf(fd, "set cpo&vim") < 0 1837 || put_eol(fd) < 0) { 1838 return FAIL; 1839 } 1840 } 1841 } 1842 if (c1 && putc(c1, fd) < 0) { 1843 return FAIL; 1844 } 1845 if (mp->m_noremap != REMAP_YES && fprintf(fd, "nore") < 0) { 1846 return FAIL; 1847 } 1848 if (fputs(cmd, fd) < 0) { 1849 return FAIL; 1850 } 1851 if (buf != NULL && fputs(" <buffer>", fd) < 0) { 1852 return FAIL; 1853 } 1854 if (mp->m_nowait && fputs(" <nowait>", fd) < 0) { 1855 return FAIL; 1856 } 1857 if (mp->m_silent && fputs(" <silent>", fd) < 0) { 1858 return FAIL; 1859 } 1860 if (mp->m_expr && fputs(" <expr>", fd) < 0) { 1861 return FAIL; 1862 } 1863 1864 if (putc(' ', fd) < 0 1865 || put_escstr(fd, mp->m_keys, 0) == FAIL 1866 || putc(' ', fd) < 0 1867 || put_escstr(fd, mp->m_str, 1) == FAIL 1868 || put_eol(fd) < 0) { 1869 return FAIL; 1870 } 1871 c1 = c2; 1872 c2 = c3; 1873 c3 = NUL; 1874 } while (c1 != NUL); 1875 } 1876 } 1877 } 1878 if (did_cpo) { 1879 if (fprintf(fd, "let &cpo=s:cpo_save") < 0 1880 || put_eol(fd) < 0 1881 || fprintf(fd, "unlet s:cpo_save") < 0 1882 || put_eol(fd) < 0) { 1883 return FAIL; 1884 } 1885 } 1886 return OK; 1887 } 1888 1889 // write escape string to file 1890 // "what": 0 for :map lhs, 1 for :map rhs, 2 for :set 1891 // 1892 // return FAIL for failure, OK otherwise 1893 int put_escstr(FILE *fd, const char *strstart, int what) 1894 { 1895 uint8_t *str = (uint8_t *)strstart; 1896 1897 // :map xx <Nop> 1898 if (*str == NUL && what == 1) { 1899 if (fprintf(fd, "<Nop>") < 0) { 1900 return FAIL; 1901 } 1902 return OK; 1903 } 1904 1905 for (; *str != NUL; str++) { 1906 // Check for a multi-byte character, which may contain escaped 1907 // K_SPECIAL bytes. 1908 const char *p = mb_unescape((const char **)&str); 1909 if (p != NULL) { 1910 while (*p != NUL) { 1911 if (fputc(*p++, fd) < 0) { 1912 return FAIL; 1913 } 1914 } 1915 str--; 1916 continue; 1917 } 1918 1919 int c = *str; 1920 // Special key codes have to be translated to be able to make sense 1921 // when they are read back. 1922 if (c == K_SPECIAL && what != 2) { 1923 int modifiers = 0; 1924 if (str[1] == KS_MODIFIER) { 1925 modifiers = str[2]; 1926 str += 3; 1927 1928 // Modifiers can be applied too to multi-byte characters. 1929 p = mb_unescape((const char **)&str); 1930 1931 if (p == NULL) { 1932 c = *str; 1933 } else { 1934 // retrieve codepoint (character number) from unescaped string 1935 c = utf_ptr2char(p); 1936 str--; 1937 } 1938 } 1939 if (c == K_SPECIAL) { 1940 c = TO_SPECIAL(str[1], str[2]); 1941 str += 2; 1942 } 1943 if (IS_SPECIAL(c) || modifiers) { // special key 1944 if (fputs(get_special_key_name(c, modifiers), fd) < 0) { 1945 return FAIL; 1946 } 1947 continue; 1948 } 1949 } 1950 1951 // A '\n' in a map command should be written as <NL>. 1952 // A '\n' in a set command should be written as \^V^J. 1953 if (c == NL) { 1954 if (what == 2) { 1955 if (fprintf(fd, "\\\026\n") < 0) { 1956 return FAIL; 1957 } 1958 } else { 1959 if (fprintf(fd, "<NL>") < 0) { 1960 return FAIL; 1961 } 1962 } 1963 continue; 1964 } 1965 1966 // Some characters have to be escaped with CTRL-V to 1967 // prevent them from misinterpreted in DoOneCmd(). 1968 // A space, Tab and '"' has to be escaped with a backslash to 1969 // prevent it to be misinterpreted in do_set(). 1970 // A space has to be escaped with a CTRL-V when it's at the start of a 1971 // ":map" rhs. 1972 // A '<' has to be escaped with a CTRL-V to prevent it being 1973 // interpreted as the start of a special key name. 1974 // A space in the lhs of a :map needs a CTRL-V. 1975 if (what == 2 && (ascii_iswhite(c) || c == '"' || c == '\\')) { 1976 if (putc('\\', fd) < 0) { 1977 return FAIL; 1978 } 1979 } else if (c < ' ' || c > '~' || c == '|' 1980 || (what == 0 && c == ' ') 1981 || (what == 1 && str == (uint8_t *)strstart && c == ' ') 1982 || (what != 2 && c == '<')) { 1983 if (putc(Ctrl_V, fd) < 0) { 1984 return FAIL; 1985 } 1986 } 1987 if (putc(c, fd) < 0) { 1988 return FAIL; 1989 } 1990 } 1991 return OK; 1992 } 1993 1994 /// Check the string "keys" against the lhs of all mappings. 1995 /// Return pointer to rhs of mapping (mapblock->m_str). 1996 /// NULL when no mapping found. 1997 /// 1998 /// @param exact require exact match 1999 /// @param ign_mod ignore preceding modifier 2000 /// @param abbr do abbreviations 2001 /// @param mp_ptr return: pointer to mapblock or NULL 2002 /// @param local_ptr return: buffer-local mapping or NULL 2003 char *check_map(char *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, 2004 int *local_ptr, int *rhs_lua) 2005 { 2006 *rhs_lua = LUA_NOREF; 2007 2008 int len = (int)strlen(keys); 2009 for (int local = 1; local >= 0; local--) { 2010 // loop over all hash lists 2011 for (int hash = 0; hash < 256; hash++) { 2012 mapblock_T *mp; 2013 if (abbr) { 2014 if (hash > 0) { // there is only one list. 2015 break; 2016 } 2017 if (local) { 2018 mp = curbuf->b_first_abbr; 2019 } else { 2020 mp = first_abbr; 2021 } 2022 } else if (local) { 2023 mp = curbuf->b_maphash[hash]; 2024 } else { 2025 mp = maphash[hash]; 2026 } 2027 for (; mp != NULL; mp = mp->m_next) { 2028 // skip entries with wrong mode, wrong length and not matching ones 2029 if ((mp->m_mode & mode) && (!exact || mp->m_keylen == len)) { 2030 char *s = mp->m_keys; 2031 int keylen = mp->m_keylen; 2032 if (ign_mod && keylen >= 3 2033 && (uint8_t)s[0] == K_SPECIAL && (uint8_t)s[1] == KS_MODIFIER) { 2034 s += 3; 2035 keylen -= 3; 2036 } 2037 int minlen = keylen < len ? keylen : len; 2038 if (strncmp(s, keys, (size_t)minlen) == 0) { 2039 if (mp_ptr != NULL) { 2040 *mp_ptr = mp; 2041 } 2042 if (local_ptr != NULL) { 2043 *local_ptr = local; 2044 } 2045 *rhs_lua = mp->m_luaref; 2046 return mp->m_luaref == LUA_NOREF ? mp->m_str : NULL; 2047 } 2048 } 2049 } 2050 } 2051 } 2052 2053 return NULL; 2054 } 2055 2056 /// "hasmapto()" function 2057 void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 2058 { 2059 const char *mode; 2060 const char *const name = tv_get_string(&argvars[0]); 2061 bool abbr = false; 2062 char buf[NUMBUFLEN]; 2063 if (argvars[1].v_type == VAR_UNKNOWN) { 2064 mode = "nvo"; 2065 } else { 2066 mode = tv_get_string_buf(&argvars[1], buf); 2067 if (argvars[2].v_type != VAR_UNKNOWN) { 2068 abbr = tv_get_number(&argvars[2]); 2069 } 2070 } 2071 2072 rettv->vval.v_number = map_to_exists(name, mode, abbr); 2073 } 2074 2075 /// Fill a Dict with all applicable maparg() like dictionaries 2076 /// 2077 /// @param mp The maphash that contains the mapping information 2078 /// @param buffer_value The "buffer" value 2079 /// @param abbr True if abbreviation 2080 /// @param compatible True for compatible with old maparg() dict 2081 /// 2082 /// @return Dict. 2083 static Dict mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt, 2084 const int buffer_value, const bool abbr, const bool compatible, 2085 Arena *arena) 2086 FUNC_ATTR_NONNULL_ARG(1) 2087 { 2088 Dict dict = arena_dict(arena, 19); 2089 char *const lhs = str2special_arena(mp->m_keys, compatible, !compatible, arena); 2090 char *mapmode = arena_alloc(arena, 7, false); 2091 map_mode_to_chars(mp->m_mode, mapmode); 2092 int noremap_value; 2093 2094 if (compatible) { 2095 // Keep old compatible behavior 2096 // This is unable to determine whether a mapping is a <script> mapping 2097 noremap_value = !!mp->m_noremap; 2098 } else { 2099 // Distinguish between <script> mapping 2100 // If it's not a <script> mapping, check if it's a noremap 2101 noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap; 2102 } 2103 2104 if (mp->m_luaref != LUA_NOREF) { 2105 PUT_C(dict, "callback", LUAREF_OBJ(api_new_luaref(mp->m_luaref))); 2106 } else { 2107 String rhs = cstr_as_string(compatible 2108 ? mp->m_orig_str 2109 : str2special_arena(mp->m_str, false, true, arena)); 2110 PUT_C(dict, "rhs", STRING_OBJ(rhs)); 2111 } 2112 if (mp->m_desc != NULL) { 2113 PUT_C(dict, "desc", CSTR_AS_OBJ(mp->m_desc)); 2114 } 2115 PUT_C(dict, "lhs", CSTR_AS_OBJ(lhs)); 2116 PUT_C(dict, "lhsraw", CSTR_AS_OBJ(mp->m_keys)); 2117 if (lhsrawalt != NULL) { 2118 // Also add the value for the simplified entry. 2119 PUT_C(dict, "lhsrawalt", CSTR_AS_OBJ(lhsrawalt)); 2120 } 2121 PUT_C(dict, "noremap", INTEGER_OBJ(noremap_value)); 2122 PUT_C(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0)); 2123 PUT_C(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0)); 2124 PUT_C(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0)); 2125 PUT_C(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid)); 2126 PUT_C(dict, "scriptversion", INTEGER_OBJ(1)); 2127 PUT_C(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum)); 2128 PUT_C(dict, "buffer", INTEGER_OBJ(buffer_value)); 2129 PUT_C(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0)); 2130 PUT_C(dict, "replace_keycodes", INTEGER_OBJ(mp->m_replace_keycodes ? 1 : 0)); 2131 PUT_C(dict, "mode", CSTR_AS_OBJ(mapmode)); 2132 PUT_C(dict, "abbr", INTEGER_OBJ(abbr ? 1 : 0)); 2133 PUT_C(dict, "mode_bits", INTEGER_OBJ(mp->m_mode)); 2134 2135 return dict; 2136 } 2137 2138 static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) 2139 { 2140 // Return empty string for failure. 2141 rettv->v_type = VAR_STRING; 2142 rettv->vval.v_string = NULL; 2143 2144 char *keys = (char *)tv_get_string(&argvars[0]); 2145 if (*keys == NUL) { 2146 return; 2147 } 2148 2149 const char *which; 2150 char buf[NUMBUFLEN]; 2151 bool abbr = false; 2152 bool get_dict = false; 2153 2154 if (argvars[1].v_type != VAR_UNKNOWN) { 2155 which = tv_get_string_buf_chk(&argvars[1], buf); 2156 if (argvars[2].v_type != VAR_UNKNOWN) { 2157 abbr = (bool)tv_get_number(&argvars[2]); 2158 if (argvars[3].v_type != VAR_UNKNOWN) { 2159 get_dict = (bool)tv_get_number(&argvars[3]); 2160 } 2161 } 2162 } else { 2163 which = ""; 2164 } 2165 if (which == NULL) { 2166 return; 2167 } 2168 2169 char *keys_buf = NULL; 2170 char *alt_keys_buf = NULL; 2171 bool did_simplify = false; 2172 const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; 2173 const int mode = get_map_mode((char **)&which, 0); 2174 2175 char *keys_simplified = replace_termcodes(keys, strlen(keys), &keys_buf, 0, 2176 flags, &did_simplify, p_cpo); 2177 mapblock_T *mp = NULL; 2178 int buffer_local; 2179 LuaRef rhs_lua; 2180 char *rhs = check_map(keys_simplified, mode, exact, false, abbr, &mp, &buffer_local, 2181 &rhs_lua); 2182 if (did_simplify) { 2183 // When the lhs is being simplified the not-simplified keys are 2184 // preferred for printing, like in do_map(). 2185 replace_termcodes(keys, strlen(keys), &alt_keys_buf, 0, 2186 flags | REPTERM_NO_SIMPLIFY, NULL, p_cpo); 2187 rhs = check_map(alt_keys_buf, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua); 2188 } 2189 2190 if (!get_dict) { 2191 // Return a string. 2192 if (rhs != NULL) { 2193 if (*rhs == NUL) { 2194 rettv->vval.v_string = xstrdup("<Nop>"); 2195 } else { 2196 rettv->vval.v_string = str2special_save(rhs, false, false); 2197 } 2198 } else if (rhs_lua != LUA_NOREF) { 2199 rettv->vval.v_string = nlua_funcref_str(mp->m_luaref, NULL); 2200 } 2201 } else { 2202 // Return a dictionary. 2203 if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) { 2204 Arena arena = ARENA_EMPTY; 2205 Dict dict = mapblock_fill_dict(mp, did_simplify ? keys_simplified : NULL, 2206 buffer_local, abbr, true, &arena); 2207 object_to_vim_take_luaref(&DICT_OBJ(dict), rettv, true, NULL); 2208 arena_mem_free(arena_finish(&arena)); 2209 } else { 2210 // Return an empty dictionary. 2211 tv_dict_alloc_ret(rettv); 2212 } 2213 } 2214 2215 xfree(keys_buf); 2216 xfree(alt_keys_buf); 2217 } 2218 2219 /// Get the mapping mode from the mode string. 2220 /// It may contain multiple characters, eg "nox", or "!", or ' ' 2221 /// Return 0 if there is an error. 2222 static int get_map_mode_string(const char *const mode_string, const bool abbr) 2223 { 2224 const char *p = mode_string; 2225 const int MASK_V = MODE_VISUAL | MODE_SELECT; 2226 const int MASK_MAP = MODE_VISUAL | MODE_SELECT | MODE_NORMAL | MODE_OP_PENDING; 2227 const int MASK_BANG = MODE_INSERT | MODE_CMDLINE; 2228 2229 if (*p == NUL) { 2230 p = " "; // compatibility 2231 } 2232 int mode = 0; 2233 int modec; 2234 while ((modec = (uint8_t)(*p++))) { 2235 int tmode; 2236 switch (modec) { 2237 case 'i': 2238 tmode = MODE_INSERT; break; 2239 case 'l': 2240 tmode = MODE_LANGMAP; break; 2241 case 'c': 2242 tmode = MODE_CMDLINE; break; 2243 case 'n': 2244 tmode = MODE_NORMAL; break; 2245 case 'x': 2246 tmode = MODE_VISUAL; break; 2247 case 's': 2248 tmode = MODE_SELECT; break; 2249 case 'o': 2250 tmode = MODE_OP_PENDING; break; 2251 case 't': 2252 tmode = MODE_TERMINAL; break; 2253 case 'v': 2254 tmode = MASK_V; break; 2255 case '!': 2256 tmode = MASK_BANG; break; 2257 case ' ': 2258 tmode = MASK_MAP; break; 2259 default: 2260 return 0; // error, unknown mode character 2261 } 2262 mode |= tmode; 2263 } 2264 if ((abbr && (mode & ~MASK_BANG) != 0) 2265 || (!abbr && (mode & (mode - 1)) != 0 // more than one bit set 2266 && ( 2267 // false if multiple bits set in mode and mode is fully 2268 // contained in one mask 2269 !(((mode & MASK_BANG) != 0 && (mode & ~MASK_BANG) == 0) 2270 || ((mode & MASK_MAP) != 0 && (mode & ~MASK_MAP) == 0))))) { 2271 return 0; 2272 } 2273 2274 return mode; 2275 } 2276 2277 /// "mapset()" function 2278 void f_mapset(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 2279 { 2280 const char *which; 2281 char buf[NUMBUFLEN]; 2282 int is_abbr; 2283 dict_T *d; 2284 2285 // If first arg is a dict, then that's the only arg permitted. 2286 const bool dict_only = argvars[0].v_type == VAR_DICT; 2287 2288 if (dict_only) { 2289 d = argvars[0].vval.v_dict; 2290 which = tv_dict_get_string(d, "mode", false); 2291 is_abbr = (int)tv_dict_get_bool(d, "abbr", -1); 2292 if (which == NULL || is_abbr < 0) { 2293 emsg(_(e_entries_missing_in_mapset_dict_argument)); 2294 return; 2295 } 2296 } else { 2297 which = tv_get_string_buf_chk(&argvars[0], buf); 2298 if (which == NULL) { 2299 return; 2300 } 2301 is_abbr = (int)tv_get_bool(&argvars[1]); 2302 if (tv_check_for_dict_arg(argvars, 2) == FAIL) { 2303 return; 2304 } 2305 d = argvars[2].vval.v_dict; 2306 } 2307 const int mode = get_map_mode_string(which, is_abbr); 2308 if (mode == 0) { 2309 semsg(_(e_illegal_map_mode_string_str), which); 2310 return; 2311 } 2312 2313 // Get the values in the same order as above in get_maparg(). 2314 char *lhs = tv_dict_get_string(d, "lhs", false); 2315 char *lhsraw = tv_dict_get_string(d, "lhsraw", false); 2316 char *lhsrawalt = tv_dict_get_string(d, "lhsrawalt", false); 2317 char *orig_rhs = tv_dict_get_string(d, "rhs", false); 2318 LuaRef rhs_lua = LUA_NOREF; 2319 dictitem_T *callback_di = tv_dict_find(d, S_LEN("callback")); 2320 if (callback_di != NULL) { 2321 if (callback_di->di_tv.v_type == VAR_FUNC) { 2322 ufunc_T *fp = find_func(callback_di->di_tv.vval.v_string); 2323 if (fp != NULL && (fp->uf_flags & FC_LUAREF)) { 2324 rhs_lua = api_new_luaref(fp->uf_luaref); 2325 orig_rhs = ""; 2326 } 2327 } 2328 } 2329 if (lhs == NULL || lhsraw == NULL || orig_rhs == NULL) { 2330 emsg(_(e_entries_missing_in_mapset_dict_argument)); 2331 api_free_luaref(rhs_lua); 2332 return; 2333 } 2334 2335 int noremap = tv_dict_get_number(d, "noremap") != 0 ? REMAP_NONE : 0; 2336 if (tv_dict_get_number(d, "script") != 0) { 2337 noremap = REMAP_SCRIPT; 2338 } 2339 MapArguments args = { 2340 .expr = tv_dict_get_number(d, "expr") != 0, 2341 .silent = tv_dict_get_number(d, "silent") != 0, 2342 .nowait = tv_dict_get_number(d, "nowait") != 0, 2343 .replace_keycodes = tv_dict_get_number(d, "replace_keycodes") != 0, 2344 .desc = tv_dict_get_string(d, "desc", true), 2345 }; 2346 scid_T sid = (scid_T)tv_dict_get_number(d, "sid"); 2347 linenr_T lnum = (linenr_T)tv_dict_get_number(d, "lnum"); 2348 bool buffer = tv_dict_get_number(d, "buffer") != 0; 2349 // mode from the dict is not used 2350 2351 set_maparg_rhs(orig_rhs, strlen(orig_rhs), rhs_lua, sid, p_cpo, &args); 2352 2353 mapblock_T **map_table = buffer ? curbuf->b_maphash : maphash; 2354 mapblock_T **abbr_table = buffer ? &curbuf->b_first_abbr : &first_abbr; 2355 2356 // Delete any existing mapping for this lhs and mode. 2357 MapArguments unmap_args = MAP_ARGUMENTS_INIT; 2358 set_maparg_lhs_rhs(lhs, strlen(lhs), "", 0, LUA_NOREF, p_cpo, &unmap_args); 2359 unmap_args.buffer = buffer; 2360 buf_do_map(MAPTYPE_UNMAP_LHS, &unmap_args, mode, is_abbr, curbuf); 2361 xfree(unmap_args.rhs); 2362 xfree(unmap_args.orig_rhs); 2363 2364 mapblock_T *mp_result[2] = { NULL, NULL }; 2365 2366 mp_result[0] = map_add(curbuf, map_table, abbr_table, lhsraw, &args, 2367 noremap, mode, is_abbr, sid, lnum, false); 2368 if (lhsrawalt != NULL) { 2369 mp_result[1] = map_add(curbuf, map_table, abbr_table, lhsrawalt, &args, 2370 noremap, mode, is_abbr, sid, lnum, true); 2371 } 2372 2373 if (mp_result[0] != NULL && mp_result[1] != NULL) { 2374 mp_result[0]->m_alt = mp_result[1]; 2375 mp_result[1]->m_alt = mp_result[0]; 2376 } 2377 } 2378 2379 /// "maplist()" function 2380 void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 2381 { 2382 const int flags = REPTERM_FROM_PART | REPTERM_DO_LT; 2383 const bool abbr = argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]); 2384 2385 tv_list_alloc_ret(rettv, kListLenUnknown); 2386 2387 // Do it twice: once for global maps and once for local maps. 2388 for (int buffer_local = 0; buffer_local <= 1; buffer_local++) { 2389 for (int hash = 0; hash < 256; hash++) { 2390 mapblock_T *mp; 2391 if (abbr) { 2392 if (hash > 0) { // there is only one abbr list 2393 break; 2394 } 2395 if (buffer_local) { 2396 mp = curbuf->b_first_abbr; 2397 } else { 2398 mp = first_abbr; 2399 } 2400 } else if (buffer_local) { 2401 mp = curbuf->b_maphash[hash]; 2402 } else { 2403 mp = maphash[hash]; 2404 } 2405 for (; mp; mp = mp->m_next) { 2406 if (mp->m_simplified) { 2407 continue; 2408 } 2409 2410 char *keys_buf = NULL; 2411 bool did_simplify = false; 2412 2413 Arena arena = ARENA_EMPTY; 2414 char *lhs = str2special_arena(mp->m_keys, true, false, &arena); 2415 replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify, 2416 p_cpo); 2417 2418 Dict dict = mapblock_fill_dict(mp, did_simplify ? keys_buf : NULL, buffer_local, abbr, true, 2419 &arena); 2420 typval_T d = TV_INITIAL_VALUE; 2421 object_to_vim_take_luaref(&DICT_OBJ(dict), &d, true, NULL); 2422 assert(d.v_type == VAR_DICT); 2423 tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict); 2424 arena_mem_free(arena_finish(&arena)); 2425 xfree(keys_buf); 2426 } 2427 } 2428 } 2429 } 2430 2431 /// "maparg()" function 2432 void f_maparg(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 2433 { 2434 get_maparg(argvars, rettv, true); 2435 } 2436 2437 /// "mapcheck()" function 2438 void f_mapcheck(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 2439 { 2440 get_maparg(argvars, rettv, false); 2441 } 2442 2443 /// Add a mapping. Unlike @ref do_map this copies the string arguments, so 2444 /// static or read-only strings can be used. 2445 /// 2446 /// @param lhs C-string containing the lhs of the mapping 2447 /// @param rhs C-string containing the rhs of the mapping 2448 /// @param mode Bitflags representing the mode in which to set the mapping. 2449 /// See @ref get_map_mode. 2450 /// @param buffer If true, make a buffer-local mapping for curbuf 2451 void add_map(char *lhs, char *rhs, int mode, bool buffer) 2452 { 2453 MapArguments args = MAP_ARGUMENTS_INIT; 2454 set_maparg_lhs_rhs(lhs, strlen(lhs), rhs, strlen(rhs), LUA_NOREF, p_cpo, &args); 2455 args.buffer = buffer; 2456 2457 buf_do_map(MAPTYPE_NOREMAP, &args, mode, false, curbuf); 2458 xfree(args.rhs); 2459 xfree(args.orig_rhs); 2460 } 2461 2462 /// Any character has an equivalent 'langmap' character. This is used for 2463 /// keyboards that have a special language mode that sends characters above 2464 /// 128 (although other characters can be translated too). The "to" field is a 2465 /// Vim command character. This avoids having to switch the keyboard back to 2466 /// ASCII mode when leaving Insert mode. 2467 /// 2468 /// langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim 2469 /// commands. 2470 /// langmap_mapga.ga_data is a sorted table of langmap_entry_T. 2471 /// This does the same as langmap_mapchar[] for characters >= 256. 2472 /// 2473 /// With multi-byte support use growarray for 'langmap' chars >= 256 2474 typedef struct { 2475 int from; 2476 int to; 2477 } langmap_entry_T; 2478 2479 static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE; 2480 2481 /// Search for an entry in "langmap_mapga" for "from". If found set the "to" 2482 /// field. If not found insert a new entry at the appropriate location. 2483 static void langmap_set_entry(int from, int to) 2484 { 2485 langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); 2486 unsigned a = 0; 2487 assert(langmap_mapga.ga_len >= 0); 2488 unsigned b = (unsigned)langmap_mapga.ga_len; 2489 2490 // Do a binary search for an existing entry. 2491 while (a != b) { 2492 unsigned i = (a + b) / 2; 2493 int d = entries[i].from - from; 2494 2495 if (d == 0) { 2496 entries[i].to = to; 2497 return; 2498 } 2499 if (d < 0) { 2500 a = i + 1; 2501 } else { 2502 b = i; 2503 } 2504 } 2505 2506 ga_grow(&langmap_mapga, 1); 2507 2508 // insert new entry at position "a" 2509 entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a; 2510 memmove(entries + 1, entries, 2511 ((unsigned)langmap_mapga.ga_len - a) * sizeof(langmap_entry_T)); 2512 langmap_mapga.ga_len++; 2513 entries[0].from = from; 2514 entries[0].to = to; 2515 } 2516 2517 /// Apply 'langmap' to multi-byte character "c" and return the result. 2518 int langmap_adjust_mb(int c) 2519 { 2520 langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); 2521 int a = 0; 2522 int b = langmap_mapga.ga_len; 2523 2524 while (a != b) { 2525 int i = (a + b) / 2; 2526 int d = entries[i].from - c; 2527 2528 if (d == 0) { 2529 return entries[i].to; // found matching entry 2530 } 2531 if (d < 0) { 2532 a = i + 1; 2533 } else { 2534 b = i; 2535 } 2536 } 2537 return c; // no entry found, return "c" unmodified 2538 } 2539 2540 void langmap_init(void) 2541 { 2542 for (int i = 0; i < 256; i++) { 2543 langmap_mapchar[i] = (uint8_t)i; // we init with a one-to-one map 2544 } 2545 ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8); 2546 } 2547 2548 /// Called when langmap option is set; the language map can be 2549 /// changed at any time! 2550 const char *did_set_langmap(optset_T *args) 2551 { 2552 ga_clear(&langmap_mapga); // clear the previous map first 2553 langmap_init(); // back to one-to-one map 2554 2555 for (char *p = p_langmap; p[0] != NUL;) { 2556 char *p2; 2557 for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';'; 2558 MB_PTR_ADV(p2)) { 2559 if (p2[0] == '\\' && p2[1] != NUL) { 2560 p2++; 2561 } 2562 } 2563 if (p2[0] == ';') { 2564 p2++; // abcd;ABCD form, p2 points to A 2565 } else { 2566 p2 = NULL; // aAbBcCdD form, p2 is NULL 2567 } 2568 while (p[0]) { 2569 if (p[0] == ',') { 2570 p++; 2571 break; 2572 } 2573 if (p[0] == '\\' && p[1] != NUL) { 2574 p++; 2575 } 2576 int from = utf_ptr2char(p); 2577 const char *const from_ptr = p; 2578 int to = NUL; 2579 const char *to_ptr = ""; 2580 if (p2 == NULL) { 2581 MB_PTR_ADV(p); 2582 if (p[0] != ',') { 2583 if (p[0] == '\\') { 2584 p++; 2585 } 2586 to = utf_ptr2char(to_ptr = p); 2587 } 2588 } else { 2589 if (p2[0] != ',') { 2590 if (p2[0] == '\\') { 2591 p2++; 2592 } 2593 to = utf_ptr2char(to_ptr = p2); 2594 } 2595 } 2596 if (to == NUL) { 2597 snprintf(args->os_errbuf, args->os_errbuflen, 2598 _("E357: 'langmap': Matching character missing for %s"), 2599 transchar(from)); 2600 return args->os_errbuf; 2601 } 2602 2603 if (from >= 256) { 2604 langmap_set_entry(from, to); 2605 } else { 2606 if (to > UCHAR_MAX) { 2607 swmsg(true, "'langmap': Mapping from %.*s to %.*s will not work properly", 2608 utf_ptr2len(from_ptr), from_ptr, utf_ptr2len(to_ptr), to_ptr); 2609 } 2610 langmap_mapchar[from & 255] = (uint8_t)to; 2611 } 2612 2613 // Advance to next pair 2614 MB_PTR_ADV(p); 2615 if (p2 != NULL) { 2616 MB_PTR_ADV(p2); 2617 if (*p == ';') { 2618 p = p2; 2619 if (p[0] != NUL) { 2620 if (p[0] != ',') { 2621 snprintf(args->os_errbuf, args->os_errbuflen, 2622 _("E358: 'langmap': Extra characters after semicolon: %s"), 2623 p); 2624 return args->os_errbuf; 2625 } 2626 p++; 2627 } 2628 break; 2629 } 2630 } 2631 } 2632 } 2633 2634 return NULL; 2635 } 2636 2637 static void do_exmap(exarg_T *eap, int isabbrev) 2638 { 2639 char *cmdp = eap->cmd; 2640 int mode = get_map_mode(&cmdp, eap->forceit || isabbrev); 2641 2642 int maptype; 2643 if (*cmdp == 'n') { 2644 maptype = MAPTYPE_NOREMAP; 2645 } else if (*cmdp == 'u') { 2646 maptype = MAPTYPE_UNMAP; 2647 } else { 2648 maptype = MAPTYPE_MAP; 2649 } 2650 MapArguments parsed_args; 2651 int result = str_to_mapargs(eap->arg, maptype == MAPTYPE_UNMAP, &parsed_args); 2652 switch (result) { 2653 case 0: 2654 break; 2655 case 1: 2656 emsg(_(e_invarg)); 2657 goto free_rhs; 2658 break; 2659 default: 2660 assert(false && "Unknown return code from str_to_mapargs!"); 2661 goto free_rhs; 2662 } 2663 switch (buf_do_map(maptype, &parsed_args, mode, isabbrev, curbuf)) { 2664 case 1: 2665 emsg(_(e_invarg)); 2666 break; 2667 case 2: 2668 emsg(isabbrev ? _(e_noabbr) : _(e_nomap)); 2669 break; 2670 case 5: 2671 semsg(isabbrev ? _(e_abbreviation_already_exists_for_str) 2672 : _(e_mapping_already_exists_for_str), 2673 parsed_args.lhs); 2674 break; 2675 case 6: 2676 semsg(isabbrev ? _(e_global_abbreviation_already_exists_for_str) 2677 : _(e_global_mapping_already_exists_for_str), 2678 parsed_args.lhs); 2679 } 2680 free_rhs: 2681 xfree(parsed_args.rhs); 2682 xfree(parsed_args.orig_rhs); 2683 } 2684 2685 /// ":abbreviate" and friends. 2686 void ex_abbreviate(exarg_T *eap) 2687 { 2688 do_exmap(eap, true); // almost the same as mapping 2689 } 2690 2691 /// ":map" and friends. 2692 void ex_map(exarg_T *eap) 2693 { 2694 // If we are in a secure mode we print the mappings for security reasons. 2695 if (secure) { 2696 secure = 2; 2697 msg_outtrans(eap->cmd, 0, false); 2698 msg_putchar('\n'); 2699 } 2700 do_exmap(eap, false); 2701 } 2702 2703 /// ":unmap" and friends. 2704 void ex_unmap(exarg_T *eap) 2705 { 2706 do_exmap(eap, false); 2707 } 2708 2709 /// ":mapclear" and friends. 2710 void ex_mapclear(exarg_T *eap) 2711 { 2712 do_mapclear(eap->cmd, eap->arg, eap->forceit, false); 2713 } 2714 2715 /// ":abclear" and friends. 2716 void ex_abclear(exarg_T *eap) 2717 { 2718 do_mapclear(eap->cmd, eap->arg, true, true); 2719 } 2720 2721 /// Set, tweak, or remove a mapping in a mode. Acts as the implementation for 2722 /// functions like @ref nvim_buf_set_keymap. 2723 /// 2724 /// Arguments are handled like @ref nvim_set_keymap unless noted. 2725 /// @param buffer Buffer handle for a specific buffer, or 0 for the current 2726 /// buffer, or -1 to signify global behavior ("all buffers") 2727 /// @param is_unmap When true, removes the mapping that matches {lhs}. 2728 void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mode, String lhs, 2729 String rhs, Dict(keymap) *opts, Error *err) 2730 { 2731 LuaRef lua_funcref = LUA_NOREF; 2732 bool global = (buffer == -1); 2733 if (global) { 2734 buffer = 0; 2735 } 2736 buf_T *target_buf = find_buffer_by_handle(buffer, err); 2737 2738 if (!target_buf) { 2739 return; 2740 } 2741 2742 const sctx_T save_current_sctx = api_set_sctx(channel_id); 2743 2744 MapArguments parsed_args = MAP_ARGUMENTS_INIT; 2745 if (opts) { 2746 parsed_args.nowait = opts->nowait; 2747 parsed_args.noremap = opts->noremap; 2748 parsed_args.silent = opts->silent; 2749 parsed_args.script = opts->script; 2750 parsed_args.expr = opts->expr; 2751 parsed_args.unique = opts->unique; 2752 parsed_args.replace_keycodes = opts->replace_keycodes; 2753 if (HAS_KEY(opts, keymap, callback)) { 2754 lua_funcref = opts->callback; 2755 opts->callback = LUA_NOREF; 2756 } 2757 if (HAS_KEY(opts, keymap, desc)) { 2758 parsed_args.desc = string_to_cstr(opts->desc); 2759 } 2760 } 2761 parsed_args.buffer = !global; 2762 2763 if (parsed_args.replace_keycodes && !parsed_args.expr) { 2764 api_set_error(err, kErrorTypeValidation, "\"replace_keycodes\" requires \"expr\""); 2765 goto fail_and_free; 2766 } 2767 2768 if (!set_maparg_lhs_rhs(lhs.data, lhs.size, 2769 rhs.data, rhs.size, lua_funcref, 2770 p_cpo, &parsed_args)) { 2771 api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data); 2772 goto fail_and_free; 2773 } 2774 2775 if (parsed_args.lhs_len > MAXMAPLEN || parsed_args.alt_lhs_len > MAXMAPLEN) { 2776 api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data); 2777 goto fail_and_free; 2778 } 2779 2780 char *p = mode.size > 0 ? mode.data : "m"; 2781 bool forceit = *p == '!'; 2782 // integer value of the mapping mode, to be passed to do_map() 2783 int mode_val = get_map_mode(&p, forceit); 2784 if (forceit) { 2785 assert(p == mode.data); 2786 p++; 2787 } 2788 bool is_abbrev = (mode_val & (MODE_INSERT | MODE_CMDLINE)) != 0 && *p == 'a'; 2789 if (is_abbrev) { 2790 p++; 2791 } 2792 if (mode.size > 0 && (size_t)(p - mode.data) != mode.size) { 2793 api_set_error(err, kErrorTypeValidation, "Invalid mode shortname: \"%s\"", mode.data); 2794 goto fail_and_free; 2795 } 2796 2797 if (parsed_args.lhs_len == 0) { 2798 api_set_error(err, kErrorTypeValidation, "Invalid (empty) LHS"); 2799 goto fail_and_free; 2800 } 2801 2802 bool is_noremap = parsed_args.noremap; 2803 assert(!(is_unmap && is_noremap)); 2804 2805 if (!is_unmap && lua_funcref == LUA_NOREF 2806 && (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) { 2807 if (rhs.size == 0) { // assume that the user wants RHS to be a <Nop> 2808 parsed_args.rhs_is_noop = true; 2809 } else { 2810 abort(); // should never happen 2811 } 2812 } else if (is_unmap && (parsed_args.rhs_len || parsed_args.rhs_lua != LUA_NOREF)) { 2813 if (parsed_args.rhs_len) { 2814 api_set_error(err, kErrorTypeValidation, 2815 "Gave nonempty RHS in unmap command: %s", parsed_args.rhs); 2816 } else { 2817 api_set_error(err, kErrorTypeValidation, "Gave nonempty RHS for unmap"); 2818 } 2819 goto fail_and_free; 2820 } 2821 2822 // buf_do_map() reads noremap/unmap as its own argument. 2823 int maptype_val = MAPTYPE_MAP; 2824 if (is_unmap) { 2825 maptype_val = MAPTYPE_UNMAP; 2826 } else if (is_noremap) { 2827 maptype_val = MAPTYPE_NOREMAP; 2828 } 2829 2830 switch (buf_do_map(maptype_val, &parsed_args, mode_val, is_abbrev, target_buf)) { 2831 case 0: 2832 break; 2833 case 1: 2834 api_set_error(err, kErrorTypeException, e_invarg, 0); 2835 goto fail_and_free; 2836 case 2: 2837 api_set_error(err, kErrorTypeException, e_nomap, 0); 2838 goto fail_and_free; 2839 case 5: 2840 api_set_error(err, kErrorTypeException, 2841 is_abbrev ? e_abbreviation_already_exists_for_str 2842 : e_mapping_already_exists_for_str, lhs.data); 2843 goto fail_and_free; 2844 break; 2845 case 6: 2846 api_set_error(err, kErrorTypeException, 2847 is_abbrev ? e_global_abbreviation_already_exists_for_str 2848 : e_global_mapping_already_exists_for_str, lhs.data); 2849 goto fail_and_free; 2850 default: 2851 assert(false && "Unrecognized return code!"); 2852 goto fail_and_free; 2853 } // switch 2854 2855 fail_and_free: 2856 current_sctx = save_current_sctx; 2857 NLUA_CLEAR_REF(parsed_args.rhs_lua); 2858 xfree(parsed_args.rhs); 2859 xfree(parsed_args.orig_rhs); 2860 xfree(parsed_args.desc); 2861 } 2862 2863 /// Get an array containing dictionaries describing mappings 2864 /// based on mode and buffer id 2865 /// 2866 /// @param mode The abbreviation for the mode 2867 /// @param buf The buffer to get the mapping array. NULL for global 2868 /// @returns Array of maparg()-like dictionaries describing mappings 2869 ArrayOf(Dict) keymap_array(String mode, buf_T *buf, Arena *arena) 2870 { 2871 ArrayBuilder mappings = KV_INITIAL_VALUE; 2872 kvi_init(mappings); 2873 2874 char *p = mode.size > 0 ? mode.data : "m"; 2875 bool forceit = *p == '!'; 2876 // Convert the string mode to the integer mode stored within each mapblock. 2877 int int_mode = get_map_mode(&p, forceit); 2878 if (forceit) { 2879 assert(p == mode.data); 2880 p++; 2881 } 2882 bool is_abbrev = (int_mode & (MODE_INSERT | MODE_CMDLINE)) != 0 && *p == 'a'; 2883 2884 // Determine the desired buffer value 2885 int buffer_value = (buf == NULL) ? 0 : buf->handle; 2886 2887 for (int i = 0; i < (is_abbrev ? 1 : MAX_MAPHASH); i++) { 2888 for (const mapblock_T *current_maphash = is_abbrev 2889 ? (buf ? buf->b_first_abbr : first_abbr) 2890 : (buf ? buf->b_maphash[i] : maphash[i]); 2891 current_maphash; 2892 current_maphash = current_maphash->m_next) { 2893 if (current_maphash->m_simplified) { 2894 continue; 2895 } 2896 // Check for correct mode 2897 if (int_mode & current_maphash->m_mode) { 2898 kvi_push(mappings, DICT_OBJ(mapblock_fill_dict(current_maphash, 2899 current_maphash->m_alt 2900 ? current_maphash->m_alt->m_keys : NULL, 2901 buffer_value, 2902 is_abbrev, false, arena))); 2903 } 2904 } 2905 } 2906 2907 return arena_take_arraybuilder(arena, &mappings); 2908 }