--- Select a page element with a visual interface.
--
-- This module allows you to change the style of hints used to hint elements for
-- selection in `follow` mode, as well as other modes that use the visual hint
-- overlay.
--
-- # Using a custom character set for hint labels
--
-- To customize the characters used in hint labels, you can
-- specify a _label maker function_ by assigning a function to the
-- @ref{label_maker} property. This label maker function composes
-- several _label composer functions_ into a chain, which it returns.
-- Then, when a hinting mode (such as @ref{follow} mode) is entered,
-- this chain of functions is called to construct the labels. The label
-- maker function itself is only called once.
--
-- ## Default label maker
--
-- To see how this works in practice, let's examine the default label maker
-- function. `trim()`, `sort()`, `reverse()`, and `charset()` are all label
-- composer functions, and all the label maker function does is chain them
-- together and return the result.
--
--     select.label_maker = function ()
--         return trim(sort(reverse(numbers())))
--     end
--
-- Conceptually, `numbers()` produces produces an array of numerical hints:
--
--     { "01", "02", "03", "04", "05", ... , "10", "11", "12", ... }
--
-- Next, `reverse()` reverses each individual hint. This makes typing to
-- match hints quicker: by moving the variation in hints from the last
-- character to the first character, which is the first character typed
-- when matching, we make the first character typed filter many more hints:
--
--     { "10", "20", "30", "40", "50", ... , "01", "11", "21", ... }
--
-- Next, `sort()` sorts the hints. This step doesn't affect matching speed, but
-- makes the hints shown on a page appear more orderly:
--
--     { "01", "10", "11", "20", "21", "30", "31", "40", "41", ... }
--
-- Last, `trim()` will remove any unnecessary hint suffixes. For
-- example, `"01"` is the only hint beginning with `0`; therefore, once
-- the user has typed `0`, this is the only matchable hint, and the `1`
-- contributes nothing:
--
--     { "0", "10", "11", "20", "21", "30", "31", "40", "41", ... }
--
-- This is the final list of hint labels that will be used for selection.
--
-- # Label composer functions
--
-- All label composer functions return a function that takes a single
-- argument `n` and produces an array of `n` hints. The nature of the
-- hints will vary based on the arguments provided to the composer
-- function. For example, the function returned by `charset()` will
-- use the provided set of characters to generate its hints, while the
-- function returned by `sort()` will first call the label composer
-- function passed to `sort()` to obtain a set of hints to sort.
--
-- ## Available functions
--
-- These label composer functions produce an initial generator function.
--
-- - `charset(str)`: Generates hints using the characters in `str`. Non-latin
-- characters are supported.
-- - `numbers()`: Generates hints using numbers. This is equivalent to
-- calling `charset()` with the parameter `"0123456789"`.
-- - `interleave(left, right)`: Similar to `charset()`, this generates
-- hints that alternate between letters of the `left` and `right` strings. It is
-- mostly useful for alternating between letters on the left and right sides of
-- one's keyboard, as this makes hints easier to type quickly.
--
-- These label composer functions accept a single generator function, and
-- return another function. This allows them to be chained.
--
-- - `reverse(func)`: Reverses the letters of each hint generated by `func()`.
-- - `sort(func)`: Sorts the hints generated by `func()`.
-- - `trim(func)`: Trims extra letters off the hints generated by
-- `func()`. Specifically, if a prefix of any hint is not a prefix of any other
-- hint, then the hint is shortened to that prefix.
--
-- @module select
-- @copyright 2017 Aidan Holm <aidanholm@gmail.com>

local _M = {}

local wrapped = { label_maker = nil }

--- @property label_maker
-- Function that specifies how to generate hint labels.
--
-- This function is executed on the web process, with a custom environment that
-- provides access to the label composer functions.
-- @readwrite
-- @type function

local wm = require_web_module("select_wm")

luakit.add_signal("web-extension-created", function (view)
    if wrapped.label_maker then
        wm:emit_signal(view, "set_label_maker", wrapped.label_maker)
    end
end)

local mt = {
    __index = wrapped,
    __newindex = function (_, k, v)
        assert(type(v) == "function", "property 'label_maker' must be a function")
        if k == "label_maker" then
            wrapped.label_maker = v
            wm:emit_signal("set_label_maker", v)
        end
    end,
}

return setmetatable(_M, mt)

-- vim: et:sw=4:ts=8:sts=4:tw=80
