From aed8ce9da277f5ecffe968b324f242c41c3b752a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 10:50:31 +0200 Subject: Adding upstream version 2:9.0.1378. Signed-off-by: Daniel Baumann --- src/map.c | 3203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3203 insertions(+) create mode 100644 src/map.c (limited to 'src/map.c') diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..7c95286 --- /dev/null +++ b/src/map.c @@ -0,0 +1,3203 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * map.c: Code for mappings and abbreviations. + */ + +#include "vim.h" + +/* + * List used for abbreviations. + */ +static mapblock_T *first_abbr = NULL; // first entry in abbrlist + +/* + * Each mapping is put in one of the 256 hash lists, to speed up finding it. + */ +static mapblock_T *(maphash[256]); +static int maphash_valid = FALSE; + +// When non-zero then no mappings can be added or removed. Prevents mappings +// to change while listing them. +static int map_locked = 0; + +/* + * Make a hash value for a mapping. + * "mode" is the lower 4 bits of the State for the mapping. + * "c1" is the first character of the "lhs". + * Returns a value between 0 and 255, index in maphash. + * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode. + */ +#define MAP_HASH(mode, c1) (((mode) & (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING | MODE_TERMINAL)) ? (c1) : ((c1) ^ 0x80)) + +/* + * Get the start of the hashed map list for "state" and first character "c". + */ + mapblock_T * +get_maphash_list(int state, int c) +{ + return maphash[MAP_HASH(state, c)]; +} + +/* + * Get the buffer-local hashed map list for "state" and first character "c". + */ + mapblock_T * +get_buf_maphash_list(int state, int c) +{ + return curbuf->b_maphash[MAP_HASH(state, c)]; +} + + int +is_maphash_valid(void) +{ + return maphash_valid; +} + +/* + * Initialize maphash[] for first use. + */ + static void +validate_maphash(void) +{ + if (maphash_valid) + return; + + CLEAR_FIELD(maphash); + maphash_valid = TRUE; +} + +/* + * Delete one entry from the abbrlist or maphash[]. + * "mpp" is a pointer to the m_next field of the PREVIOUS entry! + */ + static void +map_free(mapblock_T **mpp) +{ + mapblock_T *mp; + + mp = *mpp; + vim_free(mp->m_keys); + vim_free(mp->m_str); + vim_free(mp->m_orig_str); + *mpp = mp->m_next; +#ifdef FEAT_EVAL + reset_last_used_map(mp); +#endif + vim_free(mp); +} + +/* + * Return characters to represent the map mode in an allocated string. + * Returns NULL when out of memory. + */ + static char_u * +map_mode_to_chars(int mode) +{ + garray_T mapmode; + + ga_init2(&mapmode, 1, 7); + + if ((mode & (MODE_INSERT | MODE_CMDLINE)) == (MODE_INSERT | MODE_CMDLINE)) + ga_append(&mapmode, '!'); // :map! + else if (mode & MODE_INSERT) + ga_append(&mapmode, 'i'); // :imap + else if (mode & MODE_LANGMAP) + ga_append(&mapmode, 'l'); // :lmap + else if (mode & MODE_CMDLINE) + ga_append(&mapmode, 'c'); // :cmap + else if ((mode + & (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING)) + == (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING)) + ga_append(&mapmode, ' '); // :map + else + { + if (mode & MODE_NORMAL) + ga_append(&mapmode, 'n'); // :nmap + if (mode & MODE_OP_PENDING) + ga_append(&mapmode, 'o'); // :omap + if (mode & MODE_TERMINAL) + ga_append(&mapmode, 't'); // :tmap + if ((mode & (MODE_VISUAL | MODE_SELECT)) == (MODE_VISUAL | MODE_SELECT)) + ga_append(&mapmode, 'v'); // :vmap + else + { + if (mode & MODE_VISUAL) + ga_append(&mapmode, 'x'); // :xmap + if (mode & MODE_SELECT) + ga_append(&mapmode, 's'); // :smap + } + } + + ga_append(&mapmode, NUL); + return (char_u *)mapmode.ga_data; +} + +/* + * Output a line for one mapping. + */ + static void +showmap( + mapblock_T *mp, + int local) // TRUE for buffer-local map +{ + int len = 1; + char_u *mapchars; + + if (message_filtered(mp->m_keys) && message_filtered(mp->m_str)) + return; + + // Prevent mappings to be cleared while at the more prompt. + // Must jump to "theend" instead of returning. + ++map_locked; + + if (msg_didout || msg_silent != 0) + { + msg_putchar('\n'); + if (got_int) // 'q' typed at MORE prompt + goto theend; + } + + mapchars = map_mode_to_chars(mp->m_mode); + if (mapchars != NULL) + { + msg_puts((char *)mapchars); + len = (int)STRLEN(mapchars); + vim_free(mapchars); + } + + while (++len <= 3) + msg_putchar(' '); + + // Display the LHS. Get length of what we write. + len = msg_outtrans_special(mp->m_keys, TRUE, 0); + do + { + msg_putchar(' '); // pad with blanks + ++len; + } while (len < 12); + + if (mp->m_noremap == REMAP_NONE) + msg_puts_attr("*", HL_ATTR(HLF_8)); + else if (mp->m_noremap == REMAP_SCRIPT) + msg_puts_attr("&", HL_ATTR(HLF_8)); + else + msg_putchar(' '); + + if (local) + msg_putchar('@'); + else + msg_putchar(' '); + + // Use FALSE below if we only want things like to show up as such on + // the rhs, and not M-x etc, TRUE gets both -- webb + if (*mp->m_str == NUL) + msg_puts_attr("", HL_ATTR(HLF_8)); + else + msg_outtrans_special(mp->m_str, FALSE, 0); +#ifdef FEAT_EVAL + if (p_verbose > 0) + last_set_msg(mp->m_script_ctx); +#endif + msg_clr_eos(); + out_flush(); // show one line at a time + +theend: + --map_locked; +} + + static int +map_add( + mapblock_T **map_table, + mapblock_T **abbr_table, + char_u *keys, + char_u *rhs, + char_u *orig_rhs, + int noremap, + int nowait, + int silent, + int mode, + int is_abbr, +#ifdef FEAT_EVAL + int expr, + scid_T sid, // -1 to use current_sctx + int scriptversion, + linenr_T lnum, +#endif + int simplified) +{ + mapblock_T *mp = ALLOC_CLEAR_ONE(mapblock_T); + + if (mp == NULL) + return FAIL; + + // If CTRL-C has been mapped, don't always use it for Interrupting. + if (*keys == Ctrl_C) + { + if (map_table == curbuf->b_maphash) + curbuf->b_mapped_ctrl_c |= mode; + else + mapped_ctrl_c |= mode; + } + + mp->m_keys = vim_strsave(keys); + mp->m_str = vim_strsave(rhs); + mp->m_orig_str = vim_strsave(orig_rhs); + if (mp->m_keys == NULL || mp->m_str == NULL) + { + vim_free(mp->m_keys); + vim_free(mp->m_str); + vim_free(mp->m_orig_str); + vim_free(mp); + return FAIL; + } + mp->m_keylen = (int)STRLEN(mp->m_keys); + mp->m_noremap = noremap; + mp->m_nowait = nowait; + mp->m_silent = silent; + mp->m_mode = mode; + mp->m_simplified = simplified; +#ifdef FEAT_EVAL + mp->m_expr = expr; + if (sid > 0) + { + mp->m_script_ctx.sc_sid = sid; + mp->m_script_ctx.sc_lnum = lnum; + mp->m_script_ctx.sc_version = scriptversion; + } + else + { + mp->m_script_ctx = current_sctx; + mp->m_script_ctx.sc_lnum += SOURCING_LNUM; + } +#endif + + // add the new entry in front of the abbrlist or maphash[] list + if (is_abbr) + { + mp->m_next = *abbr_table; + *abbr_table = mp; + } + else + { + int n = MAP_HASH(mp->m_mode, mp->m_keys[0]); + + mp->m_next = map_table[n]; + map_table[n] = mp; + } + return OK; +} + +/* + * List mappings. When "haskey" is FALSE all mappings, otherwise mappings that + * match "keys[keys_len]". + */ + static void +list_mappings( + int keyround, + int abbrev, + int haskey, + char_u *keys, + int keys_len, + int mode, + int *did_local) +{ + // Prevent mappings to be cleared while at the more prompt. + ++map_locked; + + if (p_verbose > 0 && keyround == 1) + { + if (seenModifyOtherKeys) + msg_puts(_("Seen modifyOtherKeys: true\n")); + + if (modify_otherkeys_state != MOKS_INITIAL) + { + char *name = _("Unknown"); + switch (modify_otherkeys_state) + { + case MOKS_INITIAL: break; + case MOKS_OFF: name = _("Off"); break; + case MOKS_ENABLED: name = _("On"); break; + case MOKS_DISABLED: name = _("Disabled"); break; + case MOKS_AFTER_T_TE: name = _("Cleared"); break; + } + + char buf[200]; + vim_snprintf(buf, sizeof(buf), + _("modifyOtherKeys detected: %s\n"), name); + msg_puts(buf); + } + + if (kitty_protocol_state != KKPS_INITIAL) + { + char *name = _("Unknown"); + switch (kitty_protocol_state) + { + case KKPS_INITIAL: break; + case KKPS_OFF: name = _("Off"); break; + case KKPS_ENABLED: name = _("On"); break; + case KKPS_DISABLED: name = _("Disabled"); break; + case KKPS_AFTER_T_TE: name = _("Cleared"); break; + } + + char buf[200]; + vim_snprintf(buf, sizeof(buf), + _("Kitty keyboard protocol: %s\n"), name); + msg_puts(buf); + } + } + + // need to loop over all global hash lists + for (int hash = 0; hash < 256 && !got_int; ++hash) + { + mapblock_T *mp; + + if (abbrev) + { + if (hash != 0) // there is only one abbreviation list + break; + mp = curbuf->b_first_abbr; + } + else + mp = curbuf->b_maphash[hash]; + for ( ; mp != NULL && !got_int; mp = mp->m_next) + { + // check entries with the same mode + if (!mp->m_simplified && (mp->m_mode & mode) != 0) + { + if (!haskey) // show all entries + { + showmap(mp, TRUE); + *did_local = TRUE; + } + else + { + int n = mp->m_keylen; + if (STRNCMP(mp->m_keys, keys, + (size_t)(n < keys_len ? n : keys_len)) == 0) + { + showmap(mp, TRUE); + *did_local = TRUE; + } + } + } + } + } + + --map_locked; +} + +/* + * map[!] : show all key mappings + * map[!] {lhs} : show key mapping for {lhs} + * map[!] {lhs} {rhs} : set key mapping for {lhs} to {rhs} + * noremap[!] {lhs} {rhs} : same, but no remapping for {rhs} + * unmap[!] {lhs} : remove key mapping for {lhs} + * abbr : show all abbreviations + * abbr {lhs} : show abbreviations for {lhs} + * abbr {lhs} {rhs} : set abbreviation for {lhs} to {rhs} + * noreabbr {lhs} {rhs} : same, but no remapping for {rhs} + * unabbr {lhs} : remove abbreviation for {lhs} + * + * maptype: MAPTYPE_MAP for :map + * MAPTYPE_UNMAP for :unmap + * MAPTYPE_NOREMAP for noremap + * + * arg is pointer to any arguments. Note: arg cannot be a read-only string, + * it will be modified. + * + * for :map mode is MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING + * for :map! mode is MODE_INSERT | MODE_CMDLINE + * for :cmap mode is MODE_CMDLINE + * for :imap mode is MODE_INSERT + * for :lmap mode is MODE_LANGMAP + * for :nmap mode is MODE_NORMAL + * for :vmap mode is MODE_VISUAL | MODE_SELECT + * for :xmap mode is MODE_VISUAL + * for :smap mode is MODE_SELECT + * for :omap mode is MODE_OP_PENDING + * for :tmap mode is MODE_TERMINAL + * + * for :abbr mode is MODE_INSERT | MODE_CMDLINE + * for :iabbr mode is MODE_INSERT + * for :cabbr mode is MODE_CMDLINE + * + * Return 0 for success + * 1 for invalid arguments + * 2 for no match + * 4 for out of mem + * 5 for entry not unique + */ + int +do_map( + int maptype, + char_u *arg, + int mode, + int abbrev) // not a mapping but an abbreviation +{ + char_u *keys; + mapblock_T *mp, **mpp; + char_u *rhs; + char_u *p; + int n; + int len = 0; // init for GCC + int hasarg; + int haskey; + int do_print; + int keyround; + char_u *keys_buf = NULL; + char_u *alt_keys_buf = NULL; + char_u *arg_buf = NULL; + int retval = 0; + int do_backslash; + mapblock_T **abbr_table; + mapblock_T **map_table; + int unique = FALSE; + int nowait = FALSE; + int silent = FALSE; + int special = FALSE; +#ifdef FEAT_EVAL + int expr = FALSE; +#endif + int did_simplify = FALSE; + int noremap; + char_u *orig_rhs; + + keys = arg; + map_table = maphash; + abbr_table = &first_abbr; + + // For ":noremap" don't remap, otherwise do remap. + if (maptype == MAPTYPE_NOREMAP) + noremap = REMAP_NONE; + else + noremap = REMAP_YES; + + // Accept , , ,