Age | Commit message (Collapse) | Author |
|
The nullary login() call (login with saved credentials) has been tested, but
the binary login(username, password) call is known not to work yet.
|
|
Add listviews(), viewinfo(), click(), doubleclick(), drag(), keypress() and
type().
WIP: These are ported from Python LEAP equivalents, but the Lua implementation
has only been partially tested.
|
|
The 'startup' table, the module's namespace, must be defined near the top
because its local waitfor:process() override references startup.
The byname table's metatable's __index() function wants to raise an error if
you try to access an undefined entry, but it referenced t[k] to check that,
producing infinite recursion. Use rawget(t, k) instead.
Also use new leap.WaitFor(args) syntax instead of leap.WaitFor:new(args).
|
|
The discussions we've read about Lua classes conventionally use
ClassName:new() as the constructor, and so far we've followed that convention.
But setting metaclass(ClassName).__call = ClassName.new permits Lua to respond
to calls of the form ClassName(ctor args) by implicitly calling
ClassName:new(ctor args).
Introduce util.classctor(). Calling util.classctor(ClassName) sets ClassName's
metaclass's __call to ClassName's constructor method. If the constructor method
is named something other than new(), pass ClassName.method as the second arg.
Use util.classctor() on each of our classes that defines a new() method.
Replace ClassName:new(args) calls with ClassName(args) calls throughout.
|
|
in addition to a list {'name1', 'name2', ...}.
|
|
|
|
|
|
|
|
|
|
ScopedRegistrarHelper
|
|
There are two conventions for Lua function calls. You can call a function with
positional arguments as usual:
f(1, 2, 3)
Lua makes it easy to handle omitted positional arguments: their values are nil.
But as in C++, positional arguments get harder to read when there are many, or
when you want to omit arguments other than the last ones.
Alternatively, using Lua syntactic sugar, you can pass a single argument which
is a table containing the desired function arguments. For this you can use
table constructor syntax to effect keyword arguments:
f{a=1, b=2, c=3}
A call passing keyword arguments is more readable because you explicitly
associate the parameter name with each argument value. Moreover, it gracefully
handles the case of multiple optional arguments. The reader need not be
concerned about parameters *not* being passed.
Now you're coding a Lua module with a number of functions. Some have numerous
or complicated arguments; some do not. For simplicity, you code the simple
functions to accept positional arguments, the more complicated functions to
accept the single-table argument style.
But how the bleep is a consumer of your module supposed to remember which
calling style to use for a given function?
mapargs() blurs the distinction, accepting either style. Coding a function
like this (where '...' is literal code, not documentation ellipsis):
function f(...)
local args = mapargs({'a', 'b', 'c'}, ...)
-- now use args.a, args.b, args.c
end
supports calls like:
f(1, 2, 3)
f{1, 2, 3}
f{c=3, a=1, b=2}
f{1, 2, c=3}
f{c=3, 1, 2} -- unlike Python!
In every call above, args.a == 1, args.b == 2, args.c == 3.
Moreover, omitting arguments (or explicitly passing nil, positionally or by
keyword) works correctly.
test_mapargs.lua exercises these cases.
|
|
so the user need not reverse-engineer the code to figure out the output.
|
|
|
|
Since timers presents a timers.Timer Lua class supporting queries and
cancellation, make TimersListener::scheduleAfter() and scheduleEvery() respond
immediately so the newly constructed Timer object has the reqid necessary to
perform those subsequent operations.
This requires that Lua invocations of these operations avoid calling the
caller's callback with that initial response.
Reinvent leap.generate() to return a Lua object supporting next() and done()
methods. A plain Lua coroutine that (indirectly) calls fiber.wait() confuses
the fiber scheduler, so avoid implementing generate() as a Lua coroutine.
Add a bit more leap.lua diagnostic output.
|
|
|
|
|
|
leap.eventstream() is used when we expect the viewer's LLEventAPI to send an
immediate first response with the reqid from the request, followed by some
number of subsequent responses bearing the same reqid. The difference between
eventstream() and generate() is that generate() expects the caller to request
each such response, whereas eventstream calls the caller's callback with each
response.
cancelreq() is for canceling the background fiber launched by eventstream()
before the callback tells it to quit.
Make WaitFor:close() remove the object from the waitfors list; similarly, make
WaitForReqid:close() remove the object from the pending list. For this reason,
cleanup() must iterate over a copy of each of the pending and waitfors lists.
Instead of unregisterWaitFor() manually searching the waitfors list, use
table.find().
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
script
|
|
|
|
|
|
|
|
|
|
following promotion of secondlife/viewer #705: Maintenance X
|
|
|
|
|
|
|
|
|
|
LLAvatarListUpdater is an LLEventTimer subclass meant to be a base class of
still other subclasses. One would presume that every one of them should
override tick(), since LLAvatarListUpdater::tick() is a no-op that simply asks
to be called again. But making it abstract (=0) produces errors since at least
one subclass does not define its own tick() method. This seems less than
useful, since the specific tick() method is the whole point of deriving from
LLEventTimer, but oh well.
|
|
Instead of maintaining a whole separate unordered_map to look up target times,
make room in the HandleMap entry for the target time. There's still
circularity, but the split into doAtTime1() and doAtTime2() resolves it: since
doAtTime2() accepts the mHandles iterator created by doAtTime1(), doAtTime2()
can simply store the new mQueue handle_type into the appropriate slot.
Also sprinkle in a few more override keywords for consistency.
|
|
Some timer use cases need to know not only whether the timer is active, but
how much time remains before it (next) fires.
Introduce LLLater::mDoneTimes to track, for each handle, the timestamp at
which it's expected to fire. We can't just look up the target timestamp in
mQueue's func_at entry because there's no documented way to navigate from a
handle_type to a node iterator or pointer. Nor can we store it in mHandles
because of order dependency: we need the mDoneTimes iterator so we can bind it
into the Periodic functor for doPeriodically(), but we need the mQueue handle
to store in mHandles. If we could find the mQueue node from the new handle, we
could update the func_at entry after emplace() -- but if we could find the
mQueue node from a handle, we wouldn't need to store the target timestamp
separately anyway.
Split LLLater::doAtTime() into internal doAtTime1() and doAtTime2(): the first
creates an mDoneTimes entry and returns an iterator, the second finishes
creating new mQueue and mHandles entries based on that mDoneTimes entry.
This lets doPeriodically()'s Periodic bind the mDoneTimes iterator. Then
instead of continually incrementing an internal data member, it increments the
mDoneTimes entry to set the next upcoming timestamp. That lets getRemaining()
report the next upcoming timestamp rather than only the original one.
Add LLEventTimer::isRunning() and getRemaining(), forwarding to its LLLater
handle.
Fix various LLEventTimer subclass references to mEventTimer.stop(), etc.
Fix non-inline LLEventTimer subclass tick() overrides for bool, not BOOL.
Remove LLAppViewer::idle() call to LLEventTimer::updateClass(). Since
LLApp::stepFrame() already calls LLCallbackList::callFunctions(), assume we've
already handled that every tick.
|