mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 11:28:22 +00:00
Merge #8194 from justinmk/fix-menu
fix ":menu Item.SubItem", fix menu_get("foo")
This commit is contained in:
@@ -5666,23 +5666,24 @@ max({expr}) Return the maximum value of all items in {expr}.
|
|||||||
|
|
||||||
menu_get({path}, {modes}) *menu_get()*
|
menu_get({path}, {modes}) *menu_get()*
|
||||||
Returns a |List| of |Dictionaries| describing |menus| (defined
|
Returns a |List| of |Dictionaries| describing |menus| (defined
|
||||||
by |:menu|, |:amenu|, etc.).
|
by |:menu|, |:amenu|, …), including |hidden-menus|.
|
||||||
{path} limits the result to a subtree of the menu hierarchy
|
|
||||||
(empty string matches all menus). E.g. to get items in the
|
{path} matches a menu by name, or all menus if {path} is an
|
||||||
"File" menu subtree: >
|
empty string. Example: >
|
||||||
:echo menu_get('File','')
|
:echo menu_get('File','')
|
||||||
|
:echo menu_get('')
|
||||||
<
|
<
|
||||||
{modes} is a string of zero or more modes (see |maparg()| or
|
{modes} is a string of zero or more modes (see |maparg()| or
|
||||||
|creating-menus| for the list of modes). "a" means "all".
|
|creating-menus| for the list of modes). "a" means "all".
|
||||||
|
|
||||||
For example: >
|
Example: >
|
||||||
nnoremenu &Test.Test inormal
|
nnoremenu &Test.Test inormal
|
||||||
inoremenu Test.Test insert
|
inoremenu Test.Test insert
|
||||||
vnoremenu Test.Test x
|
vnoremenu Test.Test x
|
||||||
echo menu_get("")
|
echo menu_get("")
|
||||||
<
|
|
||||||
returns something like this:
|
< returns something like this: >
|
||||||
>
|
|
||||||
[ {
|
[ {
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
|
@@ -660,7 +660,8 @@ static void free_menu_string(vimmenu_T *menu, int idx)
|
|||||||
///
|
///
|
||||||
/// @param[in] menu if null, starts from root_menu
|
/// @param[in] menu if null, starts from root_menu
|
||||||
/// @param modes, a choice of \ref MENU_MODES
|
/// @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
|
/// @see menu_get
|
||||||
static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
|
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
|
// visit recursively all children
|
||||||
list_T *const children_list = tv_list_alloc(kListLenMayKnow);
|
list_T *const children_list = tv_list_alloc(kListLenMayKnow);
|
||||||
for (menu = menu->children; menu != NULL; menu = menu->next) {
|
for (menu = menu->children; menu != NULL; menu = menu->next) {
|
||||||
dict_T *dic = menu_get_recursive(menu, modes);
|
dict_T *d = menu_get_recursive(menu, modes);
|
||||||
if (tv_dict_len(dict) > 0) {
|
if (tv_dict_len(d) > 0) {
|
||||||
tv_list_append_dict(children_list, dic);
|
tv_list_append_dict(children_list, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tv_dict_add_list(dict, S_LEN("submenus"), children_list);
|
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
|
/// @return false if could not find path_name
|
||||||
bool menu_get(char_u *const path_name, int modes, list_T *list)
|
bool menu_get(char_u *const path_name, int modes, list_T *list)
|
||||||
{
|
{
|
||||||
vimmenu_T *menu;
|
vimmenu_T *menu = find_menu(root_menu, path_name, modes);
|
||||||
menu = find_menu(root_menu, path_name, modes);
|
|
||||||
if (!menu) {
|
if (!menu) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (; menu != NULL; menu = menu->next) {
|
for (; menu != NULL; menu = menu->next) {
|
||||||
dict_T *dict = menu_get_recursive(menu, modes);
|
dict_T *d = menu_get_recursive(menu, modes);
|
||||||
if (dict && tv_dict_len(dict) > 0) {
|
if (d && tv_dict_len(d) > 0) {
|
||||||
tv_list_append_dict(list, dict);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Find menu matching required name and modes
|
/// Find menu matching `name` and `modes`.
|
||||||
///
|
///
|
||||||
/// @param menu top menu to start looking from
|
/// @param menu top menu to start looking from
|
||||||
/// @param name path towards the menu
|
/// @param name path towards the menu
|
||||||
/// @return menu if \p name is null, found menu or NULL
|
/// @return menu if \p name is null, found menu or NULL
|
||||||
vimmenu_T *
|
static vimmenu_T *find_menu(vimmenu_T *menu, char_u *name, int modes)
|
||||||
find_menu(vimmenu_T *menu, char_u * name, int modes)
|
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
|
||||||
while (*name) {
|
while (*name) {
|
||||||
|
// find the end of one dot-separated name and put a NUL at the dot
|
||||||
p = menu_name_skip(name);
|
p = menu_name_skip(name);
|
||||||
while (menu != NULL) {
|
while (menu != NULL) {
|
||||||
if (menu_name_equal(name, menu)) {
|
if (menu_name_equal(name, menu)) {
|
||||||
/* Found menu */
|
// Found menu
|
||||||
if (*p != NUL && menu->children == NULL) {
|
if (*p != NUL && menu->children == NULL) {
|
||||||
EMSG(_(e_notsubmenu));
|
if (*p != NUL) {
|
||||||
return NULL;
|
EMSG(_(e_notsubmenu));
|
||||||
} else if ((menu->modes & modes) == 0x0) {
|
return NULL;
|
||||||
EMSG(_(e_othermode));
|
} else if ((menu->modes & modes) == 0x0) {
|
||||||
return NULL;
|
EMSG(_(e_othermode));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*p == NUL) { // found a full match
|
||||||
|
return menu;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -780,6 +790,7 @@ find_menu(vimmenu_T *menu, char_u * name, int modes)
|
|||||||
EMSG2(_(e_nomenu), name);
|
EMSG2(_(e_nomenu), name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// Found a match, search the sub-menu.
|
||||||
name = p;
|
name = p;
|
||||||
menu = menu->children;
|
menu = menu->children;
|
||||||
}
|
}
|
||||||
@@ -1235,7 +1246,7 @@ static char_u *popup_mode_name(char_u *name, int idx)
|
|||||||
///
|
///
|
||||||
/// @return a pointer to allocated memory.
|
/// @return a pointer to allocated memory.
|
||||||
static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext)
|
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)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
@@ -63,25 +63,27 @@ describe('menu_get', function()
|
|||||||
|
|
||||||
before_each(function()
|
before_each(function()
|
||||||
clear()
|
clear()
|
||||||
command('nnoremenu &Test.Test inormal<ESC>')
|
command([=[
|
||||||
command('inoremenu Test.Test insert')
|
nnoremenu &Test.Test inormal<ESC>
|
||||||
command('vnoremenu Test.Test x')
|
inoremenu Test.Test insert
|
||||||
command('cnoremenu Test.Test cmdmode')
|
vnoremenu Test.Test x
|
||||||
command('menu Test.Nested.test level1')
|
cnoremenu Test.Test cmdmode
|
||||||
command('menu Test.Nested.Nested2 level2')
|
menu Test.Nested.test level1
|
||||||
|
menu Test.Nested.Nested2 level2
|
||||||
|
|
||||||
command('nnoremenu <script> Export.Script p')
|
nnoremenu <script> Export.Script p
|
||||||
command('tmenu Export.Script This is the tooltip')
|
tmenu Export.Script This is the tooltip
|
||||||
command('menu ]Export.hidden thisoneshouldbehidden')
|
menu ]Export.hidden thisoneshouldbehidden
|
||||||
|
|
||||||
command('nnoremenu Edit.Paste p')
|
nnoremenu Edit.Paste p
|
||||||
command('cnoremenu Edit.Paste <C-R>"')
|
cnoremenu Edit.Paste <C-R>"
|
||||||
|
]=])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("path='', modes='a'", function()
|
it("path='', modes='a'", function()
|
||||||
local m = funcs.menu_get("","a");
|
local m = funcs.menu_get("","a");
|
||||||
-- HINT: To print the expected table and regenerate the tests:
|
-- HINT: To print the expected table and regenerate the tests:
|
||||||
-- print(require('pl.pretty').dump(m))
|
-- print(require('inspect')(m))
|
||||||
local expected = {
|
local expected = {
|
||||||
{
|
{
|
||||||
shortcut = "T",
|
shortcut = "T",
|
||||||
@@ -306,10 +308,13 @@ describe('menu_get', function()
|
|||||||
eq(expected, m)
|
eq(expected, m)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('matching path, default modes', function()
|
it('matching path, all modes', function()
|
||||||
local m = funcs.menu_get("Export", "a")
|
local m = funcs.menu_get("Export", "a")
|
||||||
local expected = {
|
local expected = { {
|
||||||
{
|
hidden = 0,
|
||||||
|
name = "Export",
|
||||||
|
priority = 500,
|
||||||
|
submenus = { {
|
||||||
tooltip = "This is the tooltip",
|
tooltip = "This is the tooltip",
|
||||||
hidden = 0,
|
hidden = 0,
|
||||||
name = "Script",
|
name = "Script",
|
||||||
@@ -323,8 +328,8 @@ describe('menu_get', function()
|
|||||||
silent = 0
|
silent = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} }
|
||||||
}
|
} }
|
||||||
eq(expected, m)
|
eq(expected, m)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -349,8 +354,6 @@ describe('menu_get', function()
|
|||||||
name = "Test",
|
name = "Test",
|
||||||
hidden = 0
|
hidden = 0
|
||||||
},
|
},
|
||||||
{
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
priority = 500,
|
priority = 500,
|
||||||
name = "Test"
|
name = "Test"
|
||||||
@@ -363,14 +366,22 @@ describe('menu_get', function()
|
|||||||
local m = funcs.menu_get("Test","i")
|
local m = funcs.menu_get("Test","i")
|
||||||
local expected = {
|
local expected = {
|
||||||
{
|
{
|
||||||
mappings = {
|
shortcut = "T",
|
||||||
i = {
|
submenus = {
|
||||||
sid = 1,
|
{
|
||||||
noremap = 1,
|
mappings = {
|
||||||
enabled = 1,
|
i = {
|
||||||
rhs = "insert",
|
sid = 1,
|
||||||
silent = 0
|
noremap = 1,
|
||||||
}
|
enabled = 1,
|
||||||
|
rhs = "insert",
|
||||||
|
silent = 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
priority = 500,
|
||||||
|
name = "Test",
|
||||||
|
hidden = 0
|
||||||
|
},
|
||||||
},
|
},
|
||||||
priority = 500,
|
priority = 500,
|
||||||
name = "Test",
|
name = "Test",
|
||||||
|
Reference in New Issue
Block a user