Scripts
A plugin with main = "main.rn" in its manifest runs that script, written
in Rune. notesy compiles it when the
plugin starts and runs it on a thread of its own, so the window never waits
for it.
#More than one file
A script can be split up with Rune's modules: mod helpers; in main.rn
takes in helpers.rn beside it (or helpers/mod.rn), and its public
functions are then helpers::name(). Modules can have modules of their own
the same way, a folder down each time.
rust// main.rn
use notesy::log;
mod helpers;
pub fn ready() {
log::info(`twice 2 is ${helpers::double(2)}`);
}
// helpers.rn
pub fn double(n) { n * 2 }
Every file comes from the plugin's own folder, and none through a link: a script can't take in a file from anywhere else. Packing takes every file in the folder, so the modules go with it.
#What a script can reach
Rune itself has no files, network or processes. notesy adds its own
modules, under notesy::, and only the ones the plugin's permissions cover:
a script that uses a module it wasn't given doesn't compile.
rustuse notesy::{events, log, settings, store};
| Module | Needs | Page |
|---|---|---|
notesy::log |
nothing | notesy::log |
notesy::events |
per event | notesy::events |
notesy::store |
nothing | notesy::store |
notesy::settings |
nothing | notesy::settings |
notesy::secrets |
nothing | notesy::secrets |
notesy::json |
nothing | notesy::json |
notesy::toml |
nothing | notesy::toml |
notesy::yaml |
nothing | notesy::yaml |
notesy::files |
nothing (its own folder only) | notesy::files |
notesy::icons, notesy::canvas |
nothing (its [[icons]] without a file) |
notesy::icons |
notesy::Event |
nothing: what events::on takes |
notesy::events |
notesy::{Icon, Color, Tone, Side, Method, Command} |
nothing: notesy's names, as enums | Names: Icon, Color, Tone, Side, Method, Command, Menu, Sidebar, Event |
notesy::view |
nothing | notesy::view |
notesy::commands |
commands |
notesy::commands |
notesy::panels, notesy::views |
ui |
notesy::panels and notesy::views |
notesy::sections |
ui |
notesy::sections |
notesy::status |
ui |
notesy::status |
notesy::notices |
notify |
notesy::notices |
notesy::clipboard |
clipboard.write to copy, clipboard.read to paste |
notesy::clipboard |
notesy::links |
links.open |
notesy::links |
notesy::notes |
notes.read to read, notes.write to change |
notesy::notes |
notesy::editor |
editor |
notesy::editor |
notesy::net |
net (hosts in [net]) |
notesy::net |
notesy::accounts |
accounts (and [[accounts]]) |
notesy::accounts |
notesy::blocks |
markdown (languages in [contributes] blocks) |
notesy::blocks |
How the runtime was built, and why: plan.md.
#Its lifecycle
A script may define any of these; notesy calls each one it defines, in this order over a plugin's life:
| Function | When |
|---|---|
pub fn load() |
It's loaded, before anything else reaches it: set yourself up here. |
pub fn updated(from, to) |
It runs another version than last time (from and to are version strings): bring your store along. |
pub fn ready() |
notesy is up, with a vault open and its tabs back: start what needs the app or the notes. A plugin turned on later hears this right after load. |
pub fn setting_changed(key) |
The user changed one of its settings. |
pub fn unloading() |
It's being turned off, or notesy is quitting: save and let go, quickly. |
Events it subscribed to with events::on arrive in between, one at a time,
in the order they happened.
#Limits
Every call into a script (a lifecycle function, an event handler) runs within limits:
| Limit | Default | When it's reached |
|---|---|---|
| Instructions per call | 1,000,000 | the call is halted: "it ran too long" |
| Instructions per view | 5,000,000 | the view is halted |
| Memory, across its calls | 64 MiB | the allocation fails, and the call with it (what earlier calls kept counts too) |
| Failures a minute | 3 | the plugin is stopped |
Values going between a script and notesy (what it keeps, shares, sends as JSON, or builds a view from) nest at most 64 deep: a list or object nested deeper is an error where it's handed over.
A failure is a call that errors (a panic, a ? on an error, a wrong type)
or is halted. Each goes to the plugin's log on the Plugins page. The third
in a minute stops the plugin, with a notice saying which and why; it stays
stopped until notesy starts again or it's turned off and on.
Waiting costs nothing: a script that has nothing to do isn't running.
#Errors
If the script doesn't compile, the plugin doesn't start, and its log shows what the compiler said, with the file and line:
error: Expected expression but got `;`
┌─ main.rn:1:26
│
1 │ pub fn ready() { let x = ; }
│ ^
Errors while it runs show the function or event they happened in, like
note.saved: there's no event “note.eaten”.
Warnings go to its log as it starts, and notesy plugin check prints
them: the compiler's (a template with nothing in it), and what notesy
knows Rune runs wrong (the trap below), each with
its file and line.
#Values
What a script keeps and is given are plain values: true and false,
integers, floats, strings, vectors and objects (#{ key: value }) of those.
An event is an object with its name and its fields
(notesy::events). Paths are always relative to the vault
(Daily/2026-09-12.md), never the machine's.
#A trap in Rune 0.14
In a match on text or a number, an arm whose block ends in a variable of
its own gives nothing, not the variable:
rustuse notesy::view;
fn part(kind) {
match kind {
// Comes out as nothing: a view with it says “item 2: nothing can't be kept”.
"tags" => { let chips = view::chips(["#a"]); chips.target = "tag"; chips },
_ => view::note(kind),
}
}
Build such a part in a function of its own ("tags" => tag_chips()), or end
the block in a call (view::chips(…)). A match on an Option
(Some(x) => { … }) is fine.
Every page
- Overview
- plugin.toml: Every field of plugin.toml
- Permissions: What a plugin can ask for, when notesy asks, and what changes it
- Scripts: How a script runs: its lifecycle, events, limits and errors
- Packing and installing: Making, checking, signing, packing and installing
- notesy::log: Lines for its log on the Plugins page
- notesy::events: Hearing what happens, and every event
- notesy::commands: Adding commands, and running notesy's
- notesy::store: Keeping its own data
- notesy::settings: Reading its settings
- notesy::secrets: Keys and tokens, in the system keychain
- notesy::notes: Reading and changing the vault's notes
- notesy::editor: The note in front
- notesy::files: A folder of its own
- notesy::links: Opening pages in the browser
- notesy::clipboard: Copying and pasting
- notesy::view: What panels, tabs and sections show
- notesy::panels and notesy::views: Adding side panels and tabs
- notesy::sections: Sidebar sections
- notesy::menus: Items in notesy's right-click menus
- notesy::status: Status bar items
- notesy::notices: Notices
- notesy::dialogs: Asking in a dialog, notesy's kinds or its own
- notesy::cards: Its part of the tree's hover cards
- notesy::boards: Boards' cards and arrows, and kinds of card of its own
- notesy::blocks: Drawing its fenced blocks
- notesy::icons: Drawing its own icons
- notesy::net: Requests to the sites it names
- notesy::accounts: Signing in to a service
- notesy::json: Reading and writing JSON
- notesy::toml: Reading and writing TOML
- notesy::yaml: Reading and writing YAML, and a note's front matter
- notesy::time: Now, written in the user's time zone, dates read, how long ago
- notesy::math: Trigonometry and the like, for drawing
- Names: Icon, Color, Tone, Side, Method, Command, Menu, Sidebar, Event: Notesy's names as enums
- notesy::preview: Its own screens for notesy preview
- notesy::perf: Timing its own work
- notesy::tex: Math macros for every note's formulas