app.context - Context API
Access Finder selection context and plugin directory information.
Not the same thing as the
contextargument your menu handler receives.
function MyPlugin:handleAction(context)
local files = context.selectedFiles -- property, snapshot of this click
local files = app.context.selectedFiles() -- function, queried right now
end
- The handler’s
contextargument is a snapshot taken when the menu was clicked, with justselectedFilesandcurrentDirectory. Prefer it inside handlers — it is guaranteed to match what the user had selected.- The
app.context.*global API queries live, at call time. Use it outside handlers: ingetMenuTitle, in background timers, in coroutines — places where nocontextargument exists.During a long-running task the user may change the selection, and the two will disagree. If you want “what was selected when they clicked”, use the argument.
Permission: L0 Safe — always available, no declaration needed
Methods
app.context.selectedFiles()
Gets the file paths selected in Finder.
Returns: table - Array of absolute paths
local files = app.context.selectedFiles()
for _, path in ipairs(files) do
app.log.info(path)
end
app.context.currentDirectory()
Gets the directory of the current Finder window.
Returns: string - Directory path
local dir = app.context.currentDirectory()
-- "/Users/username/Documents"
app.context.pluginsDirectory()
Gets the plugin installation directory.
Returns: string - Directory path
local dir = app.context.pluginsDirectory()
-- "~/Library/Group Containers/group.net.ymlab.iRightMenu.pro/Plugins"
app.context.pluginDirectory()
Gets the current plugin’s install directory.
Returns: string - Directory path
local dir = app.context.pluginDirectory()
-- "~/Library/Group Containers/.../Plugins/com.example.my-plugin"
-- Read a plugin resource file
local configPath = app.path.join(dir, "config.json")
Read-only. This holds content shipped inside the plugin bundle, and updating the plugin replaces the whole directory. Writing here means losing the data on the next update at best, and breaking signature verification at worst. Use
dataDirectory()below for anything you need to write.
app.context.dataDirectory()
Gets the plugin’s own writable directory (since 1.3.0). Caches, databases and state files belong here.
Returns: string - Directory path; returns nil, error on failure
The directory is created on first call. Because it lives outside the install directory:
- Updating the plugin does not wipe it — that is the whole point
- Uninstalling the plugin deletes it along with the plugin
- It is included in iCloud backup and restore when that is enabled
app.settings already stores its data in this directory, so you do not have to manage it.
local dataDir = app.context.dataDirectory()
-- "~/Library/Group Containers/group.net.ymlab.iRightMenu.pro/PluginData/com.example.my-plugin"
-- Keep a cache that survives updates
local cachePath = app.path.join(dataDir, "cache.json")
app.file.write(cachePath, app.json.stringify(myCache))
Failure only happens when there is no plugin context (for example when called outside the plugin lifecycle). Normal plugin code will not hit it, but handle it anyway:
local dataDir, err = app.context.dataDirectory()
if not dataDir then
app.log.error("Could not get data directory: " .. tostring(err))
return
end
Examples
Processing selected files
function MyPlugin:handleAction(context)
local files = app.context.selectedFiles()
local dir = app.context.currentDirectory()
app.log.info("Current directory: " .. dir)
app.log.info("Selected files: " .. #files)
for i, file in ipairs(files) do
app.log.info("File " .. i .. ": " .. file)
end
end
Reading plugin configuration
function MyPlugin:loadConfig()
local pluginDir = app.context.pluginDirectory()
local configPath = app.path.join(pluginDir, "config.json")
if app.path.exists(configPath) then
local content = app.file.read(configPath)
return app.json.parse(content)
end
return {}
end