2 -- ion/ioncore/ioncore_menudb.lua -- Routines for defining menus.
4 -- Copyright (c) Tuomo Valkonen 2004-2006.
6 -- Ion is free software; you can redistribute it and/or modify it under
7 -- the terms of the GNU Lesser General Public License as published by
8 -- the Free Software Foundation; either version 2.1 of the License, or
9 -- (at your option) any later version.
12 local ioncore=_G.ioncore
15 -- Table to hold defined menus.
19 -- Menu construction {{{
22 -- Define a new menu with \var{name} being the menu's name and \var{tab}
23 -- being a table of menu entries. If \var{tab.append} is set, the entries
24 -- are appended to previously-defined ones, if possible.
25 function ioncore.defmenu(name, tab)
26 if menus[name] and type(tab)=="table" and tab.append then
27 if type(menus[name])~="table" then
28 ioncore.warn(TR("Unable to append to non-table menu"))
31 table.append(menus[name], tab)
39 -- Returns a menu defined with \fnref{ioncore.defmenu}.
40 function ioncore.getmenu(name)
45 -- Define context menu for context \var{ctx}, \var{tab} being a table
47 function ioncore.defctxmenu(ctx, ...)
49 if #arg>1 and type(arg[1])=="string" then
51 tab.label=ioncore.gettext(arg[1])
55 ioncore.defmenu("ctxmenu-"..ctx, tab)
59 -- Returns a context menu defined with \fnref{ioncore.defctxmenu}.
60 function ioncore.getctxmenu(name)
61 return menus["ctxmenu-"..name]
65 function ioncore.evalmenu(menu, args)
66 if type(menu)=="string" then
67 return ioncore.evalmenu(menus[menu], args)
68 elseif type(menu)=="function" then
70 return menu(unpack(args))
74 elseif type(menu)=="table" then
81 -- Use this function to define normal menu entries. The string \var{name}
82 -- is the string shown in the visual representation of menu, and the
83 -- parameter \var{cmd} and \var{guard} are similar to those of
84 -- \fnref{ioncore.defbindings}.
85 function ioncore.menuentry(name, cmd, guard)
86 local fn, gfn=ioncore.compile_cmd(cmd, guard)
88 return {name=ioncore.gettext(name), func=fn, guard_func=gfn}
93 -- Use this function to define menu entries for submenus. The parameter
94 -- \fnref{sub_or_name} is either a table of menu entries or the name
95 -- of an already defined menu. The initial menu entry to highlight can be
96 -- specified by \var{options.initial} as either an integer starting from 1,
97 -- or a function that returns such a number. Another option supported is
98 -- \var{options.noautoexpand} that will cause \fnref{mod_query.query_menu}
99 -- to not automatically expand this submenu.
100 function ioncore.submenu(name, sub_or_name, options)
105 name=ioncore.gettext(name),
106 submenu_fn=function()
107 return ioncore.evalmenu(sub_or_name)
109 initial=options.initial,
110 noautoexpand=options.noautoexpand,
118 -- Workspace and window lists {{{
120 local function makelist(list)
121 local function mkentry(tgt)
122 return menuentry(tgt:name(), function() tgt:goto() end)
124 local entries=table.map(mkentry, list)
125 table.sort(entries, function(a, b) return a.name < b.name end)
129 function menus.windowlist()
130 return makelist(ioncore.clientwin_list())
133 function menus.workspacelist()
134 return makelist(ioncore.region_list("WGenWS"))
143 local function mplex_of(reg)
144 while reg and not obj_is(reg, "WMPlex") do
150 local function selectstyle(look, where)
153 local fname=ioncore.get_savefile('look')
155 local function writeit()
156 local f, err=io.open(fname, 'w')
158 mod_query.message(where, err)
160 f:write(string.format('dopath("%s")\n', look))
165 if not mod_query then
172 where=mplex_of(where)
178 query_message(where, TR("Cannot save selection."))
182 mod_query.query_yesno(where, TR("Save look selection in %s?", fname),
186 local function receive_styles(str)
191 if string.len(data)>ioncore.RESULT_DATA_LIMIT then
192 error(TR("Too much result data"))
194 str=coroutine.yield()
201 for look in string.gfind(data, "(look[-_][^\n]*)%.lua\n") do
202 if not found[look] then
204 table.insert(styles, look)
210 for _, look in ipairs(styles) do
212 table.insert(stylemenu, menuentry(look,
214 selectstyle(look_, where)
218 table.insert(stylemenu, menuentry(TR("Refresh list"),
219 ioncore.refresh_stylelist))
221 menus.stylemenu=stylemenu
226 -- Refresh list of known style files.
227 function ioncore.refresh_stylelist()
228 local cmd=ioncore.lookup_script("ion-completefile")
230 local path=ioncore.get_paths().searchpath
231 local function mkarg(s)
235 return (" "..string.shell_safe(s).."/look_"..
236 " "..string.shell_safe(s).."/look-")
241 cmd=cmd..string.gsub(path..":", "([^:]*):", mkarg)
243 ioncore.popen_bgread(cmd, coroutine.wrap(receive_styles))
253 local function classes(reg)
254 local function classes_(t)
255 if t.__parentclass then
256 classes_(t.__parentclass)
258 coroutine.yield(t.__typename)
260 return coroutine.wrap(function() classes_(reg) end)
264 local function modeparts(mode)
266 return function() return end
269 local f, s, v=string.gmatch(mode, "(%-?[^-]+)");
271 local function nxt(_, m)
273 return (v and (m .. v))
280 local function get_ctxmenu(reg, sub, is_par)
283 local function cp(m2)
285 for k, v in ipairs(m2) do
286 local v2=table.copy(v)
290 v2.func=function() return ofunc(reg, sub) end
293 if v2.submenu_fn then
294 local ofn=v2.submenu_fn
295 v2.submenu_fn=function() return cp(ofn()) end
304 local function add_ctxmenu(m2, use_label)
311 m.label=(use_label and m2.label) or m.label
315 local mgr=reg:manager()
316 local mgrname=(mgr and mgr:name()) or nil
317 local mode=(reg.mode and reg:mode())
319 for s in classes(reg) do
320 local nm="ctxmenu-"..s
321 add_ctxmenu(ioncore.evalmenu(nm), true)
322 for m in modeparts(mode) do
323 add_ctxmenu(ioncore.evalmenu(nm.."."..m), false)
326 add_ctxmenu(ioncore.evalmenu(nm.."@"..mgrname), false)
332 function menus.ctxmenu(reg, sub)
333 local m=get_ctxmenu(reg, sub, false);
339 local mm = get_ctxmenu(reg, sub, true)
341 local nm=mm.label or obj_typename(reg)
342 table.insert(m, ioncore.submenu(nm, mm))
353 ioncore.refresh_stylelist()