viml: introduce menu_get() function #6322

menu_get({path}, {modes}). See :h menu_get.
This commit is contained in:
Matthieu Coudron 2017-03-21 03:21:53 +01:00 committed by Justin M. Keyes
parent e6d54407ba
commit dc685387a3
9 changed files with 629 additions and 132 deletions

View File

@ -5508,6 +5508,46 @@ max({expr}) Return the maximum value of all items in {expr}.
items in {expr} cannot be used as a Number this results in
an error. An empty |List| or |Dictionary| results in zero.
menu_get({path}, {modes}) *menu_get()*
Returns a |Dictionary| with all the submenu of {path} (set to
an empty string to match all menus). Only the commands matching {modes} are
returned ('a' for all, 'i' for insert see |creating-menus|).
For instance, executing:
>
nnoremenu &Test.Test inormal
inoremenu Test.Test insert
vnoremenu Test.Test x
echo menu_get("")
<
should produce an output with a similar structure:
>
[ {
"hidden": 0,
"name": "Test",
"priority": 500,
"shortcut": 84,
"submenus": [ {
"hidden": 0,
"mappings": {
i": {
"enabled": 1,
"noremap": 1,
"rhs": "insert",
"sid": 1,
"silent": 0
},
n": { ... },
s": { ... },
v": { ... }
},
"name": "Test",
"priority": 500,
"shortcut": 0
} ]
} ]
<
*min()*
min({expr}) Return the minimum value of all items in {expr}.
{expr} can be a list or a dictionary. For a dictionary,

View File

@ -47,6 +47,7 @@
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/keymap.h"
@ -8173,6 +8174,19 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
/// "menu_get(path [, modes])" function
static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
tv_list_alloc_ret(rettv);
int modes = MENU_ALL_MODES;
if (argvars[1].v_type == VAR_STRING) {
const char_u *const strmodes = (char_u *)tv_get_string(&argvars[1]);
modes = get_menu_cmd_modes(strmodes, false, NULL, NULL);
}
menu_get((char_u *)tv_get_string(&argvars[0]), modes, rettv->vval.v_list);
}
/*
* "extend(list, list [, idx])" function
* "extend(dict, dict [, action])" function

View File

@ -2,10 +2,10 @@
--
-- Keys:
--
-- args Number of arguments, list with maximum and minimum number of arguments
-- or list with a minimum number of arguments only. Defaults to zero
-- args Number of arguments, list with maximum and minimum number of arguments
-- or list with a minimum number of arguments only. Defaults to zero
-- arguments.
-- func Name of the C function which implements the VimL function. Defaults to
-- func Name of the C function which implements the VimL function. Defaults to
-- `f_{funcname}`.
local varargs = function(nr)
@ -208,6 +208,7 @@ return {
matchstr={args={2, 4}},
matchstrpos={args={2,4}},
max={args=1},
menu_get={args={1, 2}},
min={args=1},
mkdir={args={1, 3}},
mode={args={0, 1}},

View File

@ -1,4 +1,4 @@
bit = require 'bit'
local bit = require 'bit'
-- Description of the values below is contained in ex_cmds_defs.h file.
local RANGE = 0x001

View File

@ -5,12 +5,15 @@
#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h"
/* Values for "noremap" argument of ins_typebuf(). Also used for
* map->m_noremap and menu->noremap[]. */
#define REMAP_YES 0 /* allow remapping */
#define REMAP_NONE -1 /* no remapping */
#define REMAP_SCRIPT -2 /* remap script-local mappings only */
#define REMAP_SKIP -3 /* no remapping for first char */
/// Values for "noremap" argument of ins_typebuf(). Also used for
/// map->m_noremap and menu->noremap[].
/// @addtogroup REMAP_VALUES
/// @{
#define REMAP_YES 0 ///< allow remapping
#define REMAP_NONE -1 ///< no remapping
#define REMAP_SCRIPT -2 ///< remap script-local mappings only
#define REMAP_SKIP -3 ///< no remapping for first char
/// @}
#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */
#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */

View File

@ -932,12 +932,13 @@ int utf_char2len(int c)
return 6;
}
/*
* Convert Unicode character "c" to UTF-8 string in "buf[]".
* Returns the number of bytes.
* This does not include composing characters.
*/
int utf_char2bytes(int c, char_u *buf)
/// Convert Unicode character to UTF-8 string
///
/// @param c character to convert to \p buf
/// @param[out] buf UTF-8 string generated from \p c, does not add \0
/// @return the number of bytes (between 1 and 6)
/// @note This does not include composing characters.
int utf_char2bytes(int c, char_u *const buf)
{
if (c < 0x80) { /* 7 bits */
buf[0] = c;

View File

@ -26,7 +26,7 @@
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/eval/typval.h"
#define MENUDEPTH 10 /* maximum depth of menus */
@ -38,8 +38,8 @@
/* The character for each menu mode */
static char_u menu_mode_chars[] = {'n', 'v', 's', 'o', 'i', 'c', 't'};
/// The character for each menu mode
static char_u menu_mode_chars[] = { 'n', 'v', 's', 'o', 'i', 'c', 't' };
static char_u e_notsubmenu[] = N_(
"E327: Part of menu-item path is not sub-menu");
@ -47,17 +47,14 @@ static char_u e_othermode[] = N_("E328: Menu only exists in another mode");
static char_u e_nomenu[] = N_("E329: No menu \"%s\"");
/*
* Do the :menu command and relatives.
*/
void
ex_menu (
exarg_T *eap /* Ex command arguments */
)
/// Do the :menu command and relatives.
/// @param eap Ex command arguments
void
ex_menu(exarg_T *eap)
{
char_u *menu_path;
int modes;
char_u *map_to;
char_u *map_to; // command mapped to the menu entry
int noremap;
bool silent = false;
int unmenu;
@ -93,9 +90,12 @@ ex_menu (
}
/* Locate an optional "icon=filename" argument. */
// Locate an optional "icon=filename" argument
// Kept just the command parsing from vim for compativility but no further
// processing is done
if (STRNCMP(arg, "icon=", 5) == 0) {
arg += 5;
// icon = arg;
while (*arg != NUL && *arg != ' ') {
if (*arg == '\\')
STRMOVE(arg, arg + 1);
@ -107,12 +107,12 @@ ex_menu (
}
}
/*
* Fill in the priority table.
*/
for (p = arg; *p; ++p)
if (!ascii_isdigit(*p) && *p != '.')
// Fill in the priority table.
for (p = arg; *p; p++) {
if (!ascii_isdigit(*p) && *p != '.') {
break;
}
}
if (ascii_iswhite(*p)) {
for (i = 0; i < MENUDEPTH && !ascii_iswhite(*arg); ++i) {
pri_tab[i] = getdigits_long(&arg);
@ -226,8 +226,7 @@ ex_menu (
menuarg.modes = modes;
menuarg.noremap[0] = noremap;
menuarg.silent[0] = silent;
add_menu_path(menu_path, &menuarg, pri_tab, map_to
);
add_menu_path(menu_path, &menuarg, pri_tab, map_to);
/*
* For the PopUp menu, add a menu for each mode separately.
@ -252,16 +251,18 @@ theend:
;
}
/*
* Add the menu with the given name to the menu hierarchy
*/
static int
add_menu_path (
char_u *menu_path,
vimmenu_T *menuarg, /* passes modes, iconfile, iconidx,
icon_builtin, silent[0], noremap[0] */
long *pri_tab,
char_u *call_data
/// Add the menu with the given name to the menu hierarchy
///
/// @param[out] menuarg menu entry
/// @param[] pri_tab priority table
/// @param[in] call_data Right hand side command
static int
add_menu_path(
const char_u *const menu_path,
vimmenu_T *menuarg,
const long *const pri_tab,
const char_u *const call_data
)
{
char_u *path_name;
@ -296,8 +297,9 @@ add_menu_path (
if (map_to != NULL) {
en_name = name;
name = map_to;
} else
} else {
en_name = NULL;
}
dname = menu_text(name, NULL, NULL);
if (*dname == NUL) {
/* Only a mnemonic or accelerator is not valid. */
@ -311,14 +313,15 @@ add_menu_path (
while (menu != NULL) {
if (menu_name_equal(name, menu) || menu_name_equal(dname, menu)) {
if (*next_name == NUL && menu->children != NULL) {
if (!sys_menu)
if (!sys_menu) {
EMSG(_("E330: Menu path must not lead to a sub-menu"));
}
goto erret;
}
if (*next_name != NUL && menu->children == NULL
) {
if (!sys_menu)
if (*next_name != NUL && menu->children == NULL) {
if (!sys_menu) {
EMSG(_(e_notsubmenu));
}
goto erret;
}
break;
@ -352,7 +355,7 @@ add_menu_path (
menu->modes = modes;
menu->enabled = MENU_ALL_MODES;
menu->name = vim_strsave(name);
/* separate mnemonic and accelerator text from actual menu name */
// separate mnemonic and accelerator text from actual menu name
menu->dname = menu_text(name, &menu->mnemonic, &menu->actext);
if (en_name != NULL) {
menu->en_name = vim_strsave(en_name);
@ -364,9 +367,7 @@ add_menu_path (
menu->priority = pri_tab[pri_idx];
menu->parent = parent;
/*
* Add after menu that has lower priority.
*/
// Add after menu that has lower priority.
menu->next = *lower_pri;
*lower_pri = menu;
@ -392,8 +393,9 @@ add_menu_path (
name = next_name;
xfree(dname);
dname = NULL;
if (pri_tab[pri_idx + 1] != -1)
++pri_idx;
if (pri_tab[pri_idx + 1] != -1) {
pri_idx++;
}
}
xfree(path_name);
@ -419,8 +421,7 @@ add_menu_path (
// Don't do this for "<Nop>".
c = 0;
d = 0;
if (amenu && call_data != NULL && *call_data != NUL
) {
if (amenu && call_data != NULL && *call_data != NUL) {
switch (1 << i) {
case MENU_VISUAL_MODE:
case MENU_SELECT_MODE:
@ -438,9 +439,9 @@ add_menu_path (
if (c != 0) {
menu->strings[i] = xmalloc(STRLEN(call_data) + 5 );
menu->strings[i][0] = c;
if (d == 0)
if (d == 0) {
STRCPY(menu->strings[i] + 1, call_data);
else {
} else {
menu->strings[i][1] = d;
STRCPY(menu->strings[i] + 2, call_data);
}
@ -452,8 +453,9 @@ add_menu_path (
menu->strings[i][len + 1] = Ctrl_G;
menu->strings[i][len + 2] = NUL;
}
} else
} else {
menu->strings[i] = p;
}
menu->noremap[i] = menuarg->noremap[0];
menu->silent[i] = menuarg->silent[0];
}
@ -657,20 +659,109 @@ static void free_menu_string(vimmenu_T *menu, int idx)
menu->strings[idx] = NULL;
}
/*
* Show the mapping associated with a menu item or hierarchy in a sub-menu.
*/
static int show_menus(char_u *path_name, int modes)
/// Export menus
///
/// @param[in] menu if null, starts from root_menu
/// @param modes, a choice of \ref MENU_MODES
/// @return a dict with name/commands
/// @see menu_get
static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
{
dict_T *dict;
char buf[sizeof(menu->mnemonic)];
int mnemonic_len;
if (!menu || (menu->modes & modes) == 0x0) {
return NULL;
}
dict = tv_dict_alloc();
tv_dict_add_str(dict, S_LEN("name"), (char *)menu->dname);
tv_dict_add_nr(dict, S_LEN("priority"), (int)menu->priority);
tv_dict_add_nr(dict, S_LEN("hidden"), menu_is_hidden(menu->dname));
if (menu->mnemonic) {
mnemonic_len = utf_char2bytes(menu->mnemonic, (u_char *)buf);
buf[mnemonic_len] = '\0';
tv_dict_add_str(dict, S_LEN("shortcut"), buf);
}
if (menu->modes & MENU_TIP_MODE && menu->strings[MENU_INDEX_TIP]) {
tv_dict_add_str(dict, S_LEN("tooltip"),
(char *)menu->strings[MENU_INDEX_TIP]);
}
if (!menu->children) {
// leaf menu
dict_T *commands = tv_dict_alloc();
tv_dict_add_dict(dict, S_LEN("mappings"), commands);
for (int bit = 0; bit < MENU_MODES; bit++) {
if ((menu->modes & modes & (1 << bit)) != 0) {
dict_T *impl = tv_dict_alloc();
if (*menu->strings[bit] == NUL) {
tv_dict_add_str(impl, S_LEN("rhs"), (char *)"<Nop>");
} else {
tv_dict_add_str(impl, S_LEN("rhs"), (char *)menu->strings[bit]);
}
tv_dict_add_nr(impl, S_LEN("silent"), menu->silent[bit]);
tv_dict_add_nr(impl, S_LEN("enabled"),
(menu->enabled & (1 << bit)) ? 1 : 0);
tv_dict_add_nr(impl, S_LEN("noremap"),
(menu->noremap[bit] & REMAP_NONE) ? 1 : 0);
tv_dict_add_nr(impl, S_LEN("sid"),
(menu->noremap[bit] & REMAP_SCRIPT) ? 1 : 0);
tv_dict_add_dict(commands, (char *)&menu_mode_chars[bit], 1, impl);
}
}
} else {
// visit recursively all children
list_T *children_list = tv_list_alloc();
for (menu = menu->children; menu != NULL; menu = menu->next) {
dict_T *dic = menu_get_recursive(menu, modes);
if (dict && tv_dict_len(dict) > 0) {
tv_list_append_dict(children_list, dic);
}
}
tv_dict_add_list(dict, S_LEN("submenus"), children_list);
}
return dict;
}
/// Export menus matching path \p path_name
///
/// @param path_name
/// @param modes supported modes, see \ref MENU_MODES
/// @param[in,out] list must be allocated
/// @return false if could not find path_name
bool menu_get(char_u *const path_name, int modes, list_T *list)
{
char_u *p;
char_u *name;
vimmenu_T *menu;
vimmenu_T *parent = NULL;
menu = find_menu(root_menu, path_name, modes);
if (!menu) {
return false;
}
for (; menu != NULL; menu = menu->next) {
dict_T *dict = menu_get_recursive(menu, modes);
if (dict && tv_dict_len(dict) > 0) {
tv_list_append_dict(list, dict);
}
}
return true;
}
menu = root_menu;
name = path_name = vim_strsave(path_name);
/* First, find the (sub)menu with the given name */
/// Find menu matching required name and modes
///
/// @param menu top menu to start looking from
/// @param name path towards the menu
/// @return menu if \p name is null, found menu or NULL
vimmenu_T *
find_menu(vimmenu_T *menu, char_u * name, int modes)
{
char_u *p;
while (*name) {
p = menu_name_skip(name);
while (menu != NULL) {
@ -678,39 +769,46 @@ static int show_menus(char_u *path_name, int modes)
/* Found menu */
if (*p != NUL && menu->children == NULL) {
EMSG(_(e_notsubmenu));
xfree(path_name);
return FAIL;
return NULL;
} else if ((menu->modes & modes) == 0x0) {
EMSG(_(e_othermode));
xfree(path_name);
return FAIL;
return NULL;
}
break;
}
menu = menu->next;
}
if (menu == NULL) {
EMSG2(_(e_nomenu), name);
xfree(path_name);
return FAIL;
return NULL;
}
name = p;
parent = menu;
menu = menu->children;
}
xfree(path_name);
return menu;
}
/// Show the mapping associated with a menu item or hierarchy in a sub-menu.
static int show_menus(char_u *const path_name, int modes)
{
vimmenu_T *menu;
// First, find the (sub)menu with the given name
menu = find_menu(root_menu, path_name, modes);
if (!menu) {
return FAIL;
}
/* Now we have found the matching menu, and we list the mappings */
/* Highlight title */
MSG_PUTS_TITLE(_("\n--- Menus ---"));
show_menus_recursive(parent, modes, 0);
show_menus_recursive(menu->parent, modes, 0);
return OK;
}
/*
* Recursively show the mappings associated with the menus under the given one
*/
/// Recursively show the mappings associated with the menus under the given one
static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
{
int i;
@ -993,12 +1091,13 @@ char_u *get_menu_names(expand_T *xp, int idx)
return str;
}
/*
* Skip over this element of the menu path and return the start of the next
* element. Any \ and ^Vs are removed from the current element.
* "name" may be modified.
*/
char_u *menu_name_skip(char_u *name)
/// Skip over this element of the menu path and return the start of the next
/// element. Any \ and ^Vs are removed from the current element.
///
/// @param name may be modified.
/// @return start of the next element
char_u *menu_name_skip(char_u *const name)
{
char_u *p;
@ -1018,16 +1117,16 @@ char_u *menu_name_skip(char_u *name)
* Return TRUE when "name" matches with menu "menu". The name is compared in
* two ways: raw menu name and menu name without '&'. ignore part after a TAB.
*/
static int menu_name_equal(char_u *name, vimmenu_T *menu)
static bool menu_name_equal(const char_u *const name, vimmenu_T *const menu)
{
if (menu->en_name != NULL
&& (menu_namecmp(name, menu->en_name)
|| menu_namecmp(name, menu->en_dname)))
return TRUE;
return true;
return menu_namecmp(name, menu->name) || menu_namecmp(name, menu->dname);
}
static int menu_namecmp(char_u *name, char_u *mname)
static bool menu_namecmp(const char_u *const name, const char_u *const mname)
{
int i;
@ -1038,18 +1137,20 @@ static int menu_namecmp(char_u *name, char_u *mname)
&& (mname[i] == NUL || mname[i] == TAB);
}
/*
* Return the modes specified by the given menu command (eg :menu! returns
* MENU_CMDLINE_MODE | MENU_INSERT_MODE).
* If "noremap" is not NULL, then the flag it points to is set according to
* whether the command is a "nore" command.
* If "unmenu" is not NULL, then the flag it points to is set according to
* whether the command is an "unmenu" command.
*/
static int
get_menu_cmd_modes (
char_u *cmd,
int forceit, /* Was there a "!" after the command? */
/// converts a string into a combination of \ref MENU_MODES
/// (eg :menu! returns MENU_CMDLINE_MODE | MENU_INSERT_MODE)
///
/// @param[in] cmd a string like 'n' (normal) or 'a' (all)
/// @param[in] forceit Was there a "!" after the command?
/// @param[out] If "noremap" is not NULL, then the flag it points to is set
/// according to whether the command is a "nore" command.
/// @param[out] unmenu is not NULL, then the flag it points to is set according
/// to whether the command is an "unmenu" command.
int
get_menu_cmd_modes(
const char_u * cmd,
bool forceit,
int *noremap,
int *unmenu
)
@ -1090,12 +1191,15 @@ get_menu_cmd_modes (
}
/* FALLTHROUGH */
default:
--cmd;
if (forceit) /* menu!! */
cmd--;
if (forceit) {
// menu!!
modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE;
else /* menu */
} else {
// menu
modes = MENU_NORMAL_MODE | MENU_VISUAL_MODE | MENU_SELECT_MODE
| MENU_OP_PENDING_MODE;
}
}
if (noremap != NULL)
@ -1201,12 +1305,14 @@ int menu_is_separator(char_u *name)
return name[0] == '-' && name[STRLEN(name) - 1] == '-';
}
/*
* Return TRUE if the menu is hidden: Starts with ']'
*/
/// True if a popup menu or starts with \ref MNU_HIDDEN_CHAR
///
/// @return true if the menu is hidden
static int menu_is_hidden(char_u *name)
{
return (name[0] == ']') || (menu_is_popup(name) && name[5] != NUL);
return (name[0] == MNU_HIDDEN_CHAR)
|| (menu_is_popup(name) && name[5] != NUL);
}
/*

View File

@ -6,7 +6,9 @@
#include "nvim/types.h" // for char_u and expand_T
#include "nvim/ex_cmds_defs.h" // for exarg_T
/* Indices into vimmenu_T->strings[] and vimmenu_T->noremap[] for each mode */
/// Indices into vimmenu_T->strings[] and vimmenu_T->noremap[] for each mode
/// \addtogroup MENU_INDEX
/// @{
#define MENU_INDEX_INVALID -1
#define MENU_INDEX_NORMAL 0
#define MENU_INDEX_VISUAL 1
@ -16,8 +18,12 @@
#define MENU_INDEX_CMDLINE 5
#define MENU_INDEX_TIP 6
#define MENU_MODES 7
/// @}
/// note MENU_INDEX_TIP is not a 'real' mode
/* Menu modes */
/// Menu modes
/// \addtogroup MENU_MODES
/// @{
#define MENU_NORMAL_MODE (1 << MENU_INDEX_NORMAL)
#define MENU_VISUAL_MODE (1 << MENU_INDEX_VISUAL)
#define MENU_SELECT_MODE (1 << MENU_INDEX_SELECT)
@ -26,31 +32,30 @@
#define MENU_CMDLINE_MODE (1 << MENU_INDEX_CMDLINE)
#define MENU_TIP_MODE (1 << MENU_INDEX_TIP)
#define MENU_ALL_MODES ((1 << MENU_INDEX_TIP) - 1)
/*note MENU_INDEX_TIP is not a 'real' mode*/
/// @}
/* Start a menu name with this to not include it on the main menu bar */
/// Start a menu name with this to not include it on the main menu bar
#define MNU_HIDDEN_CHAR ']'
typedef struct VimMenu vimmenu_T;
struct VimMenu {
int modes; /* Which modes is this menu visible for? */
int enabled; /* for which modes the menu is enabled */
char_u *name; /* Name of menu, possibly translated */
char_u *dname; /* Displayed Name ("name" without '&') */
char_u *en_name; /* "name" untranslated, NULL when "name"
* was not translated */
char_u *en_dname; /* "dname" untranslated, NULL when "dname"
* was not translated */
int mnemonic; /* mnemonic key (after '&') */
char_u *actext; /* accelerator text (after TAB) */
long priority; /* Menu order priority */
char_u *strings[MENU_MODES]; /* Mapped string for each mode */
int noremap[MENU_MODES]; /* A REMAP_ flag for each mode */
bool silent[MENU_MODES]; /* A silent flag for each mode */
vimmenu_T *children; /* Children of sub-menu */
vimmenu_T *parent; /* Parent of menu */
vimmenu_T *next; /* Next item in menu */
int modes; ///< Which modes is this menu visible for
int enabled; ///< for which modes the menu is enabled
char_u *name; ///< Name of menu, possibly translated
char_u *dname; ///< Displayed Name ("name" without '&')
char_u *en_name; ///< "name" untranslated, NULL when
///< was not translated
char_u *en_dname; ///< NULL when "dname" untranslated
int mnemonic; ///< mnemonic key (after '&')
char_u *actext; ///< accelerator text (after TAB)
long priority; ///< Menu order priority
char_u *strings[MENU_MODES]; ///< Mapped string for each mode
int noremap[MENU_MODES]; ///< A \ref REMAP_VALUES flag for each mode
bool silent[MENU_MODES]; ///< A silent flag for each mode
vimmenu_T *children; ///< Children of sub-menu
vimmenu_T *parent; ///< Parent of menu
vimmenu_T *next; ///< Next item in menu
};

View File

@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, command, nvim = helpers.clear, helpers.command, helpers.nvim
local expect, feed = helpers.expect, helpers.feed
local eq, eval = helpers.eq, helpers.eval
local funcs = helpers.funcs
describe(':emenu', function()
@ -56,3 +58,328 @@ describe(':emenu', function()
eq('thiscmdmode', eval('getcmdline()'))
end)
end)
describe('menu_get', function()
before_each(function()
clear()
command('nnoremenu &Test.Test inormal<ESC>')
command('inoremenu Test.Test insert')
command('vnoremenu Test.Test x')
command('cnoremenu Test.Test cmdmode')
command('menu Test.Nested.test level1')
command('menu Test.Nested.Nested2 level2')
command('nnoremenu <script> Export.Script p')
command('tmenu Export.Script This is the tooltip')
command('menu ]Export.hidden thisoneshouldbehidden')
command('nnoremenu Edit.Paste p')
command('cnoremenu Edit.Paste <C-R>"')
end)
it('no path, all modes', function()
local m = funcs.menu_get("","a");
-- You can use the following to print the expected table
-- and regenerate the tests:
-- local pretty = require('pl.pretty');
-- print(pretty.dump(m))
local expected = {
{
shortcut = "T",
hidden = 0,
submenus = {
{
mappings = {
i = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "insert",
silent = 0
},
s = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "x",
silent = 0
},
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "inormal\27",
silent = 0
},
v = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "x",
silent = 0
},
c = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "cmdmode",
silent = 0
}
},
priority = 500,
name = "Test",
hidden = 0
},
{
priority = 500,
name = "Nested",
submenus = {
{
mappings = {
o = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
},
v = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
},
s = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
},
n = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level1",
silent = 0
}
},
priority = 500,
name = "test",
hidden = 0
},
{
mappings = {
o = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
},
v = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
},
s = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
},
n = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "level2",
silent = 0
}
},
priority = 500,
name = "Nested2",
hidden = 0
}
},
hidden = 0
}
},
priority = 500,
name = "Test"
},
{
priority = 500,
name = "Export",
submenus = {
{
tooltip = "This is the tooltip",
hidden = 0,
name = "Script",
priority = 500,
mappings = {
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "p",
silent = 0
}
}
}
},
hidden = 0
},
{
priority = 500,
name = "Edit",
submenus = {
{
mappings = {
c = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "\18\"",
silent = 0
},
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "p",
silent = 0
}
},
priority = 500,
name = "Paste",
hidden = 0
}
},
hidden = 0
},
{
priority = 500,
name = "]Export",
submenus = {
{
mappings = {
o = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
},
v = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
},
s = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
},
n = {
sid = 0,
noremap = 0,
enabled = 1,
rhs = "thisoneshouldbehidden",
silent = 0
}
},
priority = 500,
name = "hidden",
hidden = 0
}
},
hidden = 1
}
}
eq(expected, m)
end)
it('matching path, default modes', function()
local m = funcs.menu_get("Export", "a")
local expected = {
{
tooltip = "This is the tooltip",
hidden = 0,
name = "Script",
priority = 500,
mappings = {
n = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "p",
silent = 0
}
}
}
}
eq(expected, m)
end)
it('no path, matching modes', function()
local m = funcs.menu_get("","i")
local expected = {
{
shortcut = "T",
hidden = 0,
submenus = {
{
mappings = {
i = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "insert",
silent = 0
}
},
priority = 500,
name = "Test",
hidden = 0
},
{
}
},
priority = 500,
name = "Test"
}
}
eq(expected, m)
end)
it('matching path and modes', function()
local m = funcs.menu_get("Test","i")
local expected = {
{
mappings = {
i = {
sid = 1,
noremap = 1,
enabled = 1,
rhs = "insert",
silent = 0
}
},
priority = 500,
name = "Test",
hidden = 0
}
}
eq(expected, m)
end)
end)