--- /dev/null
+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
#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);
#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.
/*
* 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
{
{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},
{'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},
{'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},
{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},
// 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.