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]>
This commit is contained in:
1 parent
6eedbe0ce2
commit
84aefbecdb
31 files changed
+3289
-341
No files matched your search
@@ -91,8 +91,13 @@ lines.
|
||||
deletes this node and the next two, with their branches, as vim's `3dd`
|
||||
takes three lines. Which-key says how many as you type (`2d3`: 6 nodes).
|
||||
- Rapid entry is what happens after `o`, `O` or `a`: Enter starts the next
|
||||
sibling, Tab / Shift-Tab indent and outdent it, Enter on an empty line stops.
|
||||
Esc switches to vim motions inside the text; a second Esc leaves.
|
||||
sibling, Tab / Shift-Tab indent and outdent the idea being typed, and Enter
|
||||
on an empty idea stops (the empty idea goes away). Esc switches to vim keys
|
||||
inside the text; a second Esc leaves. Inside a title, `o` and `O` start a
|
||||
new sibling too.
|
||||
- `>>` puts the node under the one above it, as its last child; `<<` takes it
|
||||
out a level, right after its old parent. Both place the node below its new
|
||||
neighbors, and keep its branch with it.
|
||||
- `C` (connect mode) edits the connection to another node. Aimed at your own
|
||||
parent, it styles or cuts the branch line; cutting makes the node loose.
|
||||
- `M` (move mode) moves the branch; `M` again switches to just the node.
|
||||
@@ -104,6 +109,36 @@ lines.
|
||||
bar shows key hints, and `?` opens searchable help.
|
||||
- Keys can be changed in `keys.toml`, in vim notation.
|
||||
|
||||
**Editing text** (settled in stage 6)
|
||||
- A title is typed right in its box on the canvas (zoomed to Normal while it's
|
||||
edited). The box grows with the text, the terminal's cursor sits in it, and
|
||||
the border takes the insert color while you type.
|
||||
- The cursor's shape follows the mode, as in vim: a bar while typing (and in
|
||||
the command line), a block on the letter with vim keys, and the terminal's
|
||||
own shape elsewhere.
|
||||
- The document follows the text as you type, so every view stays current. The
|
||||
whole edit is one undo step (in rapid entry, one per idea); inside the text,
|
||||
`u` and `Ctrl-r` undo and redo the edit's own changes.
|
||||
- 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
|
||||
the system clipboard.
|
||||
- `.` inside the text repeats the last change there, typing included. `.` on
|
||||
nodes comes with node yank and paste, in stage 8.
|
||||
- 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.
|
||||
- Tab and Shift-Tab only move a new idea; on an existing title they say that
|
||||
`>>` and `<<` do it.
|
||||
- The mouse while editing: a click in the text moves the text cursor; a click
|
||||
anywhere else keeps the text, finishes the edit and does what a click does; a
|
||||
double-click on a title starts editing at that letter.
|
||||
- A portal's title is its document's name, so it isn't edited in place: rename
|
||||
that document instead.
|
||||
- The editor handles bodies (several lines) too, but they're edited in the Note
|
||||
view, in stage 7.
|
||||
|
||||
**Files and saving**
|
||||
- Documents are RON files ending in `.cum`. Configs are TOML: `config.toml`,
|
||||
`keys.toml` and `themes/<name>.toml`.
|
||||
@@ -228,18 +263,20 @@ backlinks, and the backlink paths in every document it points to.
|
||||
breadcrumb (or a message), and the keys typed so far (`2g` above).
|
||||
|
||||
**Mouse** (on the canvas; other views get click, double-click and scroll):
|
||||
click selects, double-click edits the title, dragging a node moves it with its
|
||||
branch, dragging empty space pans, scrolling pans, Ctrl+drag selects a
|
||||
rectangle, Ctrl+click adds or removes one node, right-click opens a menu built
|
||||
from the same actions as the keys. Zoom is on the `+` and `-` keys.
|
||||
click selects, double-click edits the title (from the letter clicked),
|
||||
dragging a node moves it with its branch, dragging empty space pans, scrolling
|
||||
pans, Ctrl+drag selects a rectangle, Ctrl+click adds or removes one node,
|
||||
right-click opens a menu built from the same actions as the keys. Zoom is on
|
||||
the `+` and `-` keys.
|
||||
|
||||
## Modes and keys
|
||||
|
||||
```rust
|
||||
enum Mode {
|
||||
Normal,
|
||||
Insert(TextEdit), // typing a title or body; rapid entry lives here
|
||||
TextNormal(TextEdit), // vim motions inside that text
|
||||
Text(TextEdit), // a title or body being edited: typing (INSERT) or vim
|
||||
// keys inside it (TEXT); the editor knows which, so the
|
||||
// two can't disagree. Rapid entry lives here too.
|
||||
Visual(Visual), // anchor + Rectangle or Branches
|
||||
Move(Grab), // a node or a branch being moved
|
||||
Connect(Connect), // the source node and the link being styled
|
||||
@@ -261,8 +298,8 @@ text).
|
||||
| **Modes** | `v` `V` visual · `M` move · `C` connect · `:` command · Esc back to normal |
|
||||
| **Leader** `<Space>` | `c` color · `s` style · `B` border · `t` tags · `p` new portal · `i` inbox · `b` documents · `v` then `c`/`o`/`n` for canvas / outline / note · `w` which-key on/off · `?` help |
|
||||
| **Panes, documents** | `Ctrl-w v` `Ctrl-w s` split · `Ctrl-w hjkl` focus · `Ctrl-w c` close · `Ctrl-w o` only · `Ctrl-w =` even sizes · `gt` `gT` `]b` `[b` next / previous document · `ZZ` close pane |
|
||||
| **Typing** | `Ctrl-w` delete word · `Ctrl-u` delete line · arrows, Home, End · Enter (title: done or next sibling; body: new line) · Tab Shift-Tab (new node: child / back out) · Esc to vim motions |
|
||||
| **Inside text** | `h j k l w b e 0 ^ $ f t x r J o O p P u Ctrl-r .` · `d` `c` `y` with motions and `iw aw i" a" i( a(` · `i a I A` back to typing |
|
||||
| **Typing** | `Backspace` `Delete` · `Ctrl-w` delete word · `Ctrl-u` delete line · arrows, Home, End · Enter (title: done, or after `o O a` the next idea; body: new line) · Tab Shift-Tab (a new idea: under the one above / out a level) · Esc to vim keys |
|
||||
| **Inside text** | `h j k l w b e 0 ^ $ gg G` (and arrows, Home, End) · `f t F T ; ,` · `d` `c` `y` with any motion and `iw aw i" a" i( a(` · `x X s S D C Y` · `r ~ J p P` · `u Ctrl-r .` · `i a I A` back to typing · `o O` (title: a new sibling; body: a new line) · Esc done |
|
||||
| **Move mode** | `hjkl` 1 cell · `HJKL` 5 cells · `M` branch ↔ node · Enter or Esc done |
|
||||
| **Connect mode** | move to the target as usual · Enter link · `d` remove · `>` attach as child · `<Space>` style menu (`s` named, `a` arrows, `l` line, `c` color, `t` label) · Esc cancel |
|
||||
| **Visual** | `d y > < M C` and `<Space>c` `<Space>s` `<Space>t` act on the whole selection · `o` swaps ends |
|
||||
@@ -340,7 +377,9 @@ glyphs = "unicode" # "ascii" for fonts without box-drawing characters
|
||||
completion_popup = "as-you-type" # "on-tab": only after Tab, like vim's wildmenu
|
||||
|
||||
# keys.toml: sections motions, normal, canvas, outline, note, visual, move,
|
||||
# connect, list; commands by name (src/input/command.rs); "nothing" unbinds
|
||||
# connect, list, text (vim keys inside text), insert (typing: one key each,
|
||||
# the others type themselves); commands by name (src/input/command.rs);
|
||||
# "nothing" unbinds
|
||||
leader = "<Space>"
|
||||
[normal]
|
||||
"<Space>x" = "delete-branch"
|
||||
@@ -399,13 +438,15 @@ cumulus/
|
||||
├─ command/ registry, parse, complete, history
|
||||
├─ view/ mod.rs (the View trait), canvas/ (camera, boxes, lines, route, scene, render,
|
||||
│ navigate, placement, view), outline, note, board
|
||||
├─ ui/ text_editor (+ vim normal), which_key, command_line, line_input, status_bar,
|
||||
│ document_bar, card, menu, picker, help, theme, glyphs
|
||||
├─ ui/ text_input (a line of text and its cursor), text_editor/ (vim inside text:
|
||||
│ motion, object, layout), which_key, command_line, theme, glyphs; later
|
||||
│ status_bar, document_bar, card, menu, picker, help
|
||||
├─ 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);
|
||||
later App, panes (split tree), jumps, registers, portals (cache, backlinks,
|
||||
renames), update, render, terminal (setup, teardown, panic hook)
|
||||
└─ app/ action, mode, buffer, commands (keys every view shares), calls (`:` commands),
|
||||
text_edit (a title being edited, rapid entry), registers; later App, panes
|
||||
(split tree), jumps, portals (cache, backlinks, renames), update, render,
|
||||
terminal (setup, teardown, panic hook)
|
||||
```
|
||||
|
||||
**Flow:** a terminal event comes in → the key engine turns keys into a typed
|
||||
@@ -418,8 +459,16 @@ document actions go to the document's `Buffer` (the only place a document
|
||||
changes: the edit, its undo step, the cursor and the marks), the rest change
|
||||
the mode or the app → the screen is drawn from the state.
|
||||
|
||||
While a title is edited, keys go to the edit (`app::text_edit`) instead: when
|
||||
typing, a key the `insert` table binds is a command (Enter, Tab, Backspace…)
|
||||
and any other key types itself; with vim keys, the key engine reads the `text`
|
||||
table, where operators take motions as targets too (`dw`, `c$`, `dfx`). The
|
||||
edit answers with actions like everything else.
|
||||
|
||||
Edits travel as data (`EditOp`), so views never touch the document. A `Group`
|
||||
makes several edits one undo step: a whole move-mode session, a mouse drag.
|
||||
makes several edits one undo step: a whole move-mode session, a mouse drag, a
|
||||
text edit, an idea in rapid entry. A group whose edits cancel out (an idea
|
||||
added, then left empty) leaves no step at all.
|
||||
|
||||
```rust
|
||||
trait View { // settled in stage 5
|
||||
@@ -488,5 +537,10 @@ one commit.
|
||||
- **Model:** tree rules, undo/redo round trips, folding.
|
||||
- **Canvas:** camera conversions, routing and junctions (small text snapshots),
|
||||
hit-testing, nearest-node moves.
|
||||
- **Text editing:** vim keys inside text driven key by key (motions, operators,
|
||||
text objects, `.`, undo), rapid entry, empty titles, registers.
|
||||
- **The example:** its tests drive the whole loop on a test terminal, keys and
|
||||
mouse in and the screen out, so what a stage says works is checked end to
|
||||
end.
|
||||
- **Files:** RON round trip, load errors, config parsing, and backlink and
|
||||
rename fix-ups, in temporary folders.
|
||||
Reference in new issue
Block a user