summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Filelist2
-rw-r--r--runtime/doc/builtin.txt6
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--src/Make_cyg_ming.mak12
-rw-r--r--src/Make_mvc.mak12
-rw-r--r--src/Make_vms.mms2
-rw-r--r--src/Makefile12
-rw-r--r--src/create_nvcmdidxs.vim72
-rw-r--r--src/evalfunc.c2
-rw-r--r--src/main.c3
-rw-r--r--src/normal.c126
-rw-r--r--src/nv_cmdidxs.h209
-rw-r--r--src/proto/normal.pro2
-rw-r--r--src/version.c2
14 files changed, 399 insertions, 64 deletions
diff --git a/Filelist b/Filelist
index 070b7574d3..15d000e4b8 100644
--- a/Filelist
+++ b/Filelist
@@ -113,6 +113,7 @@ SRC_ALL = \
src/nbdebug.h \
src/netbeans.c \
src/normal.c \
+ src/nv_cmdidxs.h \
src/ops.c \
src/option.c \
src/option.h \
@@ -443,6 +444,7 @@ SRC_UNIX = \
src/configure \
src/configure.ac \
src/create_cmdidxs.vim \
+ src/create_nvcmdidxs.vim \
src/gui_at_fs.c \
src/gui_at_sb.c \
src/gui_at_sb.h \
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index bfb63d0d59..f858440a9e 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -292,6 +292,7 @@ inputrestore() Number restore typeahead
inputsave() Number save and clear typeahead
inputsecret({prompt} [, {text}]) String like input() but hiding the text
insert({object}, {item} [, {idx}]) List insert {item} in {object} [before {idx}]
+internal_get_nv_cmdchar({idx}) Number command character at this index
interrupt() none interrupt script execution
invert({expr}) Number bitwise invert
isdirectory({directory}) Number |TRUE| if {directory} is a directory
@@ -4622,6 +4623,11 @@ insert({object}, {item} [, {idx}]) *insert()*
Can also be used as a |method|: >
mylist->insert(item)
+<
+ *internal_get_nv_cmdchar()*
+internal_get_nv_cmdchar({idx})
+ Return the normal/visual mode command character at the
+ specified index. To be used only during the Vim build process.
interrupt() *interrupt()*
Interrupt script execution. It works more or less like the
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 66b267f935..ec6db500a6 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1110,6 +1110,7 @@ Testing: *test-functions*
assert_nobeep() assert that a command does not cause a beep
assert_fails() assert that a command fails
assert_report() report a test failure
+ internal_get_nv_cmdchar() normal/visual command character at an index
test_alloc_fail() make memory allocation fail
test_autochdir() enable 'autochdir' during startup
test_override() test with Vim internal overrides
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index a415631aba..46e95b44b4 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -1147,6 +1147,16 @@ endif
cmdidxs: ex_cmds.h
vim --clean -X --not-a-term -u create_cmdidxs.vim
+# Run vim script to generate the normal/visual mode command lookup table.
+# This only needs to be run when a new normal/visual mode command has been
+# added. If this fails because you don't have Vim yet:
+# - change nv_cmds[] in normal.c to add the new normal/visual mode command.
+# - build Vim
+# - run "make nvcmdidxs" using the new Vim to generate nv_cmdidxs.h
+# - rebuild Vim to use the newly generated nv_cmdidxs.h file.
+nvcmdidxs: normal.c
+ ./$(TARGET) --clean -X --not-a-term -u create_nvcmdidxs.vim
+
###########################################################################
INCL = vim.h alloc.h ascii.h ex_cmds.h feature.h errors.h globals.h \
keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \
@@ -1209,6 +1219,8 @@ $(OUTDIR)/hardcopy.o: hardcopy.c $(INCL) version.h
$(OUTDIR)/misc1.o: misc1.c $(INCL) version.h
+$(OUTDIR)/normal.o: normal.c $(INCL) nv_cmdidxs.h
+
$(OUTDIR)/netbeans.o: netbeans.c $(INCL) version.h
$(OUTDIR)/version.o: version.c $(INCL) version.h
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 3100d38f60..7852150563 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -1446,6 +1446,16 @@ clean: testclean
cmdidxs: ex_cmds.h
vim --clean -X --not-a-term -u create_cmdidxs.vim
+# Run vim script to generate the normal/visual mode command lookup table.
+# This only needs to be run when a new normal/visual mode command has been
+# added. If this fails because you don't have Vim yet:
+# - change nv_cmds[] in normal.c to add the new normal/visual mode command.
+# - build Vim
+# - run "make nvcmdidxs" using the new Vim to generate nv_cmdidxs.h
+# - rebuild Vim to use the newly generated nv_cmdidxs.h file.
+nvcmdidxs: normal.c
+ .\$(VIM) --clean -X --not-a-term -u create_nvcmdidxs.vim
+
test:
cd testdir
$(MAKE) /NOLOGO -f Make_dos.mak
@@ -1709,7 +1719,7 @@ $(OUTDIR)/netbeans.obj: $(OUTDIR) netbeans.c $(NBDEBUG_SRC) $(INCL) version.h
$(OUTDIR)/channel.obj: $(OUTDIR) channel.c $(INCL)
-$(OUTDIR)/normal.obj: $(OUTDIR) normal.c $(INCL)
+$(OUTDIR)/normal.obj: $(OUTDIR) normal.c $(INCL) nv_cmdidxs.h
$(OUTDIR)/option.obj: $(OUTDIR) option.c $(INCL) optiondefs.h
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index 5ee4aabaeb..0569054f65 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -977,7 +977,7 @@ mbyte.obj : mbyte.c vim.h [.auto]config.h feature.h os_unix.h \
normal.obj : normal.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
- errors.h globals.h
+ errors.h globals.h nv_cmdidxs.h
ops.obj : ops.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \
[.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h
diff --git a/src/Makefile b/src/Makefile
index cdb491be25..549b8177b7 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2144,6 +2144,16 @@ autoconf:
cmdidxs: ex_cmds.h
vim --clean -X --not-a-term -u create_cmdidxs.vim
+# Run vim script to generate the normal/visual mode command lookup table.
+# This only needs to be run when a new normal/visual mode command has been
+# added. If this fails because you don't have Vim yet:
+# - change nv_cmds[] in normal.c to add the new normal/visual mode command.
+# - build Vim
+# - run "make nvcmdidxs" using the new Vim to generate nv_cmdidxs.h
+# - rebuild Vim to use the newly generated nv_cmdidxs.h file.
+nvcmdidxs: normal.c
+ ./$(VIMTARGET) --clean -X --not-a-term -u create_nvcmdidxs.vim
+
# The normal command to compile a .c file to its .o file.
# Without or with ALL_CFLAGS.
@@ -4002,7 +4012,7 @@ objects/move.o: move.c vim.h protodef.h auto/config.h feature.h os_unix.h \
objects/normal.o: normal.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h termdefs.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 errors.h
+ proto.h globals.h errors.h nv_cmdidxs.h
objects/ops.o: ops.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h termdefs.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/create_nvcmdidxs.vim b/src/create_nvcmdidxs.vim
new file mode 100644
index 0000000000..2dd5fdb546
--- /dev/null
+++ b/src/create_nvcmdidxs.vim
@@ -0,0 +1,72 @@
+vim9script
+
+# This script generates the table nv_cmd_idx[] which contains the index in
+# nv_cmds[] table (normal.c) for each of the command character supported in
+# normal/visual mode.
+# This is used to speed up the command lookup in nv_cmds[].
+#
+# Script should be run using "make nvcmdidxs", every time the nv_cmds[] table
+# in src/normal.c changes.
+
+def Create_nvcmdidxs_table()
+ var nv_cmdtbl: list<dict<number>> = []
+
+ # Generate the table of normal/visual mode command characters and their
+ # corresponding index.
+ var idx: number = 0
+ var ch: number
+ while true
+ ch = internal_get_nv_cmdchar(idx)
+ if ch == -1
+ break
+ endif
+ add(nv_cmdtbl, {idx: idx, cmdchar: ch})
+ idx += 1
+ endwhile
+
+ # sort the table by the command character
+ sort(nv_cmdtbl, (a, b) => a.cmdchar - b.cmdchar)
+
+ # Compute the highest index upto which the command character can be directly
+ # used as an index.
+ var nv_max_linear: number = 0
+ for i in range(nv_cmdtbl->len())
+ if i != nv_cmdtbl[i].cmdchar
+ nv_max_linear = i - 1
+ break
+ endif
+ endfor
+
+ # Generate a header file with the table
+ var output: list<string> =<< trim END
+ /*
+ * Automatically generated code by the create_nvcmdidxs.vim script.
+ *
+ * Table giving the index in nv_cmds[] to lookup based on
+ * the command character.
+ */
+
+ // nv_cmd_idx[<normal mode command character>] => nv_cmds[] index
+ static const unsigned short nv_cmd_idx[] =
+ {
+ END
+
+ # Add each command character in comment and the corresponding index
+ var tbl: list<string> = mapnew(nv_cmdtbl, (k, v) =>
+ ' /* ' .. printf('%5d', v.cmdchar) .. ' */ ' ..
+ printf('%3d', v.idx) .. ','
+ )
+ output += tbl
+
+ output += [ '};', '',
+ '// The highest index for which',
+ '// nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char]']
+ output += ['static const int nv_max_linear = ' .. nv_max_linear .. ';']
+
+ writefile(output, "nv_cmdidxs.h")
+enddef
+
+Create_nvcmdidxs_table()
+quit
+
+# vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 045e5444f3..879fe2239f 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -1737,6 +1737,8 @@ static funcentry_T global_functions[] =
ret_string, f_inputsecret},
{"insert", 2, 3, FEARG_1, arg23_insert,
ret_first_arg, f_insert},
+ {"internal_get_nv_cmdchar", 1, 1, FEARG_1, arg1_number,
+ ret_number, f_internal_get_nv_cmdchar},
{"interrupt", 0, 0, 0, NULL,
ret_void, f_interrupt},
{"invert", 1, 1, FEARG_1, arg1_number,
diff --git a/src/main.c b/src/main.c
index 72d0211432..7c0c4e64fc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -901,9 +901,6 @@ common_init(mparm_T *paramp)
qnx_init(); // PhAttach() for clipboard, (and gui)
#endif
- // Init the table of Normal mode commands.
- init_normal_cmds();
-
/*
* Allocate space for the generic buffers (needed for set_init_1() and
* emsg()).
diff --git a/src/normal.c b/src/normal.c
index 412700ae1a..2e8521ce00 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -19,7 +19,6 @@ static int VIsual_mode_orig = NUL; // saved Visual mode
#ifdef FEAT_EVAL
static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount);
#endif
-static int nv_compare(const void *s1, const void *s2);
static void unshift_special(cmdarg_T *cap);
#ifdef FEAT_CMDL_INFO
static void del_from_showcmd(int);
@@ -128,6 +127,34 @@ static void nv_drop(cmdarg_T *cap);
#endif
static void nv_cursorhold(cmdarg_T *cap);
+#ifdef FEAT_GUI
+#define NV_VER_SCROLLBAR nv_ver_scrollbar
+#define NV_HOR_SCROLLBAR nv_hor_scrollbar
+#else
+#define NV_VER_SCROLLBAR nv_error
+#define NV_HOR_SCROLLBAR nv_error
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+#define NV_TABLINE nv_tabline
+#define NV_TABMENU nv_tabmenu
+#else
+#define NV_TABLINE nv_error
+#define NV_TABMENU nv_error
+#endif
+
+#ifdef FEAT_NETBEANS_INTG
+#define NV_NBCMD nv_nbcmd
+#else
+#define NV_NBCMD nv_error
+#endif
+
+#ifdef FEAT_DND
+#define NV_DROP nv_drop
+#else
+#define NV_DROP nv_error
+#endif
+
/*
* Function to be called for a Normal or Visual mode command.
* The argument is a cmdarg_T.
@@ -159,8 +186,14 @@ typedef void (*nv_func_T)(cmdarg_T *cap);
/*
* This table contains one entry for every Normal or Visual mode command.
- * The order doesn't matter, init_normal_cmds() will create a sorted index.
+ * The order doesn't matter, this will be sorted by the create_nvcmdidx.vim
+ * script to generate the nv_cmd_idx[] lookup table.
* It is faster when all keys from zero to '~' are present.
+ *
+ * After changing the "nv_cmds" table:
+ * 1. Build Vim with "make"
+ * 2. Run "make nvcmdidxs" to re-generate the nv_cmdidxs.h file.
+ * 3. Build Vim with "make" to use the newly generated index table.
*/
static const struct nv_cmd
{
@@ -193,8 +226,6 @@ static const struct nv_cmd
{Ctrl_T, nv_tagpop, NV_NCW, 0},
{Ctrl_U, nv_halfpage, 0, 0},
{Ctrl_V, nv_visual, 0, FALSE},
- {'V', nv_visual, 0, FALSE},
- {'v', nv_visual, 0, FALSE},
{Ctrl_W, nv_window, 0, 0},
{Ctrl_X, nv_addsub, 0, 0},
{Ctrl_Y, nv_scroll_line, 0, FALSE},
@@ -258,6 +289,7 @@ static const struct nv_cmd
{'S', nv_subst, NV_KEEPREG, 0},
{'T', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD},
{'U', nv_Undo, 0, 0},
+ {'V', nv_visual, 0, FALSE},
{'W', nv_wordcmd, 0, TRUE},
{'X', nv_abbrev, NV_KEEPREG, 0},
{'Y', nv_abbrev, NV_KEEPREG, 0},
@@ -289,6 +321,7 @@ static const struct nv_cmd
{'s', nv_subst, NV_KEEPREG, 0},
{'t', nv_csearch, NV_NCH_ALW|NV_LANG, FORWARD},
{'u', nv_undo, 0, 0},
+ {'v', nv_visual, 0, FALSE},
{'w', nv_wordcmd, 0, FALSE},
{'x', nv_abbrev, NV_KEEPREG, 0},
{'y', nv_operator, 0, 0},
@@ -356,20 +389,12 @@ static const struct nv_cmd
{K_F1, nv_help, NV_NCW, 0},
{K_XF1, nv_help, NV_NCW, 0},
{K_SELECT, nv_select, 0, 0},
-#ifdef FEAT_GUI
- {K_VER_SCROLLBAR, nv_ver_scrollbar, 0, 0},
- {K_HOR_SCROLLBAR, nv_hor_scrollbar, 0, 0},
-#endif
-#ifdef FEAT_GUI_TABLINE
- {K_TABLINE, nv_tabline, 0, 0},
- {K_TABMENU, nv_tabmenu, 0, 0},
-#endif
-#ifdef FEAT_NETBEANS_INTG
- {K_F21, nv_nbcmd, NV_NCH_ALW, 0},
-#endif
-#ifdef FEAT_DND
- {K_DROP, nv_drop, NV_STS, 0},
-#endif
+ {K_VER_SCROLLBAR, NV_VER_SCROLLBAR, 0, 0},
+ {K_HOR_SCROLLBAR, NV_HOR_SCROLLBAR, 0, 0},
+ {K_TABLINE, NV_TABLINE, 0, 0},
+ {K_TABMENU, NV_TABMENU, 0, 0},
+ {K_F21, NV_NBCMD, NV_NCH_ALW, 0},
+ {K_DROP, NV_DROP, NV_STS, 0},
{K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0},
{K_PS, nv_edit, 0, 0},
{K_COMMAND, nv_colon, 0, 0},
@@ -379,55 +404,42 @@ static const struct nv_cmd
// Number of commands in nv_cmds[].
#define NV_CMDS_SIZE ARRAY_LENGTH(nv_cmds)
-#ifndef PROTO // cproto doesn't like this
-// Sorted index of commands in nv_cmds[].
-static short nv_cmd_idx[NV_CMDS_SIZE];
-#endif
-
-// The highest index for which
-// nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char]
-static int nv_max_linear;
+// Include the lookuptable generated by create_nvcmdidx.vim.
+#include "nv_cmdidxs.h"
+#if defined(FEAT_EVAL) || defined(PROTO)
/*
- * Compare functions for qsort() below, that checks the command character
- * through the index in nv_cmd_idx[].
+ * Return the command character for the given command index. This function is
+ * used to auto-generate nv_cmd_idx[].
*/
- static int
-nv_compare(const void *s1, const void *s2)
+ void
+f_internal_get_nv_cmdchar(typval_T *argvars, typval_T *rettv)
{
- int c1, c2;
+ int idx;
+ int cmd_char;
- // The commands are sorted on absolute value.
- c1 = nv_cmds[*(const short *)s1].cmd_char;
- c2 = nv_cmds[*(const short *)s2].cmd_char;
- if (c1 < 0)
- c1 = -c1;
- if (c2 < 0)
- c2 = -c2;
- return c1 - c2;
-}
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = -1;
-/*
- * Initialize the nv_cmd_idx[] table.
- */
- void
-init_normal_cmds(void)
-{
- int i;
+ if (check_for_number_arg(argvars, 0) == FAIL)
+ return;
- // Fill the index table with a one to one relation.
- for (i = 0; i < (int)NV_CMDS_SIZE; ++i)
- nv_cmd_idx[i] = i;
+ idx = tv_get_number(&argvars[0]);
+ if (idx < 0 || idx >= (int)NV_CMDS_SIZE)
+ return;
- // Sort the commands by the command character.
- qsort((void *)&nv_cmd_idx, (size_t)NV_CMDS_SIZE, sizeof(short), nv_compare);
+ cmd_char = nv_cmds[idx].cmd_char;
- // Find the first entry that can't be indexed by the command character.
- for (i = 0; i < (int)NV_CMDS_SIZE; ++i)
- if (i != nv_cmds[nv_cmd_idx[i]].cmd_char)
- break;
- nv_max_linear = i - 1;
+ // We use the absolute value of the character. Special keys have a
+ // negative value, but are sorted on their absolute value.
+ if (cmd_char < 0)
+ cmd_char = -cmd_char;
+
+ rettv->vval.v_number = cmd_char;
+
+ return;
}
+#endif
/*
* Search for a command in the commands table.
diff --git a/src/nv_cmdidxs.h b/src/nv_cmdidxs.h
new file mode 100644
index 0000000000..60071e4824
--- /dev/null
+++ b/src/nv_cmdidxs.h
@@ -0,0 +1,209 @@
+/*
+ * Automatically generated code by the create_nvcmdidxs.vim script.
+ *
+ * Table giving the index in nv_cmds[] to lookup based on
+ * the command character.
+ */
+
+// nv_cmd_idx[<normal mode command character>] => nv_cmds[] index
+static const unsigned short nv_cmd_idx[] =
+{
+ /* 0 */ 0,
+ /* 1 */ 1,
+ /* 2 */ 2,
+ /* 3 */ 3,
+ /* 4 */ 4,
+ /* 5 */ 5,
+ /* 6 */ 6,
+ /* 7 */ 7,
+ /* 8 */ 8,
+ /* 9 */ 9,
+ /* 10 */ 10,
+ /* 11 */ 11,
+ /* 12 */ 12,
+ /* 13 */ 13,
+ /* 14 */ 14,
+ /* 15 */ 15,
+ /* 16 */ 16,
+ /* 17 */ 17,
+ /* 18 */ 18,
+ /* 19 */ 19,
+ /* 20 */ 20,
+ /* 21 */ 21,
+ /* 22 */ 22,
+ /* 23 */ 23,
+ /* 24 */ 24,
+ /* 25 */ 25,
+ /* 26 */ 26,
+ /* 27 */ 27,
+ /* 28 */ 28,
+ /* 29 */ 29,
+ /* 30 */ 30,
+ /* 31 */ 31,
+ /* 32 */ 32,
+ /* 33 */ 33,
+ /* 34 */ 34,
+ /* 35 */ 35,
+ /* 36 */ 36,
+ /* 37 */ 37,
+ /* 38 */ 38,
+ /* 39 */ 39,
+ /* 40 */ 40,
+ /* 41 */ 41,
+ /* 42 */ 42,
+ /* 43 */ 43,
+ /* 44 */ 44,
+ /* 45 */ 45,
+ /* 46 */ 46,
+ /* 47 */ 47,
+ /* 48 */ 48,
+ /* 49 */ 49,
+ /* 50 */ 50,
+ /* 51 */ 51,
+ /* 52 */ 52,
+ /* 53 */ 53,
+ /* 54 */ 54,
+ /* 55 */ 55,
+ /* 56 */ 56,
+ /* 57 */ 57,
+ /* 58 */ 58,
+ /* 59 */ 59,
+ /* 60 */ 60,
+ /* 61 */ 61,
+ /* 62 */ 62,
+ /* 63 */ 63,
+ /* 64 */ 64,
+ /* 65 */ 65,
+ /* 66 */ 66,
+ /* 67 */ 67,
+ /* 68 */ 68,
+ /* 69 */ 69,
+ /* 70 */ 70,
+ /* 71 */ 71,
+ /* 72 */ 72,
+ /* 73 */ 73,
+ /* 74 */ 74,
+ /* 75 */ 75,
+ /* 76 */ 76,
+ /* 77 */ 77,
+ /* 78 */ 78,
+ /* 79 */ 79,
+ /* 80 */ 80,
+ /* 81 */ 81,
+ /* 82 */ 82,
+ /* 83 */ 83,
+ /* 84 */ 84,
+ /* 85 */ 85,
+ /* 86 */ 86,
+ /* 87 */ 87,
+ /* 88 */ 88,
+ /* 89 */ 89,
+ /* 90 */ 90,
+ /* 91 */ 91,
+ /* 92 */ 92,
+ /* 93 */ 93,
+ /* 94 */ 94,
+ /* 95 */ 95,
+ /* 96 */ 96,
+ /* 97 */ 97,
+ /* 98 */ 98,
+ /* 99 */ 99,
+ /* 100 */ 100,
+ /* 101 */ 101,
+ /* 102 */ 102,
+ /* 103 */ 103,
+ /* 104 */ 104,
+ /* 105 */ 105,
+ /* 106 */ 106,
+ /* 107 */ 107,
+ /* 108 */ 108,
+ /* 109 */ 109,
+ /* 110 */ 110,
+ /* 111 */ 111,
+ /* 112 */ 112,
+ /* 113 */ 113,
+ /* 114 */ 114,
+ /* 115 */ 115,
+ /* 116 */ 116,
+ /* 117 */ 117,
+ /* 118 */ 118,
+ /* 119 */ 119,
+ /* 120 */ 120,
+ /* 121 */ 121,
+ /* 122 */ 122,
+ /* 123 */ 123,
+ /* 124 */ 124,
+ /* 125 */ 125,
+ /* 126 */ 126,
+ /* 163 */ 127,
+ /* 1277 */ 156,
+ /* 1533 */ 158,
+ /* 11517 */ 132,
+ /* 11773 */ 134,
+ /* 12029 */ 135,
+ /* 12285 */ 138,
+ /* 12541 */ 139,
+ /* 12581 */ 180,
+ /* 12619 */ 174,
+ /* 12651 */ 181,
+ /* 12797 */ 140,
+ /* 12835 */ 175,
+ /* 13053 */ 141,
+ /* 13131 */ 166,
+ /* 13309 */ 142,
+ /* 13347 */ 160,
+ /* 13387 */ 170,
+ /* 13565 */ 143,
+ /* 13643 */ 168,
+ /* 13821 */ 150,
+ /* 14122 */ 171,
+ /* 14144 */ 169,
+ /* 14374 */ 179,
+ /* 14845 */ 182,
+ /* 16966 */ 188,
+ /* 17515 */ 177,
+ /* 17917 */ 133,
+ /* 18173 */ 136,
+ /* 18795 */ 152,
+ /* 19453 */ 129,
+ /* 19709 */ 128,
+ /* 19965 */ 130,
+ /* 20075 */ 167,
+ /* 20221 */ 131,
+ /* 20477 */ 153,
+ /* 20587 */ 165,
+ /* 20733 */ 178,
+ /* 21328 */ 191,
+ /* 22013 */ 161,
+ /* 22269 */ 164,
+ /* 22525 */ 176,
+ /* 22767 */ 187,
+ /* 22768 */ 186,
+ /* 22773 */ 183,
+ /* 22776 */ 185,
+ /* 22777 */ 184,
+ /* 22781 */ 172,
+ /* 23037 */ 144,
+ /* 23293 */ 145,
+ /* 23549 */ 146,
+ /* 23805 */ 147,
+ /* 24061 */ 148,
+ /* 24317 */ 149,
+ /* 24573 */ 189,
+ /* 24829 */ 190,
+ /* 25085 */ 151,
+ /* 25195 */ 154,
+ /* 25707 */ 157,
+ /* 25853 */ 137,
+ /* 26621 */ 192,
+ /* 26731 */ 173,
+ /* 26877 */ 193,
+ /* 26917 */ 163,
+ /* 27755 */ 159,
+ /* 29291 */ 162,
+ /* 30059 */ 155,
+};
+
+// The highest index for which
+// nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char]
+static const int nv_max_linear = 126;
diff --git a/src/proto/normal.pro b/src/proto/normal.pro
index ad0e95ab5c..70c0b97fc7 100644
--- a/src/proto/normal.pro
+++ b/src/proto/normal.pro
@@ -1,5 +1,5 @@
/* normal.c */
-void init_normal_cmds(void);
+void f_internal_get_nv_cmdchar(typval_T *argvars, typval_T *rettv);
void normal_cmd(oparg_T *oap, int toplevel);
void check_visual_highlight(void);
void end_visual_mode(void);
diff --git a/src/version.c b/src/version.c
index 84300baa7a..e5499ade66 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4252,
+/**/
4251,
/**/
4250,