Flying Meat
FS • VoodooPad: Script Plugins
Make sure to check out the new wiki located at http://flyingmeat.com/wikka/. This one will eventually be retired.

Script Plugins

(For a quick start tutorial on writing a script plugin, visit the "Hello World in Lua" page. For a bunch of examples, see Lua Plugin Snippets)

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:

  • two dashes (--) mark the beginning of a comment, so that's not run by Lua.
  • methods are called with ":", so when we do "document:fileName()" we are calling the fileName method of the document. (In objective-c this would be written as [document fileName] , and in java or python, it would be document.fileName())
  • vpconsole() is a special method that is build into VoodooPad, and not a standard part of the Lua language.

What else can you call on windowController or document? (And the technical names are "VPPluginWindowController" and "VPPluginDocument")

VPPluginWindowController:

  • :textView() returns the current NSTextView
  • :window() returns the current NSWindow
  • :setStatus(string) will send a string to the little status field at the bottom of the window.
  • :key() will return the "key" for the current page name
  • :document() will return an object that represents the current document.

The document that is returned by windowController:document() is known as "VPPluginDocument"

VPPluginDocument:

  • :countOfPages() returns the number of pages in a document.
  • :pageForKey(string) returns an object that represents the page for the given key
  • :keys() returns a NSArray of all the keys in the document
  • :fileName() returns the (posix) path of the document
  • :synchronizeDocs() tells the document to commit all the data in the windows.
  • :openPageWithTitle(string) open a page with the given title- if the page does not exist it is created.
  • :createNewPageWithName(string) makes a new page, and returns it as an object.

VPData is the class that represents the contents on a page, plus other attributes.

VPData

  • :modifiedDate() returns a NSDate representing the last time it was changed
  • :createdDate() returns a NSDate representing the time it was created
  • :displayName() returns a (possibly) mixed case name of the page
  • :key() returns the "key" of the page, which is always lowercase.
  • :dataAsAttributedString() returns the contents of the page as a NSMutableAttributedString
  • :setDataAsAttributedString(attributedString) sets the content of the page to the value passed in as a NSAttributedString.
  • :isEncrypted() returns a boolean to let you know if the page is encrypted or not.
  • :uuid() returns a Universally Unique Identifier (UUID) for the page.
  • :type() returns the type of the page, such as VPPageType, VPAliasType, VPURLType, VPFileAliasType, and VPInjectedFileType.
  • :metaValueForKey() returns the meta value for the given key, or null if it isn't there.
  • :metaValues() returns a NSDictionary of the meta values and keys for the page.

For a full list of methods, check out VPPlugin.h which you can grab from the Plugin Development page.

Extra functions

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:
posix.access, chdir, chmod, chown, ctermid, dir, errno, exec, files, fork, getcwd, getenv, getgroup, getlogin, getpasswd, getprocessid, kill, link, mkdir, mkfifo, pathconf, putenv, readlink, rmdir, setgid, setuid, sleep, stat, symlink, sysconf, times, ttyname, umask, uname, unlink, utime, wait, mkstemp, setenv, unsetenv

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

Type Conversions

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:

page:dataAsAttributedString():mutableString():setString("hi")

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()
VPPageType, VPAliasType, VPURLType, VPFileAliasType, VPInjectedFileType

And here are some constant meta names you might find useful.:
VPFileWrapperMetaName, VPUTIMetaName

Extra data names:
VPIconExtraDataName (used for embed applications, to store the icon in).

Printing out stuff for debugging or whatever:
vpconsole("hello!") (used for debugging or whatever you'd like to use it for).

Other topics: