pub struct Model<B> {
pub rows: Vec<Row>,
pub mode: Mode,
pub status: String,
pub dirty: bool,
/* private fields */
}Fields§
§rows: Vec<Row>§mode: Mode§status: StringThe last thing that happened worth saying out loud — almost always a
refusal (rejected: ..., only mapping keys can be renamed).
Empty until something happens. A frontend draws this in whatever it uses for a status line, and an empty string is what lets it draw nothing: a bar that opens holding a word nobody asked for teaches the reader to stop reading it, which is the one thing a refusal channel cannot afford.
dirty: boolImplementations§
Source§impl<B: Backend> Model<B>
impl<B: Backend> Model<B>
Build a model that hides the given top-level mapping keys from the row
projection while keeping them in the document (see
tree::build_rows). For an embedder whose
format reserves some top-level keys (prov/diaryx-managed frontmatter).
Sourcepub fn with_managed(
backend: B,
hidden: Vec<String>,
derived: Vec<String>,
) -> Result<Self>
pub fn with_managed( backend: B, hidden: Vec<String>, derived: Vec<String>, ) -> Result<Self>
Build a model over backend distinguishing the two kinds of managed key:
hidden ones produce no row (edited through another affordance), while
derived ones keep their row but decline every edit (the workspace
maintains them — see derived).
A key in both is hidden: no row means nothing to mark read-only.
Sourcepub fn with_collapsed(
backend: B,
hidden: Vec<String>,
derived: Vec<String>,
collapsed: Vec<Vec<Seg>>,
) -> Result<Self>
pub fn with_collapsed( backend: B, hidden: Vec<String>, derived: Vec<String>, collapsed: Vec<Vec<Seg>>, ) -> Result<Self>
Build a model whose containers at collapsed arrive shut, before the
first row list is ever built.
A document can have one field nobody reads as a list: an index document’s
contents is one row per child — ninety-five of them in a year index,
ahead of the four fields anyone types by hand. Such a section wants to open
as a summary, not a wall you scroll past. Toggling it afterwards through
activate would work, but that is the interactive
door: it moves the selection and rebuilds the row list once per container.
Seeding the set here costs neither — the paths are in place before
reload, so the opening frame is already correct.
A path that names a scalar (or nothing at all) is inert rather than an error, so a caller can name the keys it wants collapsed without first checking which of them turned out to be containers.
Sourcepub fn set_demoted(&mut self, keys: Vec<String>)
pub fn set_demoted(&mut self, keys: Vec<String>)
Name the top-level keys the page projection sinks below the rest.
Out-of-band like set_schema, and for the same
reason: it is presentation the embedder knows and the document does
not. A diaryx host knows part_of is drawn by the sidebar and id by
nothing at all; the fig-backed model reading the same frontmatter has no
way to tell either from a field somebody typed.
Adds to the derived keys already demoted rather than replacing them, so a
caller names only what the constructor did not. Rebuilds the pages, so
the next page already reflects it.
Root keys, matched exactly. A path is demoted when its first segment is one of these, so naming a container demotes everything under it.
Sourcepub fn set_inline_budget(&mut self, budget: InlineBudget)
pub fn set_inline_budget(&mut self, budget: InlineBudget)
Set how much of a container’s subtree the page projection inlines rather than drills.
Out-of-band like set_demoted, and for the same
reason: the right amount is a fact about the room the pages are drawn
in — a frontmatter panel wants the whole document on one page, a narrow
pane over a deep config wants a page per level — and only the embedder
knows which it is. Rebuilds the pages, so the next
page already reflects it.
The cursor stays on the row it was on, by path rather than by index — a budget is the one setting that changes how many rows a page has, so the index under the cursor is exactly what it invalidates. Raising the budget far enough turns row three of a list into the third field of its first entry, and a reader who resized a window did not ask to be moved.
Sourcepub fn inline_budget(&self) -> InlineBudget
pub fn inline_budget(&self) -> InlineBudget
The inline budget the page projection is currently built with.
Sourcepub fn fit_to_room(&mut self, room: usize)
pub fn fit_to_room(&mut self, room: usize)
Set the inline budget from the room a page actually has
(InlineBudget::fitting) — room being how many rows a frontend can
draw items into, once its own chrome has taken what it needs.
set_inline_budget is the embedder deciding;
this is the embedder measuring, which is the same decision made against
the one fact that turns out to settle it. A frontend that can be resized
calls this whenever the room changes, which is cheap to do every frame:
the pages are rebuilt only when the answer moves.
Sourcepub fn enter_document(&mut self)
pub fn enter_document(&mut self)
Open the document at the first page that says something.
A document whose root holds one container — {repo: [...]}, and every
file that is one list under one key — has a root page with a single drill
row on it, naming the thing you are obviously about to open. That is the
same page PageItem::descend_to exists to skip, arrived at from
outside rather than from a row, and the reasons match: it costs a
navigation step to be told the name of the file you just opened.
Called once, by the frontend, after the budget is set — it is a decision
about where to start, not a property of the projection, and re-running
it on every rebuild would take the root page away from a reader who had
pressed h to reach it. Nothing is lost either way: the root page is one
step out, and the row’s own ops are the ops of the container this lands
in.
Sourcepub fn is_demoted(&self, path: &[Seg]) -> bool
pub fn is_demoted(&self, path: &[Seg]) -> bool
Whether the node at path sits under a demoted top-level key — the
page projection’s own is_derived.
Sourcepub fn set_schema(&mut self, schema: Schema)
pub fn set_schema(&mut self, schema: Schema)
Inject a schema out-of-band — the embedder precedent, mirroring
with_hidden. For a host whose backend does not
supply one but that knows the governing schema (a diaryx host feeding a
fig-backed frontmatter block plus its resolved workspace config).
Sourcepub fn rule_at(&self, path: &[Seg]) -> Option<&FieldRule>
pub fn rule_at(&self, path: &[Seg]) -> Option<&FieldRule>
The schema rule governing the node at path, if any — for a frontend
deciding a widget (a picker for an enum field) or presentation.
Sourcepub fn set_annotations(&mut self, annotations: Vec<Annotation>)
pub fn set_annotations(&mut self, annotations: Vec<Annotation>)
Hand the model the host’s findings about this document, replacing
whatever it was given last — a broken link, a duplicate id, a rule only
a workspace can check (annotate).
Out-of-band like set_schema and
set_demoted, and for the same reason: flower-core
is one document with no filesystem, so it can never compute one of
these. They are re-attached to the rows on every rebuild, so an edit
does not wipe the markers out from under a reader — but nothing here
re-checks them either, so a host refreshes after a save (or whenever its
own check finishes) by calling this again. An empty list clears them.
Sourcepub fn annotations(&self) -> &[Annotation]
pub fn annotations(&self) -> &[Annotation]
The findings the host last supplied, in the order it gave them.
Sourcepub fn annotation_at(&self, path: &[Seg]) -> Option<&Annotation>
pub fn annotation_at(&self, path: &[Seg]) -> Option<&Annotation>
The finding that applies at path: the one addressed exactly at it, or
failing that the one at its nearest annotated ancestor.
The inheriting answer, for a caller asking about a node — an item of a
list is in trouble when the list is. The rows carry the exact answer
instead (PageItem::annotation), because
a marker that came down a subtree would point at every row but the one
that is wrong.
Sourcepub fn root_kind(&self) -> &'static str
pub fn root_kind(&self) -> &'static str
The kind of the document root, for a frontend deciding how to add a
top-level entry: "map", "seq", or "scalar".
How many of the hidden top-level keys are actually present in the document — for a “N managed fields” affordance.
Sourcepub fn is_derived(&self, path: &[Seg]) -> bool
pub fn is_derived(&self, path: &[Seg]) -> bool
Whether the node at path sits under a workspace-maintained (derived)
top-level key — for a frontend rendering it read-only rather than as an
editable control. Edits to it are declined at the commit funnel regardless.
Sourcepub fn addable_fields(&self) -> Vec<&FieldRule> ⓘ
pub fn addable_fields(&self) -> Vec<&FieldRule> ⓘ
The schema-declared top-level fields the document does not yet carry — what an “add field” affordance offers, so a declared field is reachable before it exists.
Rows are projected from the document
(build_rows), so a field the schema declares
but the document omits has no row and is otherwise unreachable: the user
would have to know the key and type it exactly. This closes that gap —
it is the schema’s half of the row list, and the reason a declared type
is worth writing down for a field that is empty.
Only a rule addressing exactly one top-level key names an addable field: an each-item or subtree rule governs within a field rather than naming one. Hidden (managed) keys are never offered — the embedder reserves those. Order follows the schema’s own rule order, so a caller can present them as declared.
Sourcepub fn source_snapshot(&self) -> String
pub fn source_snapshot(&self) -> String
The canonical serialized document — what the embedder writes on save.
Sourcepub fn backend(&self) -> &B
pub fn backend(&self) -> &B
The backend, for backend-specific reads (e.g. a prov backend’s body).
Sourcepub fn backend_mut(&mut self) -> &mut B
pub fn backend_mut(&mut self) -> &mut B
The backend, for backend-specific operations that do not change the metadata tree flower renders (e.g. replacing a prov document’s prose body). An op that does change the metadata leaves the view stale — go through the model’s own edit methods for those.
pub fn set_status(&mut self, s: impl Into<String>)
Sourcepub fn mark_saved(&mut self)
pub fn mark_saved(&mut self)
Clear the dirty flag after the embedder has persisted the source.
Moves the baseline dirty is measured against to the
bytes just written, and leaves the journal alone: a save is not a
history boundary, so undo still runs back through it — and undoing to
the saved text reads as clean again, because the flag is a comparison
and not a count.
Sourcepub fn item_key(&self, seq_path: &[Seg], index: usize) -> Option<String>
pub fn item_key(&self, seq_path: &[Seg], index: usize) -> Option<String>
A stable identity for item index of the sequence at seq_path, or
None when nothing can name it.
The backend first (Backend::item_key) — it is the component that may
have a real identity to hand — and otherwise the projection’s own guess:
a mapping item is named by whichever of its fields best names it on a
page (page::title_keys/page::title_of, the same answer the row
already shows), and a scalar item by its own text. Neither is guaranteed
unique, which is why every use of this treats a repeat as “the first
one”: a list of five identical strings has nothing to tell its items
apart with, and behaving as though it did would be worse than falling
back to the index.
Public because a host holding an id of its own — a navigation stack, a breadcrumb — needs the same answer the model re-resolves against.
Sourcepub fn selected_path(&self) -> Option<Vec<Seg>>
pub fn selected_path(&self) -> Option<Vec<Seg>>
The path of whatever is selected in the active view.
The seam that lets one set of edit operations serve both projections: an
edit is a path plus a value, and which list the user picked that path from
is not something commit should have to know.
Sourcepub fn select_row(&mut self, index: usize)
pub fn select_row(&mut self, index: usize)
Put the tree cursor on index, clamped to the row list.
Switches to the tree projection first, and that is the point of the
method rather than a side effect. A row index is a coordinate in the row
list a caller last rendered; it names nothing on a page. A host driving
both surfaces — a metadata pane beside a settings page — would otherwise
hand a row index to a model still standing in the page projection, where
the very next delete_selected reads the page
cursor and quietly removes a different node.
So the vocabularies assert. Every method that establishes a cursor names
the projection its coordinates belong to (page_enter
and the rest do the same for pages), and the methods that merely read a
cursor stay neutral — a delete deletes what is selected, in whichever view
the user is actually looking at.
A no-op when the model is already in the tree.
pub fn move_down(&mut self)
pub fn move_up(&mut self)
Sourcepub fn expand_or_enter(&mut self)
pub fn expand_or_enter(&mut self)
l: expand a collapsed container, else step into its first child.
Sourcepub fn collapse_or_leave(&mut self)
pub fn collapse_or_leave(&mut self)
h: collapse an expanded container, else step out to the parent row.
Sourcepub fn set_view(&mut self, view: ViewMode)
pub fn set_view(&mut self, view: ViewMode)
Switch projection, carrying the cursor across so the node you were on in one view is the node you are on in the other.
Without that, switching would be a jump cut: you fold down to one key in the tree, switch to pages, and land at the top of the root page with no idea where your key went. Carrying the selection makes the two views two ways of looking at one position, which is the only reading under which having both is worth it.
Sourcepub fn toggle_view(&mut self)
pub fn toggle_view(&mut self)
Toggle between the tree and the page view.
Sourcepub fn parent_page(&self) -> &Page
pub fn parent_page(&self) -> &Page
The page one level out — what a two-pane frontend draws on the left. Empty
when focus is the root, which has no parent.
Sourcepub fn focus(&self) -> &[Seg]
pub fn focus(&self) -> &[Seg]
The container the page view is listing. Empty is the document root.
Sourcepub fn page_selected(&self) -> usize
pub fn page_selected(&self) -> usize
The index of the selected item on page.
Sourcepub fn pages_would_degenerate(&self) -> bool
pub fn pages_would_degenerate(&self) -> bool
Whether a two-pane layout would waste one pane on this document.
A document whose root has nothing to drill into — a flat list of keys, a sequence of scalars, anything a generous budget has poured onto one page — has no navigation to put in a sidebar, and splitting the width for it would cost half the room and buy nothing. A frontend checks this to fall back to a single full-width pane.
The second case is the same waste one level along: when the page the
cursor is on is the one that leads the split
(page_leads_the_split), the right pane is
a preview of what the cursor would open, and a page with nothing to open
has no preview to put there.
Sourcepub fn page_leads_the_split(&self) -> bool
pub fn page_leads_the_split(&self) -> bool
Whether the page the cursor is on belongs in the left pane, with the right one previewing what the cursor would open.
Two panes are two consecutive levels of one lineage, and the left one is
the outermost that offers a choice. Usually that is the page the current
one was opened from. But a page can be opened from one that has a single
row on it — the root of {repo: [...]}, or any level
enter_document started past — and drawing that
on the left spends half the width on a row nobody can choose between.
Then this page leads instead, and the pane that would have repeated its
parent previews its child.
Sourcepub fn focus_on(&mut self, path: &[Seg])
pub fn focus_on(&mut self, path: &[Seg])
Point the page view at whichever page lists path, with the cursor on
it — the by-path counterpart to drilling, and how a view switch carries
the selection across.
It searches from the root outward rather than from path inward, because
more than one page can contain a node and the outermost is the right one:
an inlined group’s member is listed on the grandparent’s page (that is what
inlining means), and also on the group’s own page, which is a place page
navigation would never have left you. A path that doesn’t resolve is inert.
Sourcepub fn page_at(&self, path: &[Seg]) -> Page
pub fn page_at(&self, path: &[Seg]) -> Page
The page listing the container at path, without going there.
page is where the user is; this is any other level, built
on demand and thrown away. A frontend whose navigation is a stack needs it:
the OS asks “what is the screen for this path element?” for levels the
model is not focused on, and answering by moving the focus would make
rendering a screen a navigation.
Total, like build_page: a path that doesn’t
resolve, or that names a scalar, yields an empty page.
Sourcepub fn peek_page(&self) -> Option<Page>
pub fn peek_page(&self) -> Option<Page>
The page the selected item would open.
A two-pane frontend showing the root’s categories on the left has nothing
to put on the right until you have drilled into something — and an empty
half-screen is a poor advertisement for splitting the width. Previewing
the selected category’s page fills it with the thing you are about to open
anyway, which is what a settings sidebar does. None for a scalar, which
has no page.
Sourcepub fn page_move_down(&mut self)
pub fn page_move_down(&mut self)
j in the page view.
Sourcepub fn page_move_up(&mut self)
pub fn page_move_up(&mut self)
k in the page view.
Sourcepub fn page_select(&mut self, index: usize)
pub fn page_select(&mut self, index: usize)
Stand on row index of the page — a click, where j/k are a walk.
The page counterpart to select_row, and clamped
the same way: a row past the end is the last row, and an empty page
keeps the cursor at zero. It cannot land the cursor anywhere the walk
could not, only faster.
Sourcepub fn page_enter(&mut self)
pub fn page_enter(&mut self)
l/Enter in the page view: open the selected container as a page, or
begin editing the selected scalar.
A group header opens too. Its members are already on screen, so opening it shows nothing new — but it is the door to operating on the group as a container (append, insert, reorder) rather than on the members, and a container that is visible but cannot be entered is a worse surprise than a page that repeats what you could already see.
Sourcepub fn page_back(&mut self)
pub fn page_back(&mut self)
h/Esc in the page view: pop back to the page that listed the row you
opened, restoring the cursor to it.
One level out is the wrong answer once a row can compress, for the same
reason it is the wrong left pane
(rebuild_pages): opening exports › journal
deliberately skips the exports page because it holds nothing but that
one row, and handing it back on the way out makes leaving cost two steps
where arriving cost one — on a page whose only row is the name of the
place you just left. So this walks out past every level a row compressed
past, and lands where the row was tapped.
Nothing becomes unreachable by it. A compressed row’s
path is the outermost container, so renaming,
deleting, reordering and adding to exports are all still that row’s ops
on the page this lands on — the skipped page never held anything else.
Sourcepub fn is_collapsed(&self, path: &[Seg]) -> bool
pub fn is_collapsed(&self, path: &[Seg]) -> bool
Whether the container at path is collapsed. Answers for a node with no
row too (one nested inside another collapsed container), which
Row::expanded cannot.
Sourcepub fn set_collapsed(&mut self, path: &[Seg], collapsed: bool)
pub fn set_collapsed(&mut self, path: &[Seg], collapsed: bool)
Collapse or expand the container at path, leaving the selection where the
user put it — the by-path, non-interactive counterpart to
activate.
activate folds the selected row, so driving it from a path means moving
the selection first and putting it back after. This doesn’t: it re-anchors
onto whatever was selected before, and only falls back to path itself when
the selection was a descendant that the fold just took off screen.
A path naming a scalar (or nothing) is inert — see
with_collapsed.
Sourcepub fn choices_at(&self, path: &[Seg]) -> Option<Vec<Choice>>
pub fn choices_at(&self, path: &[Seg]) -> Option<Vec<Choice>>
The values a picker at path should offer, or None when there is no
list to offer and a value must be typed.
Two sources, in order. A Constraint::Enum
rule answers from its own terms — retired ones included, flagged in the
choice’s detail, because a term already written in the document has to
stay re-choosable. Otherwise the backend is asked
(Backend::candidates), which is where a reference field’s
candidates come from; a backend over a standalone file has none.
A list’s append position answers too. Asked about a sequence, this
re-asks about its first item (path.0) — a rule written with
PathPat::each_item_of is
index-agnostic, so the placeholder matches whatever governs the items,
which is the same trick the commit funnel’s validation uses. A frontend
offering “add to this list” therefore gets the list’s vocabulary without
having to guess an index that does not exist yet.
Sourcepub fn begin_choose(&mut self)
pub fn begin_choose(&mut self)
Open the picker on the selected node, or fall back to
begin_edit when there is nothing to pick from.
The fallback is the point: a host binds one key and gets a list where
there is a list and a text field where there is not, rather than having
to ask first and bind two. A closed vocabulary makes the picker the only
route to a value that validates, and free text stays reachable anyway
(begin_edit) — what is typed goes through the same
validation the picker’s values would.
Sourcepub fn visible_choices(&self) -> Vec<&Choice>
pub fn visible_choices(&self) -> Vec<&Choice>
The choices the picker is currently showing — everything offered, cut to
what the filter matches. Empty outside Mode::Choosing.
Sourcepub fn choice_selected(&self) -> Option<&Choice>
pub fn choice_selected(&self) -> Option<&Choice>
The choice under the picker’s cursor, if any.
Sourcepub fn choose_next(&mut self)
pub fn choose_next(&mut self)
Move the picker’s cursor down one filtered row.
Sourcepub fn choose_prev(&mut self)
pub fn choose_prev(&mut self)
Move the picker’s cursor up one filtered row.
Sourcepub fn choose_push(&mut self, c: char)
pub fn choose_push(&mut self, c: char)
Narrow the picker by one more typed character (case-insensitive substring of the label). The cursor returns to the top of what is left, so what is highlighted is always a row that is on screen.
Sourcepub fn choose_backspace(&mut self)
pub fn choose_backspace(&mut self)
Undo one character of the picker’s filter.
Sourcepub fn choose_commit(&mut self)
pub fn choose_commit(&mut self)
Commit the choice under the cursor, replacing the node’s value.
A no-op (beyond leaving the picker) when the filter has cut the list to nothing: there is no value to write, and inventing one from what was typed would be the free-text path wearing the picker’s clothes.
Sourcepub fn choose_cancel(&mut self)
pub fn choose_cancel(&mut self)
Leave the picker, writing nothing.
pub fn begin_edit(&mut self)
Sourcepub fn begin_edit_leading_comment(&mut self)
pub fn begin_edit_leading_comment(&mut self)
Open the selected node’s leading comment block for editing, seeded with what is there (empty when there is none). Any node, container or scalar: a comment above a table is as much the table’s as one above a key.
Sourcepub fn begin_edit_trailing_comment(&mut self)
pub fn begin_edit_trailing_comment(&mut self)
Open the selected node’s trailing comment for editing, seeded with what is
there. See begin_edit_leading_comment.
pub fn edit_push(&mut self, c: char)
pub fn edit_backspace(&mut self)
pub fn edit_cancel(&mut self)
pub fn edit_commit(&mut self)
Sourcepub fn set_leading_comment(&mut self, path: &[Seg], text: Option<&str>)
pub fn set_leading_comment(&mut self, path: &[Seg], text: Option<&str>)
Set (or, with None, remove) the own-line comment block above the node at
path, refreshing the view. The by-path counterpart of committing an
EditSlot::LeadingComment edit, for an embedder or FFI.
Sourcepub fn set_trailing_comment(&mut self, path: &[Seg], text: Option<&str>)
pub fn set_trailing_comment(&mut self, path: &[Seg], text: Option<&str>)
Set (or, with None, remove) the same-line comment after the value at
path, refreshing the view. See
set_leading_comment.
Sourcepub fn leading_comment_at(&self, path: &[Seg]) -> Option<String>
pub fn leading_comment_at(&self, path: &[Seg]) -> Option<String>
The own-line comment block above the node at path, if the backend
reports one — a fresh read, not the copy on a page item.
Sourcepub fn trailing_comment_at(&self, path: &[Seg]) -> Option<String>
pub fn trailing_comment_at(&self, path: &[Seg]) -> Option<String>
The same-line comment after the value at path, if the backend reports
one.
Sourcepub fn set_value_at(&mut self, path: &[Seg], value: Value)
pub fn set_value_at(&mut self, path: &[Seg], value: Value)
Programmatically replace the value at path (any depth), refreshing the
view. The non-interactive counterpart to edit_commit
— for an embedder or FFI that edits by path rather than through the
selection.
Sourcepub fn set_scalar_text(&mut self, path: &[Seg], text: &str)
pub fn set_scalar_text(&mut self, path: &[Seg], text: &str)
Set the scalar at path from an edit-buffer text, coercing by the
schema’s expected type when known (a str field keeps "123" a string)
and otherwise guessing by literal shape — the by-path, schema-aware analog
of edit_commit. Validation (closed-vocabulary
rejection) still happens at the commit funnel.
Sourcepub fn rename_key(&mut self, path: &[Seg], new_key: &str)
pub fn rename_key(&mut self, path: &[Seg], new_key: &str)
Rename the mapping entry at path to new_key, keeping its value and
re-anchoring the selection onto the renamed entry. A no-op (with a status
hint) when path doesn’t end in a key — a sequence item has no key. The
backend rejects a name that collides with an existing sibling key.
Sourcepub fn insert_key(&mut self, map_path: &[Seg], key: &str, value: Value)
pub fn insert_key(&mut self, map_path: &[Seg], key: &str, value: Value)
Insert key = value into the mapping at map_path, selecting the new
entry. A frontend offers this on a map container; the backend rejects a
duplicate key or a non-mapping target, leaving the document untouched.
Sourcepub fn insert_key_text(&mut self, map_path: &[Seg], key: &str, text: &str)
pub fn insert_key_text(&mut self, map_path: &[Seg], key: &str, text: &str)
Insert key = text into the mapping at map_path, coercing text by the
type the schema declares for the new entry and otherwise guessing by literal
shape — the insert-shaped analog of
set_scalar_text.
Prefer this to insert_key whenever the value comes
from a user’s text: a caller that shape-guesses on its own writes 2026 as
an integer into a field the schema declares str, and gets no say from the
schema it is otherwise honoring everywhere else.
Sourcepub fn append_item(&mut self, seq_path: &[Seg], value: Value)
pub fn append_item(&mut self, seq_path: &[Seg], value: Value)
Append value to the sequence at seq_path, selecting the new item.
Sourcepub fn append_item_text(&mut self, seq_path: &[Seg], text: &str)
pub fn append_item_text(&mut self, seq_path: &[Seg], text: &str)
Append text to the sequence at seq_path, coercing it by the type the
schema declares for the sequence’s items and otherwise guessing by literal
shape — the append-shaped analog of
set_scalar_text.
The item’s type comes from the rule matching the item path (an each-item or
subtree rule), not from the rule on the list itself: tags is a seq, its
items are str.
Sourcepub fn move_selected_up(&mut self)
pub fn move_selected_up(&mut self)
Move the selected row one place earlier among its siblings — a sequence item via fig’s array-move, a mapping entry via a one-swap reorder.
Sourcepub fn move_selected_down(&mut self)
pub fn move_selected_down(&mut self)
Move the selected row one place later among its siblings.
Sourcepub fn value_at(&self, path: &[Seg]) -> Option<&Value>
pub fn value_at(&self, path: &[Seg]) -> Option<&Value>
The value the document currently holds at path (the whole tree for the
empty path), or None when the path doesn’t resolve — for a frontend
reading a row’s value without reaching for the backend.
Sourcepub fn seq_len(&self, path: &[Seg]) -> usize
pub fn seq_len(&self, path: &[Seg]) -> usize
The length of the sequence at path (0 for a non-sequence) — the index an
append will land at.
Sourcepub fn delete_selected(&mut self)
pub fn delete_selected(&mut self)
x: delete the selected mapping entry or sequence item.
Sourcepub fn history_len(&self) -> usize
pub fn history_len(&self) -> usize
How many edits are on the undo journal — the depth
undo can walk back through.
A host composing flower with another editor reads it to know whether there is anything of flower’s to undo before it dispatches the keystroke (provui’s session, holding flower’s metadata beside leaf’s body).
Sourcepub fn redo_len(&self) -> usize
pub fn redo_len(&self) -> usize
How many undone edits are available to redo. Reset to 0
by the next fresh commit.
Sourcepub fn edit_seq(&self) -> u64
pub fn edit_seq(&self) -> u64
A number that increases on every successful commit, undo and redo, and on nothing else.
Not a depth — undoing advances it as surely as editing does, because what it counts is how many times the document has changed, not how far from the start it is. A host holding two editors keeps one ordered history by recording which editor’s sequence number moved, so “body edit, metadata edit, body edit” undoes in that order without either editor knowing the other exists.
Sourcepub fn undo(&mut self) -> bool
pub fn undo(&mut self) -> bool
Undo the most recent edit, putting the cursor back where it was made.
The inverse goes through the same Backend::apply the edit did, so a
backend that declines an edit declines its undo too — and a
workspace-maintained key refuses here exactly as it refuses there. The
schema is not re-consulted: the value being restored is one the
document already held, and a vocabulary that has since tightened is not
a reason to strand a user one edit away from where they were.
Returns whether the document moved: false when there was nothing to
undo, or the inverse was refused, and in either case with a status
saying which. A host composing two editors dispatches an undo to one of
them and needs to know whether it landed without snapshotting
edit_seq around the call.