aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--ClientHamr/GuiLua/skang.lua186
1 files changed, 186 insertions, 0 deletions
diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua
new file mode 100644
index 0000000..25aedac
--- /dev/null
+++ b/ClientHamr/GuiLua/skang.lua
@@ -0,0 +1,186 @@
1-- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated.
2
3-- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular.
4-- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module".
5-- TODO - Except for the "passing the name in as ..." part. B-(
6do -- Only I'm not gonna indent this.
7
8
9local skangModuleBegin = function (name, author, copyright, version, timestamp, skin)
10 local _M = {} -- This is what we return to require().
11 _M._NAME = name -- Catch the module name passed in from require(), so that the file name can change.
12 _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M.
13 _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name.
14
15 _M.AUTHOR = author
16 _M.COPYRIGHT = copyright .. ' ' .. author
17 _M.VERSION = version .. ' lookup version here ' .. timestamp
18 -- TODO - If there's no skin passed in, try to find the file skin .. '.skang' and load that instead.
19 _M.DEFAULT_SKANG = skin
20
21 package.loaded[_M._NAME] = _M -- Stuff the result into where require() can find it, instead of returning it at the end.
22 -- Returning it at the end does the same thing.
23 -- This is so that we can have all the module stuff at the top.
24 -- Should do this before any further require(), so that circular references don't blow out.
25
26 --_G[_M._NAME] = _M -- Stuff it into a global of the same name.
27 -- Not such a good idea to stomp on global name space.
28 -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway.
29 -- This is why module() is broken.
30
31 --local _G = _G -- Stop stuff from here leaking into the callers _G.
32 -- Also works around the setfenv() below discarding all the old globals.
33 -- Though now we have to use _G.foo to access globals.
34
35 -- An alternative to the local _G is to declare as local ALL our imports here. May be worthwhile to do both this and local _G?
36 -- basic, is it called "basic", might be called "base"? Might have to include individual names.
37 _M.print = print
38 _M.getfenv = getfenv
39 _M.setfenv = setfenv
40 _M.require = require
41 _M.coroutine = coroutine -- Apparently this is part of basic, but it comes in it's own table anyway.
42 _M.package = package
43 _M.string = string
44 _M.table = table
45 _M.math = math
46 _M.io = io
47 _M.os = os
48 _M.debug = debug
49
50 _M.savedEnvironment = getfenv(3)
51 -- setfenv() sets the environment for the FUNCTION, but we are not in a function.
52 -- Though if we are being require()ed, then require() calls a loader, which calls us, hence we are the function.
53 -- The number is the stack level -
54 -- 0 running thread, 1 current function, 2 function that called this function, etc
55 setfenv(3, _M) -- Use the result for our internal global environment, so we don't need to qualify our internal names.
56 -- So the below "_M.bar" becomes "bar". Which might not be what we want, since we are using
57 -- _M.bar for the Thing, not the local bar the Thing wraps. So we leave _M.bar as is, coz we have _M._M above. B-)
58 -- Since _M is empty at this point, we loose the other globals, but that's we why declare local copies of stuff above.
59 -- Dunno if this causes problems with the do ... end style of joining modules. It does.
60 -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time.
61
62 return _M
63end
64
65-- This is so the setfenv() stack count above is correct, and we can access ThingSpace in the final moduleBegin() version below, and STILL use this for ourselves. lol
66local smb = function (name, author, copyright, version, timestamp, skin)
67 local result = skangModuleBegin(name, author, copyright, version, timestamp, skin)
68 return result
69end
70
71local _M = smb(..., 'David Seikel', '2014', '0.0', '2014-03-19 19:01:00', nil)
72
73ThingSpace = {}
74ThingSpace.cache = {}
75ThingSpace.commands = {}
76ThingSpace.modules = {}
77ThingSpace.parameters = {}
78ThingSpace.widgets = {}
79
80moduleBegin = function (name, author, copyright, version, timestamp, skin)
81 local result = skangModuleBegin(name, author, copyright, version, timestamp, skin)
82 ThingSpace.modules[name] = {module = _M, name = name, }
83 return result
84end
85
86module = function ()
87end
88load = function ()
89end
90clear = function ()
91end
92window = function (width, height, title)
93end
94quit = function ()
95end
96
97-- skang.newParam stashes the default value into _M['bar'], and the details into ThingSpace.parameters['bar'].
98-- Actually, if it's not required, and there's no default, then skip setting _M['bar'].
99-- Could even use _index to skip setting it if it's not required and there is a default.
100-- Also should add a metatable, and __newindex() that passes all setting of this variable to skang so it can update other stuff like linked widgets.
101-- TODO - Users might want to use two or more copies of this module. Keep that in mind. local a = require 'test', b = require 'test' might handle that though?
102-- Not unless skang.newParam() knows about a and b, which it wont.
103-- Both a and b get the same table, not different copies of it.
104-- Perhaps clone the table if it exists? There is no Lua table cloner, would have to write one. Only clone the parameters, the rest can be linked back to the original.
105-- Then we have to deal with widgets linking to specific clones.
106-- Actually, not sure matrix-RAD solved that either. lol
107-- This could even be done with an array of these arguments, not including the _M.
108newParam = function (module, name, required, shortcut, default, help)
109 module[name] = default
110 ThingSpace.parameters[name] = {module = module, name = name, required = required, shortcut = shortcut, default = default, help = help, }
111 print(name .. ' -> ' .. shortcut .. ' -> ' .. help)
112end
113
114-- skang.newCommand stashes the function into _M['func'], and stashes it all (including the function) into ThingSpace.commands['func'].
115-- TODO - Could use _call so that ThingSpace.commands['foo'](arg) works.
116newCommand = function (module, name, types, help, func)
117 module[name] = func
118 ThingSpace.commands[name] = {module = module, name = name, help = help, func = func, }
119 print(name .. '(' .. types .. ') -> ' .. help)
120end
121
122
123-- TODO - Some function stubs, for now. Fill them up later.
124module = function (name)
125end
126clear = function ()
127end
128window = function (width, height, title)
129end
130load = function (name)
131end
132get = function (name)
133end
134set = function (name, value)
135end
136quit = function ()
137end
138
139newCommand(_M, 'module', 'name', '', module)
140newCommand(_M, 'clear', '', '', clear)
141newCommand(_M, 'window', 'w,h,name', '', window)
142newCommand(_M, 'load', 'name', '', load)
143newCommand(_M, 'get', 'name', '', get) -- This should be in the modules, not actually here.
144newCommand(_M, 'set', 'name,data', '', set) -- This should be in the modules, not actually here.
145newCommand(_M, 'quit', '', '', quit)
146
147
148-- Restore the environment.
149moduleEnd = function (module)
150 setfenv(2, module.savedEnvironment)
151end
152
153moduleEnd(_M)
154
155end
156
157
158
159
160-- Gotta check out this _ENV thing, 5.2 only. Seems to replace the need for setfenv(). Seems like setfenv should do what we want, and is more backward compatible.
161-- "_ENV is not supported directly in 5.1, so its use can prevent a module from remaining compatible with 5.1.
162-- Maybe you can simulate _ENV with setfenv and trapping gets/sets to it via __index/__newindex metamethods, or just avoid _ENV."
163--[[ This is a Lua version of what module() does. Apparently the _LOADED stuff is needed somehow, even though it's a local? Think that was bogus.
164
165local _LOADED = package.loaded
166function _G.module (modname, ...)
167 local ns = _LOADED[modname]
168 if type(ns) ~= "table" then
169 ns = findtable (_G, modname)
170 if not ns then
171 error (string.format ("name conflict for module '%s'", modname))
172 end
173 _LOADED[modname] = ns
174 end
175 if not ns._NAME then
176 ns._NAME = modname
177 ns._M = ns
178 ns._PACKAGE = gsub (modname, "[^.]*$", "")
179 end
180 setfenv (2, ns)
181 for i, f in ipairs (arg) do
182 f (ns)
183 end
184end
185
186]]