util.menu_iterator: cleaned indentation; added wiki entry; closes #386

This commit is contained in:
Luca CPZ 2018-02-17 14:06:20 +01:00
parent af3427c7df
commit 1b909160d6
3 changed files with 64 additions and 59 deletions

View file

@ -10,6 +10,7 @@ local timer = require("gears.timer")
local debug = require("debug") local debug = require("debug")
local io = { lines = io.lines, local io = { lines = io.lines,
open = io.open } open = io.open }
local pairs = pairs
local rawget = rawget local rawget = rawget
local table = { sort = table.sort } local table = { sort = table.sort }
@ -179,9 +180,8 @@ function helpers.spairs(t)
end end
end end
-- create trivial partition of a set. The trivial partition set is the simplest -- create the partition of singletons of a given set
-- partition of a set. For e.g., the trivial partition set of {a, b, c}, is -- example: the trivial partition set of {a, b, c}, is {{a}, {b}, {c}}
-- simply {{a}, {b}, {c}}.
function helpers.trivial_partition_set(set) function helpers.trivial_partition_set(set)
local ss = {} local ss = {}
for _,e in pairs(set) do for _,e in pairs(set) do

View file

@ -7,16 +7,22 @@
--]] --]]
-- Menu iterator using naughty.notify -- Menu iterator with Naughty notifications
-- lain.util.menu_iterator
local naughty = require("naughty") local naughty = require("naughty")
local util = require("lain.util") local util = require("lain.util")
local atable = require("awful.util").table
local assert = assert
local pairs = pairs
local tconcat = table.concat
local unpack = unpack
local state = { cid = nil } local state = { cid = nil }
local function naughty_destroy_callback(reason) local function naughty_destroy_callback(reason)
if reason == naughty.notificationClosedReason.expired or local closed = naughty.notificationClosedReason
reason == naughty.notificationClosedReason.dismissedByUser then if reason == closed.expired or reason == closed.dismissedByUser then
local actions = state.index and state.menu[state.index - 1][2] local actions = state.index and state.menu[state.index - 1][2]
if actions then if actions then
for _,action in pairs(actions) do for _,action in pairs(actions) do
@ -28,14 +34,15 @@ local function naughty_destroy_callback(reason)
end end
end end
-- Iterates over a list of pairs {label, {callbacks}}. After timeout, the last -- Iterates over a menu.
-- visited choice associated callbacks are executed. -- After the timeout, callbacks associated to the last visited choice are
-- * menu: a list of pairs {label, {callbacks} -- executed. Inputs:
-- * timeout: time to wait before confirming menu selection -- * menu: a list of {label, {callbacks}} pairs
-- * icon: icon to display left to the choiced label -- * timeout: time to wait before confirming the menu selection
-- * icon: icon to display in the notification of the chosen label
local function iterate(menu, timeout, icon) local function iterate(menu, timeout, icon)
timeout = timeout or 4 -- default timeout for each menu entry local timeout = timeout or 4 -- default timeout for each menu entry
icon = icon or nil -- icon to display on the menu local icon = icon or nil -- icon to display on the menu
-- Build the list of choices -- Build the list of choices
if not state.index then if not state.index then
@ -44,7 +51,7 @@ local function iterate(menu, timeout, icon)
end end
-- Select one and display the appropriate notification -- Select one and display the appropriate notification
local label, action local label
local next = state.menu[state.index] local next = state.menu[state.index]
state.index = state.index + 1 state.index = state.index + 1
@ -54,6 +61,7 @@ local function iterate(menu, timeout, icon)
else else
label, _ = unpack(next) label, _ = unpack(next)
end end
state.cid = naughty.notify({ state.cid = naughty.notify({
text = label, text = label,
icon = icon, icon = icon,
@ -64,31 +72,28 @@ local function iterate(menu, timeout, icon)
}).id }).id
end end
-- Generates a menu compatible with the iterate function argument and suitable -- Generates a menu compatible with the first argument of `iterate` function and
-- for the following cases: -- suitable for the following cases:
-- * all possible choices individually. -- * all possible choices individually (partition of singletons);
-- * all possible choices are all the possible subsets of the set of individual -- * all possible subsets of the set of choices (powerset).
-- choices (the powerset)
-- --
-- The following describes the function arguments: -- Inputs:
-- * args: an array containing the following members: -- * args: an array containing the following members:
-- * choices: the list of choices from which to generate the menu -- * choices: Array of choices (string) on which the menu will be
-- * name: the displayed name of the menu (in the form "name: choices") -- generated.
-- * selected_cb: the callback to execute for each selected choice. Takes -- * name: Displayed name of the menu (in the form "name: choices").
-- the choice as a string argument. The function -- * selected_cb: Callback to execute for each selected choice. Takes
-- menu_iterator.naughty_destroy_callback will handle nil -- the choice as a string argument. Can be `nil` (no action
-- callbacks. It is then fine to pass nil callbacks. -- to execute).
-- * rejected_cb: the callback to execute for each rejected choice (in the -- * rejected_cb: Callback to execute for each rejected choice (possible
-- set of possible choices, but not selected). Takes the -- choices which are not selected). Takes the choice as a
-- choice as a string argument. The function -- string argument. Can be `nil` (no action to execute).
-- menu_iterator.naughty_destroy_callback will handle nil -- * extra_choices: An array of extra { choice_str, callback_fun } pairs to be
-- callbacks. It is then fine to pass nil callbacks. -- added to the menu. Each callback_fun can be `nil`.
-- * extra_choices: an array of pairs { choice_text, cb } for extra choices to -- * combination: The combination of choices to generate. Possible values:
-- be added to the menu. The function -- "powerset" and "single" (default).
-- menu_iterator.naughty_destroy_callback will handle nil -- Output:
-- callbacks. It is then fine to pass nil callbacks. -- * m: menu to be iterated over.
-- * combination: the combination of choice to generate. Possible choices
-- are "powerset" and "single" (the default).
local function menu(args) local function menu(args)
local choices = assert(args.choices or args[1]) local choices = assert(args.choices or args[1])
local name = assert(args.name or args[2]) local name = assert(args.name or args[2])
@ -97,43 +102,43 @@ local function menu(args)
local extra_choices = args.extra_choices or {} local extra_choices = args.extra_choices or {}
local ch_combinations = args.combination == "powerset" and helpers.powerset(choices) or helpers.trivial_partition_set(choices) local ch_combinations = args.combination == "powerset" and helpers.powerset(choices) or helpers.trivial_partition_set(choices)
for _,c in pairs(extra_choices) do for _,c in pairs(extra_choices) do
ch_combinations = awful.util.table.join(ch_combinations, {{c[1]}}) ch_combinations = atable.join(ch_combinations, {{c[1]}})
end end
local m = {} local m = {} -- the menu
for _,c in pairs(ch_combinations) do for _,c in pairs(ch_combinations) do
if #c > 0 then if #c > 0 then
local cbs = {} local cbs = {}
-- selected choices -- selected choices
for _,ch in pairs(c) do for _,ch in pairs(c) do
if awful.util.table.hasitem(choices, ch) then if atable.hasitem(choices, ch) then
cbs[#cbs + 1] = selected_cb and function() selected_cb(ch) end or nil cbs[#cbs + 1] = selected_cb and function() selected_cb(ch) end or nil
end end
end end
-- rejected choices -- rejected choices
for _,ch in pairs(choices) do for _,ch in pairs(choices) do
if not awful.util.table.hasitem(c, ch) and awful.util.table.hasitem(choices, ch) then if not atable.hasitem(c, ch) and atable.hasitem(choices, ch) then
cbs[#cbs + 1] = rejected_cb and function() rejected_cb(ch) end or nil cbs[#cbs + 1] = rejected_cb and function() rejected_cb(ch) end or nil
end end
end end
-- add user extra choices (like the choice "None" for e.g.) -- add user extra choices (like the choice "None" for example)
for _,x in pairs(extra_choices) do for _,x in pairs(extra_choices) do
if x[1] == c[1] then if x[1] == c[1] then
cbs[#cbs + 1] = x[2] cbs[#cbs + 1] = x[2]
end end
end end
m[#m + 1] = { name .. ": " .. table.concat(c, " + "), cbs } m[#m + 1] = { name .. ": " .. tconcat(c, " + "), cbs }
end end
end end
return m return m
end end
return { return { iterate = iterate, menu = menu }
iterate = iterate,
menu = menu
}

2
wiki

@ -1 +1 @@
Subproject commit e8860c7593f86584b45ada7d5232f32915ba20a6 Subproject commit 967f567364e9304e79ddfb552096f3f0874950f6