summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-08-01 14:28:24 +0200
committerBram Moolenaar <Bram@vim.org>2019-08-01 14:28:24 +0200
commitb66bab381c8ba71fd6e92327d1d34c6f8a65f2a7 (patch)
tree0ce017c26ce910c3c0cf9aa02ddfb904fc319042
parent3f9bdeb2a521a408c04fd9584a752845b3accbbd (diff)
patch 8.1.1785: map functionality mixed with character inputv8.1.1785
Problem: Map functionality mixed with character input. Solution: Move the map functionality to a separate file. (Yegappan Lakshmanan, closes #4740) Graduate the +localmap feature.
-rw-r--r--Filelist2
-rw-r--r--src/Make_cyg_ming.mak1
-rw-r--r--src/Make_morph.mak1
-rw-r--r--src/Make_mvc.mak4
-rw-r--r--src/Make_vms.mms11
-rw-r--r--src/Makefile10
-rw-r--r--src/README.md1
-rw-r--r--src/buffer.c2
-rw-r--r--src/evalfunc.c80
-rw-r--r--src/ex_docmd.c80
-rw-r--r--src/feature.h4
-rw-r--r--src/getchar.c2250
-rw-r--r--src/map.c2268
-rw-r--r--src/proto.h1
-rw-r--r--src/proto/getchar.pro19
-rw-r--r--src/proto/map.pro27
-rw-r--r--src/structs.h3
-rw-r--r--src/version.c6
18 files changed, 2343 insertions, 2427 deletions
diff --git a/Filelist b/Filelist
index d4d390c60a..0246ac77c7 100644
--- a/Filelist
+++ b/Filelist
@@ -60,6 +60,7 @@ SRC_ALL = \
src/keymap.h \
src/macros.h \
src/main.c \
+ src/map.c \
src/mark.c \
src/mbyte.c \
src/memfile.c \
@@ -199,6 +200,7 @@ SRC_ALL = \
src/proto/json.pro \
src/proto/list.pro \
src/proto/main.pro \
+ src/proto/map.pro \
src/proto/mark.pro \
src/proto/mbyte.pro \
src/proto/memfile.pro \
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index 17847cc39e..2fb4bf86d2 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -736,6 +736,7 @@ OBJ = \
$(OUTDIR)/json.o \
$(OUTDIR)/list.o \
$(OUTDIR)/main.o \
+ $(OUTDIR)/map.o \
$(OUTDIR)/mark.o \
$(OUTDIR)/memfile.o \
$(OUTDIR)/memline.o \
diff --git a/src/Make_morph.mak b/src/Make_morph.mak
index f292934dd1..f75afd3079 100644
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -56,6 +56,7 @@ SRC = arabic.c \
json.c \
list.c \
main.c \
+ map.c \
mark.c \
mbyte.c \
memfile.c \
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 04cdd0841c..6b6d073fa0 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -745,6 +745,7 @@ OBJ = \
$(OUTDIR)\json.obj \
$(OUTDIR)\list.obj \
$(OUTDIR)\main.obj \
+ $(OUTDIR)\map.obj \
$(OUTDIR)\mark.obj \
$(OUTDIR)\mbyte.obj \
$(OUTDIR)\memfile.obj \
@@ -1556,6 +1557,8 @@ $(OUTDIR)/list.obj: $(OUTDIR) list.c $(INCL)
$(OUTDIR)/main.obj: $(OUTDIR) main.c $(INCL) $(CUI_INCL)
+$(OUTDIR)/map.obj: $(OUTDIR) map.c $(INCL)
+
$(OUTDIR)/mark.obj: $(OUTDIR) mark.c $(INCL)
$(OUTDIR)/memfile.obj: $(OUTDIR) memfile.c $(INCL)
@@ -1769,6 +1772,7 @@ proto.h: \
proto/json.pro \
proto/list.pro \
proto/main.pro \
+ proto/map.pro \
proto/mark.pro \
proto/memfile.pro \
proto/memline.pro \
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index 2fd98b8a85..39957491b5 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -312,8 +312,8 @@ SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c change.c charset.c \
evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c \
if_cscope.c if_xcmdsrv.c fileio.c findfile.c fold.c getchar.c \
hardcopy.c hashtab.c highlight.c indent.c insexpand.c json.c list.c \
- main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
- misc2.c move.c normal.c ops.c option.c popupmnu.c popupwin.c \
+ main.c map.c mark.c menu.c mbyte.c memfile.c memline.c message.c \
+ misc1.c misc2.c move.c normal.c ops.c option.c popupmnu.c popupwin.c \
profiler.c quickfix.c regexp.c search.c session.c sha256.c sign.c \
spell.c spellfile.c syntax.c tag.c term.c termlib.c testing.c \
textprop.c ui.c undo.c usercmd.c userfunc.c version.c viminfo.c \
@@ -327,8 +327,8 @@ OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj change.
ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj if_xcmdsrv.obj \
fileio.obj findfile.obj fold.obj getchar.obj hardcopy.obj hashtab.obj \
highlight.obj indent.obj insexpand.obj json.obj list.obj main.obj \
- mark.obj menu.obj memfile.obj memline.obj message.obj misc1.obj \
- misc2.obj move.obj mbyte.obj normal.obj ops.obj option.obj \
+ map.obj mark.obj menu.obj memfile.obj memline.obj message.obj \
+ misc1.obj misc2.obj move.obj mbyte.obj normal.obj ops.obj option.obj \
popupmnu.obj popupwin.obj profiler.obj quickfix.obj regexp.obj \
search.obj session.obj sha256.obj sign.obj spell.obj spellfile.obj \
syntax.obj tag.obj term.obj termlib.obj testing.obj textprop.obj \
@@ -630,6 +630,9 @@ main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
arabic.c
+map.obj : map.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
mark.obj : mark.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
diff --git a/src/Makefile b/src/Makefile
index 503fe0375d..bcfc5132a9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1612,6 +1612,7 @@ BASIC_SRC = \
json.c \
list.c \
main.c \
+ map.c \
mark.c \
memfile.c \
memline.c \
@@ -1735,6 +1736,7 @@ OBJ_COMMON = \
objects/indent.o \
objects/insexpand.o \
objects/list.o \
+ objects/map.o \
objects/mark.o \
objects/memline.o \
objects/menu.o \
@@ -1879,6 +1881,7 @@ PRO_AUTO = \
json.pro \
list.pro \
main.pro \
+ map.pro \
mark.pro \
mbyte.pro \
memfile.pro \
@@ -3169,6 +3172,9 @@ objects/list.o: list.c
objects/main.o: main.c
$(CCC) -o $@ main.c
+objects/map.o: map.c
+ $(CCC) -o $@ map.c
+
objects/mark.o: mark.c
$(CCC) -o $@ mark.c
@@ -3604,6 +3610,10 @@ objects/main.o: main.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h globals.h
+objects/map.o: map.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h
objects/mark.o: mark.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff --git a/src/README.md b/src/README.md
index f8eb9c4c72..c02a69648e 100644
--- a/src/README.md
+++ b/src/README.md
@@ -38,6 +38,7 @@ highlight.c | syntax highlighting
indent.c | C and Lisp indentation
insexpand.c | Insert mode completion
mark.c | marks
+map.c | mapping and abbreviations
mbyte.c | multi-byte character handling
memfile.c | storing lines for buffers in a swapfile
memline.c | storing lines for buffers in memory
diff --git a/src/buffer.c b/src/buffer.c
index 4e60751eb4..3251e37d6a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -951,10 +951,8 @@ free_buffer_stuff(
#ifdef FEAT_NETBEANS_INTG
netbeans_file_killed(buf);
#endif
-#ifdef FEAT_LOCALMAP
map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */
map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */
-#endif
VIM_CLEAR(buf->b_start_fenc);
}
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 8253df8201..7eff7ad357 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6189,9 +6189,7 @@ f_has(typval_T *argvars, typval_T *rettv)
"lispindent",
#endif
"listcmds",
-#ifdef FEAT_LOCALMAP
"localmap",
-#endif
#ifdef FEAT_LUA
# ifndef DYNAMIC_LUA
"lua",
@@ -7396,84 +7394,6 @@ f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = (varnumber_T)time(NULL);
}
- static void
-get_maparg(typval_T *argvars, typval_T *rettv, int exact)
-{
- char_u *keys;
- char_u *which;
- char_u buf[NUMBUFLEN];
- char_u *keys_buf = NULL;
- char_u *rhs;
- int mode;
- int abbr = FALSE;
- int get_dict = FALSE;
- mapblock_T *mp;
- int buffer_local;
-
- /* return empty string for failure */
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- keys = tv_get_string(&argvars[0]);
- if (*keys == NUL)
- return;
-
- if (argvars[1].v_type != VAR_UNKNOWN)
- {
- which = tv_get_string_buf_chk(&argvars[1], buf);
- if (argvars[2].v_type != VAR_UNKNOWN)
- {
- abbr = (int)tv_get_number(&argvars[2]);
- if (argvars[3].v_type != VAR_UNKNOWN)
- get_dict = (int)tv_get_number(&argvars[3]);
- }
- }
- else
- which = (char_u *)"";
- if (which == NULL)
- return;
-
- mode = get_map_mode(&which, 0);
-
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
- rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
- vim_free(keys_buf);
-
- if (!get_dict)
- {
- /* Return a string. */
- if (rhs != NULL)
- {
- if (*rhs == NUL)
- rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
- else
- rettv->vval.v_string = str2special_save(rhs, FALSE);
- }
-
- }
- else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
- {
- /* Return a dictionary. */
- char_u *lhs = str2special_save(mp->m_keys, TRUE);
- char_u *mapmode = map_mode_to_chars(mp->m_mode);
- dict_T *dict = rettv->vval.v_dict;
-
- dict_add_string(dict, "lhs", lhs);
- dict_add_string(dict, "rhs", mp->m_orig_str);
- dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
- dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
- dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
- dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
- dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
- dict_add_number(dict, "buffer", (long)buffer_local);
- dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
- dict_add_string(dict, "mode", mapmode);
-
- vim_free(lhs);
- vim_free(mapmode);
- }
-}
-
#ifdef FEAT_FLOAT
/*
* "log()" function
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 1ddd28ffe5..514985633a 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -29,11 +29,6 @@ static void free_cmdmod(void);
static void append_command(char_u *cmd);
static char_u *find_command(exarg_T *eap, int *full);
-static void ex_abbreviate(exarg_T *eap);
-static void ex_map(exarg_T *eap);
-static void ex_unmap(exarg_T *eap);
-static void ex_mapclear(exarg_T *eap);
-static void ex_abclear(exarg_T *eap);
#ifndef FEAT_MENU
# define ex_emenu ex_ni
# define ex_menu ex_ni
@@ -231,7 +226,6 @@ static void ex_read(exarg_T *eap);
static void ex_pwd(exarg_T *eap);
static void ex_equal(exarg_T *eap);
static void ex_sleep(exarg_T *eap);
-static void do_exmap(exarg_T *eap, int isabbrev);
static void ex_winsize(exarg_T *eap);
static void ex_wincmd(exarg_T *eap);
#if defined(FEAT_GUI) || defined(UNIX) || defined(VMS) || defined(MSWIN)
@@ -5347,61 +5341,6 @@ getargopt(exarg_T *eap)
return OK;
}
-/*
- * ":abbreviate" and friends.
- */
- static void
-ex_abbreviate(exarg_T *eap)
-{
- do_exmap(eap, TRUE); /* almost the same as mapping */
-}
-
-/*
- * ":map" and friends.
- */
- static void
-ex_map(exarg_T *eap)
-{
- /*
- * If we are sourcing .exrc or .vimrc in current directory we
- * print the mappings for security reasons.
- */
- if (secure)
- {
- secure = 2;
- msg_outtrans(eap->cmd);
- msg_putchar('\n');
- }
- do_exmap(eap, FALSE);
-}
-
-/*
- * ":unmap" and friends.
- */
- static void
-ex_unmap(exarg_T *eap)
-{
- do_exmap(eap, FALSE);
-}
-
-/*
- * ":mapclear" and friends.
- */
- static void
-ex_mapclear(exarg_T *eap)
-{
- map_clear(eap->cmd, eap->arg, eap->forceit, FALSE);
-}
-
-/*
- * ":abclear" and friends.
- */
- static void
-ex_abclear(exarg_T *eap)
-{
- map_clear(eap->cmd, eap->arg, TRUE, TRUE);
-}
-
static void
ex_autocmd(exarg_T *eap)
{
@@ -7782,25 +7721,6 @@ do_sleep(long msec)
(void)vpeekc();
}
- static void
-do_exmap(exarg_T *eap, int isabbrev)
-{
- int mode;
- char_u *cmdp;
-
- cmdp = eap->cmd;
- mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
-
- switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
- eap->arg, mode, isabbrev))
- {
- case 1: emsg(_(e_invarg));
- break;
- case 2: emsg((isabbrev ? _(e_noabbr) : _(e_nomap)));
- break;
- }
-}
-
/*
* ":winsize" command (obsolete).
*/
diff --git a/src/feature.h b/src/feature.h
index e46947daf8..e2166a135b 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -166,10 +166,8 @@
/*
* +localmap Mappings and abbreviations local to a buffer.
+ * Now always included.
*/
-#ifdef FEAT_NORMAL
-# define FEAT_LOCALMAP
-#endif
/*
* +insert_expand CTRL-N/CTRL-P/CTRL-X in insert mode. Takes about
diff --git a/src/getchar.c b/src/getchar.c
index 0048ae0f6a..8c1a01a3e4 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -52,26 +52,6 @@ static int typeahead_char = 0; /* typeahead char that's not flushed */
*/
static int block_redo = FALSE;
-/*
- * 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) & (NORMAL + VISUAL + SELECTMODE + OP_PENDING + TERMINAL)) ? (c1) : ((c1) ^ 0x80))
-
-/*
- * 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;
-
-/*
- * List used for abbreviations.
- */
-static mapblock_T *first_abbr = NULL; /* first entry in abbrlist */
-
static int KeyNoremap = 0; /* remapping flags */
/*
@@ -113,13 +93,7 @@ static void init_typebuf(void);
static void may_sync_undo(void);
static void closescript(void);
static int vgetorpeek(int);
-static void map_free(mapblock_T **);
-static void validate_maphash(void);
-static void showmap(mapblock_T *mp, int local);
static int inchar(char_u *buf, int maxlen, long wait_time);
-#ifdef FEAT_EVAL
-static char_u *eval_map_expr(char_u *str, int c);
-#endif
/*
* Free and clear a buffer.
@@ -911,6 +885,15 @@ init_typebuf(void)
}
/*
+ * Returns TRUE when keys cannot be remapped.
+ */
+ int
+noremap_keys(void)
+{
+ return KeyNoremap & (RM_NONE|RM_SCRIPT);
+}
+
+/*
* Insert a string in position 'offset' in the typeahead buffer (for "@r"
* and ":normal" command, vgetorpeek() and check_termcode()).
*
@@ -1962,9 +1945,7 @@ vgetorpeek(int advance)
int keylen;
char_u *s;
mapblock_T *mp;
-#ifdef FEAT_LOCALMAP
mapblock_T *mp2;
-#endif
mapblock_T *mp_match;
int mp_match_len = 0;
int timedout = FALSE; /* waited for more than 1 second
@@ -2112,7 +2093,7 @@ vgetorpeek(int advance)
mp = NULL;
max_mlen = 0;
c1 = typebuf.tb_buf[typebuf.tb_off];
- if (no_mapping == 0 && maphash_valid
+ if (no_mapping == 0 && is_maphash_valid()
&& (no_zero_mapping == 0 || c1 != '0')
&& (typebuf.tb_maplen == 0
|| (p_remap
@@ -2141,19 +2122,15 @@ vgetorpeek(int advance)
nolmaplen = 0;
}
#endif
-#ifdef FEAT_LOCALMAP
- /* First try buffer-local mappings. */
- mp = curbuf->b_maphash[MAP_HASH(local_State, c1)];
- mp2 = maphash[MAP_HASH(local_State, c1)];
+ // First try buffer-local mappings.
+ mp = get_buf_maphash_list(local_State, c1);
+ mp2 = get_maphash_list(local_State, c1);
if (mp == NULL)
{
- /* There are no buffer-local mappings. */
+ // There are no buffer-local mappings.
mp = mp2;
mp2 = NULL;
}
-#else
- mp = maphash[MAP_HASH(local_State, c1)];
-#endif
/*
* Loop until a partly matching mapping is found or
* all (local) mappings have been checked.
@@ -2164,10 +2141,8 @@ vgetorpeek(int advance)
mp_match = NULL;
mp_match_len = 0;
for ( ; mp != NULL;
-#ifdef FEAT_LOCALMAP
- mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
-#endif
- (mp = mp->m_next))
+ mp->m_next == NULL ? (mp = mp2, mp2 = NULL)
+ : (mp = mp->m_next))
{
/*
* Only consider an entry if the first character
@@ -3194,2196 +3169,3 @@ input_available(void)
);
}
#endif
-
-/*
- * 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: 0 for :map, 1 for :unmap, 2 for noremap.
- *
- * arg is pointer to any arguments. Note: arg cannot be a read-only string,
- * it will be modified.
- *
- * for :map mode is NORMAL + VISUAL + SELECTMODE + OP_PENDING
- * for :map! mode is INSERT + CMDLINE
- * for :cmap mode is CMDLINE
- * for :imap mode is INSERT
- * for :lmap mode is LANGMAP
- * for :nmap mode is NORMAL
- * for :vmap mode is VISUAL + SELECTMODE
- * for :xmap mode is VISUAL
- * for :smap mode is SELECTMODE
- * for :omap mode is OP_PENDING
- * for :tmap mode is TERMINAL
- *
- * for :abbr mode is INSERT + CMDLINE
- * for :iabbr mode is INSERT
- * for :cabbr mode is 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 */
- char_u *newstr;
- int hasarg;
- int haskey;
- int did_it = FALSE;
-#ifdef FEAT_LOCALMAP
- int did_local = FALSE;
-#endif
- int round;
- char_u *keys_buf = NULL;
- char_u *arg_buf = NULL;
- int retval = 0;
- int do_backslash;
- int hash;
- int new_hash;
- 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 noremap;
- char_u *orig_rhs;
-
- keys = arg;
- map_table = maphash;
- abbr_table = &first_abbr;
-
- /* For ":noremap" don't remap, otherwise do remap. */
- if (maptype == 2)
- noremap = REMAP_NONE;
- else
- noremap = REMAP_YES;
-
- /* Accept <buffer>, <nowait>, <silent>, <expr> <script> and <unique> in
- * any order. */
- for (;;)
- {
-#ifdef FEAT_LOCALMAP
- /*
- * Check for "<buffer>": mapping local to buffer.
- */
- if (STRNCMP(keys, "<buffer>", 8) == 0)
- {
- keys = skipwhite(keys + 8);
- map_table = curbuf->b_maphash;
- abbr_table = &curbuf->b_first_abbr;
- continue;
- }
-#endif
-
- /*
- * Check for "<nowait>": don't wait for more characters.
- */
- if (STRNCMP(keys, "<nowait>", 8) == 0)
- {
- keys = skipwhite(keys + 8);
- nowait = TRUE;
- continue;
- }
-
- /*
- * Check for "<silent>": don't echo commands.
- */
- if (STRNCMP(keys, "<silent>", 8) == 0)
- {
- keys = skipwhite(keys + 8);
- silent = TRUE;
- continue;
- }
-
- /*
- * Check for "<special>": accept special keys in <>
- */
- if (STRNCMP(keys, "<special>", 9) == 0)
- {
- keys = skipwhite(keys + 9);
- special = TRUE;
- continue;
- }
-
-#ifdef FEAT_EVAL
- /*
- * Check for "<script>": remap script-local mappings only
- */
- if (STRNCMP(keys, "<script>", 8) == 0)
- {
- keys = skipwhite(keys + 8);
- noremap = REMAP_SCRIPT;
- continue;
- }
-
- /*
- * Check for "<expr>": {rhs} is an expression.
- */
- if (STRNCMP(keys, "<expr>", 6) == 0)
- {
- keys = skipwhite(keys + 6);
- expr = TRUE;
- continue;
- }
-#endif
- /*
- * Check for "<unique>": don't overwrite an existing mapping.
- */
- if (STRNCMP(keys, "<unique>", 8) == 0)
- {
- keys = skipwhite(keys + 8);
- unique = TRUE;
- continue;
- }
- break;
- }
-
- validate_maphash();
-
- /*
- * Find end of keys and skip CTRL-Vs (and backslashes) in it.
- * Accept backslash like CTRL-V when 'cpoptions' does not contain 'B'.
- * with :unmap white space is included in the keys, no argument possible.
- */
- p = keys;
- do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
- while (*p && (maptype == 1 || !VIM_ISWHITE(*p)))
- {
- if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) &&
- p[1] != NUL)
- ++p; /* skip CTRL-V or backslash */
- ++p;
- }
- if (*p != NUL)
- *p++ = NUL;
-
- p = skipwhite(p);
- rhs = p;
- hasarg = (*rhs != NUL);
- haskey = (*keys != NUL);
-
- /* check for :unmap without argument */
- if (maptype == 1 && !haskey)
- {
- retval = 1;
- goto theend;
- }
-
- /*
- * If mapping has been given as ^V<C_UP> say, then replace the term codes
- * with the appropriate two bytes. If it is a shifted special key, unshift
- * it too, giving another two bytes.
- * replace_termcodes() may move the result to allocated memory, which
- * needs to be freed later (*keys_buf and *arg_buf).
- * replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
- */
- if (haskey)
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special);
- orig_rhs = rhs;
- if (hasarg)
- {
- if (STRICMP(rhs, "<nop>") == 0) /* "<Nop>" means nothing */
- rhs = (char_u *)"";
- else
- rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special);
- }
-
- /*
- * check arguments and translate function keys
- */
- if (haskey)
- {
- len = (int)STRLEN(keys);
- if (len > MAXMAPLEN) /* maximum length of MAXMAPLEN chars */
- {
- retval = 1;
- goto theend;
- }
-
- if (abbrev && maptype != 1)
- {
- /*
- * If an abbreviation ends in a keyword character, the
- * rest must be all keyword-char or all non-keyword-char.
- * Otherwise we won't be able to find the start of it in a
- * vi-compatible way.
- */
- if (has_mbyte)
- {
- int first, last;
- int same = -1;
-
- first = vim_iswordp(keys);
- last = first;
- p = keys + (*mb_ptr2len)(keys);
- n = 1;
- while (p < keys + len)
- {
- ++n; /* nr of (multi-byte) chars */
- last = vim_iswordp(p); /* type of last char */
- if (same == -1 && last != first)
- same = n - 1; /* count of same char type */
- p += (*mb_ptr2len)(p);
- }
- if (last && n > 2 && same >= 0 && same < n - 1)
- {
- retval = 1;
- goto theend;
- }
- }
- else if (vim_iswordc(keys[len - 1])) // ends in keyword char
- for (n = 0; n < len - 2; ++n)
- if (vim_iswordc(keys[n]) != vim_iswordc(keys[len - 2]))
- {
- retval = 1;
- goto theend;
- }
- /* An abbreviation cannot contain white space. */
- for (n = 0; n < len; ++n)
- if (VIM_ISWHITE(keys[n]))
- {
- retval = 1;
- goto theend;
- }
- }
- }
-
- if (haskey && hasarg && abbrev) /* if we will add an abbreviation */
- no_abbr = FALSE; /* reset flag that indicates there are
- no abbreviations */
-
- if (!haskey || (maptype != 1 && !hasarg))
- msg_start();
-
-#ifdef FEAT_LOCALMAP
- /*
- * Check if a new local mapping wasn't already defined globally.
- */
- if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1)
- {
- /* need to loop over all global hash lists */
- for (hash = 0; hash < 256 && !got_int; ++hash)
- {
- if (abbrev)
- {
- if (hash != 0) /* there is only one abbreviation list */
- break;
- mp = first_abbr;
- }
- else
- mp = maphash[hash];
- for ( ; mp != NULL && !got_int; mp = mp->m_next)
- {
- /* check entries with the same mode */
- if ((mp->m_mode & mode) != 0
- && mp->m_keylen == len
- && unique
- && STRNCMP(mp->m_keys, keys, (size_t)len) == 0)
- {
- if (abbrev)
- semsg(_("E224: global abbreviation already exists for %s"),
- mp->m_keys);
- else
- semsg(_("E225: global mapping already exists for %s"),
- mp->m_keys);
- retval = 5;
- goto theend;
- }
- }
- }
- }
-
- /*
- * When listing global mappings, also list buffer-local ones here.
- */
- if (map_table != curbuf->b_maphash && !hasarg && maptype != 1)
- {
- /* need to loop over all global hash lists */
- for (hash = 0; hash < 256 && !got_int; ++hash)
- {
- 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_mode & mode) != 0)
- {
- if (!haskey) /* show all entries */
- {
- showmap(mp, TRUE);
- did_local = TRUE;
- }
- else
- {
- n = mp->m_keylen;
- if (STRNCMP(mp->m_keys, keys,
- (size_t)(n < len ? n : len)) == 0)
- {
- showmap(mp, TRUE);
- did_local = TRUE;
- }
- }
- }
- }
- }
- }
-#endif
-
- /*
- * Find an entry in the maphash[] list that matches.
- * For :unmap we may loop two times: once to try to unmap an entry with a
- * matching 'from' part, a second time, if the first fails, to unmap an
- * entry with a matching 'to' part. This was done to allow ":ab foo bar"
- * to be unmapped by typing ":unab foo", where "foo" will be replaced by
- * "bar" because of the abbreviation.
- */
- for (round = 0; (round == 0 || maptype == 1) && round <= 1
- && !did_it && !got_int; ++round)
- {
- /* need to loop over all hash lists */
- for (hash = 0; hash < 256 && !got_int; ++hash)
- {
- if (abbrev)
- {
- if (hash > 0) /* there is only one abbreviation list */
- break;
- mpp = abbr_table;
- }
- else
- mpp = &(map_table[hash]);
- for (mp = *mpp; mp != NULL && !got_int; mp = *mpp)
- {
-
- if (!(mp->m_mode & mode)) /* skip entries with wrong mode */
- {
- mpp = &(mp->m_next);
- continue;
- }
- if (!haskey) /* show all entries */
- {
- showmap(mp, map_table != maphash);
- did_it = TRUE;
- }
- else /* do we have a match? */
- {
- if (round) /* second round: Try unmap "rhs" string */
- {
- n = (int)STRLEN(mp->m_str);
- p = mp->m_str;
- }
- else
- {
- n = mp->m_keylen;
- p = mp->m_keys;
- }
- if (STRNCMP(p, keys, (size_t)(n < len ? n : len)) == 0)
- {
- if (maptype == 1) /* delete entry */
- {
- /* Only accept a full match. For abbreviations we
- * ignore trailing space when matching with the
- * "lhs", since an abbreviation can't have
- * trailing space. */
- if (n != len && (!abbrev || round || n > len
- || *skipwhite(keys + n) != NUL))
- {
- mpp = &(mp->m_next);
- continue;
- }
- /*
- * We reset the indicated mode bits. If nothing is
- * left the entry is deleted below.
- */
- mp->m_mode &= ~mode;
- did_it = TRUE; /* remember we did something */
- }
- else if (!hasarg) /* show matching entry */
- {
- showmap(mp, map_table != maphash);
- did_it = TRUE;
- }
- else if (n != len) /* new entry is ambiguous */
- {
- mpp = &(mp->m_next);
- continue;
- }
- else if (unique)
- {
- if (abbrev)
- semsg(_("E226: abbreviation already exists for %s"),
- p);
- else
- semsg(_("E227: mapping already exists for %s"), p);
- retval = 5;
- goto theend;
- }
- else /* new rhs for existing entry */
- {
- mp->m_mode &= ~mode; /* remove mode bits */
- if (mp->m_mode == 0 && !did_it) /* reuse entry */
- {
- newstr = vim_strsave(rhs);
- if (newstr == NULL)
- {
- retval = 4; /* no mem */
- goto theend;
- }
- vim_free(mp->m_str);
- mp->m_str = newstr;
- vim_free(mp->m_orig_str);
- mp->m_orig_str = vim_strsave(orig_rhs);
- mp->m_noremap = noremap;
- mp->m_nowait = nowait;
- mp->m_silent = silent;
- mp->m_mode = mode;
-#ifdef FEAT_EVAL
- mp->m_expr = expr;
- mp->m_script_ctx = current_sctx;
- mp->m_script_ctx.sc_lnum += sourcing_lnum;