summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LUA_API.rst183
-rw-r--r--Lua API.html172
-rw-r--r--library/lua/dfhack.lua2
3 files changed, 256 insertions, 101 deletions
diff --git a/LUA_API.rst b/LUA_API.rst
index e8c413fe..5fc653bb 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -4,9 +4,26 @@ DFHack Lua API
.. contents::
-====================
-DF structure wrapper
-====================
+The current version of DFHack has extensive support for
+the Lua scripting language, providing access to:
+
+1. Raw data structures used by the game.
+2. Many C++ functions for high-level access to these
+ structures, and interaction with dfhack itself.
+3. Some functions exported by C++ plugins.
+
+Lua code can be used both for writing scripts, which
+are treated by DFHack command line prompt almost as
+native C++ commands, and invoked by plugins written in c++.
+
+This document describes native API available to Lua in detail.
+For the most part it does not describe utility functions
+implemented by Lua files located in hack/lua/...
+
+
+=========================
+DF data structure wrapper
+=========================
DF structures described by the xml files in library/xml are exported
to lua code as a tree of objects and functions under the ``df`` global,
@@ -479,29 +496,6 @@ Input & Output
If the interactive console is not accessible, returns *nil, error*.
-Miscellaneous
--------------
-
-* ``dfhack.run_script(name[,args...])``
-
- Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
- The ``name`` argument should be the name stem, as would be used on the command line.
- Note that the script is re-read from the file every time it is called, and errors
- are propagated to the caller.
-
-* ``dfhack.with_suspend(f[,args...])``
-
- Calls ``f`` with arguments after grabbing the DF core suspend lock.
- Suspending is necessary for accessing a consistent state of DF memory.
-
- Returned values and errors are propagated through after releasing
- the lock. It is safe to nest suspends.
-
- Every thread is allowed only one suspend per DF frame, so it is best
- to group operations together in one big critical section. A plugin
- can choose to run all lua code inside a C++-side suspend lock.
-
-
Exception handling
------------------
@@ -531,30 +525,6 @@ Exception handling
Compares to coroutine.resume like dfhack.safecall vs pcall.
-* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])``
-
- Invokes ``fn`` with ``args``, and after it returns or throws an
- error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from
- ``fn`` are propagated, and errors are re-thrown.
-
- The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``,
- and the ``always`` boolean specifies if cleanup should be called in any case,
- or only in case of an error.
-
-* ``dfhack.with_finalize(cleanup_fn,fn[,args...])``
-
- Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``.
- Implemented using ``call_with_finalizer(0,true,...)``.
-
-* ``dfhack.with_onerror(cleanup_fn,fn[,args...])``
-
- Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error.
- Implemented using ``call_with_finalizer(0,false,...)``.
-
-* ``dfhack.with_temp_object(obj,fn[,args...])``
-
- Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``.
-
* ``dfhack.exception``
Metatable of error objects used by dfhack. The objects have the
@@ -580,6 +550,46 @@ Exception handling
The default value of the ``verbose`` argument of ``err:tostring()``.
+Locking and finalization
+------------------------
+
+* ``dfhack.with_suspend(f[,args...])``
+
+ Calls ``f`` with arguments after grabbing the DF core suspend lock.
+ Suspending is necessary for accessing a consistent state of DF memory.
+
+ Returned values and errors are propagated through after releasing
+ the lock. It is safe to nest suspends.
+
+ Every thread is allowed only one suspend per DF frame, so it is best
+ to group operations together in one big critical section. A plugin
+ can choose to run all lua code inside a C++-side suspend lock.
+
+* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])``
+
+ Invokes ``fn`` with ``args``, and after it returns or throws an
+ error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from
+ ``fn`` are propagated, and errors are re-thrown.
+
+ The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``,
+ and the ``always`` boolean specifies if cleanup should be called in any case,
+ or only in case of an error.
+
+* ``dfhack.with_finalize(cleanup_fn,fn[,args...])``
+
+ Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``.
+ Implemented using ``call_with_finalizer(0,true,...)``.
+
+* ``dfhack.with_onerror(cleanup_fn,fn[,args...])``
+
+ Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error.
+ Implemented using ``call_with_finalizer(0,false,...)``.
+
+* ``dfhack.with_temp_object(obj,fn[,args...])``
+
+ Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``.
+
+
Persistent configuration storage
--------------------------------
@@ -1312,6 +1322,42 @@ Features:
Invokes all listeners contained in the event in an arbitrary
order using ``dfhack.safecall``.
+
+=======
+Modules
+=======
+
+DFHack sets up the lua interpreter so that the built-in ``require``
+function can be used to load shared lua code from hack/lua/.
+The ``dfhack`` namespace reference itself may be obtained via
+``require('dfhack')``, although it is initially created as a
+global by C++ bootstrap code.
+
+The following functions are provided:
+
+* ``mkmodule(name)``
+
+ Creates an environment table for the module. Intended to be used as::
+
+ local _ENV = mkmodule('foo')
+ ...
+ return _ENV
+
+ If called the second time, returns the same table; thus providing reload support.
+
+* ``reload(name)``
+
+ Reloads a previously ``require``-d module *"name"* from the file.
+ Intended as a help for module development.
+
+* ``dfhack.BASE_G``
+
+ This variable contains the root global environment table, which is
+ used as a base for all module and script environments. Its contents
+ should be kept limited to the standard Lua library and API described
+ in this document.
+
+
=======
Plugins
=======
@@ -1373,3 +1419,40 @@ sort
Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.
+
+
+=======
+Scripts
+=======
+
+Any files with the .lua extension placed into hack/scripts/*
+are automatically used by the DFHack core as commands. The
+matching command name consists of the name of the file sans
+the extension.
+
+**NOTE:** Scripts placed in subdirectories still can be accessed, but
+do not clutter the ``ls`` command list; thus it is preferred
+for obscure developer-oriented scripts and scripts used by tools.
+When calling such scripts, always use '/' as the separator for
+directories, e.g. ``devel/lua-example``.
+
+Scripts are re-read from disk every time they are used
+(this may be changed later to check the file change time); however
+the global variable values persist in memory between calls.
+Every script gets its own separate environment for global
+variables.
+
+Arguments are passed in to the scripts via the **...** built-in
+quasi-variable; when the script is called by the DFHack core,
+they are all guaranteed to be non-nil strings.
+
+DFHack core invokes the scripts in the *core context* (see above);
+however it is possible to call them from any lua code (including
+from other scripts) in any context, via the same function the core uses:
+
+* ``dfhack.run_script(name[,args...])``
+
+ Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
+ The ``name`` argument should be the name stem, as would be used on the command line.
+
+Note that this function lets errors propagate to the caller.
diff --git a/Lua API.html b/Lua API.html
index 47cf08ab..04e89936 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -320,7 +320,7 @@ ul.auto-toc {
<div class="contents topic" id="contents">
<p class="topic-title first">Contents</p>
<ul class="simple">
-<li><a class="reference internal" href="#df-structure-wrapper" id="id1">DF structure wrapper</a><ul>
+<li><a class="reference internal" href="#df-data-structure-wrapper" id="id1">DF data structure wrapper</a><ul>
<li><a class="reference internal" href="#typed-object-references" id="id2">Typed object references</a><ul>
<li><a class="reference internal" href="#primitive-references" id="id3">Primitive references</a></li>
<li><a class="reference internal" href="#struct-references" id="id4">Struct references</a></li>
@@ -336,8 +336,8 @@ ul.auto-toc {
<li><a class="reference internal" href="#dfhack-api" id="id10">DFHack API</a><ul>
<li><a class="reference internal" href="#native-utilities" id="id11">Native utilities</a><ul>
<li><a class="reference internal" href="#input-output" id="id12">Input &amp; Output</a></li>
-<li><a class="reference internal" href="#miscellaneous" id="id13">Miscellaneous</a></li>
-<li><a class="reference internal" href="#exception-handling" id="id14">Exception handling</a></li>
+<li><a class="reference internal" href="#exception-handling" id="id13">Exception handling</a></li>
+<li><a class="reference internal" href="#locking-and-finalization" id="id14">Locking and finalization</a></li>
<li><a class="reference internal" href="#persistent-configuration-storage" id="id15">Persistent configuration storage</a></li>
<li><a class="reference internal" href="#material-info-lookup" id="id16">Material info lookup</a></li>
</ul>
@@ -360,15 +360,31 @@ ul.auto-toc {
</li>
</ul>
</li>
-<li><a class="reference internal" href="#plugins" id="id29">Plugins</a><ul>
-<li><a class="reference internal" href="#burrows" id="id30">burrows</a></li>
-<li><a class="reference internal" href="#sort" id="id31">sort</a></li>
+<li><a class="reference internal" href="#modules" id="id29">Modules</a></li>
+<li><a class="reference internal" href="#plugins" id="id30">Plugins</a><ul>
+<li><a class="reference internal" href="#burrows" id="id31">burrows</a></li>
+<li><a class="reference internal" href="#sort" id="id32">sort</a></li>
</ul>
</li>
+<li><a class="reference internal" href="#scripts" id="id33">Scripts</a></li>
</ul>
</div>
-<div class="section" id="df-structure-wrapper">
-<h1><a class="toc-backref" href="#id1">DF structure wrapper</a></h1>
+<p>The current version of DFHack has extensive support for
+the Lua scripting language, providing access to:</p>
+<ol class="arabic simple">
+<li>Raw data structures used by the game.</li>
+<li>Many C++ functions for high-level access to these
+structures, and interaction with dfhack itself.</li>
+<li>Some functions exported by C++ plugins.</li>
+</ol>
+<p>Lua code can be used both for writing scripts, which
+are treated by DFHack command line prompt almost as
+native C++ commands, and invoked by plugins written in c++.</p>
+<p>This document describes native API available to Lua in detail.
+For the most part it does not describe utility functions
+implemented by Lua files located in hack/lua/...</p>
+<div class="section" id="df-data-structure-wrapper">
+<h1><a class="toc-backref" href="#id1">DF data structure wrapper</a></h1>
<p>DF structures described by the xml files in library/xml are exported
to lua code as a tree of objects and functions under the <tt class="docutils literal">df</tt> global,
which broadly maps to the <tt class="docutils literal">df</tt> namespace in C++.</p>
@@ -764,28 +780,8 @@ string, global environment and command-line history file.</p>
</li>
</ul>
</div>
-<div class="section" id="miscellaneous">
-<h3><a class="toc-backref" href="#id13">Miscellaneous</a></h3>
-<ul>
-<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.run_script(name[,args...])</span></tt></p>
-<p>Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
-The <tt class="docutils literal">name</tt> argument should be the name stem, as would be used on the command line.
-Note that the script is re-read from the file every time it is called, and errors
-are propagated to the caller.</p>
-</li>
-<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_suspend(f[,args...])</span></tt></p>
-<p>Calls <tt class="docutils literal">f</tt> with arguments after grabbing the DF core suspend lock.
-Suspending is necessary for accessing a consistent state of DF memory.</p>
-<p>Returned values and errors are propagated through after releasing
-the lock. It is safe to nest suspends.</p>
-<p>Every thread is allowed only one suspend per DF frame, so it is best
-to group operations together in one big critical section. A plugin
-can choose to run all lua code inside a C++-side suspend lock.</p>
-</li>
-</ul>
-</div>
<div class="section" id="exception-handling">
-<h3><a class="toc-backref" href="#id14">Exception handling</a></h3>
+<h3><a class="toc-backref" href="#id13">Exception handling</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.error(msg[,level[,verbose]])</span></tt></p>
<p>Throws a dfhack exception object with location and stack trace.
@@ -808,25 +804,6 @@ returning. Intended as a convenience function.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.saferesume(coroutine[,args...])</span></tt></p>
<p>Compares to coroutine.resume like dfhack.safecall vs pcall.</p>
</li>
-<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])</span></tt></p>
-<p>Invokes <tt class="docutils literal">fn</tt> with <tt class="docutils literal">args</tt>, and after it returns or throws an
-error calls <tt class="docutils literal">cleanup_fn</tt> with <tt class="docutils literal">cleanup_args</tt>. Any return values from
-<tt class="docutils literal">fn</tt> are propagated, and errors are re-thrown.</p>
-<p>The <tt class="docutils literal">num_cleanup_args</tt> integer specifies the number of <tt class="docutils literal">cleanup_args</tt>,
-and the <tt class="docutils literal">always</tt> boolean specifies if cleanup should be called in any case,
-or only in case of an error.</p>
-</li>
-<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_finalize(cleanup_fn,fn[,args...])</span></tt></p>
-<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt>.
-Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,true,...)</span></tt>.</p>
-</li>
-<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_onerror(cleanup_fn,fn[,args...])</span></tt></p>
-<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt> on any thrown error.
-Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,false,...)</span></tt>.</p>
-</li>
-<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_temp_object(obj,fn[,args...])</span></tt></p>
-<p>Calls <tt class="docutils literal"><span class="pre">fn(obj,args...)</span></tt>, then finalizes with <tt class="docutils literal">obj:delete()</tt>.</p>
-</li>
<li><p class="first"><tt class="docutils literal">dfhack.exception</tt></p>
<p>Metatable of error objects used by dfhack. The objects have the
following properties:</p>
@@ -859,6 +836,39 @@ following properties:</p>
</li>
</ul>
</div>
+<div class="section" id="locking-and-finalization">
+<h3><a class="toc-backref" href="#id14">Locking and finalization</a></h3>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_suspend(f[,args...])</span></tt></p>
+<p>Calls <tt class="docutils literal">f</tt> with arguments after grabbing the DF core suspend lock.
+Suspending is necessary for accessing a consistent state of DF memory.</p>
+<p>Returned values and errors are propagated through after releasing
+the lock. It is safe to nest suspends.</p>
+<p>Every thread is allowed only one suspend per DF frame, so it is best
+to group operations together in one big critical section. A plugin
+can choose to run all lua code inside a C++-side suspend lock.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])</span></tt></p>
+<p>Invokes <tt class="docutils literal">fn</tt> with <tt class="docutils literal">args</tt>, and after it returns or throws an
+error calls <tt class="docutils literal">cleanup_fn</tt> with <tt class="docutils literal">cleanup_args</tt>. Any return values from
+<tt class="docutils literal">fn</tt> are propagated, and errors are re-thrown.</p>
+<p>The <tt class="docutils literal">num_cleanup_args</tt> integer specifies the number of <tt class="docutils literal">cleanup_args</tt>,
+and the <tt class="docutils literal">always</tt> boolean specifies if cleanup should be called in any case,
+or only in case of an error.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_finalize(cleanup_fn,fn[,args...])</span></tt></p>
+<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt>.
+Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,true,...)</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_onerror(cleanup_fn,fn[,args...])</span></tt></p>
+<p>Calls <tt class="docutils literal">fn</tt> with arguments, then finalizes with <tt class="docutils literal">cleanup_fn</tt> on any thrown error.
+Implemented using <tt class="docutils literal"><span class="pre">call_with_finalizer(0,false,...)</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.with_temp_object(obj,fn[,args...])</span></tt></p>
+<p>Calls <tt class="docutils literal"><span class="pre">fn(obj,args...)</span></tt>, then finalizes with <tt class="docutils literal">obj:delete()</tt>.</p>
+</li>
+</ul>
+</div>
<div class="section" id="persistent-configuration-storage">
<h3><a class="toc-backref" href="#id15">Persistent configuration storage</a></h3>
<p>This api is intended for storing configuration options in the world itself.
@@ -1470,15 +1480,45 @@ order using <tt class="docutils literal">dfhack.safecall</tt>.</p>
</div>
</div>
</div>
+<div class="section" id="modules">
+<h1><a class="toc-backref" href="#id29">Modules</a></h1>
+<p>DFHack sets up the lua interpreter so that the built-in <tt class="docutils literal">require</tt>
+function can be used to load shared lua code from hack/lua/.
+The <tt class="docutils literal">dfhack</tt> namespace reference itself may be obtained via
+<tt class="docutils literal"><span class="pre">require('dfhack')</span></tt>, although it is initially created as a
+global by C++ bootstrap code.</p>
+<p>The following functions are provided:</p>
+<ul>
+<li><p class="first"><tt class="docutils literal">mkmodule(name)</tt></p>
+<p>Creates an environment table for the module. Intended to be used as:</p>
+<pre class="literal-block">
+local _ENV = mkmodule('foo')
+...
+return _ENV
+</pre>
+<p>If called the second time, returns the same table; thus providing reload support.</p>
+</li>
+<li><p class="first"><tt class="docutils literal">reload(name)</tt></p>
+<p>Reloads a previously <tt class="docutils literal">require</tt>-d module <em>&quot;name&quot;</em> from the file.
+Intended as a help for module development.</p>
+</li>
+<li><p class="first"><tt class="docutils literal">dfhack.BASE_G</tt></p>
+<p>This variable contains the root global environment table, which is
+used as a base for all module and script environments. Its contents
+should be kept limited to the standard Lua library and API described
+in this document.</p>
+</li>
+</ul>
+</div>
<div class="section" id="plugins">
-<h1><a class="toc-backref" href="#id29">Plugins</a></h1>
+<h1><a class="toc-backref" href="#id30">Plugins</a></h1>
<p>DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by
<tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua
module file is still necessary for <tt class="docutils literal">require</tt> to read.</p>
<p>The following plugins have lua support.</p>
<div class="section" id="burrows">
-<h2><a class="toc-backref" href="#id30">burrows</a></h2>
+<h2><a class="toc-backref" href="#id31">burrows</a></h2>
<p>Implements extended burrow manipulations.</p>
<p>Events:</p>
<ul>
@@ -1516,11 +1556,41 @@ set is the same as used by the command line.</p>
<p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p>
</div>
<div class="section" id="sort">
-<h2><a class="toc-backref" href="#id31">sort</a></h2>
+<h2><a class="toc-backref" href="#id32">sort</a></h2>
<p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p>
</div>
</div>
+<div class="section" id="scripts">
+<h1><a class="toc-backref" href="#id33">Scripts</a></h1>
+<p>Any files with the .lua extension placed into hack/scripts/*
+are automatically used by the DFHack core as commands. The
+matching command name consists of the name of the file sans
+the extension.</p>
+<p><strong>NOTE:</strong> Scripts placed in subdirectories still can be accessed, but
+do not clutter the <tt class="docutils literal">ls</tt> command list; thus it is preferred
+for obscure developer-oriented scripts and scripts used by tools.
+When calling such scripts, always use '/' as the separator for
+directories, e.g. <tt class="docutils literal"><span class="pre">devel/lua-example</span></tt>.</p>
+<p>Scripts are re-read from disk every time they are used
+(this may be changed later to check the file change time); however
+the global variable values persist in memory between calls.
+Every script gets its own separate environment for global
+variables.</p>
+<p>Arguments are passed in to the scripts via the <strong>...</strong> built-in
+quasi-variable; when the script is called by the DFHack core,
+they are all guaranteed to be non-nil strings.</p>
+<p>DFHack core invokes the scripts in the <em>core context</em> (see above);
+however it is possible to call them from any lua code (including
+from other scripts) in any context, via the same function the core uses:</p>
+<ul>
+<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.run_script(name[,args...])</span></tt></p>
+<p>Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
+The <tt class="docutils literal">name</tt> argument should be the name stem, as would be used on the command line.</p>
+</li>
+</ul>
+<p>Note that this function lets errors propagate to the caller.</p>
+</div>
</div>
</body>
</html>
diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua
index d200a6c5..d56d4df6 100644
--- a/library/lua/dfhack.lua
+++ b/library/lua/dfhack.lua
@@ -68,6 +68,8 @@ function dfhack.with_temp_object(obj,fn,...)
return dfhack.call_with_finalizer(1,true,call_delete,obj,fn,obj,...)
end
+dfhack.exception.__index = dfhack.exception
+
-- Module loading
function mkmodule(module,env)