Files
ElyOffice/crates/ely-office/src/engine.rs
T
ZacharyZhang-NY b7fca0146d Ely Office: six offline-first desktop apps in Rust and GPUI
ElyDoc, ElyTable, ElyShow (LibreOfficeKit), ElyPDF (MuPDF), ElyTree (Git),
ElyMark (Milkdown and CodeMirror in CEF). ElyMail and ElyAgent follow.
2026-10-08 21:20:08 -04:00

90 lines
3.3 KiB
Rust

//! What a document engine gives the shell (§6).
use std::{
io,
path::Path,
sync::{Arc, Mutex},
};
use ely_platform::AppId;
use gpui::{App, Context, Entity, FocusHandle, Window};
use crate::Host;
/// Where a load starts.
pub enum Load<'a, I> {
/// A file and its password, empty for none.
File(&'a Path, &'a str),
/// Text bytes already at the path, read as told.
Import(&'a Path, &'a I),
}
/// A kernel behind the shell: loads, writes, history, views.
pub trait Engine: Sized + 'static {
type Worker: Send + 'static;
type Doc: Clone + Send + 'static;
type View: 'static;
/// What a load hands the window.
type Loaded: Send + 'static;
/// How text files are read.
type Import: Clone + Send + 'static;
/// Loads off the window; a locked file fails PermissionDenied.
fn load(worker: &mut Self::Worker, from: Load<Self::Import>) -> io::Result<Self::Loaded>;
/// The view over a load, its document and history mark.
fn open(
worker: &Arc<Mutex<Self::Worker>>,
loaded: Self::Loaded,
window: &mut Window,
cx: &mut App,
) -> io::Result<(Self::Doc, Entity<Self::View>, String)>;
/// Checked before the file is overwritten; a risk stops it.
fn unsound(_worker: &mut Self::Worker, _doc: &Self::Doc) -> io::Result<Option<crate::Risk>> {
Ok(None)
}
/// What saving in place would lose, macros aside.
fn risk(_loaded: &Self::Loaded) -> Option<crate::Risk> {
None
}
/// The undo history as a mark to compare.
fn history(worker: &mut Self::Worker, doc: &Self::Doc) -> io::Result<String>;
/// Writes `doc` as `format` to `path`.
fn write(
worker: &mut Self::Worker,
doc: &Self::Doc,
path: &Path,
format: &str,
) -> io::Result<()>;
/// A copy of `doc` at `path`; `doc` stays.
fn snapshot(_worker: &mut Self::Worker, _doc: &Self::Doc, _path: &Path, format: &str) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Unsupported, format!("no snapshot as .{format}")))
}
fn close(worker: &mut Self::Worker, doc: Self::Doc) -> io::Result<()>;
/// A closing view's images, for the shell to free.
fn retire(view: &Entity<Self::View>, cx: &mut App) -> ely_gpui_component::primitives::Retired;
/// Why the worker ended, if it did (§6.3).
fn ended(_worker: &mut Self::Worker) -> Option<String> {
None
}
/// A fresh worker in place of an ended one.
fn restart(_app: AppId, _worker: &mut Self::Worker) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Unsupported, "this engine does not restart"))
}
/// Every input sent has reached the kernel.
fn settled(view: &Self::View) -> bool;
/// Edits landed so far.
fn edited(view: &Self::View) -> u64;
/// An edit is sent but not landed.
fn edit_pending(view: &Self::View) -> bool;
fn focus(view: &Self::View) -> FocusHandle;
/// The document was saved at history `mark`.
fn saved(view: &Entity<Self::View>, mark: &str, cx: &mut App);
/// Calls `reported` with the modified flag, `failed` with errors.
fn watch<H: Host<Engine = Self>>(
view: &Entity<Self::View>,
cx: &mut Context<H>,
reported: impl Fn(&mut H, &Entity<Self::View>, bool, &mut Context<H>) + 'static,
failed: impl Fn(&mut H, &str, &mut Context<H>) + 'static,
);
}