It is hard and time-consuming to write everything from scratch. Usually, we rely on libraries for common tasks. The libraries themselves bring some dependencies, and so on. Thankfully, there is no need in figuring out the dependency graph and managing dependency versions manually – package managers do the boring work for us.
LuaRocks is the most commonly used package manager for Lua. It is also a repository of libraries for all occasions. Marta supports LuaRocks out-of-the-box.
In this tutorial, we will create a plugin that creates files with arbitrary names. We will use the uuid library for name generation.
Multi-file plugins
Single-file plugins does not support LuaRocks dependencies, so we need to create a multi-file plugin.
Create the plugin structure as in the snippet below. Declare a plugin and an action in init.lua
.
Plugins/
uuid/
init.lua
marta
Module
If you read the previous tutorials, you know that plugins are declared with a plugin { ... }
block, and actions – with an action { ... }
block. Well, this is only a part of truth.
Marta API comes in two modules: marta
contains core API functionality, and martax
provides utilities and helpers. We never used marta
directly as its contents is implicitly exposed in single-file plugins. The reason is simplicity: if should be as fast as possible to write a trivial plugin.
However, this is not always the desirable behavior for complex plugins: they may want to set global variables with the same name as some marta
member. So in multi-file plugins we need either to replace plugin { ... }
with marta.plugin { ... }
, or expose marta
members explicitly:
marta.plugin { ... }
marta.action { ... }
or
marta.expose()
plugin { ... }
action { ... }
You are free to choose the way you prefer. In this tutorials we will use marta.expose()
as it avoids code duplication.
Check if your multi-file plugin loads successfully. Fix issues if needed.
Downloading LuaRocks Dependencies
Marta supports LuaRocks dependency trees, but does not download dependencies itself. Instead, external libraries have to be bundled with the plugin. We use the luarocks
command-line utility to download them.
- Install LuaRocks. If you use Homebrew, the easiest way to install
luarocks
is to install thelua
package. - Open the Terminal, navigate to the plugin directory (
~/Library/Application Support/org.yanex.marta/Plugins/uuid
). - Run
luarocks install --tree rocks uuid
. This will download theuuid
library and all its dependencies (if any) to./rocks
.
The resulting tree (find . -type f
) should look like this:
./init.lua
./rocks/lib/luarocks/rocks-5.4/manifest
./rocks/lib/luarocks/rocks-5.4/uuid/0.3-1/rock_manifest
./rocks/lib/luarocks/rocks-5.4/uuid/0.3-1/uuid-0.3-1.rockspec
./rocks/lib/luarocks/rocks-5.4/uuid/0.3-1/doc/README.md
./rocks/share/lua/5.4/uuid.lua
While you can remove the ./rocks/lib/luarocks/rocks-5.4
directory, do not forget to include third-party library licenses if you plan to distribute the plugin.
Attaching LuaRocks Dependencies
Call marta.useRocks()
in the beginning of init.lua
to import LuaRocks dependencies. By default, useRocks()
will import the rocks
directory contents. You can provide a custom directory name, e.g. useRocks("dependencies")
.
Let’s add an action to check if the library is attached correctly:
marta.useRocks()
local uuid = require("uuid")
action {
id = "check",
name = "Check UUID",
apply = function()
martax.alert(uuid())
end
}
Now you can restart Marta and run your action. The alert with a random UUID should be displayed.
File Creation
Our action creates new files. So we need to check if the current file system is writable, and notify the user if it isn’t.
action {
id = "create.file",
name = "Create UUID file",
apply = function(context)
local parent = context.activePane.model.folder
if not parent then return end
if not parent.fileSystem:supports("writeAccess") then
martax.alert("Can not create a file.", "File system is read only.")
return
end
end
}
context.activePane.model.folder
returns aFile
for the current pane folder.martax.alert()
accepts up to four arguments:alert(message)
alert(message, informativeText)
alert(message, informativeText, buttons)
- For
buttons
you can pass a single name or a string array. alert()
returns an index of the pressed button.
- For
alert(message, informativeText, buttons, style)
style
can bewarning
,critical
orinformational
(default).
We need also a bit of code to actually create a file:
local file = parent:append(uuid())
local access = martax.access("rwxr--r--")
file:writeText("File content.", "create", access)
file.fileSystem:flush()
We could attach luaposix and call open()
, but it would only work for the local file system. Our approach is FS-agnostic.
The final flush()
call is not required. However, it instructs a file system to write pending data to disk immediately and flush the caches.
Here’s the final version of the plugin:
marta.expose()
marta.useRocks()
plugin {
id = "marta.example.deps",
name = "LuaRocks experiments",
apiVersion = "2.2"
}
local uuid = require("uuid")
action {
id = "check",
name = "Check UUID",
apply = function()
martax.alert(uuid())
end
}
action {
id = "create.file",
name = "Create UUID file",
apply = function(context)
local parent = context.activePane.model.folder
if not parent then return end
if not parent.fileSystem:supports("writeAccess") then
martax.alert("Can not create a file.", "File system is read only.")
return
end
local file = parent:append(uuid())
local access = martax.access("rwxr--r--")
file:writeText("File content.", "create", access)
file.fileSystem:flush()
end
}