diff options
Diffstat (limited to 'noctalia.d.luau')
| -rw-r--r-- | noctalia.d.luau | 796 |
1 files changed, 796 insertions, 0 deletions
diff --git a/noctalia.d.luau b/noctalia.d.luau new file mode 100644 index 0000000..5ec34a0 --- /dev/null +++ b/noctalia.d.luau @@ -0,0 +1,796 @@ +--!strict +-- Type definitions for the Noctalia plugin API (plugin_api 32). +-- +-- luau-lsp *definition file*: it declares the host-injected globals (noctalia.*, +-- barWidget.*, shortcut.*, launcher.*, desktopWidget.*, panel.*, ui.*) so authors +-- get autocomplete and typo diagnostics. Annotations are a runtime no-op. +-- See README.md ("Editor setup") for pointing luau-lsp at this file. +-- +-- Prop tables are exhaustive: the host logs and skips any prop not listed here. +-- "API n" marks the plugin_api level a member requires. + +-- ── Shared value shapes ────────────────────────────────────────────────────── + +export type CommandResult = { + exitCode: number, + stdout: string, + stderr: string, + timedOut: boolean, + stdoutTruncated: boolean, + stderrTruncated: boolean, +} + +export type HttpRequest = { + url: string, + method: string?, -- defaults to "GET" + headers: { string }?, -- each entry is a full "Header: value" line + body: string?, + basic_username: string?, + basic_password: string?, + follow_redirects: boolean?, + -- Disables origin certificate and hostname verification; trusted endpoints only. API 7. + allow_insecure_tls: boolean?, +} + +export type HttpResponse = { + ok: boolean, -- transport success (not the HTTP status) + status: number, + body: string, +} + +export type HttpStreamResult = { + ok: boolean, -- transport success (not the HTTP status) + status: number, -- HTTP status code (0 when ok is false) +} + +export type HttpStreamHandle = { + stop: () -> (), -- cancel the stream; idempotent, suppresses onClose +} + +export type Output = { + name: string, + description: string, + width: number, + height: number, + x: number, + y: number, + scale: number, + focused: boolean, +} + +export type WallpaperMask = { + path: string, + wallpaperPath: string, +} + +export type PanelContextMenuAction = { + kind: "item"?, -- may be omitted for action rows + id: string, + label: string, + enabled: boolean?, -- defaults to true +} + +export type PanelContextMenuHeader = { + kind: "header", + label: string, +} + +export type PanelContextMenuSeparator = { + kind: "separator", +} + +export type PanelContextMenuItem = PanelContextMenuAction | PanelContextMenuHeader | PanelContextMenuSeparator + +export type PanelContextMenuRequest = { + items: { PanelContextMenuItem }, + onActivate: string, + context: (string | number | boolean)?, + maxVisible: number?, -- defaults to 12, valid range 1..30 +} + +-- A tooltip row: { key, value } or the positional array form { key, value }. +export type TooltipRow = { key: string?, value: string? } + +export type LauncherResult = { + id: string?, + title: string?, + subtitle: string?, + glyph: string?, + icon: string?, + badge: string?, + category: string?, -- must match a [[launcher_provider.category]] label + presentation: string?, + query: string?, -- on activate, set this provider's query to this sub-query (host adds the prefix) + score: number?, +} + +export type SystemStats = { + sampledAtMs: number?, -- epoch ms of the latest aggregate sample (API 16) + -- Absent sensors are nil rather than 0, so "no probe" is distinguishable from "idle". + cpu: { usagePercent: number, tempC: number?, freqMhz: number?, maxFreqMhz: number? }, + ram: { usagePercent: number, usedMb: number, totalMb: number }, + swap: { usedMb: number, totalMb: number }, + gpu: { tempC: number?, usagePercent: number?, vramUsedBytes: number?, vramTotalBytes: number? }, + net: { + rxBytesPerSec: number, + txBytesPerSec: number, + interfaces: { [string]: { rxBytesPerSec: number, txBytesPerSec: number } }, + }, + loadAvg: { number }, -- 1, 5 and 15 minute averages +} + +export type DiskMount = { + path: string, + source: string, + filesystem: string, +} + +export type DiskStats = { + usagePercent: number, + totalBytes: number, + freeBytes: number, + availableBytes: number, +} + +-- Noctalia provides Luau's built-in `require(path: string): any` for explicit relative `.luau` modules (API 22). + +-- ── noctalia.* - shared across every entry type ────────────────────────────── + +export type NoctaliaState = { + set: (key: string, value: any) -> (), + get: (key: string) -> any, + watch: (key: string, callback: (value: any) -> ()) -> (), +} + +export type NoctaliaJson = { + decode: (str: string) -> (any, string?), -- value, or (nil, err) + encode: (value: any, pretty: boolean?) -> (string?, string?), +} + +export type NoctaliaString = { + trim: (s: string) -> string, + urlEncode: (s: string) -> string, + urlDecode: (s: string) -> string, +} + +-- API 20. Paths resolve like the filesystem APIs. `load` returning true means the +-- request was accepted, not that decoding succeeded; at most eight loads may be +-- pending. Names and pending callbacks are released when this runtime reloads. +export type NoctaliaSound = { + load: (name: string, path: string, onLoaded: (ok: boolean, error: string?) -> ()) -> boolean, + play: (name: string) -> (), +} + +export type Noctalia = { + log: (msg: string) -> (), + + -- Subprocess. A string runs through /bin/sh -c; an argv table (API 24) executes + -- the program directly. With no callback, runAsync is a detached fire-and-forget + -- launch; timeoutMs is clamped to [50, 60000]. + runAsync: (cmdOrArgv: string | { string }, onResult: ((result: CommandResult) -> ())?, timeoutMs: number?) -> boolean, + runStream: (cmd: string, onLine: (line: string) -> ()) -> boolean, + runInTerminal: (cmd: string) -> boolean, + commandExists: (name: string) -> boolean, + -- onResult(true) iff a running process command line matches all needles. + processMatches: (onResult: (matched: boolean) -> (), ...string) -> boolean, + flatpakAppInstalled: (appId: string) -> boolean, + portalAvailable: () -> boolean, + + -- Outputs / display. + focusedOutputName: () -> string?, + outputs: () -> { Output }, + isDarkMode: () -> boolean, + -- Active theme palette color for a role ("primary", "surface", "on_surface", ...) as + -- "#RRGGBB"; nil for unknown role names. API 31. + getColor: (role: string) -> string?, + -- Effective shell config by dotted path ("bar.main.position", "shell.offline_mode"). + -- Array indices are zero-based ("bar.order[0]"); nil when the path matches nothing. API 26. + getSetting: (path: string) -> any, + + -- Resolves an app id (desktop-entry id / StartupWMClass), or a raw icon name when no + -- entry matches, to an icon path for ui.image. nil when nothing resolves. + appIconPath: (appIdOrIconName: string, sizePx: number?) -> string?, + + -- Wallpaper. setWallpaper(path) targets all outputs; setWallpaper(connector, path) targets one. + setWallpaperEnabled: (connector: string, enabled: boolean) -> (), + setWallpaper: (connectorOrPath: string, path: string?) -> (), + wallpaperDirectory: () -> string?, + -- Source-aligned output mask: 0 keeps desktop widgets visible, 255 erases them to + -- reveal the wallpaper. API 25. + wallpaperPath: (connector: string) -> string?, + setWallpaperMask: (connector: string, mask: WallpaperMask?) -> (), + + togglePanel: (panelId: string) -> (), -- "author/plugin:panel" + -- Opens the settings window at this plugin's settings; no-op without settings. API 15. + openSettings: () -> (), + -- The callback receives the canonical #RRGGBB color, or nil when cancelled. + openColorPicker: (initialColor: string, onClose: (color: string?) -> ()) -> boolean, + + notify: (title: string, body: string?) -> (), + notifyError: (title: string, body: string?) -> (), + + copyToClipboard: (text: string, mimeType: string) -> boolean, + clipboardText: () -> string?, -- nil when empty or non-text + getenv: (name: string) -> string?, + expandPath: (path: string) -> string, + formatTime: (pattern: string, unixSeconds: number?, timezone: string?) -> string, + timeFormat: () -> string, -- [shell].time_format, e.g. "{:%H:%M}" (API 19) + dateFormat: () -> string, -- [shell].date_format, e.g. "%A, %x" (API 19) + -- True when `name` is empty (system local) or names a zone in the active database. API 19. + isValidTimezone: (name: string) -> boolean, + nowMs: () -> number, -- the only sub-second clock; formatTime and os.time are whole-second (API 12) + + -- System monitor. nil when [system.monitor] is disabled. The first systemStats call + -- opts this plugin into its optional CPU/GPU probes. API 12. + systemStats: () -> SystemStats?, + -- Per-core usage in /proc/stat order; nil until the first delta lands. Offline cores are + -- absent, so length can change and an index is not a core id. + cpuCores: () -> { number }?, + -- Physical block-device filesystems, deduped by source, sorted by mount path. API 16. + diskMounts: () -> { DiskMount }, + -- statvfs snapshot for an absolute or ~/ path; the path is retained for sampling. API 16. + diskStats: (path: string) -> DiskStats?, + + setUpdateInterval: (ms: number) -> (), -- update() tick rate, clamped to >= 16ms + + -- Filesystem (paths resolve ~ -> $HOME, absolute verbatim, else plugin-relative). + readFile: (path: string) -> (string?, string?), -- contents, or (nil, err) + readFileAsync: (path: string, onResult: (contents: string?, err: string?) -> ()) -> boolean, -- API 23 + writeFile: (path: string, contents: string) -> (boolean, string?), + mkdirAll: (path: string) -> (boolean, string?), -- like mkdir -p; existing dir is success + removeFile: (path: string) -> (boolean, string?), -- files only, refuses directories + renameFile: (from: string, to: string) -> (boolean, string?), + fileExists: (path: string) -> boolean, + fileInfo: (path: string) -> ({ size: number, mtime: number, isDir: boolean }?, string?), + listDir: (path: string) -> ({ string }?, string?), + pluginDir: () -> string?, + -- Per-plugin persistent data dir, created on demand; survives updates, honors + -- NOCTALIA_STATE_HOME. Use for durable data (state is in-memory only). + pluginDataDir: () -> (string?, string?), + + -- Registers a font file so its family works in setFont / a label's fontFamily. + -- Returns the family name, or (nil, err); visible to every surface once loaded. + loadFont: (path: string) -> (string?, string?), + + -- Translation against the plugin's own translations/<lang>.json. + tr: (key: string, subst: { [string]: string | number | boolean }?) -> string, + trp: (key: string, count: number, subst: { [string]: string | number | boolean }?) -> string, + + -- HTTP (honors shell.offline_mode; download dest resolves like readFile). + http: (req: HttpRequest, onResponse: (response: HttpResponse) -> ()) -> boolean, + -- Long-lived stream (e.g. SSE). onLine fires per line (CR trimmed); onClose fires once + -- unless stopped through the handle. Non-2xx bodies stream to onLine and the status + -- arrives in onClose. Cancelled on script reload; nil when it could not start. API 4. + httpStream: ( + req: HttpRequest, + onLine: (line: string) -> (), + onClose: (result: HttpStreamResult) -> () + ) -> HttpStreamHandle?, + download: (url: string, destPath: string, onDone: (success: boolean) -> ()) -> boolean, + + fuzzyScore: (pattern: string, text: string) -> number?, -- nil if no match + + getConfig: (key: string) -> any, -- string | number | boolean | {string} | {[string]: string} | nil + + state: NoctaliaState, + sound: NoctaliaSound, + json: NoctaliaJson, + string: NoctaliaString, +} + +declare noctalia: Noctalia + +-- ── ui.* - declarative control tree (bar widgets, desktop widgets, panels) ─── + +-- One node of a ui.* tree. +export type UiNode = { + type: string, + props: { [string]: any }, + children: { UiNode }, +} + +-- A palette role ("primary", "on_surface"), a role with alpha ("primary/0.6", +-- resolved live against the palette), or a hex value ("#rrggbb" / "#rrggbbaa"). +export type UiColor = string + +-- A callback prop takes the name of a plugin global, or a function (API 9) that is +-- render-scoped: re-rendering replaces it, and an event on a node the current tree no +-- longer contains does nothing. An empty name counts as unset. Every argument arrives +-- as a string, for named handlers and closures alike. +export type UiClickHandler = string | (() -> ()) +-- state is "true" on enter and "false" on leave; key is the node's `key` ("" when unset). +-- Only the innermost hovered node reports, and every "true" is matched by a "false". +export type UiHoverHandler = string | ((state: string, key: string) -> ()) +export type UiChangeHandler = string | ((value: string) -> ()) +export type UiSelectHandler = string | ((index: string, text: string) -> ()) +export type UiScrollHandler = string | ((offset: string, maxOffset: string) -> ()) +-- Pointer position normalized to the graph's own box, "0.0000".."1.0000", 0,0 top-left. +export type UiPointerHandler = string | ((normX: string, normY: string) -> ()) +export type UiDropHandler = string | ((payload: string, value: string) -> ()) + +-- Common to every node. `opacity` is a group opacity: it fades children too, so use a +-- translucent `fill` for a translucent background. `key` gives a child stable identity +-- across renders (keeps input text, hover state, and closures aligned with their row). +export type UiCommonProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, +} + +-- ui.column / ui.row. Children stretch across the cross axis unless `align` says otherwise. +-- onClick makes the whole container a click target and joins the tab order (Enter/Space); +-- a container with only onHover passes clicks through to an enclosing target. +export type UiFlexProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + gap: number?, + padding: number?, + paddingH: number?, + paddingV: number?, + align: ("start" | "center" | "end" | "stretch")?, + justify: ("start" | "center" | "end" | "space_between")?, + fill: UiColor?, + radius: number?, + border: UiColor?, + borderWidth: number?, + minWidth: number?, + minHeight: number?, + onClick: UiClickHandler?, + onHover: UiHoverHandler?, + tooltip: string?, -- shown on hover (API 32); wraps the container in a hover target; cleared when dropped +} + +-- ui.box. Leaf node: it takes no children (use a column/row for content). +export type UiBoxProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + fill: UiColor?, + radius: number?, + border: UiColor?, + borderWidth: number?, + softness: number?, + onClick: UiClickHandler?, + onHover: UiHoverHandler?, + tooltip: string?, -- shown on hover (API 32); wraps the box in a hover target; cleared when dropped +} + +-- ui.label. Unset text props inherit the host defaults (in a bar, the bar's or widget's +-- font_family/font_weight and scale). fontFamily needs noctalia.loadFont first. +-- baseline "pictographic" centers art/icon fonts anchored at the ink top. +export type UiLabelProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + text: string?, + fontSize: number?, + color: UiColor?, + fontWeight: ("thin" | "light" | "normal" | "medium" | "semibold" | "bold" | "heavy")?, + fontFamily: string?, + baseline: ("text" | "textFixedHeight" | "inkCentered" | "pictographic")?, + maxWidth: number?, + maxLines: number?, + textAlign: ("start" | "center" | "end")?, +} + +-- ui.markdown. Read-only block; re-parsed only when text or the surface scale changes. API 21. +export type UiMarkdownProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + text: string?, +} + +-- ui.glyph. `name` is a Tabler/Nerd-Font glyph; `size` is a glyph size in px. +export type UiGlyphProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + name: string?, + size: number?, + color: UiColor?, +} + +-- ui.image. Local files only: download remote previews first, then pass the saved path. +export type UiImageProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + path: string?, -- plugin-relative, ~, or absolute + radius: number?, + fit: ("contain" | "cover" | "stretch")?, + border: UiColor?, + borderWidth: number?, + onClick: UiClickHandler?, + onHover: UiHoverHandler?, + tooltip: string?, -- shown on hover (API 32); wraps the image in a hover target; cleared when dropped +} + +export type UiSeparatorProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + thickness: number?, + color: UiColor?, + spacing: number?, + orientation: ("auto" | "horizontal" | "vertical")?, +} + +-- ui.spacer: flexible filler, sized with flexGrow. +export type UiSpacerProps = UiCommonProps + +export type UiProgressProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + progress: number?, -- 0..1 + fill: UiColor?, + track: UiColor?, + radius: number?, +} + +-- ui.button. Setting only `glyph` clears a retained button's previous text. `tooltip` +-- shows in bar widgets and panels, never on desktop widgets; dropping it clears it. +-- In bar widgets a button hugs its content unless sized with width/height/controlSize. +export type UiButtonProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + text: string?, + glyph: string?, + fontSize: number?, + glyphSize: number?, + variant: ("default" | "primary" | "secondary" | "destructive" | "outline" | "ghost")?, + contentAlign: ("start" | "center" | "end")?, + controlSize: ("sm" | "md" | "lg")?, -- 32 / 38 / 44px tiers; `height` wins when both are set + tooltip: string?, + enabled: boolean?, + selected: boolean?, + onClick: UiClickHandler?, + onRightClick: UiClickHandler?, -- the only place panel.openContextMenu may be called + onHover: UiHoverHandler?, +} + +-- ui.graph. Takes no clicks. The pointer callbacks (API 29) are coalesced on one shared +-- stream, so the newest event wins and a leave never arrives ahead of a position it +-- followed. Every entered graph reports its leave, including when the graph is dropped or +-- rewired - but that teardown leave only reaches a *named* handler, since a closure from +-- the render that dropped the graph is already superseded. +export type UiGraphProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + values: { number }?, -- 0..1, clamped + values2: { number }?, + color: UiColor?, + color2: UiColor?, + lineWidth: number?, + fillOpacity: number?, + onPointerMove: UiPointerHandler?, + onPointerLeave: UiClickHandler?, +} + +-- ui.input (panels only; skipped with a warning in the bar). Uncontrolled: `value` seeds +-- the field once, then the host owns the text - keep a stable `key` so edits survive a +-- re-render, and read them through onChange/onSubmit. `focus` grabs the keyboard when the +-- control is *created*, never on a later render; a fresh `key` focuses again. +-- multiline and password are mutually exclusive; multiline submits on Ctrl+Enter, or on +-- Enter with submitOnEnter (Shift+Enter then inserts the newline). +export type UiInputProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + value: string?, + placeholder: string?, + fontSize: number?, + controlSize: ("sm" | "md" | "lg")?, + password: boolean?, + multiline: boolean?, + submitOnEnter: boolean?, -- API 21 + frameVisible: boolean?, -- false hides the native background/border, keeps editing (API 27) + focus: boolean?, + enabled: boolean?, + onChange: UiChangeHandler?, + onSubmit: UiChangeHandler?, +} + +-- ui.select (panels only; no dropdowns inside a persistent panel). Value-driven: +-- pass selectedIndex on every render and update it from onChange, which receives the +-- selected index and its text. +export type UiSelectProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + options: { string }?, + selectedIndex: number?, + placeholder: string?, + controlSize: ("sm" | "md" | "lg")?, + enabled: boolean?, + onChange: UiSelectHandler?, +} + +-- ui.slider. Value-driven, but `value` is re-applied only while not dragging, so +-- re-rendering mid-drag with a draft value is safe. onChange reports every change +-- (coalesced); onDragEnd fires with no arguments when the interaction ends - pointer +-- release and keyboard adjustment. The wheel does not adjust plugin sliders. +export type UiSliderProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + min: number?, + max: number?, + step: number?, + value: number?, + controlSize: ("sm" | "md" | "lg")?, + enabled: boolean?, + onChange: UiChangeHandler?, + onDragEnd: UiClickHandler?, +} + +-- ui.toggle. Value-driven; onChange receives "true" / "false". +export type UiToggleProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + checked: boolean?, + enabled: boolean?, + onChange: UiChangeHandler?, +} + +-- ui.scroll (panels only; skipped with a warning in the bar). Vertical scrolling +-- container with a column's layout props. stickToBottom, onScroll and +-- scrollToBottomRev are API 21. +export type UiScrollProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + gap: number?, + padding: number?, + paddingH: number?, + paddingV: number?, + align: ("start" | "center" | "end" | "stretch")?, + justify: ("start" | "center" | "end" | "space_between")?, + fill: UiColor?, + radius: number?, + border: UiColor?, + borderWidth: number?, + stickToBottom: boolean?, -- stay pinned to the bottom until the user scrolls away + scrollToBottomRev: number?, -- jumps to the bottom on first sight and on every change + onScroll: UiScrollHandler?, +} + +-- ui.dragSource (panels only, API 5). Marks a subtree draggable: a grip glyph, or a whole +-- row through previewAncestor. dragType and payload are required - a missing, mistyped, +-- empty or over-limit value disables the control for that render. Limits: payload 16 KiB, +-- dragType 256 bytes. +export type UiDragSourceProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + gap: number?, + padding: number?, + paddingH: number?, + paddingV: number?, + align: ("start" | "center" | "end" | "stretch")?, + justify: ("start" | "center" | "end" | "space_between")?, + fill: UiColor?, + radius: number?, + border: UiColor?, + borderWidth: number?, + minWidth: number?, + minHeight: number?, + dragType: string, -- matched against a dropZone's `accepts` + payload: string, -- opaque; first onDrop argument + enabled: boolean?, + tooltip: string?, + previewAncestor: number?, -- integer 0..8 parent levels the ghost shows; 1 previews the row around a grip + liftFromLayout: boolean?, -- remove the previewed row from layout while dragging +} + +-- ui.dropZone (panels only, API 5). Flex container that accepts drops; accepts, value and +-- onDrop are required (`accepts = {}` accepts nothing). Nested zones resolve to the +-- deepest accepting zone, hitSlop zones first, closest wins. The host moves nothing: the +-- callback mutates the plugin's model and re-renders. Limits: value/onDrop/each accepts +-- entry 256 bytes, at most 16 accepts entries. +export type UiDropZoneProps = { + key: string?, + width: number?, + height: number?, + flexGrow: number?, + opacity: number?, + visible: boolean?, + gap: number?, + padding: number?, + paddingH: number?, + paddingV: number?, + align: ("start" | "center" | "end" | "stretch")?, + justify: ("start" | "center" | "end" | "space_between")?, + fill: UiColor?, + radius: number?, + border: UiColor?, + borderWidth: number?, + minWidth: number?, + minHeight: number?, + accepts: { string }, -- drag types + value: string, -- opaque; second onDrop argument + onDrop: UiDropHandler, + direction: ("column" | "row")?, + enabled: boolean?, + expandOnDrag: boolean?, -- a fixed-height zone animates to the dragged row's height + hitSlop: number?, -- extra drag-only hit distance, without changing layout or clicks +} + +-- Only column, row, scroll, dragSource and dropZone host children; the rest are leaves. +declare ui: { + column: (props: UiFlexProps?, children: { UiNode }?) -> UiNode, + row: (props: UiFlexProps?, children: { UiNode }?) -> UiNode, + scroll: (props: UiScrollProps?, children: { UiNode }?) -> UiNode, + dragSource: (props: UiDragSourceProps, children: { UiNode }?) -> UiNode, + dropZone: (props: UiDropZoneProps, children: { UiNode }?) -> UiNode, + box: (props: UiBoxProps?) -> UiNode, + label: (props: UiLabelProps?) -> UiNode, + markdown: (props: UiMarkdownProps?) -> UiNode, + glyph: (props: UiGlyphProps?) -> UiNode, + image: (props: UiImageProps?) -> UiNode, + separator: (props: UiSeparatorProps?) -> UiNode, + spacer: (props: UiSpacerProps?) -> UiNode, + progress: (props: UiProgressProps?) -> UiNode, + button: (props: UiButtonProps?) -> UiNode, + graph: (props: UiGraphProps?) -> UiNode, + input: (props: UiInputProps?) -> UiNode, + select: (props: UiSelectProps?) -> UiNode, + slider: (props: UiSliderProps?) -> UiNode, + toggle: (props: UiToggleProps?) -> UiNode, +} + +-- ── barWidget.* - [[widget]] presentation ──────────────────────────────────── + +declare barWidget: { + setText: (text: string) -> (), + setGlyph: (name: string) -> (), + setImage: (path: string, watch: boolean?, width: number?, height: number?) -> (), + setTooltip: (tooltip: (string | TooltipRow | { TooltipRow })?) -> (), + clearTooltip: () -> (), + -- family: a font family name (load a file with noctalia.loadFont first). + -- baseline: "text" (default) | "textFixedHeight" | "inkCentered" | "pictographic". + setFont: (family: string, baseline: string?) -> (), + setColor: (role: string, mode: string?) -> (), + setGlyphColor: (role: string, mode: string?) -> (), + isVertical: () -> boolean, + -- Connector of the output this widget instance's bar is on; per-instance, unlike + -- noctalia.focusedOutputName(). nil when unknown. + outputName: () -> string?, + setVisible: (visible: boolean) -> (), + -- Declarative alternative to setText/setGlyph: the tree replaces the built-in + -- glyph/text row. ui.input/ui.select/ui.scroll are not supported in the bar. + render: (tree: UiNode) -> (), +} + +-- Gestures are configuration, not code: the user binds them per widget instance in +-- [widget.<id>.actions] (left, right, middle, back, forward, scroll_up, scroll_down, +-- scroll_left, scroll_right), and a binding wins over the matching callback. An action is +-- an IPC command ("media toggle"), `exec <command line>`, or `none`. Manifests declare +-- their own defaults in [widget.actions] (API 14). +-- +-- Middle click is the one to know about: every widget defaults to +-- `middle = "settings-open-widget"`, so onMiddleClick does not fire until the manifest or +-- the user binds `middle = "none"`. Scroll has one extra gate: `enable_scroll = false` +-- turns onScroll off regardless of bindings. + +-- ── shortcut.* - [[shortcut]] quick-toggle tile ────────────────────────────── + +declare shortcut: { + setLabel: (label: string) -> (), + setIcon: (on: string, off: string?) -> (), + setActive: (active: boolean) -> (), + setEnabled: (enabled: boolean) -> (), +} + +-- ── launcher.* - [[launcher_provider]] results ─────────────────────────────── + +declare launcher: { + setResults: (query: string, results: { LauncherResult }) -> (), + setQuery: (text: string) -> (), -- prefix + text (stays in provider); "" resets to root +} + +-- ── desktopWidget.* - [[desktop_widget]] declarative UI ────────────────────── + +declare desktopWidget: { + render: (tree: UiNode) -> (), + setWantsSecondTicks: (wants: boolean) -> (), -- run update() on second boundaries + setNeedsFrameTick: (needs: boolean) -> (), -- deliver onFrameTick(deltaMs) every frame +} + +-- ── panel.* - [[panel]] declarative UI ─────────────────────────────────────── + +declare panel: { + render: (tree: UiNode) -> (), + close: () -> (), + -- Opens a native menu at the originating direct pointer callback; false outside a live + -- one. onActivate receives (actionId, context) in the panel script. API 28. + openContextMenu: (request: PanelContextMenuRequest) -> boolean, + setWantsSecondTicks: (wants: boolean) -> (), + setNeedsFrameTick: (needs: boolean) -> (), -- onFrameTick(deltaMs) while open (API 18) +} + +-- ── Entry-point callbacks ──────────────────────────────────────────────────── +-- +-- Your entry defines the globals the host calls, as plain global functions - the +-- host only calls a callback if the entry defines it: +-- +-- function update() end -- bar/desktop widget, service tick +-- function onIpc(event, payload) end -- any entry (payload: string?) +-- function onClick() / onRightClick() end -- shortcut, bar widget +-- function onMiddleClick() end -- bar widget (see "Gestures" above) +-- function onHover(entered) end -- bar widget pointer enter / leave +-- function onScroll(axis, steps, startsGesture) end -- bar widget scroll; axis is "vertical" | "horizontal", +-- -- steps is whole wheel detents (negative = up / left), +-- -- startsGesture is true only on the first step of a flick +-- function onQuery(text) / onActivate(id) end -- launcher provider +-- function onFrameTick(deltaMs) end -- desktop widget, or open panel (API 18); after +-- -- setNeedsFrameTick(true), frames coalesced +-- function onAudioSpectrum(valuesCsv, stateCsv) end -- audio-reactive bar widget +-- function onOpen(context) / onClose() end -- panel lifecycle +-- function onKey(chord, pressed) end -- panel: a capture_keys chord, verbatim from the +-- -- manifest (API 13) +-- function onConfigChanged() end -- service: settings changed; getConfig() is now new +-- function onEnable() end -- service: plugin explicitly enabled (API 17) +-- function onOutputsChanged() end -- service: output set or geometry changed +-- function onExit(signal, reason) end -- any entry teardown; signal is 0 normally, 2 SIGINT, +-- -- 15 SIGTERM; reason is "reload" | "disable" | +-- -- "uninstall" | "shutdown" (API 17) +-- +-- These are intentionally NOT declared here: declaring them as globals makes +-- luau-lsp treat your definition as overwriting a built-in. |