pub struct App<D: Document> { /* private fields */ }Expand description
An app: name, document type and format, commands, views. run() opens the window; the same
definition serves the CLI and MCP (App::cli) and tests (App::headless).
use ashlar_app::{App, Cx, Session};
use ashlar_command::{CommandError, CommandSpec};
#[derive(Clone, Default, serde::Serialize, serde::Deserialize)]
struct Doc { count: i64 }
fn bump(s: &mut Session<Doc>, _: &serde_json::Value) -> Result<serde_json::Value, CommandError> {
s.edit("Bump", |d| d.count += 1);
Ok(serde_json::Value::Null)
}
fn main() -> Result<(), ashlar_app::Error> {
App::<Doc>::new("counter", "0.1.0")
.command(CommandSpec::new("count.bump", "Bump", bump).menu(&["Edit"]).shortcut("Mod+B"))
.view(|ui, cx: &mut Cx<'_, Doc>| {
ui.label(format!("{}", cx.doc().count));
if ui.button("Bump").clicked() {
cx.dispatch("count.bump", serde_json::json!({}));
}
})
.run()
}Implementations§
Source§impl<D: Document> App<D>
impl<D: Document> App<D>
Sourcepub fn new(name: impl Into<String>, version: impl Into<String>) -> Self
pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self
An app called name (lower case, used for folders, env vars and the CLI).
Sourcepub fn organization(
self,
qualifier: impl Into<String>,
org: impl Into<String>,
) -> Self
pub fn organization( self, qualifier: impl Into<String>, org: impl Into<String>, ) -> Self
Reverse-domain qualifier and organisation for the OS folders ("com", "Acme").
Sourcepub fn format(self, format: Format<D>) -> Self
pub fn format(self, format: Format<D>) -> Self
The document’s file format, with its migrations.
Sourcepub fn file_extension(self, ext: impl Into<String>) -> Self
pub fn file_extension(self, ext: impl Into<String>) -> Self
A file extension offered by Open and Save dialogs (without the dot).
Sourcepub fn commands(
self,
specs: impl IntoIterator<Item = CommandSpec<Session<D>>>,
) -> Self
pub fn commands( self, specs: impl IntoIterator<Item = CommandSpec<Session<D>>>, ) -> Self
Add commands (menus follow declaration order).
pub fn command(self, spec: CommandSpec<Session<D>>) -> Self
Sourcepub fn view(self, view: impl FnMut(&mut Ui, &mut Cx<'_, D>) + 'static) -> Self
pub fn view(self, view: impl FnMut(&mut Ui, &mut Cx<'_, D>) + 'static) -> Self
The UI, drawn inside the window’s central area each frame.
Sourcepub fn setup(self, f: impl FnOnce(&Context) + 'static) -> Self
pub fn setup(self, f: impl FnOnce(&Context) + 'static) -> Self
Runs once before the first frame (install fonts, tokens).
Sourcepub fn autosave(self, every: Option<Duration>) -> Self
pub fn autosave(self, every: Option<Duration>) -> Self
Autosave interval (None: no autosave or recovery). Default 60 s.
Sourcepub fn telemetry(self, key: impl Into<String>, endpoint: Option<&str>) -> Self
pub fn telemetry(self, key: impl Into<String>, endpoint: Option<&str>) -> Self
Telemetry (with the telemetry feature): write key and server. Always on when endpoint
is set (no notice, no switches); TRACER_DISABLED in the environment turns it off.
Sourcepub fn instructions(self, text: impl Into<String>) -> Self
pub fn instructions(self, text: impl Into<String>) -> Self
What MCP clients are told about the app.
Sourcepub fn dirs(self, dirs: AppDirs) -> Self
pub fn dirs(self, dirs: AppDirs) -> Self
Put config, data, cache and logs here instead of the OS folders (tests, portable).
Sourcepub fn canvas_id(self, id: impl Into<String>) -> Self
pub fn canvas_id(self, id: impl Into<String>) -> Self
On the web, the id of the <canvas> the app runs in (default: the app’s name, then
ashlar). When the app cannot start (no such canvas, no WebGL), a visible error appears
next to the canvas (or at the top of the page) as well as in the console. Ignored on the
desktop.
pub fn window_size(self, width: f32, height: f32) -> Self
Sourcepub fn frame_latency(self, frames: u32) -> Self
pub fn frame_latency(self, frames: u32) -> Self
Frames the GPU may queue ahead of the screen, 1 to 3 (default 1: the lowest input latency, and one swapchain image fewer, about 10 MB for a 960×640 window on a Retina screen). Apps that draw heavy GPU scenes every frame may prefer 2 for smoother throughput.
Sourcepub fn control_port(self, port: u16) -> Self
pub fn control_port(self, port: u16) -> Self
Serve the control port on this port (also --control <port> and <APP>_CONTROL_PORT).
Sourcepub fn follow_system_accent(self, follow: bool) -> Self
pub fn follow_system_accent(self, follow: bool) -> Self
Recolour the accent (hover, focus, selection) from the OS accent colour (default on). Off pins the built-in accent. Tokens the app installs itself always win over the OS.
Sourcepub fn motion(self, prefs: MotionPrefs) -> Self
pub fn motion(self, prefs: MotionPrefs) -> Self
Motion settings that win over the OS “reduce motion” setting (an app’s own motion preference). Without this the app follows the OS, at normal speed.
Sourcepub fn single_instance(self, on: bool) -> Self
pub fn single_instance(self, on: bool) -> Self
One window per app (default off). A second launch hands its arguments (the files to open)
to the running one and exits; the running one opens them with file.open and comes to the
front. The endpoint is named after the app (see App::organization); desktop only.
Sourcepub fn accept_drops(self, on: bool) -> Self
pub fn accept_drops(self, on: bool) -> Self
Open files dropped on the window (default on when the app sets a App::format or a
App::file_extension). The first file with a known extension opens with file.open
(a dirty document asks to save first); the others reach the view as
Cx::dropped_files. Off leaves drops to the view’s own input.
Sourcepub fn run_toast_actions(self, on: bool) -> Self
pub fn run_toast_actions(self, on: bool) -> Self
Run a toast’s action when it is clicked (default off). With it on, a clicked
ToastAction whose command is a registered command id
runs like a menu pick, with empty params, after the frame’s toasts are drawn; errors become
toasts. Actions naming anything else stay queued for the view’s
Toasts::take_actions.
Sourcepub fn viewport(
self,
f: impl FnOnce(ViewportBuilder) -> ViewportBuilder + 'static,
) -> Self
pub fn viewport( self, f: impl FnOnce(ViewportBuilder) -> ViewportBuilder + 'static, ) -> Self
Change the window before it opens: a minimum size, decorations, transparency… f gets
the builder ashlar made (title, size, app id, the restored placement) and returns it.
Desktop only; the headless driver has no window.
App::<i64>::new("notes", "0.1.0").viewport(|b| b.with_min_inner_size([480.0, 320.0]));Sourcepub fn icon(self, png: impl Into<Vec<u8>>) -> Self
pub fn icon(self, png: impl Into<Vec<u8>>) -> Self
The window and taskbar icon, as PNG bytes (include_bytes!("icon.png")). An image that
does not decode is logged and the default icon stays. Desktop only.
Sourcepub fn remember_window(self, on: bool) -> Self
pub fn remember_window(self, on: bool) -> Self
Remember where the window was (default on): its position, size, maximized and full
screen state go to the settings under "window" when they change and on close, and the
next launch opens the window there, kept on a visible monitor. Ignored without a window
(--headless, crate::Driver) and without an app folder (App::dirs).
Sourcepub fn scene(
self,
name: impl Into<String>,
setup: impl Fn(&mut Session<D>) + Send + Sync + 'static,
) -> Self
pub fn scene( self, name: impl Into<String>, setup: impl Fn(&mut Session<D>) + Send + Sync + 'static, ) -> Self
A named starting state: setup runs on the session (load a fixture, fill a list, set the
theme…) when the scene is applied, with --scene NAME (in a window or --headless), the
ui.scene {name} control method, the MCP tool ui_scene or crate::Driver::scene.
--list-scenes prints the names. A name declared twice keeps the first.
App::<Doc>::new("notes", "0.1.0").scene("two-notes", |s: &mut Session<Doc>| {
s.edit("Two notes", |d| d.notes = vec!["a".into(), "b".into()]);
});Sourcepub fn scene_names(&self) -> Vec<String>
pub fn scene_names(&self) -> Vec<String>
The names of the app’s scenes, in declaration order.
Sourcepub fn headless(self) -> Headless<D>
pub fn headless(self) -> Headless<D>
A session without a window, driving the same commands (tests, scripts).
Sourcepub fn runtime(self) -> Runtime<D>
pub fn runtime(self) -> Runtime<D>
The runtime without a window, for tests and benches: drive it with crate::Driver. It
ignores the OS preferences (see Runtime::set_preferences) so runs match on every machine.
Sourcepub fn cli(self) -> Cli
pub fn cli(self) -> Cli
The app’s -cli binary: commands, exec, run, mcp, serve, version, each on a
fresh headless session (or the running app with --connect PORT). Add app verbs to the
returned ashlar_cli::Cli before run().
Sourcepub fn run(self) -> Result<(), Error>
pub fn run(self) -> Result<(), Error>
Open the window and run until it closes.
With --headless on the command line, run with no window instead: a virtual-clock
crate::Driver in a temporary folder that writes --snap out.png and --tree tree.json
(after --script file.ui and --at SECONDS, at --size WxH, --scale S, --theme light|dark, --scene NAME), then exits with 0 (done), 1 (a step failed) or 2 (bad
arguments). (--headless needs the headless feature, on by default.) --scene NAME also
works with a window; --list-scenes prints the scenes.
Auto Trait Implementations§
impl<D> !RefUnwindSafe for App<D>
impl<D> !Send for App<D>
impl<D> !Sync for App<D>
impl<D> !UnwindSafe for App<D>
impl<D> Forget for App<D>
impl<D> Freeze for App<D>
impl<D> Move for App<D>
impl<D> Unpin for App<D>
impl<D> UnsafeUnpin for App<D>where
Option<Format<D>>: UnsafeUnpin,
Vec<CommandSpec<Session<D>>>: UnsafeUnpin,
Option<Box<dyn FnMut(&mut Ui, &mut Cx<'_, D>)>>: UnsafeUnpin,
Vec<(String, Arc<dyn Fn(&mut Session<D>) + Send + Sync>)>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more