Basic information
This page explains the basic concepts of the Marta API. Some of the ideas may seem trivial to you, especially if you have experience with different programming languages. However, reading the page will surely help you to dive into Marta plugin development.
Lua Distribution
Marta bundles Lua 5.4.7 from lua.org with a few customizations:
- NSLog is used instead of cout/cerr for
print
anderror
functions. This allows to see the output in the Console application. - Custom search paths are set so the plugin will not accidentally touch system-global Lua libraries. You are free to redefine paths to whatever you want.
- For single-file plugins
package.path
andpackage.cpath
are empty. - For complex plugins
package.path
isDIR/?.lua;DIR/?/init.lua
,package.cpath
isDIR/?.so
, whereDIR
is a plugin directory path.
- For single-file plugins
- You can not call
os.execute()
is it blocks the UI. Use martax.execute() instead.
Include search path: /Applications/Marta.app/Contents/Headers
.
Library search path: /Applications/Marta.app/Contents/Frameworks
.
Run Clang with the -llua
option to compile against Lua library.
Declaration Kinds
Marta API introduces several kinds of declarations. If you know some OOP language such as Java or Kotlin, this will be familiar to you.
- Modules contain all API declarations, including classes and top-level functions and values. In Lua, Marta API modules are visible as global variables. Currently, there are two modules:
marta
andmartax
. - Classes hold state and provide ways to access and/or modify it. Classes can contain other classes, methods, and properties.
- Enumerations is a set of named constants. Enumeration values can be used as flags (
OptionSet
) or used alone (Option
). - Properties are like variables. They contain some value and allow to get and, sometimes, modify it. API reference uses keywords
let
for immutable (read-only) properties andvar
for mutable (read-write) properties. - Functions are just ordinary functions. As in Lua, functions can return multiple values. Functions enclosed in a class are called methods. API reference uses the
fun
keyword for functions.
All methods are called with a colon syntax: obj:method()
. In Marta API there are no static methods.
Instantiable classes
If a class is marked as “instantiable”, you can create an instance of it in Lua and pass it to the API method.
The most obvious example is the action declaration. Normally, you define an action using the action()
function that accepts a single argument of a ActionDeclaration
type. Because the ActionDeclaration
class is instantiable, we can create a table and pass it:
action({
id = "id",
name = "Name",
apply = function(context) end
})
Lua allows to omit parentheses if the only argument type is a string literal, or a table constructor:
action {
id = "id",
name = "Name",
apply = function(context) end
}
Equatable Classes
If a class is marked as “equatable”, you can compare its instances using the ==
operator:
local folder = actionContext.activePane.model.folder
if folder then
print(folder.fileSystem.isLocal)
print(folder.fileSystem == localFileSystem)
end
Note that two comparisons above are not identical. There might be virtual file systems on top of local one, such as the file system used for the Analyze disk usage action.
Type Kinds
Marta API is strong-typed. If you pass a number value for a string-typed parameter, an error will occur. In some places, however, Marta API accepts values of several types (see union type below).
Here are the type kinds used in the API reference:
- Simple type: a class name with optional type arguments. Examples:
Int
,Array<String>
. A simple type does not acceptnil
values. - Nullable type: any type with a question mark at the end. Examples:
Int?
,Array<String>?
(nullable array of not-null items),Array<String?>
(not-null array of nullable items). - Union type: a cortege or possible types, e.g.
[String | Int]
(accepts a string or an integer),[String | Array<String>
] (accepts a string or a string array). Union type can be empty ([]
) – in some languages it is called a ‘void’ or a ‘unit’ type. - Function type: accepts functions with the specified argument and return value types. E.g.,
(String, Int) -> String
denotes a function that gets a string and an integer, and returns an another string. - Vararg type: synthetic type allowed only in function parameter type position. Accepts zero or more values of the same type. E.g.,
String?...
accepts an arbitrary number ofString?
values.
You do not need to use type annotations in Lua code, just pass values of correct types to API functions.
Built-in Types
There are several built-in types:
Any
– any type. In some programming languages it is called a variant type.Any
, however, can not hold anil
value (Any?
can).Int
– a 64-bit integer type (0
,5
,-1000
).Float
– a 64-bit float type (0.2
,0.333
).Number
– essentially,[Int | Float]
.String
– a string type. As Lua does not care about the contents of strings, in some places theString
type is used as a chunk of bytes.Boolean
– boolean type (true
,false
).Array<T>
– array type, holding elements ofT
type.Array<String>
holds only strings,Array<Any>
can hold any values.Dictionary<Key, Value>
– unsorted dictionary/map type.Dictionary<String, Int>
holds integer values accessible by string keys.Option<Enum>
– a single enumeration value. Represented as a string. For specifying aTabPosition
, use"left"
and"right"
.OptionSet<Enum>
– zero, one or multiple enumeration values. Represented as an array of strings, or a string in case of exactly one value. For specifying aConfigurationKeyConstraint
, use"array"
(one value),{"int", "boolean"}
(multiple values), or{}
(zero values).
Errors
Marta API functions typically do not throw errors. Instead, they return multiple values, first of which is an Error
class instance.
For instance, here is how you can check if the File.canonicalize()
call finished successfully:
local err, canonical = file:canonicalize()
if err then
martax.alert("An error occurred: " .. err.description)
else
martax.alert("Original path: " .. canonical.path)
end