Add the command line: commands, completion, ghost text and history

`:` opens a vim-style command line. Every command is described once, in
a typed table (name, the short form that still works, aliases, a `!`,
its arguments and what it does), so parsing, completion and the help can
never disagree. Short forms work as in vim (`:e`, `:vs`, `:q!`, `:x`),
and a test checks that no typed name can mean two commands.

Parsing turns a line into a typed Call, checking every argument against
what the app offers (open documents, nodes, colors, styles, settings),
or says what's wrong in words: the usage when an argument is missing,
the choices when a word isn't one, "did you mean :fold?" for a typo.
Documents and nodes match fuzzily (`:b gpl` finds Garden plans).

While typing, a popup above the word lists what can finish it (command
names by prefix, choices, files from the folders on disk, documents and
nodes fuzzily), with Tab and Shift-Tab putting them in the line. Ghost
text after the cursor comes from the history first, like fish's, then
from the best candidate; → or Ctrl-e takes it. Up and Down browse the
lines that start with what was typed. The line itself is a small input
that steps over whole characters, accents and emoji included.

The canvas example opens it with `:` and runs a handful of commands:
:fold, :color, :border, :tag, :focus, :rename, :in (to an Inbox),
:link, :unlink, :find, :version and :q.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
skkeyeandClaude Opus 5.5 committed 2026-10-01 03:53:51 -04:00
1 parent c2e62de172
commit bfc184f5ef
14 files changed
+2094 -11

No files matched your search

+27
View File
@@ -2,3 +2,30 @@
//! all share; for now there's the canvas.
pub mod canvas;
/// The kinds of view a pane can show.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ViewKind {
/// The 2D map.
Canvas,
/// The tree as an indented list.
Outline,
/// One node at full size, to write in.
Note,
/// Columns by tag or by color.
Board,
}
impl ViewKind {
pub const ALL: [ViewKind; 4] = [ViewKind::Canvas, ViewKind::Outline, ViewKind::Note, ViewKind::Board];
/// The view's name, as the status bar and the command line say it.
pub fn name(self) -> &'static str {
match self {
ViewKind::Canvas => "canvas",
ViewKind::Outline => "outline",
ViewKind::Note => "note",
ViewKind::Board => "board",
}
}
}