From e4a710296943674573be800f5233b24214440929 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 23 Aug 2024 20:55:22 -0400
Subject: Look for lazy UI submodules in a require/UI subdirectory.

This way encourages "UI = require 'UI'; UI.Floater"
instead of just "Floater = require 'Floater'".
Moreover, now we don't need UI to maintain a list of allowed submodules;
that's effected by membership in the subdirectory.
---
 indra/newview/scripts/lua/require/Floater.lua    | 146 -----------------------
 indra/newview/scripts/lua/require/UI.lua         |  12 +-
 indra/newview/scripts/lua/require/UI/Floater.lua | 146 +++++++++++++++++++++++
 indra/newview/scripts/lua/require/UI/popup.lua   |  53 ++++++++
 indra/newview/scripts/lua/require/popup.lua      |  53 --------
 5 files changed, 202 insertions(+), 208 deletions(-)
 delete mode 100644 indra/newview/scripts/lua/require/Floater.lua
 create mode 100644 indra/newview/scripts/lua/require/UI/Floater.lua
 create mode 100644 indra/newview/scripts/lua/require/UI/popup.lua
 delete mode 100644 indra/newview/scripts/lua/require/popup.lua

diff --git a/indra/newview/scripts/lua/require/Floater.lua b/indra/newview/scripts/lua/require/Floater.lua
deleted file mode 100644
index d057a74386..0000000000
--- a/indra/newview/scripts/lua/require/Floater.lua
+++ /dev/null
@@ -1,146 +0,0 @@
--- Floater base class
-
-local leap = require 'leap'
-local fiber = require 'fiber'
-local util = require 'util'
-
--- list of all the events that a LLLuaFloater might send
-local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events
-local event_set = {}
-for _, event in pairs(event_list) do
-    event_set[event] = true
-end
-
-local function _event(event_name)
-    if not event_set[event_name] then
-        error("Incorrect event name: " .. event_name, 3)
-    end
-    return event_name
-end
-
--- ---------------------------------------------------------------------------
-local Floater = {}
-
--- Pass:
--- relative file path to floater's XUI definition file
--- optional: sign up for additional events for defined control
--- {<control_name>={action1, action2, ...}}
-function Floater:new(path, extra)
-    local obj = setmetatable({}, self)
-    self.__index = self
-
-    local path_parts = string.split(path, '/')
-    obj.name = 'Floater ' .. path_parts[#path_parts]
-
-    obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)}
-    if extra then
-        -- validate each of the actions for each specified control
-        for control, actions in pairs(extra) do
-            for _, action in pairs(actions) do
-                _event(action)
-            end
-        end
-        obj._command.extra_events = extra
-    end
-
-    return obj
-end
-
-util.classctor(Floater)
-
-function Floater:show()
-    -- leap.eventstream() returns the first response, and launches a
-    -- background fiber to call the passed callback with all subsequent
-    -- responses.
-    local event = leap.eventstream(
-        'LLFloaterReg',
-        self._command,
-        -- handleEvents() returns false when done.
-        -- eventstream() expects a true return when done.
-        function(event) return not self:handleEvents(event) end)
-    self._pump = event.command_name
-    -- we might need the returned reqid to cancel the eventstream() fiber
-    self.reqid = event.reqid
-
-    -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if
-    -- subclass has a post_build() method. Honor the convention that if
-    -- handleEvents() returns false, we're done.
-    if not self:handleEvents(event) then
-        return
-    end
-end
-
-function Floater:post(action)
-    leap.send(self._pump, action)
-end
-
-function Floater:request(action)
-    return leap.request(self._pump, action)
-end
-
--- local inspect = require 'inspect'
-
-function Floater:handleEvents(event_data)
-    local event = event_data.event
-    if event_set[event] == nil then
-        LL.print_warning(string.format('%s received unknown event %q', self.name, event))
-    end
-
-    -- Before checking for a general (e.g.) commit() method, first look for
-    -- commit_ctrl_name(): in other words, concatenate the event name with the
-    -- ctrl_name, with an underscore between. If there exists such a specific
-    -- method, call that.
-    local handler, ret
-    if event_data.ctrl_name then
-        local specific = event .. '_' .. event_data.ctrl_name
-        handler = self[specific]
-        if handler then
-            ret = handler(self, event_data)
-            -- Avoid 'return ret or true' because we explicitly want to allow
-            -- the handler to return false.
-            if ret ~= nil then
-                return ret
-            else
-                return true
-            end
-        end
-    end
-
-    -- No specific "event_on_ctrl()" method found; try just "event()"
-    handler = self[event]
-    if handler then
-        ret = handler(self, event_data)
-        if ret ~= nil then
-            return ret
-        end
---  else
---      print(string.format('%s ignoring event %s', self.name, inspect(event_data)))
-    end
-
-    -- We check for event() method before recognizing floater_close in case
-    -- the consumer needs to react specially to closing the floater. Now that
-    -- we've checked, recognize it ourselves. Returning false terminates the
-    -- anonymous fiber function launched by leap.eventstream().
-    if event == _event('floater_close') then
-        LL.print_warning(self.name .. ' closed')
-        return false
-    end
-    return true
-end
-
--- onCtrl() permits a different dispatch style in which the general event()
--- method explicitly calls (e.g.)
--- self:onCtrl(event_data, {
---     ctrl_name=function()
---         self:post(...)
---     end,
---     ...
--- })
-function Floater:onCtrl(event_data, ctrl_map)
-    local handler = ctrl_map[event_data.ctrl_name]
-    if handler then
-        handler()
-    end
-end
-
-return Floater
diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua
index 969a2cbded..2df70fd453 100644
--- a/indra/newview/scripts/lua/require/UI.lua
+++ b/indra/newview/scripts/lua/require/UI.lua
@@ -5,17 +5,11 @@ local mapargs = require 'mapargs'
 local Timer = (require 'timers').Timer
 local util = require 'util'
 
--- Allow lazily accessing certain other modules on demand, e.g. a reference to
--- UI.Floater lazily loads the Floater module. Use of UI's __index metamethod
--- theoretically permits any other module you can require() to appear as a
--- submodule of UI, but it doesn't make sense to support (e.g.) UI.Queue.
-local submods = { 'Floater', 'popup' }
+-- Allow lazily accessing UI submodules on demand, e.g. a reference to
+-- UI.Floater lazily loads the UI/Floater module.
 local UI = util.setmetamethods{
     __index=function(t, key)
-        if not table.find(submods, key) then
-            error(`Invalid UI submodule {key}`, 2)
-        end
-        local mod = require(key)
+        local mod = require('UI/' .. key)
         -- cache the submodule
         t[key] = mod
         return mod
diff --git a/indra/newview/scripts/lua/require/UI/Floater.lua b/indra/newview/scripts/lua/require/UI/Floater.lua
new file mode 100644
index 0000000000..d057a74386
--- /dev/null
+++ b/indra/newview/scripts/lua/require/UI/Floater.lua
@@ -0,0 +1,146 @@
+-- Floater base class
+
+local leap = require 'leap'
+local fiber = require 'fiber'
+local util = require 'util'
+
+-- list of all the events that a LLLuaFloater might send
+local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events
+local event_set = {}
+for _, event in pairs(event_list) do
+    event_set[event] = true
+end
+
+local function _event(event_name)
+    if not event_set[event_name] then
+        error("Incorrect event name: " .. event_name, 3)
+    end
+    return event_name
+end
+
+-- ---------------------------------------------------------------------------
+local Floater = {}
+
+-- Pass:
+-- relative file path to floater's XUI definition file
+-- optional: sign up for additional events for defined control
+-- {<control_name>={action1, action2, ...}}
+function Floater:new(path, extra)
+    local obj = setmetatable({}, self)
+    self.__index = self
+
+    local path_parts = string.split(path, '/')
+    obj.name = 'Floater ' .. path_parts[#path_parts]
+
+    obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)}
+    if extra then
+        -- validate each of the actions for each specified control
+        for control, actions in pairs(extra) do
+            for _, action in pairs(actions) do
+                _event(action)
+            end
+        end
+        obj._command.extra_events = extra
+    end
+
+    return obj
+end
+
+util.classctor(Floater)
+
+function Floater:show()
+    -- leap.eventstream() returns the first response, and launches a
+    -- background fiber to call the passed callback with all subsequent
+    -- responses.
+    local event = leap.eventstream(
+        'LLFloaterReg',
+        self._command,
+        -- handleEvents() returns false when done.
+        -- eventstream() expects a true return when done.
+        function(event) return not self:handleEvents(event) end)
+    self._pump = event.command_name
+    -- we might need the returned reqid to cancel the eventstream() fiber
+    self.reqid = event.reqid
+
+    -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if
+    -- subclass has a post_build() method. Honor the convention that if
+    -- handleEvents() returns false, we're done.
+    if not self:handleEvents(event) then
+        return
+    end
+end
+
+function Floater:post(action)
+    leap.send(self._pump, action)
+end
+
+function Floater:request(action)
+    return leap.request(self._pump, action)
+end
+
+-- local inspect = require 'inspect'
+
+function Floater:handleEvents(event_data)
+    local event = event_data.event
+    if event_set[event] == nil then
+        LL.print_warning(string.format('%s received unknown event %q', self.name, event))
+    end
+
+    -- Before checking for a general (e.g.) commit() method, first look for
+    -- commit_ctrl_name(): in other words, concatenate the event name with the
+    -- ctrl_name, with an underscore between. If there exists such a specific
+    -- method, call that.
+    local handler, ret
+    if event_data.ctrl_name then
+        local specific = event .. '_' .. event_data.ctrl_name
+        handler = self[specific]
+        if handler then
+            ret = handler(self, event_data)
+            -- Avoid 'return ret or true' because we explicitly want to allow
+            -- the handler to return false.
+            if ret ~= nil then
+                return ret
+            else
+                return true
+            end
+        end
+    end
+
+    -- No specific "event_on_ctrl()" method found; try just "event()"
+    handler = self[event]
+    if handler then
+        ret = handler(self, event_data)
+        if ret ~= nil then
+            return ret
+        end
+--  else
+--      print(string.format('%s ignoring event %s', self.name, inspect(event_data)))
+    end
+
+    -- We check for event() method before recognizing floater_close in case
+    -- the consumer needs to react specially to closing the floater. Now that
+    -- we've checked, recognize it ourselves. Returning false terminates the
+    -- anonymous fiber function launched by leap.eventstream().
+    if event == _event('floater_close') then
+        LL.print_warning(self.name .. ' closed')
+        return false
+    end
+    return true
+end
+
+-- onCtrl() permits a different dispatch style in which the general event()
+-- method explicitly calls (e.g.)
+-- self:onCtrl(event_data, {
+--     ctrl_name=function()
+--         self:post(...)
+--     end,
+--     ...
+-- })
+function Floater:onCtrl(event_data, ctrl_map)
+    local handler = ctrl_map[event_data.ctrl_name]
+    if handler then
+        handler()
+    end
+end
+
+return Floater
diff --git a/indra/newview/scripts/lua/require/UI/popup.lua b/indra/newview/scripts/lua/require/UI/popup.lua
new file mode 100644
index 0000000000..3aaadf85ba
--- /dev/null
+++ b/indra/newview/scripts/lua/require/UI/popup.lua
@@ -0,0 +1,53 @@
+local leap = require 'leap'
+local mapargs = require 'mapargs'
+
+-- notification is any name defined in notifications.xml as
+-- <notification name=>
+-- vars is a table providing values for [VAR] substitution keys in the
+-- notification body
+-- payload prepopulates the response table
+-- wait=false means fire and forget, otherwise wait for user response
+local popup_meta = {
+    -- setting this function as getmetatable(popup).__call() means this gets
+    -- called when a consumer calls popup(notification, vars, payload)
+    __call = function(self, ...)
+        local args = mapargs('notification,vars,payload,wait', ...)
+        -- we use convenience argument names different from 'LLNotifications'
+        -- listener
+        args.name = args.notification
+        args.notification = nil
+        args.substitutions = args.vars
+        args.vars = nil
+        local wait = args.wait
+        args.wait = nil
+        args.op = 'requestAdd'
+        -- Specifically test (wait == false), NOT (not wait), because we treat
+        -- nil (omitted, default true) differently than false (explicitly
+        -- DON'T wait).
+        if wait == false then
+            leap.send('LLNotifications', args)
+        else
+            return leap.request('LLNotifications', args).response
+        end
+    end
+}
+
+local popup = setmetatable({}, popup_meta)
+
+function popup:alert(message)
+    return self('GenericAlert', {MESSAGE=message})
+end
+
+function popup:alertOK(message)
+    return self('GenericAlertOK', {MESSAGE=message})
+end
+
+function popup:alertYesCancel(message)
+    return self('GenericAlertYesCancel', {MESSAGE=message})
+end
+
+function popup:tip(message)
+    self{'SystemMessageTip', {MESSAGE=message}, wait=false}
+end
+
+return popup
diff --git a/indra/newview/scripts/lua/require/popup.lua b/indra/newview/scripts/lua/require/popup.lua
deleted file mode 100644
index 3aaadf85ba..0000000000
--- a/indra/newview/scripts/lua/require/popup.lua
+++ /dev/null
@@ -1,53 +0,0 @@
-local leap = require 'leap'
-local mapargs = require 'mapargs'
-
--- notification is any name defined in notifications.xml as
--- <notification name=>
--- vars is a table providing values for [VAR] substitution keys in the
--- notification body
--- payload prepopulates the response table
--- wait=false means fire and forget, otherwise wait for user response
-local popup_meta = {
-    -- setting this function as getmetatable(popup).__call() means this gets
-    -- called when a consumer calls popup(notification, vars, payload)
-    __call = function(self, ...)
-        local args = mapargs('notification,vars,payload,wait', ...)
-        -- we use convenience argument names different from 'LLNotifications'
-        -- listener
-        args.name = args.notification
-        args.notification = nil
-        args.substitutions = args.vars
-        args.vars = nil
-        local wait = args.wait
-        args.wait = nil
-        args.op = 'requestAdd'
-        -- Specifically test (wait == false), NOT (not wait), because we treat
-        -- nil (omitted, default true) differently than false (explicitly
-        -- DON'T wait).
-        if wait == false then
-            leap.send('LLNotifications', args)
-        else
-            return leap.request('LLNotifications', args).response
-        end
-    end
-}
-
-local popup = setmetatable({}, popup_meta)
-
-function popup:alert(message)
-    return self('GenericAlert', {MESSAGE=message})
-end
-
-function popup:alertOK(message)
-    return self('GenericAlertOK', {MESSAGE=message})
-end
-
-function popup:alertYesCancel(message)
-    return self('GenericAlertYesCancel', {MESSAGE=message})
-end
-
-function popup:tip(message)
-    self{'SystemMessageTip', {MESSAGE=message}, wait=false}
-end
-
-return popup
-- 
cgit v1.2.3