by doy (jluehrs2 at uiuc dot edu)
http://dev.litestep.com/projects/LSLua/
LSLua is a scripting interface to LiteStep using the Lua scripting language. Lua is a cross platform, open source, embeddable scripting language. This module provides an interface to the LSAPI through Lua scripts.
This document explains what LSLua as a module provides;
for convenience, each of lua code,
litestep config code, and
LSAPI code are highlighted.
See history.txt for a list of bugs and changes in LSLua.
To see how LSLua may be used, with examples, see http://wiki.litestep.com/Modules:LSLua.
See the Lua 5.1 manual for a quick reference on using Lua. See also the book Programming in Lua. Code snippets and general information can be found at the lua-users wiki. Finally, for more specific questions not covered by those resources, feel free to ask for help in #lua on irc.freenode.net
To load LSLua, put a line resembling *NetLoadModule lslua-0.5
load lslua.dll in your theme.rc. The
load lslua.dll part is important, since,
due to restrictions in NetLoadModule, all of the modules that come with
LSLua must have a .dll extension for NetLoadModule to unpack them to the
correct place. Loading LSLua threaded may be required to allow concurrent
operation of things in Lua (such as the timer module).
Threading can likely cause scripts in general to break, however. Try it
with and without threading and see for yourself.
*LuaFile <filename>
Executes the given file. This registers any functions that are declared,
and executes any statements not declared in a function. Any function
whose name begins with bang_ is also registered as a bang
command, named with the rest of the function name. For example, the
function bang_test would be registered as
!test. Bang functions take one optional string
argument consisting of the entire argument string passed to them.
*LuaBinaryModuleDir <directory>
Declares a directory to be added to the search path for binary modules
(package.cpath). Uses an extension of .dll.
*LuaScriptModuleDir <directory>
Declares a directory to be added to the search path for Lua script
modules (package.path). Uses an extension of .lua or
.lua.dll.
*LuaModuleDir <directory>
Equivalent to both of *LuaBinaryModuleDir and
*LuaScriptModuleDir.
*LuaPackageDir <directory>
This is deprecated. Same as *LuaModuleDir.
!LuaExec <lua chunk>Executes the argument as a Lua chunk. Note that new bangs are not registered using this method (this may change in the future).
LSLua defines the global table lslua which contains some
important functions and variables.
lslua.message_box (text, title)
Creates a message box with text of text and optional title of title.
Quotes do work correctly, unlike !alert.
lslua.exec (str)
Executes str as a command, like LSXCommand or
!execute [].
Uses LSExecute().
lslua.res ()
Returns a table such that lslua.res().x is the x resolution,
lslua.res().y is the y resolution, and
lslua.res().bpp is the bits per pixel.
lslua.mouse ()
Returns a table such that lslua.mouse().x is the x
coordinate of the mouse and lslua.mouse().y is the y
coordinate of the mouse.
lslua.milli ()
Returns the current number of milliseconds since the last second (use
os.date to get the rest of the time information).
lslua.versiona string containing the lslua version.
lslua.get_evar (name)
Get an evar's value in memory, not file. Returns a string, or
nil if evar is not defined. Similar to what you expect
$name$ would give.
Uses GetRCString().
Note: the preferred way to use this function is through the evar module.
lslua.get_line (evar_name)
Get an evar's raw value in memory, not file. Returns a string, or
nil if evar is not defined. Similar to get_evar but does not
return first token.
Uses GetRCLine().
lslua.set_evar (name, value)Set an evar's value in memory, not file.
Uses LSSetVariable().
Note: the preferred way to use this function is through the evar module.
lslua.rc_lines (prefix, file)Get lines with given prefix from rc file. Use empty string for prefix to return all lines. If file not specified, defaults to settings already loaded in memory. Returns a table of strings.
Uses LCReadNextCommand().
lslua.initA user defined value that is called at the very end of module load, so that bangs are registered. It is also executed in a coroutine, so timers should work.
lslua.quit
Similar to lslua.init,
but is called when lslua is unloaded.
During bang execution, !LuaExec execution, and
lslua.init() and
lslua.quit(), it also declares
the global variable CURRENT_THREAD, which is the coroutine
that contains the bang execution. See the thread
module for how this can be used.
LSLua comes with six modules designed to make certain tasks easier. To
use one, include the line require "<modulename>" at
the top of your Lua script. All functions provided by the modules are
provided in a global table with the same name as the module, so for
example, you would access the pause() function through
timer.pause().
The args module defines some useful argument parsing functions.
args.strjoin (table, sep)
Takes two arguments: a table of strings, and a string to use as the
separator. Returns a string containing all of the elements of the table
concatenated together, with elements separated by the separator string
passed as the second argument. For example, args.strjoin( { "this",
"is", "a", "test" }, " " ) == "this is a test"
args.strsplit (string, sep)
Takes two arguments: a string, and a delimiter (a separator). It splits
the string up into a table of substrings based on the delimiter, and
returns that table. For example, args.strsplit( "this is a test", "
" ) == { "this", "is", "a", "test" }
args.mstrsplit (string, sep)
The same as args.strsplit,
except it returns the results as multiple return values rather
than as a table.
args.qsplit (string [, delimiters [, leftquotes [, rightquotes
]]])
Takes between 1 and 4 arguments, some of them optional. first argument is
a string, the second is a table of strings to use as delimiters, and the
third and fourth are tables of strings to use as left and right quotes,
respectively. If the fourth argument is omitted, it defaults to the same
as the third, and if they are both omitted, they default to { "\"",
"'" }. If the second argument is omitted, it defaults to { "
" }. If any of the second, third, or fourth arguments are strings,
they are automatically converted to tables holding those strings. This
function splits the string into substrings based on the delimiter like
args.strsplit does,
but it takes into account quote characters as well. For example,
args.qsplit( "this is a 'string with quotes'" ) ==
{ "this", "is", "a", "string with quotes" }
args.qsplit( "%{hello},%{world}", ",", "%{", "}" ) == { "hello", "world" }
args.qsplit( "[this is][a test]", "", "[", "]" ) == { "this is", "a test" }
args.mqsplit (string [, delimiters [, leftquotes [, rightquotes
]]])
The same as args.qsplit,
except it returns the results as multiple return values rather than
as a table.
The evar module allows access to and (re)assignment of LiteStep evars.
Saving evars to file (like mzscript varfiles) is not yet supported, although they may be in a future release.
evar.toboolean (evar)
Takes one argument, a string for an evar's name. It returns a boolean
evaluating the given evar as a boolean as how LiteStep core would in RC
'scripting'/preprocessing: It returns false for an evar
whose value is one of these strings: "0",
"false", "off", or "no". Otherwise
it returns true.
If for some reason you need to access the evar named "toboolean", access it with a different casing, like "ToBoolean".
The evar table itself can be indexed to access the values of evars. For
example, evar.LiteStepDir == evar[ "LiteStepDir" ] --is
"C:\LiteStep\" (on my system).
The result is nil for both undefined evars and those evars
previously set to nil through the evar table (a magic value
is replaced with nil).
Keys of the evar table can be assigned to; doing so will set an evar's
value. tostring() is applied to this value. For example,
evar.nameOfEvar = 13.
Setting an evar to nil this way will actually set the evar
to a magic value.
Notes on evar access and assignment and why a magic
value for nil:
There is no way (aside from !reload or
!recycle or restarting LS) to undefine an evar,
so the evar module has its own notion of 'undefined'; It does so using
its own magic value.
So it makes no sense to set an evar to nil, because evars
are just key-value pairs where both key and value are strings --omitting
one or the other or both makes no sense.
The choice to handle nil specially is because of the
addition of evar.toboolean();
nil should be recognized as false;
why not handle nil in assignment as well?
To avoid this issue, don't associate the idea that an evar can hold
nil.
This is designed to emulate the textedit.dll/xTextedit.dll modules in Lua. It can search through files, replace lines, insert lines, delete lines, etc. The main difference is that this module uses Lua pattern matching instead of standard regexes like textedit.dll does.
textedit.append (filename, str)
Adds str as a line at the end of the file
filename.
textedit.insert (filename, pattern, str, mode)
Searches through the file filename for lines matching
pattern, and inserts str there. 'There' is
determined by part of the string mode. The mode
string can be any combination of the letters g,
i, b, and G. g means
'global', and means that the function will be applied to every matching
line in the file. i means case insensitive, which should be
self-explanitory. b means before, and only applies to
insert. If b is given, str will be inserted
before the matching line, otherwise it will be inserted after.
G means line global, and only applies for
textedit.replace().
It means that
textedit.replace()
should replace each match on a given line, instead of the first.
Returns the number of insertions made.
textedit.delete (filename, pattern, mode)
Deletes lines in filename that match pattern,
following the mode rules from
textedit.insert(). Returns the
number of deletions made.
textedit.replace (filename, pattern, replace_pattern, mode)
Searches the file filename for lines that match
pattern and replaces pattern with
replace_pattern on those lines. Captures and stuff like that
from string.gsub() are all valid here. Returns the number of
times it replaced pattern.
textedit.find (filename, pattern, mode)
Searches filename for pattern, and returns
either the number of the first line that matches, or a table containing
all lines that match if the mode string contains g.
textedit.delete_line (filename, line_num)
Deletes line number line_num from the file
filename. It returns true if the line was
successfully deleted and false otherwise.
textedit.insert_line (filename, str, line_num, before)
Inserts str into the file filename either
before line_num if before is true,
or after line_num if before is
false. Returns true if the insertion was
successful and false otherwise.
textedit.get_line (filename, line_num)
Returns a string containing the contents of line line_num in
file filename.
The thread module doesn't provide anything useful to users of LSLua, but it provides an important interface for module writers. It allows scripters to access the global coroutines defined by LSLua each time a user defined bang is called, allowing scripts to be started and resumed by name.
thread.yield ()
Yields the current bang execution, with a value of a string that is
passed to it as an argument. If you declare your own coroutines in your
code, you should always pass arguments back through
coroutine.yield(), so that you can check to be sure that
what is yielding is in fact your code, and not a thread trying to yield.
See the animation module for an example of this.
thread.resume ()Resumes the execution of the function that yielded with the name that is passed to resume.
The timer module is an interface to the timer LiteStep module, and allows for pauses to work without freezing anything or stopping LSLua from functioning.
timer.pause (delay)
Takes a single argument, defining how long to pause for, using the
timer.dll syntax for time. For example, pause(500) pauses
for 500 milliseconds, pause("3s") pauses for 3 seconds,
etc.
timer.resume ()
The function that timer.dll calls when the timer.pause() is
over. It shouldn't ever be called manually, unless you want to end a
timer.pause() early.