macotron.launcher
Add your own rows to the Macotron launcher, either as a fixed list that the launcher filters or as answers computed from the text the user types.
// Answer "2*21" with "42" right in the launcher.
macotron.launcher.query("calc", (q) => {
if (!/^[\d\s+\-*/().]+$/.test(q)) return [];
const n = Function("return (" + q + ")")();
if (!isFinite(n)) return [];
return [{
id: "result",
title: String(n),
subtitle: "Return to copy",
sfSymbol: "equal.square",
kind: "Calculator",
onClick: () => macotron.clipboard.set(String(n)),
}];
});
Rows
Both calls take rows in the same shape, LauncherItem:
| Field | Type | What it does |
|---|---|---|
id | string | Identifies the row within its provider. Stars (⌘S) and keyboard shortcuts are saved against it, so keep it stable. Defaults to the row's index. |
title | string | The main text. Defaults to the id. |
subtitle | string | Smaller text under the title. |
kind | string | The label on the right of the row, such as "Calculator". Default "Plugin". |
app | string | A bundle ID, such as com.apple.Notes. The row shows that app's icon. |
path | string | A file path. The row shows that file's Finder icon. |
sfSymbol | string | An SF Symbol name for the icon, used when there is no app or path icon. |
onClick | () => void | Runs when the user picks the row. |
Fixed lists
set(id: string, items: LauncherItem[]): void
Replaces the rows of provider id. The launcher fuzzy-matches the typed text against each row's title and subtitle, and ranks the matches together with apps and commands. With an empty query, the launcher shows only starred rows.
macotron.launcher.set("snippets", [
{ id: "omw", title: "omw", subtitle: "On my way!", onClick: () => macotron.snippets.insert("omw") },
]);
Live answers
query(id: string, handler: (query: string) => LauncherItem[] | Promise<LauncherItem[]>, opts?: { run?, secondary? }): void
Calls handler on every keystroke with the launcher's text. Calling query again with the same id replaces the handler.
Return fast, and return [] when the text is not for you. A synchronous handler that runs longer than 250 ms is interrupted.
A row that does not match the text by name, such as 42 for 2*21, is an answer and goes to the top of the list. A row that does match by name is ranked with everything else.
The handler can return a promise. The launcher does not wait for it: the keystroke shows what is ready, and the rows appear when the promise resolves. An answer to text the user has since changed is dropped. A rejected promise clears this provider's rows.
| Option | Type | What it does |
|---|---|---|
run | (rowId: string) => void | Runs a row from its id alone. The launcher calls it when the user triggers a row that is no longer on screen, for example from a keyboard shortcut after a restart. Use row ids you can act on, such as file paths. |
secondary | boolean | Set this for a provider that answers almost any text, such as a file search. Its rows never lead the list and lose ties to other results. |
// From the file-search plugin.
macotron.launcher.query("file-search", async (query) => {
const term = query.trim();
if (term.length < 2) return [];
const hits = await macotron.files.search(term, { limit: 8 });
return hits.map((h) => ({ id: h.path, title: h.name, subtitle: h.path, path: h.path, onClick: () => open(h.path) }));
}, {
secondary: true,
run: (path) => open(path),
});
Removing
remove(id: string): void
Removes the provider's fixed rows and its query handler.
The launcher shows at most 20 results at a time.
See also
macotron.commandfor named commands with arguments, which also appear in the launcher.- macotron.files and macotron.spotlight for file results.
- The
calculator.js,emoji.jsandfile-search.jsplugins.