Help home › Introduction to Lua › Lua Quick Guide

Lua

Lua Quick Guide

This quick guide is aimed primarily at people who have developed plugins, programs or macros previously using other macro, script or programming languages. Newcomers to plugins should first see How to Write Plugins.

Some Basics...

  • Lua is a case-sensitive language
  • Lua is dynamically typed.  Variables in Lua do not have fixed types, and there are no type definitions for them.

Keywords

and       break   do     else    elseif    end   false   for
function  if      in     local   nil       not   or    repeat
return    then    true   until   while

Note: keywords are case sensitive so you can define a variable called For and it will not be treated as a keyword.

Comments

Comments starts with a double hyphen (--) anywhere outside a string.  If the text immediately after a double hyphen (--) is not two opening square brackets ([[), the comment is a short comment, which runs until the end of the line. Otherwise, it is a long comment, which runs until the corresponding closing pair of square brackets (]]). Long comments are frequently used to disable code temporarily.

Example:

fhMessageBox("Hello Family Historian !") -- this is a line with a comment at the end

Variables

  • Variables have to start with a character or an underscore
  • Numeric Lua variables are 32 bit signed floating point or integers
  • Variables used in the script header must be lowercase latin characters from a to z
  • Before the first assignment to a variable, its value is nil .

There are three kinds of variables in Lua: global variables, local variables, and table fields.

  • Any variable is assumed to be global unless explicitly declared as a local.
  • Global variables are visible from anywhere
  • Local variables are only visible from inside their scope: the scope of this variables begins at the first statement after their declaration and lasts until the end of the innermost block that includes the declaration. They can be declared anywhere inside a block and start with the initial assignment local

Strings

  • Strings are delimited by single quotation marks ' ' , double quotation marks " " or square brackets [[ ]] . Only the bracket form may cover multiple lines.
  • Strings can be concatenated by two dots ..
  • They can contain most of the C-like escape sequences like '\f' (form feed), '\r' (carriage return) or '\t' (horizontal tab).
  • If a backslash character is required in a string (e.g. in a folder path) the \ must be doubled (e.g c:\\).
  • Strings in Lua can contain any 8-bit value, including embedded zeros, which can be specified as '\0'

Control Structures

Lua supports a range of control structures including

if then else
if bCondition then
  -- condition true
else
  -- condition
end      
if bCondition then
  -- condition true
elseif bCondition2
  -- condition false and condition 2 true
end  
for
for i=1,10 do
  -- loops 10 times
end 
while
i = 1
while i < 10 do
  -- loops 10 times
  i = i + 1
end 
repeat
i = 10
repeat
  print(i)
  i = i-1
until i==0

Tables

  • tables are declared using curly brackets (e.g. tblSurnames = {})
  • they can contain values of all types, including other tables
  • To iterate over the elements contained in a table, the operators ipairs() or pairs() can be used:
ipairs() iterates only over the indices in a table (only outputs the numerically indexed content)
pairs() iterates over the keys in a table
for i,strdata in ipairs(tbldata) do
   print(i,strdata)
end

Tables as arrays

Tables can be used to hold arrays of information. Table constructors can contain a comma separated list of objects to create an array. The array elements can be accessed using square brackets, table[index].
t = { 1,1,2,3,5,8,13 }
  print( t[1] )        -- returns:  1
  print( t[0] )        -- returns:  nil
  print( t[4] )        -- returns:  3
Notice that the indexing into the array starts at 1, not at zero. t[0] has the value nil , i.e. there is no element at position 0.

Tables as dictionaries

Tables can also be used to store information which is not indexed numerically, or sequentially, as arrays are.
In this dictionary usage, each element pair has a key and a value.  The key is used to identify the element (either for setting the value or for retrieving it).
A key need not be a number.  It can be a string - or a value of any other Lua variable type (but not nil).
t = { apple="green", orange="orange", banana="yellow" }
  for k,v in pairs(t) do print(k,v) end
returns:  apple   green
          orange  orange
          banana  yellow

Note: that there's no guarantee as to the order in which keys will be stored in a table when using dictionaries so the order of retrieval of keys using pairs() is not defined.

A single table can be used as both an array and as a dictionary.  You are not restricted to using table constructors as just sequentially indexed lists, or as dictionaries.  You can mix the two together.

More information and table examples can be found here: lua-users.org/wiki/Tablestutorial

functions

Functions are named bits of processing code that perform some tasks, such as calculating values or displaying information.  Lua itself provides many functions you can call from within your own plugins.  The Family Historian API also provides many more functions that you can also call (How to Write Plugins shows you how to call the fhMessageBox function for example).  But you can also define and call your own functions.  Functions can take one or more parameters which act as data input to the function.

Functions are defined using the following syntax:

           function functionname(parameters)
               -- function action
               return variable
           end
      

objects

Objects, in Lua programming terms, are in some ways like a new data type for variables (remember that variables have a data type, like string or number).  Like other data types, objects too can be assigned to variables.  So you could see an object as a new and different kind of value for a variable.  But they are also somewhat similar to functions in that they can contain named processing code.  Where a named bit of processing is part of an object, it is called a Method.  The Family Historian API includes seven types of object, each of which has numerous methods.  Like functions, methods can also take parameters.

To call a function in a plugin, you simply write the name of the function followed by round brackets.  Any parameters are added between these round brackets.  Calling an object method is the same, except that the method name must be preceded by the name of the variable that stores the object, with a colon (:) separating the variable name from the method name.  A common mistake is to write a full-stop instead of a colon, so be careful not to do that - it can be a hard mistake to spot!

In the example below, ptrBase is a variable which stores the item pointer object return by the function function call 'fhNewItemPtr'.  The second line calls the 'MoveToFirstRecord' method for the item pointer object, passing in the string 'INDI' as parameter.

ptrBase = fhNewItemPtr()
ptrBase:MoveToFirstRecord('INDI')  -- Get First Individual in File

Recommended Script header

It is recommended, although not essential, to include a comment header in your scripts in the format illustrated by this example:

--[[
@title: test script
@author: Fred Blogs
@lastupdated: June 2010
@description: 
This is a Test Script which provides an example header layout.
It displays a message box saying "Hello World"
]]
 
fhMessageBox("Hello Family Historian !") -- this is a line with a comment at the end

If you add a header such as the one above, the Plugin List window will display the information in it, when you select the script - making it much easier to identify the required script. To quickly add a script header, select Insert Script Header from the Edit menu.

Modules

Lua makes it easy to create and use modules of functions.  Modules are libraries of functions which are stored in their own plugin script file.  They can be included within any script, using the require statement.

require "module"

Modules are saved and stored in the plugin area, like any other plugin.  Although not essential, it is recommended that all modules should start with the following code:

if ... == nil then error('This is a Module') end
module(..., package.seeall)
--------------------------------

This code will throw an error, stating that the plugin is a module, if the module is run directly (instead of being called from another plugin). The use of modules makes it easy to re-use code.  However, it is a requirement of the Family Historian plugin store that each plugin can be run independently, and has no dependencies - i.e. makes no use of modules.  So if you have a plugin and you wish to submit it for inclusion in the plugin store, all module functions called by the plugin must be moved "inline", prior to submission.

For More Information

Lua links are provided on the Help menu of the Plugin Editor.  See also:  Lua Reference Manual 5.3.