Run cumulus for real: the app core and its files (stage 8a)
The playground becomes app::App, and `cumulus` runs it: the main loop with terminal setup and a panic hook, and the startup rules (./ideas.cum, else ~/ideas.cum, made the first time; files and folders by name; `cumulus new`; --paths). The documents' files: - autosave a second after the latest change (`:set noautosave` for vim-style :w), [+] in the document bar for unsaved changes; quitting saves first; without autosave :q refuses, :q! drops, ZZ saves first; - a file changed outside cumulus is read again as an undo step; with unsaved changes here too, cumulus asks which to keep; a file with a mistake in it holds autosave until it's fixed or :w saves over it; a deleted one waits for :w; nothing is reloaded under an edit; - the day's first save backs the file up to the data folder (30 days); - a document open in another cumulus is read-only ([RO]) until that one lets go: OS file locks in the data folder, so a crash leaves none; - where you left off (cursor, zoom, scroll), the recent documents (now in the documents picker) and the command history, in memory.ron; - :e (alone: read it again; ! drops changes), :new, :bd, :w, :wa, :x, :qa, <Space>i for :in, and :set for every setting. glyphs=ascii now reaches the frames and bars too, not just the canvas and outline. Stage 8 comes in four parts with a commit each (the user's choice); 8b is the settings files. The example is now a playground running the app on copies of the sample documents in a temporary folder, and the end-to-end tests moved to src/app/tests.rs, with tests for the files. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
e6f3c06ecc
commit
f6dc4564aa
47 files changed
+3985
-1024
No files matched your search
@@ -72,8 +72,9 @@ pub enum SetArg {
|
||||
/// What a command line asks for, with its arguments checked and typed.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Call {
|
||||
/// Open a document; no path reads the focused one again from its file.
|
||||
Edit {
|
||||
path: String,
|
||||
path: Option<String>,
|
||||
force: bool,
|
||||
},
|
||||
New(Option<Title>),
|
||||
@@ -240,7 +241,7 @@ fn build(spec: &Spec, bang: bool, args: &[Option<&str>], sources: &Sources) -> R
|
||||
let second = args.get(1).copied().flatten();
|
||||
let text = first.unwrap_or_default();
|
||||
Ok(match spec.id {
|
||||
Id::Edit => Call::Edit { path: text.to_string(), force: bang },
|
||||
Id::Edit => Call::Edit { path: first.map(str::to_string), force: bang },
|
||||
Id::New => Call::New(first.map(title).transpose()?),
|
||||
Id::Write => Call::Write,
|
||||
Id::WriteAll => Call::WriteAll,
|
||||
@@ -479,7 +480,7 @@ mod tests {
|
||||
assert_eq!(call("x"), Ok(Call::WriteQuit));
|
||||
assert_eq!(
|
||||
call("e notes/garden.cum"),
|
||||
Ok(Call::Edit { path: "notes/garden.cum".into(), force: false })
|
||||
Ok(Call::Edit { path: Some("notes/garden.cum".into()), force: false })
|
||||
);
|
||||
assert_eq!(call("vs outline"), Ok(Call::VSplit(Some(ViewKind::Outline))));
|
||||
assert_eq!(call("in buy a rain barrel"), Ok(Call::Capture("buy a rain barrel".into())));
|
||||
@@ -517,7 +518,7 @@ mod tests {
|
||||
assert_eq!(message(""), "type a command, like :help");
|
||||
assert_eq!(message("folx open"), "there's no command :folx; did you mean :fold?");
|
||||
assert_eq!(message("w!"), ":write doesn't take a !");
|
||||
assert_eq!(message("e"), ":e[dit][!] <file>: the file is missing");
|
||||
assert_eq!(message("b"), ":b[uffer] <document>: the document is missing");
|
||||
assert_eq!(message("fold up"), "\"up\" isn't a way to fold: use open, auto, closed");
|
||||
assert_eq!(message("fold open now"), ":fo[ld] <open|auto|closed>: \"now\" is more than it takes");
|
||||
assert_eq!(message("color corla"), "\"corla\" isn't a color: use red, orange, teal");
|
||||
|
||||
Reference in new issue
Block a user