The only way a mod starts something outside Perch. Every path is validated: https URLs only, Steam app ids only, and app references that must exist in the live installed-apps scan. Every launch is written to the log.
| Scope | Installs |
|---|---|
open | perch.open.url(url), perch.open.steam(appid), perch.open.app(ref) |
None of the three returns anything.
perch.open.url(url: string): () -- must start with https://
perch.open.steam(appid: string): () -- a string of digits, what a settings.game row stores
perch.open.app(ref: string): () -- the reference a settings.launch row stored
A refused call is logged: open.url refused (not https), open.steam refused (not an appid), open.app refused (not an installed app).
Launching what the user picked
A settings.launch row stores a launch_target_t, and its type picks the verb. A dock of such rows launches from the tap’s ctx.index:
--!strict
type tile_refs_t = { icon: field_ref_t<string>, label: field_ref_t<string> }
type fields_t = { tiles: list_ref_t<tile_refs_t> }
local tiles: { launch_target_t } = {} -- refreshed in perch.on_configure
local function open_tile(ctx: input_context_t)
local t = tiles[ctx.index or 1]
if not t then return end
if t.type == "url" then perch.open.url(t.ref)
elseif t.type == "steam" then perch.open.steam(t.ref)
else perch.open.app(t.ref) end
end
dock:place(surface.page, function(f: fields_t): node_t
return ui.list { items = f.tiles, max = 5, gap = 8,
item = function(it: tile_refs_t): node_t
return ui.column { w = 66, gap = 6, align = ui.align.center, on_click = open_tile,
ui.image { src = it.icon, w = 42, h = 42, hover = ui.hover.lift },
ui.text { text = it.label, size = 12, color = ui.color.half },
}
end }
end)
Types
export type launch_target_t = { type: "steam" | "url" | "app", ref: string, label: string, icon: string }
| Field | Meaning |
|---|---|
type | which verb opens it |
ref | the https URL, the appid digits, or the installed-app reference |
label | the display name |
icon | an https:// or file:// icon URL, or "" |
Every field is "" when nothing is picked.