aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt17
-rw-r--r--src/nvim/menu.c51
-rw-r--r--test/functional/ex_cmds/menu_spec.lua65
3 files changed, 78 insertions, 55 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 425dcede8b..5dc282f6ba 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5666,23 +5666,24 @@ max({expr}) Return the maximum value of all items in {expr}.
menu_get({path}, {modes}) *menu_get()*
Returns a |List| of |Dictionaries| describing |menus| (defined
- by |:menu|, |:amenu|, etc.).
- {path} limits the result to a subtree of the menu hierarchy
- (empty string matches all menus). E.g. to get items in the
- "File" menu subtree: >
+ by |:menu|, |:amenu|, …), including |hidden-menus|.
+
+ {path} matches a menu by name, or all menus if {path} is an
+ empty string. Example: >
:echo menu_get('File','')
+ :echo menu_get('')
<
{modes} is a string of zero or more modes (see |maparg()| or
|creating-menus| for the list of modes). "a" means "all".
- For example: >
+ Example: >
nnoremenu &Test.Test inormal
inoremenu Test.Test insert
vnoremenu Test.Test x
echo menu_get("")
-<
- returns something like this:
->
+
+< returns something like this: >
+
[ {
"hidden": 0,
"name": "Test",
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 074feb9906..aea297fce2 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -660,7 +660,8 @@ static void free_menu_string(vimmenu_T *menu, int idx)
///
/// @param[in] menu if null, starts from root_menu
/// @param modes, a choice of \ref MENU_MODES
-/// @return a dict with name/commands
+/// @return dict with name/commands
+/// @see show_menus_recursive
/// @see menu_get
static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
{
@@ -715,10 +716,10 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
// visit recursively all children
list_T *const children_list = tv_list_alloc(kListLenMayKnow);
for (menu = menu->children; menu != NULL; menu = menu->next) {
- dict_T *dic = menu_get_recursive(menu, modes);
- if (tv_dict_len(dict) > 0) {
- tv_list_append_dict(children_list, dic);
- }
+ dict_T *d = menu_get_recursive(menu, modes);
+ if (tv_dict_len(d) > 0) {
+ tv_list_append_dict(children_list, d);
+ }
}
tv_dict_add_list(dict, S_LEN("submenus"), children_list);
}
@@ -734,42 +735,51 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
/// @return false if could not find path_name
bool menu_get(char_u *const path_name, int modes, list_T *list)
{
- vimmenu_T *menu;
- menu = find_menu(root_menu, path_name, modes);
+ vimmenu_T *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);
+ dict_T *d = menu_get_recursive(menu, modes);
+ if (d && tv_dict_len(d) > 0) {
+ tv_list_append_dict(list, d);
+ }
+ if (*path_name != NUL) {
+ // If a (non-empty) path query was given, only the first node in the
+ // find_menu() result is relevant. Else we want all nodes.
+ break;
}
}
return true;
}
-/// Find menu matching required name and modes
+/// Find menu matching `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)
+static vimmenu_T *find_menu(vimmenu_T *menu, char_u *name, int modes)
{
char_u *p;
while (*name) {
+ // find the end of one dot-separated name and put a NUL at the dot
p = menu_name_skip(name);
while (menu != NULL) {
if (menu_name_equal(name, menu)) {
- /* Found menu */
+ // Found menu
if (*p != NUL && menu->children == NULL) {
- EMSG(_(e_notsubmenu));
- return NULL;
- } else if ((menu->modes & modes) == 0x0) {
- EMSG(_(e_othermode));
- return NULL;
+ if (*p != NUL) {
+ EMSG(_(e_notsubmenu));
+ return NULL;
+ } else if ((menu->modes & modes) == 0x0) {
+ EMSG(_(e_othermode));
+ return NULL;
+ }
+ }
+ if (*p == NUL) { // found a full match
+ return menu;
}
break;
}
@@ -780,6 +790,7 @@ find_menu(vimmenu_T *menu, char_u * name, int modes)
EMSG2(_(e_nomenu), name);
return NULL;
}
+ // Found a match, search the sub-menu.
name = p;
menu = menu->children;
}
@@ -1235,7 +1246,7 @@ static char_u *popup_mode_name(char_u *name, int idx)
///
/// @return a pointer to allocated memory.
static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext)
- FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
FUNC_ATTR_NONNULL_ARG(1)
{
char_u *p;
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
index 2c0535acda..2309e949c0 100644
--- a/test/functional/ex_cmds/menu_spec.lua
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -63,25 +63,27 @@ 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 &Test.Test inormal<ESC>
+ inoremenu Test.Test insert
+ vnoremenu Test.Test x
+ cnoremenu Test.Test cmdmode
+ menu Test.Nested.test level1
+ menu Test.Nested.Nested2 level2
- command('nnoremenu <script> Export.Script p')
- command('tmenu Export.Script This is the tooltip')
- command('menu ]Export.hidden thisoneshouldbehidden')
+ nnoremenu <script> Export.Script p
+ tmenu Export.Script This is the tooltip
+ menu ]Export.hidden thisoneshouldbehidden
- command('nnoremenu Edit.Paste p')
- command('cnoremenu Edit.Paste <C-R>"')
+ nnoremenu Edit.Paste p
+ cnoremenu Edit.Paste <C-R>"
+ ]=])
end)
it("path='', modes='a'", function()
local m = funcs.menu_get("","a");
-- HINT: To print the expected table and regenerate the tests:
- -- print(require('pl.pretty').dump(m))
+ -- print(require('inspect')(m))
local expected = {
{
shortcut = "T",
@@ -306,10 +308,13 @@ describe('menu_get', function()
eq(expected, m)
end)
- it('matching path, default modes', function()
+ it('matching path, all modes', function()
local m = funcs.menu_get("Export", "a")
- local expected = {
- {
+ local expected = { {
+ hidden = 0,
+ name = "Export",
+ priority = 500,
+ submenus = { {
tooltip = "This is the tooltip",
hidden = 0,
name = "Script",
@@ -323,8 +328,8 @@ describe('menu_get', function()
silent = 0
}
}
- }
- }
+ } }
+ } }
eq(expected, m)
end)
@@ -349,8 +354,6 @@ describe('menu_get', function()
name = "Test",
hidden = 0
},
- {
- }
},
priority = 500,
name = "Test"
@@ -363,14 +366,22 @@ describe('menu_get', function()
local m = funcs.menu_get("Test","i")
local expected = {
{
- mappings = {
- i = {
- sid = 1,
- noremap = 1,
- enabled = 1,
- rhs = "insert",
- silent = 0
- }
+ shortcut = "T",
+ submenus = {
+ {
+ mappings = {
+ i = {
+ sid = 1,
+ noremap = 1,
+ enabled = 1,
+ rhs = "insert",
+ silent = 0
+ },
+ },
+ priority = 500,
+ name = "Test",
+ hidden = 0
+ },
},
priority = 500,
name = "Test",