|FS • VoodooPad: Script Plugins|
Script Plugins are extensions to VoodooPad to add extra functionality. To put it simply, they are text files written in the Lua scripting language and executed inside VoodooPad. These scripts have access to certain parts of VoodooPad and may manipulate and create pages, carry out specific tasks, or just insert some text into a page.
The scripts are placed inside the ~/Library/Application Support/VoodooPad/Script PlugIns folder, with a file name that has an extension of .lua . You can also write and test your scripts within a VoodooPad page, and then just select the "Plugin->Lua->Save Page as Lua Plugin…" for a quick and easy way of developing the plugin.
When run, a script plugin is given 2 global variables named "windowController" and "document". "windowController" basically represents the window that the script is running in (and the current page), while "document" represents the whole Voodoopad document. You can then call methods on these obects to perform certain tasks. Here's an example:
Copy and paste that script into an empty VoodooPad page, and select the "Plugin->Lua->Run Page as Lua Script" menu item. You will see a little window pop up and the path of the current document print out in it.
There are a couple of things to point out here:
What else can you call on windowController or document? (And the technical names are "VPPluginWindowController" and "VPPluginDocument")
The document that is returned by windowController:document() is known as "VPPluginDocument"
VPData is the class that represents the contents on a page, plus other attributes.
For a full list of methods, check out VPPlugin.h which you can grab from the Plugin Development page.
As already mentioned, "vpconsole(string)" can be used to print out text to a little window in VoodooPad. Another function that's built in is "objc.values(objc-array)", where you pass in a NSArray and get back an iterator. This comes in pretty handy when you want to cycle through all the pages in a document:
Another extra function that needs to be mentioned is string.replace, and you use it like so:
This will take the string "VoodooPad, search for any occurrences of "Voo" and replace it with "Foo", giving us the string "FoodooPad".
An lastly, VoodooPad comes with a bunch of extra functions in the posix package:
Where do errors go?
Errors are printed out to Console.app, located in the Utilities folder. So if you have having problems running your script then it's likely that you're getting errors and you should check there. As well, any calls to print() appear in Console.app
Lua and VoodooPad talk to each other via a "bridge". Since VoodooPad is written in Objective-C (objc) and your scripts are written in Lua, a little bit of trickery has to happen behind the scenes to make things talk to each other. For instance, NSStrings in objc are converted to Lua strings, and ints, floats, doubles, longs, etc are translated into Lua numbers (Lua only has a single number type). If the bridge can't figure out how to convert an objc object into a Lua type then it is converted into a Lua table.
However, there are times when you don't want the bridge to convert a value for you. One such instance is for NSMutableString. Take this line of code:
Well, that's not going to work. When we call mutableString(), the bridge is going to convert that to a Lua string, and then when we try and add text to that object via the appendString() call Lua is going to throw an error. What we want is for the bridge to not convert the NSMutableString into a Lua string, and we do that by changing our call from attributedString:mutableString() to attributedString:objc_mutableString(). This tells the bridge to not convert the value to a Lua type, and we can then play with the value returned as a regular Objective-C type.
VoodooPad Lua Constants
Pages in a VoodooPad document have a type associated with them. This lets the system distinguish between regular pages, pdf's, urls, etc. For example all the regular pages you create are of type "VPPageType". When you write triggers and you want to play with the contents of the page, you need to make sure it's a page type first. Use these values to compare what type page is combined with a call to page:type()
And here are some constant meta names you might find useful.:
Extra data names:
Printing out stuff for debugging or whatever: