diff options
-rw-r--r-- | runtime/doc/eval.txt | 17 | ||||
-rw-r--r-- | src/nvim/menu.c | 51 | ||||
-rw-r--r-- | test/functional/ex_cmds/menu_spec.lua | 65 |
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", |