Scribe as of v1.89-test11 has a basic scripting language for tools and filters.
The syntax of the language is loosely based on Javascript, but will likely have areas that aren't implemented,
and also areas that extend the language. Over time things will likely move more towards Javascript than
away. The language has been implemented entirely by myself in C++ and because I'm not a compiler engineer
it's probably going to be highly inefficient. However the implementation is open source as part of
LGI so if you feel the need to "fix" it then, well... use the source!
So on to the actual details of the language. The benifit of having a built in language as opposed to an
addon like Python or Ruby, is that it intergrates more closely with the existing object model as defined
by Scribe and Lgi. The core variable format in the scripting language is the
GVariant class (from LGI) that can contain
any common C type (string, int, double, void*) or some custom types, in particular a
GDom* which is basically a base class for all
the complex objects in Scribe. Things like, the application, an email, a contact etc. You can get a feel for
Scribe's objects by having a look at it's
DOM (Document
Object Model). It lists all the main objects and their fields. The language allows you to access an object's
properties via the dot operator, e.g. if you are given an email object in a variable called "m", then you
can access the subject of the email using the syntax:
m.Subject
Variables don't need to by defined, they get created when needed. For instance if you do this:
k = 10;
Then the language creates a variable called "k" to store the value "10" in. So assuming you understand the
general syntax of the Javascript language you could start putting together some simple scripts. Also
at this point there is no scope yet, just one global variable scope. This is likely to change later
however.
Filters
There are
2 places that you can start scripting with test11. The first is inside a filter, if you open or create a
filter and click on the script tab, you have a text editor where you can enter script commands. The script
is executed before any of the filters conditions have been evaluated, and there are some predefined variables
that you can use:
- Object::Scribe App
- Object::Mail Mail
- Obejct::Filter Filter
And there are also a number of methods that are specific to Scribe:
- GetFolder(folder_name)
- CreateSubFolder(parent_folder, child_name, child_type)
- MoveItem(dest_folder, thing)
- Print(string)
- Load(folder)
- MsgBox(parent, msg, title[, type])
- Delete(thing)
- NewList()
- NewHashTable()
An important thing to use inside a filter script is the TestConditions field. The filter object that gets
passed to the script in the predefined variable "Filter" is the filter object currently being evaluated,
and it has a field called "TestConditions" that evaluates the current email against the conditions defined
in the conditions tab. This allows you to use the graphical conditions UI and also script the actions that
get executed if the conditions match the filter. It also means that you don't have to use the conditions
if you don't want to. You can make up your own conditions if you want, or just execute the script against
every email by having no conditions.
A simple example filter script looks like this:
if (Filter.TestConditions)
{
Fd = GetFolder("/Inbox");
if (Fd)
{
Print("Got folder '" + Fd.Name + "'\n");
Child = CreateSubFolder(Fd, Mail.Subject, "Mail");
if (Child)
{
MoveItem(Child, Mail);
}
}
}
This moves email matching the filter's conditions into a sub-folder under the inbox, named after the subject
of the email. Creating new sub-folders as new email subjects arrive. The "Print" command outputs to the
scripting console, which you can view via Tools -> Debug -> Scripting Console.
Tools
The second place that scriting can be used (so far) in Scribe is the tools menu. If you create a sub-folder
under the place where Scribe.exe is installed called "Scripts" and save some scripts in that with the
extension ".script" then when you restart Scribe the scripts will appear under the Tools menu in the main
window. These are like little add-on programs that can do some function, usually on the contents of the
current folder. An example of what you can do is provided in my
blog post about the feature. Tool scripts
are a little different to filter scripts in that you have to define a "Main" function for anything to be
executed. e.g:
function Main(App) { }
With the body of the script inside the main function. You may define other helper functions in the same
file. And in future builds you'll be able to include other code via #include as well (but not yet). So
the application object is passed in via the "App" parameter. You can then retreive a folder object and
start scanning it to operate on objects. The tools scripts are only executed when you select the menu
item corrasponding to the script.
You'll need to keep the
DOM
handy and print out your variables on the way to help with debugging. There is no debugger (other than "Print")
yet but maybe one day I'll add one. It wouldn't be particularly difficult.
Future Expansion
In the future there will be a special "Events.script" that implements
a number of event hooks to add behaviour to Scribe. So don't use that as a filename while implementing tool
scripts.
Also I'm currently working on converting the C++ tools in the Tools menu to scripts. This requires that I expand
the types of variables you can use in the scripting language to include lists and hashtables.
Built In Methods
There are some functions that come built in, like a C lib:
int Strchr(string, char[, string_length])
Returns the position of 'char' in 'string' or -1 if 'string' doesn't contain 'char'. You may
optionally supply a max number of chars to search.
j = Strchr("Some String", "t");
Where 'j' would end up being '6'.
int Strcmp(string1, string2[, case_insensitive])
Returns a comparision of 'string1' and 'string2', where if the strings are the same, the return
value is '0'. You can optionally make it case insensitive by
seting the 'case_insensitive' flag.
int Substr(string, start[, length])
Returns a sub-segment of 'string', starting with the 'start'th character and running till the end
of the string or for 'length' characters.
HashTable NewHashTable()
Creates an empty hashtable. You should access elements in the hash table via array indexing:
t = NewHashTable();
t["foo"] = 56;
k = t["foo"];
To add or change an element, just assign something to a key. To delete something use the method
'DeleteElement'.
List NewList()
Creates an empty list. You should access elements in the hash table via array indexing:
t = NewList();
t[0] = 56;
k = t[0];
Also use the method 'DeleteElement' to remove a value. Assigning something to an index that doesn't
exist has the effect of adding that value to the end.
t[-1] = 234;
Appends the value '234' to the list.
void DeleteElement(container, element)
Removes an element from a container. Works on both hash tables and lists. For a hash table pass
the element's key (a string) and for a list pass the elements index (an integer).