Back to Noctalia

Runtime API

v5-plugins-development-runtime-api.md

latest9.4 KB
Original Source

Runtime API

Most noctalia.* functions are synchronous. Methods that start subprocesses, HTTP requests, or downloads return a boolean immediately to say whether the work was accepted, then deliver results to a callback.

Runtime and settings

Section titled “Runtime and settings”

MethodReturnsDescription
noctalia.setUpdateInterval(ms)nothingSets how often this entry’s update() function runs. Values below 16 ms are clamped.
noctalia.log(msg)nothingWrites a message to Noctalia’s log with this plugin’s script context.
noctalia.isDarkMode()boolReturns whether the active theme mode is dark.
noctalia.focusedOutputName()string or nilReturns the focused output’s connector name, falling back to the preferred interactive output when needed.
noctalia.getConfig(key)setting value or nilReads a declared plugin or entry setting. Undeclared keys log a warning and return nil.

Outputs, wallpaper, and panels

Section titled “Outputs, wallpaper, and panels”

MethodReturnsDescription
noctalia.outputs()arrayReturns connected outputs as { name, description, width, height, x, y, scale, focused } tables.
noctalia.setWallpaperEnabled(connector, enabled)nothingEnables or disables Noctalia’s own wallpaper surface on one output. This is runtime-only and clears on restart.
noctalia.setWallpaper(path)nothingApplies and persists a wallpaper image on every output.
noctalia.setWallpaper(connector, path)nothingApplies and persists a wallpaper image on one output.
noctalia.wallpaperDirectory()string or nilReturns the resolved wallpaper folder for the current theme mode, or nil when unset.
noctalia.togglePanel("author/plugin:panel")nothingOpens or closes a plugin panel by full entry id.

outputs() uses the DRM connector name in name; that is the same connector string expected by compositor tools such as mpvpaper. A [[service]] may also define onOutputsChanged(), which Noctalia calls whenever the output set or geometry changes.

setWallpaper(path) behaves like the built-in wallpaper panel. Prefer it and togglePanel(id) over shelling out to the noctalia CLI from a plugin; the API path runs in-process and avoids an IPC round trip.

Time, notifications, and clipboard

Section titled “Time, notifications, and clipboard”

MethodReturnsDescription
noctalia.formatTime(pattern)stringFormats the current local time with the same tokens as Noctalia clock and filename settings.
noctalia.formatTime(pattern, unixSeconds)stringFormats a specific Unix timestamp in local time.
noctalia.notify(title, body)nothingShows an informational notification. body is optional.
noctalia.notifyError(title, body)nothingShows an error notification. body is optional.
noctalia.copyToClipboard(text, mime)boolCopies text to the clipboard with an explicit MIME type, for example "text/plain" or "text/uri-list".
noctalia.clipboardText()string or nilLatest text clipboard content (nil when empty or non-text).

%s in formatTime() expands to Unix epoch seconds.

Subprocesses and environment

Section titled “Subprocesses and environment”

MethodReturnsDescription
noctalia.runAsync(cmd)boolStarts a detached shell command and returns whether it launched. No output is captured.
noctalia.runAsync(cmd, cb)boolRuns a shell command with output capture, then calls cb(result).
noctalia.runStream(cmd, onLine)boolRuns a long-lived shell command and calls onLine(line) for each stdout line.
noctalia.runInTerminal(cmd)boolStarts a shell command in the configured terminal.
noctalia.commandExists(name)boolChecks whether an executable is available on PATH.
noctalia.processMatches(cb, ...needles)boolAsynchronously checks running processes; cb(matched) receives a boolean.
noctalia.flatpakAppInstalled(id)boolChecks whether a Flatpak app id is installed.
noctalia.portalAvailable()boolChecks whether the desktop portal is available.
noctalia.getenv(name)string or nilReads an environment variable.
noctalia.expandPath(path)stringExpands a path such as ~/Pictures to an absolute user path.

runAsync(cmd, cb) calls cb(result) once with:

{ exitCode = 0, stdout = "...", stderr = "...", timedOut = false, stdoutTruncated = false, stderrTruncated = false,}

runStream() is meant for long-running processes. The runtime terminates active streams when the script reloads, the entry is removed, or Noctalia stops the plugin.

Filesystem

Section titled “Filesystem”

MethodReturnsDescription
noctalia.readFile(path)string, or nil, errReads a file as bytes.
noctalia.writeFile(path, content)bool, optional errorWrites a file, replacing existing contents.
noctalia.mkdirAll(path)bool, optional errorCreates a directory and any missing parents (an existing directory is success).
noctalia.removeFile(path)bool, optional errorDeletes a file. Refuses directories.
noctalia.renameFile(from, to)bool, optional errorRenames or moves a file.
noctalia.fileExists(path)boolChecks whether a path exists.
noctalia.fileInfo(path)table, or nil, err{ size, mtime, isDir }, size in bytes, mtime in unix seconds.
noctalia.listDir(path)array, or nil, errLists filenames in a directory.
noctalia.pluginDir()string or nilReturns this plugin’s runtime directory.
noctalia.loadFont(path)string, or nil, errRegisters a font file and returns its family name.

Filesystem paths resolve as follows: ~ expands to $HOME, absolute paths are used as-is, and relative paths resolve against the plugin’s own directory. Plugins are trusted code, so these helpers are not sandboxed.

HTTP and downloads

Section titled “HTTP and downloads”

MethodReturnsDescription
noctalia.http(request, cb)boolStarts an async HTTP request and calls cb(response).
noctalia.download(url, dest, cb)boolDownloads a URL to a file and calls cb(ok) with a boolean.

request is a table:

{ url = "https://example.com", method = "GET", body = "", headers = { "Accept: application/json" }, basic_username = "user", basic_password = "pass", follow_redirects = false,}

Only url is required. http() calls cb(response) once with:

{ ok = true, status = 200, body = "...",}

download() resolves dest like other filesystem paths, so a relative destination writes inside the plugin directory.

Translations and data helpers

Section titled “Translations and data helpers”

MethodReturnsDescription
noctalia.tr(key)stringLooks up a translated string from translations/<lang>.json, falling back to the key.
noctalia.tr(key, subst)stringLooks up a string and replaces {name} placeholders from a table.
noctalia.trp(key, count)stringPlural translation helper; prefers <key>.one or <key>.other, then the bare key.
noctalia.trp(key, count, subst)stringPlural translation helper with substitutions. count is also available as {count}.
noctalia.json.decode(str)value, or nil, errParses JSON into Luau values.
noctalia.json.encode(value)string, or nil, errEncodes a Luau value as compact JSON.
noctalia.json.encode(value, true)string, or nil, errEncodes a Luau value as pretty JSON.
noctalia.string.trim(str)stringTrims leading and trailing whitespace.
noctalia.string.urlEncode(str)stringPercent-encodes a string for use in URLs.
noctalia.string.urlDecode(str)stringDecodes percent-encoded URL text.
noctalia.fuzzyScore(pattern, text)number or nilScores a fuzzy match with Noctalia’s native matcher. nil means no match.

json.* and string.* are synchronous pure transforms. Prefer string.urlEncode() when building query strings for http() or download().

Sharing state across entries

Section titled “Sharing state across entries”

Entries are isolated VMs - they don’t share Lua memory. Instead they exchange plain values through a per-plugin state channel:

MethodReturnsDescription
noctalia.state.set(key, value)nothingPublishes a plain value for other entries in the same plugin.
noctalia.state.get(key)value or nilReads the latest value for a key.
noctalia.state.watch(key, fn)nothingCalls fn(value) whenever the key changes.

Values are copied across entries, so they must be plain data - strings, numbers, booleans, and tables of those (not functions). A typical pattern is a [[service]] publishing data that the widget and shortcut watch.

-- ticker.luau (service)local n = 0noctalia.setUpdateInterval(1000)function update() n = n + 1 noctalia.state.set("count", n)end
-- widget.luaunoctalia.state.watch("count", function(value) barWidget.setText(tostring(value))end)