Commit Graph
7 Commits
Author SHA1 Message Date
skkeyeandClaude Opus 5.5 84aefbecdb Edit titles in their boxes, with vim keys inside the text
Titles are typed right in their boxes on the canvas: the box grows with
the text, the terminal's cursor sits in it (a bar while typing, a block
on the letter with vim keys), and the border turns the insert color.
`i`, `A` and Enter edit at the end, `I` at the start, `cc` and `S` type
the title anew. The document follows the text as it's typed, so the
layout stays current, and the whole edit is one undo step.

Esc gives vim's normal mode inside the text (TextEditor, in ui/): h l w
b e 0 ^ $, f t F T with ; and ,, the d c y operators with any of those
motions or the iw aw i" a" i( a( text objects, x X s S D C Y, r ~, p P,
counts, u and Ctrl-r for the edit's own changes, and `.` for the last
one, typing included. j k gg G and J work on lines, for bodies. It
follows vim where it's quirky too: cw acts like ce, dw stops at the end
of the line, Esc steps back onto the last letter. Keys have two new
tables, `text` and `insert`, and in text an operator takes motions as
targets (`dw`, `c$`, `2d3fx`), which which-key lists.

Rapid entry: after `o`, `O` or `a`, the new idea's title is typed at
once; Enter starts the next idea, Tab puts the one being typed under the
idea above, Shift-Tab takes it out a level, and Enter on an empty idea
stops. An idea left empty goes away without a trace in the undo history
(a group whose edits cancel out leaves no step); a title left empty
comes back as it was. Inside a title, `o` and `O` start a new sibling.

Registers are shared by the whole app, so text yanked in one title
pastes into another; `"a`-`"z` and `"_` work, and `"+` stays inside
cumulus until the app core connects the clipboard.

The mouse while editing: a click in the text moves the text cursor, a
click anywhere else keeps the text and finishes the edit, and a
double-click on a title starts editing at that letter.

`>>` and `<<` now move nodes: under the node above, as its last child,
or out a level, right after the old parent, with counts taking in the
next siblings.

The command line's input became TextInput, line-aware so the editor can
use it for bodies too; bodies themselves get edited in the Note view.
The example's tests type every key above into the app and check the
text and the cursor after each one against what vim does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 17:45:40 -04:00
skkeyeandClaude Opus 5.5 6eedbe0ce2 Pull the view interface, actions and modes out of the canvas example
The canvas example did everything itself; now it runs the way the app
will. The key engine turns keys into commands, the focused view answers
with actions, and the commands every view shares (undo, marks, adding,
deleting, folds, tree moves, modes) answer the rest. A view can still
give a key its own meaning, since it gets the first say. `:` lines become
actions the same way (app::calls).

- View trait: kind, contexts (its key tables), layout, render, command
  and mouse. layout comes before render because a view keeps the frame
  it drew, to match clicks against, and follows the cursor with its
  camera; drawing changes nothing. CanvasView owns the camera, the last
  scene and the mouse drag; it reads the rest from a ViewContext.
- Edits travel as data (EditOp), so views never touch the document.
  Buffer::apply is the one place a document changes: the edit, its undo
  step, where the cursor goes, marks and `''`.
- Mode holds each mode's own state: move mode carries its Grab (whole
  branch or not), the command line lives in Mode::Command.
- Undo groups: a whole move-mode session or mouse drag is one undo step,
  built up as it goes. After an undo the cursor lands on a node the
  change added or removed, before the others it touched.
- Actions run in order, and a problem stops the rest.

Small improvements on the way: zz centers the middle of the node, :find
says which match it's on, :unlink with no links says so, folding a node
without children says why nothing happened, and a captured idea is
placed next to a new Inbox even on the first :in.

The example has end-to-end tests now: they type key sequences and mouse
gestures into it on a test terminal, and `cargo test` runs them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 04:46:05 -04:00
skkeyeandClaude Opus 5.5 57ba2c275d Make marks and counts work, and the completion popup a setting
Marks: the engine read `ma` and `'a`, but the canvas example only said
they'd come later. It now sets and jumps to marks, and `''` goes back to
where the cursor was before the last jump (a mark, gg, G or :find).
Which-key lists `'` after `'`.

Counts on operators now mean something on nodes: `3dd` deletes this node
and the next two siblings, with their branches, the way vim's `3dd`
deletes three lines (Document::siblings_from). Counts before the operator
and before the target still multiply, and which-key now says what they
add up to: after `2d3`, the `d` entry reads "6 nodes: this one and the
next 5 siblings, with their branches".

The completion popup can now wait for Tab, like vim's wildmenu: the
`completion_popup` setting is "as-you-type" (the default) or "on-tab".
The config file comes with the app core; until then the example takes
`:set completion_popup=on-tab`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 04:17:41 -04:00
skkeyeandClaude Opus 5.5 c2e62de172 Add the key engine, which-key and keys.toml
Keys now work the way vim reads them. A key press becomes a Key (with vim
notation for writing keys: `<C-w>v`, `<leader>c`, `<<`), and the engine
collects counts (`12j`), registers (`"+p`), sequences (`gg`), operators
with their targets (`dd`, `dab`, `2d3d` multiplies to 6) and keys that take
a character (`ma`, `'A`), then hands over a typed Command. Every command
has a name and a help text in one table, and the default keys live in one
table per place they work (motions, normal, canvas, visual, move, connect,
lists).

keys.toml changes keys per section, with the leader configurable and
"nothing" to unbind. Each mistake is skipped and reported in words, with a
suggestion for mistyped command names, and a key that would hide a longer
one is reported too. The which-key popup reads the same tables: it shows
what can follow the keys typed so far, in skyshift's look and place, with
the leader menu instant and other prefixes after 300 ms. The mouse reader
turns button events into presses, double-clicks, drags and scrolls.

`Direction` moved from the glyphs to the model, since input needs it too.
The canvas example now runs on all of this, with a two-line keys.toml of
its own that makes `q` quit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 01:54:06 -04:00
skkeyeandClaude Opus 5.5 e097e53a85 Make branch lines take their parent's color
A node's color now flows down the lines to its children, mind-map style:
Watering's teal colors the lines to Rain barrel and Drip line. It used to
color the line from the root down to Watering itself, which also left the
shared bus of a parent's branches in whichever child's color was drawn
last. Branches follow their parent by default, and stay dim when the
parent has no color.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 01:40:24 -04:00
skkeyeandClaude Opus 5.5 3b58d6494d Add the canvas engine and a canvas playground example
The canvas draws a frame in three steps. Scene::build works out what's
shown and where: folding decides which nodes show, boxes are sized from
their wrapped titles (with tags and a +N badge in the bottom border), the
camera turns canvas positions into screen cells, and every branch and
cross-link gets a right-angle route. The line layer records which arms
meet in each cell, so borders and lines join with the right box-drawing
character (├ ┼ ┨ ╭), in any mix of light, thick, double, dashed and dotted.
Rendering then writes lines, arrowheads and labels, and the nodes on top.

Branches leave sideways and bend near their parent, so siblings share one
bus; cross-links take the wider gap and carry their label on the longest
level run. Far zoom keeps the full width and halves the height (one line
per node), Overview shows dots. hjkl picks the nearest node within 45° of
the direction, and new nodes find a free spot next to their parent or
sibling. The theme works out looks in layers (default, tag style, named
style, the node's own), with a mid-tone palette for dark and light
terminals, and an ASCII fallback for fonts without box drawing.

`cargo run --example canvas` opens a sample document to move around,
zoom, fold, edit and drag with the mouse. The tests compare rendered text
against the DESIGN.md mockup.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 01:17:38 -04:00
skkeyeandClaude Opus 5.5 0e03c396bf Add the project skeleton and the approved design
Cargo.toml with the release profile and lints, the toolchain pinned to
Rust 1.90.0, a build script that records the git commit for
`cumulus --version`, and rustfmt settings and cargo aliases (`cargo lint`,
`cargo linux`) as in skyshift. DESIGN.md holds the design approved after
the question rounds; README.md has build instructions and the planned keys.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 00:42:28 -04:00