notesy::zones

Places in notesy's window where a plugin hangs something of its own: an item in one of its right-click menus, or a button on one of its bars and headings. Every one is named by notesy as a Zone (Names: Icon, Color, Tone, Side, Method, Command, Menu, Sidebar, Event) — a fixed set, in code, so a place that isn't one doesn't compile. A plugin with the ui permission reaches all of them, and says nothing about them in its manifest.

rustuse notesy::{notes, notices, zones, Zone};

pub fn ready() {
    // An item in the menu of a note in the tree.
    zones::add(Zone::NoteMenu, "count", #{ title: "Count its words", icon: "number" }, |path| {
        if let Some(note) = notes::read(path) {
            notices::info(`${note.title()}: ${note.words()} words`);
        }
    });
    // A button in the window's bar, with a menu of its own.
    let sync = zones::add(Zone::TitlebarRight, "sync", #{ title: "Sync now", icon: "clock" }, || notices::info("syncing"));
    sync.menu("pause", "Pause syncing", || notices::info("paused"));
}

#The places

Menus. Each hands what it was opened on to run.

Zone Where it opens What run gets
Zone::NoteMenu On a note in the tree Its path within the vault: "Projects/Plan.md"
Zone::FileMenu On any other file in the tree (an image, a PDF …) Its path
Zone::FolderMenu On a folder in the tree Its path
Zone::TabMenu On a tab #{ title, path }: path only on a note's tab, not a plugin's tab or a plugin's own file
Zone::EditorMenu In the note's text #{ path, line, start, end }: the caret's line, counted from 1 (a right-click puts the caret there, unless it's in the selection), and the selection's start and end in characters. No path on a plugin's own file
Zone::BoardMenu On a board's empty canvas #{ path, x, y }: the board's path, and where on it, in the board's units (notesy::boards)
Zone::BoardCardMenu On a card on a board #{ path, id, type, selected }: the card's id and type, and the ids of every card and arrow picked
Zone::BoardArrowMenu On an arrow on a board #{ path, id }
Zone::NewNoteMenu On a New note button in the sidebar, right-clicked The folder its note would go in: "", the vault's top
Zone::NotesHeadingMenu On the sidebar's Notes heading nothing
Zone::TagsHeadingMenu On its Tags heading nothing

Buttons. They are about the window, so nothing reaches run — except a board's tray, which is about its board.

Zone Where it is What run gets
Zone::TitlebarLeft The window's bar, against the left of its search button nothing
Zone::TitlebarRight The window's bar, against its right nothing
Zone::BoardTray Every board's tray, beside its zoom controls (notesy::boards) #{ path, selected }: the board, and the ids picked on it
Zone::NotesHeading The sidebar's Notes heading, while the pointer is on it nothing
Zone::TagsHeading Its Tags heading nothing

A plugin's own sections, panels and buttons have places of their own, which are theirs rather than notesy's: section.menu for its items, section.action and section.heading_menu for its heading (notesy::sections), panel.menu for its panel's button (notesy::views), and entry.menu below.

#Adding one

Function What it does
zones::add(zone, key, options, run) Puts an item or a button in zone, and returns it. run gets what the place says, above.

key names it in that place: lowercase letters, digits, -, _ and ., starting with a letter. The same key can name one in each place, and adding one with a key it has there already changes it — which is how a button's title, icon and colour change as what it says changes.

options is its title, or an object:

Option What it does
title Its words in a menu; its tip on a button.
icon An icon by name (notesy::icons).
icon_color A button's icon at rest, a theme's colour or #rrggbb (Names: Icon, Color, Tone, Side, Method, Command, Menu, Sidebar, Event).
card A view (notesy::view) shown in place of a button's tip once the pointer rests on it: the same card a status item can have (notesy::status).
card_at Which side of the button that card goes: Side::Left, Side::Right, Side::Above or Side::Below; under it unless it says. A card that would go off the window goes to the other side instead, so one asked for on the left of a button hard against the window's left opens to its right.

What run gets is the plugin's because the user picked its item on it; reading what's in a note still takes notes.read (notesy::notes), and changing the text takes editor (notesy::editor).

#What it gives back

Method What it does
menu(key, options, run) On a button: adds an item to the button's own right-click menu, and returns it; run() takes nothing. A button with none opens no menu.
remove() Takes it out of the place it was put in.

#A place of its own

A plugin can open a place in what it draws, for the other plugins to hang things in. It says what is there and draws them itself, wherever it likes in its panel, its tab or its dialog; nothing shows behind its back.

rustuse notesy::{events, view, views, zones, Event};

pub fn ready() {
    let bar = zones::open("toolbar", #{ title: "The tasks toolbar" });
    let panel = views::panel("tasks", "Tasks", |note| guests(bar));
    // Others come and go while it runs: drawn again when they do.
    events::on(Event::ZoneChanged, |event| panel.refresh());
    // A press on one of them runs what that plugin put there.
    panel.on_click(|target, note| {
        if target.starts_with("guest:") {
            let parts = target.replace("guest:", "").split('/');
            bar.run(parts.next().unwrap(), parts.next().unwrap());
        }
    });
}

/// What other plugins put in it, as a row of buttons.
fn guests(bar) {
    let buttons = [];
    for e in bar.entries() {
        let button = view::button(e.title);
        button.target = `guest:${e.plugin}/${e.key}`;
        button.icon = e.icon;
        buttons.push(button);
    }
    view::columns(buttons)
}
Function What it does
zones::open(key, options) Opens a place of its own, and returns it: options is its title, or #{ title }, the name the user sees it by. Others name it <plugin>/<key>. Opening one with a key it has already retitles it.
zone.entries() What other plugins have put in it: a list of #{ plugin, key, title, icon, icon_color }, in the order they came, empty while nobody has. A plugin the vault is keeping from its notes is left out.
zone.run(plugin, entry) Runs one of them: the plugin that put it there hears it, its run() taking nothing — what the place is about is the owner's to know, and it says so by which entry it runs. The owner decides what a press on what it drew means, so nothing runs behind its back.
zone.close() Takes the place away, with whatever others put in it.

Another plugin hangs something there by name:

rustuse notesy::{notices, zones};

pub fn ready() {
    zones::add("acme.tasks/toolbar", "weather", #{ title: "The weather", icon: "partly-sun" }, || notices::info("72° and clear"));
}

An entry in a place nobody has opened does nothing, and notesy says so in the adding plugin's log rather than leaving it a mystery. A place that is not there yet is not an error: plugins load in their own order, and a plugin whose host isn't installed simply never shows.

zone.changed (notesy::events) reaches whoever opened the place when an entry comes or goes.

#Where they show

Plugins' items come after notesy's own: above "Move to Trash" in the tree's menus, at the bottom of a tab's and the editor's. A plugin's one item in a menu is a row of its own; two or more go in a submenu under the plugin's name, which opens as the pointer comes to it. Buttons from every plugin share a place, in the order they were added; keep to one or two in the window's bar, which is the window's. Whatever a script added goes when it stops.

Every page