xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit 74756448dfbd95f7526e6b25b0411eb1938e4a79

Add vifm.menus.loadcustom()
It makes a menu out of a list of strings.
Author: xaizek
Author date (UTC): 2024-12-02 22:56
Committer name: xaizek
Committer date (UTC): 2024-12-02 22:56
Parent(s): 8fc717a4ebfaf6226b3af15265e0a64cca8d85b7
Signing key: 99DC5E4DB05F6BE2
Tree: b245251a6d7b3a1746e3a700f4366f90ecdec636
File Lines added Lines deleted
ChangeLog.LuaAPI 2 0
data/vim/doc/app/vifm-lua.txt 40 1
src/lua/vifm.c 72 0
src/lua/vifmview.c 1 5
src/lua/vifmview.h 5 0
src/menus/menus.c 18 12
src/menus/menus.h 1 0
src/menus/users_menu.c 33 0
src/menus/users_menu.h 6 0
src/modes/menu.c 7 0
src/modes/menu.h 1 0
src/tags.c 2 0
tests/lua/api_menus.c 105 0
File ChangeLog.LuaAPI changed (mode: 100644) (index e688217c5..b7e30b86a)
... ... documented in the regular ChangeLog.
63 63
64 64 Added index of Lua API to the documentation for easier overview/lookup. Added index of Lua API to the documentation for easier overview/lookup.
65 65
66 Added vifm.menus.loadcustom() that makes a menu out of a list of strings.
67
66 68 Made VifmJob:errors() wait for receiving errors if the job has finished. Made VifmJob:errors() wait for receiving errors if the job has finished.
67 69
68 70 Fixed jobs created via vifm.startjob() being displayed with "UNKNOWN" for Fixed jobs created via vifm.startjob() being displayed with "UNKNOWN" for
File data/vim/doc/app/vifm-lua.txt changed (mode: 100644) (index 2e868fab2..7b06be94b)
1 *vifm-lua.txt* For Vifm version 1.0 Last change: 2024 Dec 2
1 *vifm-lua.txt* For Vifm version 1.0 Last change: 2024 Dec 3
2 2
3 3 Email for bugs and suggestions: <xaizek@posteo.net> Email for bugs and suggestions: <xaizek@posteo.net>
4 4
 
... ... Current API version: v0.1.0
24 24 |vifm-l_vifm.events| `vifm.events` global table. |vifm-l_vifm.events| `vifm.events` global table.
25 25 |vifm-l_vifm.fs| `vifm.fs` global table. |vifm-l_vifm.fs| `vifm.fs` global table.
26 26 |vifm-l_vifm.keys| `vifm.keys` global table. |vifm-l_vifm.keys| `vifm.keys` global table.
27 |vifm-l_vifm.menus| `vifm.menus` global table.
27 28 |vifm-l_vifm.opts| `vifm.opts` global table. |vifm-l_vifm.opts| `vifm.opts` global table.
28 29 |vifm-l_vifm.plugin| `vifm.plugin` global table. |vifm-l_vifm.plugin| `vifm.plugin` global table.
29 30 |vifm-l_vifm.plugins| `vifm.plugins` global table. |vifm-l_vifm.plugins| `vifm.plugins` global table.
 
... ... Table for basic/low-level file-system operations. See |vifm-l_vifm.fs|.
511 512 vifm.keys vifm.keys
512 513 Table for managing keys. See |vifm-l_vifm.keys|. Table for managing keys. See |vifm-l_vifm.keys|.
513 514
515 vifm.menus
516 Table for managing menus. See |vifm-l_vifm.menus|.
517
514 518 vifm.opts vifm.opts
515 519 Table for managing options. See |vifm-l_vifm.opts|. Table for managing options. See |vifm-l_vifm.opts|.
516 520
 
... ... Parameters:~
1091 1095 Return:~ Return:~
1092 1096 `true` on success. `true` on success.
1093 1097
1098 --------------------------------------------------------------------------------
1099 *vifm-l_vifm.menus*
1100
1101 This global `vifm.menus` table groups items related to menus.
1102
1103 vifm.menus.loadcustom({menu}) *vifm-l_vifm.menus.loadcustom()*
1104 Loads a menu with a custom list of items.
1105
1106 Possible fields of {menu}:
1107 - "title" (string)
1108 Title of the menu.
1109 - "items" (array of strings)
1110 List of items. Shouldn't be empty.
1111 - "view" (|vifm-l_VifmView|) (default: `vifm.currview()`)
1112 View associated with the menu. Navigation will happen in this view if
1113 enabled. Note: the value is currently limited to views of the current
1114 tab(s).
1115 - "withnavigation" (boolean) (default: false)
1116 When true, the items are considered to be paths that terminate at `:`
1117 optionally followed by line and column numbers (like for |vifm-%M|).
1118 Otherwise, the behaviour is like for |vifm-%m|.
1119
1120 This function is {unsafe}.
1121
1122 Parameters:~
1123 {menu} Table with information about the custom view.
1124
1125 Return:~
1126 `false` if the list of items is empty or if {menu}.view doesn't refer to the
1127 the view as `vifm.currview()` or `vifm.otherview()`.
1128 `true` on success.
1129
1094 1130 -------------------------------------------------------------------------------- --------------------------------------------------------------------------------
1095 1131 *vifm-l_vifm.opts* *vifm-l_vifm.opts*
1096 1132
 
... ... vifm.fs.rmdir({path}) |vifm-l_vifm.fs.rmdir()|
1652 1688 vifm.keys (table) |vifm-l_vifm.keys| vifm.keys (table) |vifm-l_vifm.keys|
1653 1689 vifm.keys.add({key}) |vifm-l_vifm.keys.add()| vifm.keys.add({key}) |vifm-l_vifm.keys.add()|
1654 1690
1691 vifm.menus (table) |vifm-l_vifm.menus|
1692 vifm.menus.loadcustom({menu}) |vifm-l_vifm.menus.loadcustom()|
1693
1655 1694 vifm.opts (table) |vifm-l_vifm.opts| vifm.opts (table) |vifm-l_vifm.opts|
1656 1695 vifm.opts.global (table) |vifm-l_vifm.opts.global| vifm.opts.global (table) |vifm-l_vifm.opts.global|
1657 1696
File src/lua/vifm.c changed (mode: 100644) (index 1892fefb5..d1863375e)
22 22
23 23 #include "../cfg/info.h" #include "../cfg/info.h"
24 24 #include "../engine/options.h" #include "../engine/options.h"
25 #include "../menus/users_menu.h"
25 26 #include "../modes/dialogs/msg_dialog.h" #include "../modes/dialogs/msg_dialog.h"
26 27 #include "../modes/cmdline.h" #include "../modes/cmdline.h"
27 28 #include "../ui/statusbar.h" #include "../ui/statusbar.h"
 
... ... static int VLUA_API(vifm_expand)(lua_State *lua);
78 79 static int VLUA_API(vifm_fnamemodify)(lua_State *lua); static int VLUA_API(vifm_fnamemodify)(lua_State *lua);
79 80 static int VLUA_API(vifm_input)(lua_State *lua); static int VLUA_API(vifm_input)(lua_State *lua);
80 81 static int VLUA_API(vifm_makepath)(lua_State *lua); static int VLUA_API(vifm_makepath)(lua_State *lua);
82 static int VLUA_API(vifm_menus_loadcustom)(lua_State *lua);
81 83 static int VLUA_API(vifm_run)(lua_State *lua); static int VLUA_API(vifm_run)(lua_State *lua);
82 84 static int VLUA_API(vifm_sessions_current)(lua_State *lua); static int VLUA_API(vifm_sessions_current)(lua_State *lua);
83 85 static int VLUA_API(vifm_stdout)(lua_State *lua); static int VLUA_API(vifm_stdout)(lua_State *lua);
 
... ... VLUA_DECLARE_SAFE(vifm_expand);
101 103 VLUA_DECLARE_SAFE(vifm_fnamemodify); VLUA_DECLARE_SAFE(vifm_fnamemodify);
102 104 VLUA_DECLARE_SAFE(vifm_input); VLUA_DECLARE_SAFE(vifm_input);
103 105 VLUA_DECLARE_SAFE(vifm_makepath); VLUA_DECLARE_SAFE(vifm_makepath);
106 VLUA_DECLARE_UNSAFE(vifm_menus_loadcustom);
104 107 VLUA_DECLARE_SAFE(vifm_run); VLUA_DECLARE_SAFE(vifm_run);
105 108 VLUA_DECLARE_SAFE(vifm_sessions_current); VLUA_DECLARE_SAFE(vifm_sessions_current);
106 109 VLUA_DECLARE_SAFE(vifm_stdout); VLUA_DECLARE_SAFE(vifm_stdout);
 
... ... vifm_init(lua_State *lua)
187 190 vifm_tabs_init(lua); vifm_tabs_init(lua);
188 191 lua_setfield(lua, -2, "tabs"); lua_setfield(lua, -2, "tabs");
189 192
193 /* Setup vifm.menus. */
194 lua_createtable(lua, /*narr=*/0, /*nrec=*/1);
195 lua_pushcfunction(lua, VLUA_REF(vifm_menus_loadcustom));
196 lua_setfield(lua, -2, "loadcustom"); /* vifm.menus.loadcustom */
197 lua_setfield(lua, -2, "menus"); /* vifm.menus */
198
190 199 /* Setup vifm.opts. */ /* Setup vifm.opts. */
191 200 lua_createtable(lua, /*narr=*/0, /*nrec=*/1); /* vifm.opts */ lua_createtable(lua, /*narr=*/0, /*nrec=*/1); /* vifm.opts */
192 201 lua_newtable(lua); /* vifm.opts.global */ lua_newtable(lua); /* vifm.opts.global */
 
... ... VLUA_API(vifm_makepath)(lua_State *lua)
388 397 return 1; return 1;
389 398 } }
390 399
400 /* Member of `vifm.menus` that creates a menu out of list of items. Returns a
401 * boolean, which is true on success. */
402 static int
403 VLUA_API(vifm_menus_loadcustom)(lua_State *lua)
404 {
405 luaL_checktype(lua, 1, LUA_TTABLE);
406
407 view_t *view = curr_view;
408 if(vlua_cmn_check_opt_field(lua, 1, "view", LUA_TUSERDATA))
409 {
410 view = check_view(lua, -1);
411 if(view != &lwin && view != &rwin)
412 {
413 goto fail;
414 }
415 }
416
417 int with_navigation = 0;
418 if(vlua_cmn_check_opt_field(lua, 1, "withnavigation", LUA_TBOOLEAN))
419 {
420 with_navigation = lua_toboolean(lua, -1);
421 }
422
423 vlua_cmn_check_field(lua, 1, "title", LUA_TSTRING);
424 const char *title = lua_tostring(lua, -1);
425
426 vlua_cmn_check_field(lua, 1, "items", LUA_TTABLE);
427
428 lua_Integer len = luaL_len(lua, -1);
429 strlist_t items = {
430 .items = reallocarray(NULL, len, sizeof(char *)),
431 .nitems = len
432 };
433
434 if(items.items == NULL)
435 {
436 goto fail;
437 }
438
439 int i = 0;
440 lua_pushnil(lua);
441 while(lua_next(lua, -2) != 0)
442 {
443 char *item = strdup(lua_tostring(lua, -1));
444 if(item == NULL)
445 {
446 free_string_array(items.items, i);
447 goto fail;
448 }
449
450 items.items[i++] = item;
451 lua_pop(lua, 1);
452 }
453
454 int success = (show_custom_menu(view, title, items, with_navigation) == 0);
455 lua_pushboolean(lua, success);
456 return 1;
457
458 fail:
459 lua_pushboolean(lua, 0);
460 return 1;
461 }
462
391 463 /* Runs an external command similar to :!. */ /* Runs an external command similar to :!. */
392 464 static int static int
393 465 VLUA_API(vifm_run)(lua_State *lua) VLUA_API(vifm_run)(lua_State *lua)
File src/lua/vifmview.c changed (mode: 100644) (index 07a39d224..e29bd2d07)
... ... static int VLUA_API(vifmview_selected)(lua_State *lua);
68 68 static int VLUA_IMPL(loop_selected_entries)(lua_State *lua); static int VLUA_IMPL(loop_selected_entries)(lua_State *lua);
69 69 static int VLUA_API(vifmview_unselect)(lua_State *lua); static int VLUA_API(vifmview_unselect)(lua_State *lua);
70 70 static int select_unselect(lua_State *lua, int select); static int select_unselect(lua_State *lua, int select);
71 static view_t * check_view(lua_State *lua, int index);
72 71 static view_t * find_view(lua_State *lua, unsigned int id); static view_t * find_view(lua_State *lua, unsigned int id);
73 72
74 73 VLUA_DECLARE_SAFE(vifmview_index); VLUA_DECLARE_SAFE(vifmview_index);
 
... ... select_unselect(lua_State *lua, int select)
689 688 return 1; return 1;
690 689 } }
691 690
692 /* Resolves `VifmView` user data at the specified index on the stack. Returns
693 * the pointer or aborts (Lua does longjmp()) if the view doesn't exist
694 * anymore. */
695 static view_t *
691 view_t *
696 692 check_view(lua_State *lua, int index) check_view(lua_State *lua, int index)
697 693 { {
698 694 unsigned int *id = luaL_checkudata(lua, index, "VifmView"); unsigned int *id = luaL_checkudata(lua, index, "VifmView");
File src/lua/vifmview.h changed (mode: 100644) (index 17635724c..8490df1f8)
... ... int VLUA_API(vifmview_currview)(struct lua_State *lua);
39 39 * type. */ * type. */
40 40 int VLUA_API(vifmview_otherview)(struct lua_State *lua); int VLUA_API(vifmview_otherview)(struct lua_State *lua);
41 41
42 /* Resolves `VifmView` user data at the specified index on the stack. Returns
43 * the pointer or aborts (Lua does longjmp()) if the view doesn't exist
44 * anymore. */
45 struct view_t * check_view(struct lua_State *lua, int index);
46
42 47 #endif /* VIFM__LUA__VIFMVIEW_H__ */ #endif /* VIFM__LUA__VIFMVIEW_H__ */
43 48
44 49 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
File src/menus/menus.c changed (mode: 100644) (index c1d30bf18..969a5f707)
... ... static void unstash_menu_at(menu_state_t *ms, int index);
87 87 static void move_menu_data(menu_data_t *to, menu_data_t *from); static void move_menu_data(menu_data_t *to, menu_data_t *from);
88 88 static const char * get_relative_path_base(const menu_data_t *m, static const char * get_relative_path_base(const menu_data_t *m,
89 89 const view_t *view); const view_t *view);
90 static int menu_and_view_are_in_sync(const menu_data_t *m, const view_t *view);
90 static int menu_is_in_cwd(const menu_data_t *m, const view_t *view);
91 91 static int search_menu(menu_state_t *ms, int print_errors); static int search_menu(menu_state_t *ms, int print_errors);
92 92 static int search_menu_forwards(menu_state_t *ms, int start_pos); static int search_menu_forwards(menu_state_t *ms, int start_pos);
93 93 static int search_menu_backwards(menu_state_t *ms, int start_pos); static int search_menu_backwards(menu_state_t *ms, int start_pos);
 
... ... static int navigate_to_match(menu_state_t *ms, int pos);
95 95 static int get_match_index(const menu_state_t *ms); static int get_match_index(const menu_state_t *ms);
96 96 TSTATIC void menus_drop_stash(void); TSTATIC void menus_drop_stash(void);
97 97 TSTATIC void menus_set_active(menu_data_t *m); TSTATIC void menus_set_active(menu_data_t *m);
98 TSTATIC view_t * menus_get_view(menu_data_t *m);
98 99
99 100 struct menu_state_t struct menu_state_t
100 101 { {
 
... ... draw_menu_frame(const menu_state_t *ms)
616 617 char * char *
617 618 menus_format_title(const menu_data_t *m, struct view_t *view) menus_format_title(const menu_data_t *m, struct view_t *view)
618 619 { {
619 const char *const suffix = menu_and_view_are_in_sync(m, view)
620 const char *const suffix = menu_is_in_cwd(m, view)
620 621 ? "" ? ""
621 622 : replace_home_part(m->cwd); : replace_home_part(m->cwd);
622 623 const char *const at = (suffix[0] == '\0' ? "" : " @ "); const char *const at = (suffix[0] == '\0' ? "" : " @ ");
 
... ... menus_to_custom_view(menu_state_t *ms, int very)
1068 1069 static const char * static const char *
1069 1070 get_relative_path_base(const menu_data_t *m, const view_t *view) get_relative_path_base(const menu_data_t *m, const view_t *view)
1070 1071 { {
1071 if(menu_and_view_are_in_sync(m, view))
1072 {
1073 return ".";
1074 }
1075 return m->cwd;
1072 return (menu_is_in_cwd(m, view) ? "." : m->cwd);
1076 1073 } }
1077 1074
1078 /* Checks whether menu working directory and current directory of the view are
1079 * in sync. Returns non-zero if so, otherwise zero is returned. */
1075 /* Checks whether menu's working directory and current directory are in sync.
1076 * Returns non-zero if so, otherwise zero is returned. */
1080 1077 static int static int
1081 menu_and_view_are_in_sync(const menu_data_t *m, const view_t *view)
1078 menu_is_in_cwd(const menu_data_t *m, const view_t *view)
1082 1079 { {
1083 /* NULL check is for tests. */
1084 return (view == NULL || paths_are_same(m->cwd, flist_get_dir(view)));
1080 /* NULL check is for tests. The application's working directory is that of
1081 * the current view, so ignore other views (shouldn't ignore those which are
1082 * at the same location?). */
1083 return (view == NULL)
1084 || (view == curr_view && paths_are_same(m->cwd, flist_get_dir(view)));
1085 1085 } }
1086 1086
1087 1087 int int
 
... ... menus_set_active(menu_data_t *m)
1437 1437 menu_state.d = m; menu_state.d = m;
1438 1438 } }
1439 1439
1440 TSTATIC view_t *
1441 menus_get_view(menu_data_t *m)
1442 {
1443 return m->state->view;
1444 }
1445
1440 1446 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
1441 1447 /* vim: set cinoptions+=t0 filetype=c : */ /* vim: set cinoptions+=t0 filetype=c : */
File src/menus/menus.h changed (mode: 100644) (index db7334c0e..f85e01e8d)
... ... char * menus_format_title(const menu_data_t *m, struct view_t *view);
224 224 TSTATIC_DEFS( TSTATIC_DEFS(
225 225 void menus_drop_stash(void); void menus_drop_stash(void);
226 226 void menus_set_active(menu_data_t *m); void menus_set_active(menu_data_t *m);
227 struct view_t * menus_get_view(menu_data_t *m);
227 228 ) )
228 229
229 230 #endif /* VIFM__MENUS__MENUS_H__ */ #endif /* VIFM__MENUS__MENUS_H__ */
File src/menus/users_menu.c changed (mode: 100644) (index cf08abadd..50e1b6abd)
... ... show_user_menu(view_t *view, const char command[], const char title[],
47 47 return menus_capture(view, command, 1, &m, flags); return menus_capture(view, command, 1, &m, flags);
48 48 } }
49 49
50 int
51 show_custom_menu(view_t *view, const char title[], strlist_t items,
52 int with_navigation)
53 {
54 static menu_data_t m;
55
56 /* Avoid a dialog about the menu being empty by checking for this case
57 * beforehand. */
58 if(items.nitems == 0)
59 {
60 free_string_array(items.items, items.nitems);
61 return 1;
62 }
63
64 menus_init_data(&m, view, strdup(title), strdup("No items"));
65
66 m.extra_data = with_navigation;
67 m.stashable = with_navigation;
68 m.execute_handler = &execute_users_cb;
69 m.key_handler = &users_khandler;
70
71 m.len = items.nitems;
72 m.items = items.items;
73
74 if(menus_enter(&m, view) != 0)
75 {
76 free_string_array(items.items, items.nitems);
77 return 1;
78 }
79
80 return 0;
81 }
82
50 83 /* Callback that is called when menu item is selected. Should return non-zero /* Callback that is called when menu item is selected. Should return non-zero
51 84 * to stay in menu mode. */ * to stay in menu mode. */
52 85 static int static int
File src/menus/users_menu.h changed (mode: 100644) (index 1b00c7219..dc5cdb9cd)
22 22
23 23 #include "../macros.h" #include "../macros.h"
24 24
25 struct strlist_t;
25 26 struct view_t; struct view_t;
26 27
27 28 /* Creates menu out of output of the command. Returns non-zero if status bar /* Creates menu out of output of the command. Returns non-zero if status bar
 
... ... struct view_t;
29 30 int show_user_menu(struct view_t *view, const char command[], int show_user_menu(struct view_t *view, const char command[],
30 31 const char title[], MacroFlags flags); const char title[], MacroFlags flags);
31 32
33 /* Creates menu from a list of items. Takes ownership of the items (including
34 * freeing them on error). Returns zero on success. */
35 int show_custom_menu(struct view_t *view, const char title[],
36 struct strlist_t items, int with_navigation);
37
32 38 #endif /* VIFM__MENUS__USERS_MENU_H__ */ #endif /* VIFM__MENUS__USERS_MENU_H__ */
33 39
34 40 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
File src/modes/menu.c changed (mode: 100644) (index fcc075f7b..698c1b19d)
... ... menu_get_current(void)
1192 1192 return menu; return menu;
1193 1193 } }
1194 1194
1195 /* Provides access to a static variable from tests. */
1196 TSTATIC view_t *
1197 menu_get_view(void)
1198 {
1199 return view;
1200 }
1201
1195 1202 /* Processes events from the mouse. */ /* Processes events from the mouse. */
1196 1203 static void static void
1197 1204 handle_mouse_event(key_info_t key_info, keys_info_t *keys_info) handle_mouse_event(key_info_t key_info, keys_info_t *keys_info)
File src/modes/menu.h changed (mode: 100644) (index f44278067..9527e5e2f)
... ... int modmenu_last_line(const menu_data_t *m);
76 76
77 77 TSTATIC_DEFS( TSTATIC_DEFS(
78 78 menu_data_t * menu_get_current(void); menu_data_t * menu_get_current(void);
79 struct view_t * menu_get_view(void);
79 80 ) )
80 81
81 82 #endif /* VIFM__MODES__MENU_H__ */ #endif /* VIFM__MODES__MENU_H__ */
File src/tags.c changed (mode: 100644) (index 925c11039..fd41e245f)
... ... const char *tags[] = {
773 773 "vifm-l_vifm.keys", "vifm-l_vifm.keys",
774 774 "vifm-l_vifm.keys.add()", "vifm-l_vifm.keys.add()",
775 775 "vifm-l_vifm.makepath()", "vifm-l_vifm.makepath()",
776 "vifm-l_vifm.menus",
777 "vifm-l_vifm.menus.loadcustom()",
776 778 "vifm-l_vifm.opts", "vifm-l_vifm.opts",
777 779 "vifm-l_vifm.opts.global", "vifm-l_vifm.opts.global",
778 780 "vifm-l_vifm.otherview()", "vifm-l_vifm.otherview()",
File tests/lua/api_menus.c added (mode: 100644) (index 000000000..fed6c6049)
1 #include <stic.h>
2
3 #include "../../src/engine/keys.h"
4 #include "../../src/engine/mode.h"
5 #include "../../src/lua/vlua.h"
6 #include "../../src/menus/menus.h"
7 #include "../../src/modes/menu.h"
8 #include "../../src/modes/modes.h"
9 #include "../../src/modes/wk.h"
10 #include "../../src/ui/ui.h"
11 #include "../../src/filelist.h"
12 #include "../../src/status.h"
13
14 #include <test-utils.h>
15
16 #include "asserts.h"
17
18 static vlua_t *vlua;
19
20 SETUP_ONCE()
21 {
22 stub_colmgr();
23
24 curr_view = &lwin;
25 other_view = &rwin;
26
27 curr_stats.load_stage = -1;
28 }
29
30 TEARDOWN_ONCE()
31 {
32 curr_view = NULL;
33 other_view = NULL;
34
35 curr_stats.load_stage = 0;
36 }
37
38 SETUP()
39 {
40 vlua = vlua_init();
41
42 view_setup(&lwin);
43 view_setup(&rwin);
44
45 opt_handlers_setup();
46 modes_init();
47 }
48
49 TEARDOWN()
50 {
51 vlua_finish(vlua);
52
53 view_teardown(&lwin);
54 view_teardown(&rwin);
55
56 vle_keys_reset();
57 opt_handlers_teardown();
58 }
59
60 TEST(menus_loadcustom)
61 {
62 make_abs_path(lwin.curr_dir, sizeof(lwin.curr_dir), ".", "", NULL);
63 make_abs_path(rwin.curr_dir, sizeof(rwin.curr_dir), TEST_DATA_PATH, "rename",
64 NULL);
65
66 /* Missing fields. */
67 BLUA_ENDS(vlua, ": `title` key is mandatory",
68 "print(vifm.menus.loadcustom { })");
69 BLUA_ENDS(vlua, ": `items` key is mandatory",
70 "print(vifm.menus.loadcustom { title = 't' })");
71
72 /* Empty items. */
73 GLUA_ENDS(vlua, "false",
74 "print(vifm.menus.loadcustom { title = 't', items = { } })");
75
76 /* Non-navigatable menu. */
77 GLUA_ENDS(vlua, "true",
78 "print(vifm.menus.loadcustom { title = 't', items = { 'a', 'b' } })");
79 assert_true(vle_mode_is(MENU_MODE));
80 assert_true(menus_get_view(menu_get_current()) == &lwin);
81 assert_true(menu_get_view() == &lwin);
82 assert_false(menu_get_current()->extra_data);
83
84 /* Navigatable menu. */
85 GLUA_ENDS(vlua, "true",
86 "print(vifm.menus.loadcustom {"
87 " title = 't',"
88 " items = { 'aaa', 'b' },"
89 " withnavigation = true,"
90 " view = vifm.otherview(),"
91 "})");
92 assert_true(vle_mode_is(MENU_MODE));
93 assert_true(menus_get_view(menu_get_current()) == &rwin);
94 assert_true(menu_get_view() == &rwin);
95 assert_true(menu_get_current()->extra_data);
96
97 /* Correct origin is used for relative paths. */
98 (void)vle_keys_exec_timed_out(WK_CR);
99 assert_false(vle_mode_is(MENU_MODE));
100 assert_int_equal(3, rwin.list_rows);
101 assert_string_equal("aaa", rwin.dir_entry[rwin.list_pos].name);
102 }
103
104 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
105 /* vim: set cinoptions+=t0 : */
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master