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
@@ -122,10 +122,10 @@ lines.
|
||||
- A title left empty comes back as it was, with a note saying so; a new idea
|
||||
left empty goes away.
|
||||
- Registers are shared by the whole app, as in vim: text yanked in one title
|
||||
pastes into another. `"+` stays inside cumulus until stage 8 connects it to
|
||||
pastes into another. `"+` stays inside cumulus until part 8c connects it to
|
||||
the system clipboard.
|
||||
- `.` inside the text repeats the last change there, typing included. `.` on
|
||||
nodes comes with node yank and paste, in stage 8.
|
||||
nodes comes with node yank and paste, in part 8c.
|
||||
- As in vim: `cw` changes to the end of the word, `dw` stops at the end of the
|
||||
line, `j` and `k` move by lines of text rather than wrapped rows, Esc steps
|
||||
back onto the last letter typed.
|
||||
@@ -189,15 +189,32 @@ lines.
|
||||
keys and clicks go to them, a click outside a list closes it, and they stay
|
||||
above the status bar.
|
||||
|
||||
**Files and saving**
|
||||
**Files and saving** (settled in part 8a)
|
||||
- Documents are RON files ending in `.cum`. Configs are TOML: `config.toml`,
|
||||
`keys.toml` and `themes/<name>.toml`.
|
||||
- Autosave about a second after a change (`autosave = false` for vim-style
|
||||
`:w`). A file changed outside cumulus is reloaded; if you also had unsaved
|
||||
changes, cumulus asks which to keep. Daily backups go to the data folder.
|
||||
- Autosave a second after the latest change, so typing isn't saved letter
|
||||
by letter (`autosave = false` for vim-style `:w`). Undoing back to what's
|
||||
on disk counts as no change. The document bar marks unsaved changes `[+]`.
|
||||
Quitting saves first; without autosave, `:q` with unsaved changes refuses
|
||||
(`:q!` drops them), and `ZZ` saves, then closes, as in vim.
|
||||
- Every second, cumulus looks at each file's time and size. A file changed
|
||||
outside cumulus is read again as an undo step (`u` brings back what was on
|
||||
screen); never under a text being edited or a node being moved, which it
|
||||
waits for. If you also had unsaved changes, cumulus asks which to keep
|
||||
(Esc: later; `:w` keeps yours, `:e!` takes the file's). A file with a
|
||||
mistake in it (a hand edit half done) stops autosave until it's fixed or
|
||||
`:w` saves over it; a deleted or moved file waits for `:w` to write it
|
||||
again.
|
||||
- The day's first save copies the file to the data folder's backups first
|
||||
(`backups/<uid>/2026-10-01.cum`, the last 30 days kept).
|
||||
- A document open in another cumulus opens read-only (`[RO]` in the bar)
|
||||
until that one lets go of it. The lock is the operating system's lock on
|
||||
a file in the data folder, so a crash never leaves one behind.
|
||||
- Undo per document, while cumulus runs: one step per command, per
|
||||
text-editing session, and per node in rapid entry.
|
||||
- Each document reopens where you left it (cursor, zoom, scroll).
|
||||
- Each document reopens where you left it: the cursor, and the canvas's
|
||||
zoom and scroll. The documents picker (`<Space>b`) lists the documents
|
||||
opened lately after the open ones.
|
||||
|
||||
**Screen**
|
||||
- Vim-style splits; panes on the same document share one cursor.
|
||||
@@ -419,9 +436,9 @@ document has a portal pointing here.
|
||||
)
|
||||
```
|
||||
|
||||
**Config** (TOML) lives in `%APPDATA%\cumulus` (`~/.config/cumulus` on Linux);
|
||||
`cumulus --paths` prints the folders. `:config` writes these files with a
|
||||
comment on every option, and cumulus reloads them when they change.
|
||||
**Config** (TOML) lives in `%APPDATA%\cumulus\config` (`~/.config/cumulus` on
|
||||
Linux); `cumulus --paths` prints the folders. `:config` writes these files with
|
||||
a comment on every option, and cumulus reloads them when they change.
|
||||
|
||||
```toml
|
||||
# config.toml
|
||||
@@ -467,15 +484,20 @@ label = "blocks"
|
||||
question = "question" # a #question node gets the "question" style
|
||||
```
|
||||
|
||||
**Data folder:** where you left off in each document (keyed by `uid`), command
|
||||
history, capital marks, recent documents, daily backups, and lock files. If a
|
||||
second cumulus opens a document that's already open, it opens it read-only.
|
||||
**Data folder** (`%APPDATA%\cumulus\data`, `~/.local/share/cumulus` on Linux):
|
||||
`memory.ron` (where you left off in each document, keyed by `uid`, the command
|
||||
history, recent documents; capital marks come in part 8c), `backups/` and
|
||||
`locks/`. If a second cumulus opens a document that's already open, it opens
|
||||
it read-only.
|
||||
|
||||
**Command line**
|
||||
- `cumulus` opens `./ideas.cum`, or `~/ideas.cum` if the current folder doesn't
|
||||
have one.
|
||||
- `cumulus garden.cum` opens that file; `cumulus some/folder` opens that
|
||||
folder's default document.
|
||||
have one. When neither exists, it starts a new `~/ideas.cum` (written once
|
||||
something is added): one ideas document for everywhere (the user's pick in
|
||||
part 8a).
|
||||
- `cumulus garden.cum` opens that file (a new document if there's no such
|
||||
file yet, as `:e` does); `cumulus some/folder` opens that folder's default
|
||||
document. Several can be named; the first one shows.
|
||||
- `cumulus new` creates `./ideas.cum`, and `cumulus new "Garden plans"` creates
|
||||
`./garden-plans.cum`. If the file already exists, cumulus opens it and says so.
|
||||
- `cumulus --paths`, `--version` and `--help`.
|
||||
@@ -486,7 +508,7 @@ second cumulus opens a document that's already open, it opens it read-only.
|
||||
cumulus/
|
||||
├─ Cargo.toml rust-toolchain.toml build.rs rustfmt.toml .cargo/config.toml
|
||||
├─ README.md DESIGN.md .gitignore .gitattributes
|
||||
├─ examples/ runnable checkpoints during the build (canvas.rs, …)
|
||||
├─ examples/ the playground: cumulus on copies of two sample documents (canvas.rs)
|
||||
└─ src/
|
||||
├─ main.rs command-line arguments, then app::run
|
||||
├─ lib.rs the module list
|
||||
@@ -501,15 +523,23 @@ cumulus/
|
||||
│ motion, object, layout), list (the popup list help, menus and pickers
|
||||
│ share), card (the K card), status_bar, document_bar, which_key,
|
||||
│ command_line, theme, glyphs
|
||||
├─ config/ paths, settings, keys_file, theme_file (TOML)
|
||||
├─ storage/ document_file (RON), atomic save, backups, lock, state, watch (change polling)
|
||||
└─ app/ action, mode, buffer, commands (keys every view shares), calls (`:` commands),
|
||||
text_edit (a node's text being edited, rapid entry), registers, panes (the
|
||||
split tree), popup (help, menu, pickers, card); later App, jumps, portals
|
||||
(cache, backlinks, renames), update, render, terminal (setup, teardown,
|
||||
panic hook)
|
||||
├─ config/ paths (the config and data folders), settings (and `:set`); later keys_file,
|
||||
│ theme_file (TOML)
|
||||
├─ storage/ document_file (RON), write_atomically, names (file names from titles), backup,
|
||||
│ lock, stamp (noticing changes made outside), memory (memory.ron)
|
||||
└─ app/ mod.rs (App), input (keys and the mouse, routed), update (carrying actions out),
|
||||
render, terminal (the main loop, setup, teardown, panic hook), startup (what
|
||||
`cumulus` opens), documents (the open documents and their files), files
|
||||
(saving, reloading, locks, where you left off), action, mode, buffer, commands
|
||||
(keys every view shares), calls (`:` commands), text_edit (a node's text being
|
||||
edited, rapid entry), registers, panes (the split tree), popup (help, menu,
|
||||
pickers, card, questions); later jumps, portals (cache, backlinks, renames)
|
||||
```
|
||||
|
||||
The end-to-end tests are in `app/tests.rs` (and `app/tests/files.rs`): they
|
||||
copy the sample documents to a temporary folder, type keys and click on a test
|
||||
terminal, and check the screen, the documents and the files.
|
||||
|
||||
**Flow:** a terminal event comes in → the key engine turns keys into a typed
|
||||
`Command` (with its count and register) → the focused view answers it with
|
||||
`Action`s, and `app::commands::shared` answers the commands the view leaves
|
||||
@@ -550,6 +580,9 @@ trait View { // settled in stage 5
|
||||
// Added in stage 7, with defaults:
|
||||
fn status(&self) -> String; // its name in the status bar
|
||||
fn cursor_area(&self, ctx: &ViewContext) -> Option<Rect>; // where the K card goes beside
|
||||
// Added in part 8a, with defaults (only the canvas has a camera):
|
||||
fn camera(&self) -> Option<Camera>; // kept with the document
|
||||
fn set_camera(&mut self, camera: Camera); // where you left off
|
||||
}
|
||||
// ViewContext: the document, the cursor, the mode, the theme and the view settings.
|
||||
```
|
||||
@@ -576,11 +609,16 @@ it.
|
||||
| 5 | The shared `View` interface, `Action` and `Mode`, pulled out of stages 2–4 | the example runs through it |
|
||||
| 6 | Text editor: typing, plus vim normal mode inside text | editing titles in the example |
|
||||
| 7 | Outline and Note views; splits (the split tree); status bar, document bar, help, `K` card, right-click menu, pickers (documents, colors, borders, styles, tags) | the example with splits and two documents |
|
||||
| 8 | App core: main loop, terminal setup and panic hook, buffers and panes (from the example into the app), visual and connect modes, jumps, marks, registers, files (load, autosave, reload, backups, locks, where you left off), config/theme/keys, portals, backlinks and renames, startup rules | `cumulus`: v1 |
|
||||
| 8a | App core: the main loop, terminal setup and panic hook, buffers and panes (from the example into the app), files (load, autosave, reload, backups, locks, where you left off), the startup rules and `cumulus new`, `:set` | `cumulus` |
|
||||
| 8b | Settings: config.toml, keys.toml, themes (named styles, styles by tag), `:theme`, `:config` | |
|
||||
| 8c | The rest of vim: visual mode, node yank and paste with registers (`"+`: the clipboard), `.` on nodes, `/` `n` `N`, the jump list, capital marks, `gd` | |
|
||||
| 8d | Connect mode, portals, backlinks, file names that follow the root's title | v1 |
|
||||
| 9 | v1.1: Board, Search picker, `:tidy` and align, branch out, export/import | |
|
||||
|
||||
Each stage ends with `cargo build`, `cargo lint` and `cargo test` passing, and
|
||||
one commit.
|
||||
one commit. Stage 8, as big as stages 5 to 7 together, comes in four parts
|
||||
with a commit each, and a pause after each for the user to try it (their
|
||||
choice).
|
||||
|
||||
## Crates and tooling
|
||||
|
||||
|
||||
Reference in new issue
Block a user