Repository navigation
v0.8.0
The Settings page is redesigned after tuios's: a list of fields, not a table.
A state verb answers what changed since the host's last poll instead of every row, and the catalog tells a tool's own verbs from the framework's. Every list filters with /, and an Update no longer visits list rows.
Settings page
- Sections are tabs across the top instead of a rail, so the rows get the whole width.
taband]show the next section,shift+taband[the previous, wrapping (settings.section {step}, or{name}); each section keeps its selected row. With one section there is no tab row. - One row per setting: its name on the left, its value on the right. There is no header and no Value/Default/Source columns. A
•after the name marks a value that is not the default.‹ value ›marks a valueh/lsteps. - The description under the rows says what the default is and where the value comes from: not in settings.json, set in settings.json, or settings.json holds an invalid value (with the reason) so the default applies.
- List settings: a list setting's row shows its item count (
(none)when empty), and each item is a row directly beneath it with the name column blank. On a list's rowenterornadds an item at the end. On an item rowenteroriedits it,nadds one after it,d ddeletes it andrresets the whole list. An empty item is refused. u(orctrl+z) takes back the last change made on the page and shows its row. A value that was invalid in settings.json comes back as it was.uis offered only when there is a change to take back.backspaceanddeletereset a setting, asrdoes.- The page reopens on the section and row it was left on.
State cache and deltas
- A state verb run through
cli.Shelltakes--since LIST=HASH,...and--since-cache ID(cli.StateFlags,FormatSince/ParseSince;--since=asks for every list in full, with hashes) and answers JSON Lines: a header{"state":1,"cache":ID}, then per listunchanged, adelta(the changed and added rows whole at their indexes, the removed ids) or the list infull, each with its content hash (RecordHash,ListHash). An unknown hash, another cache id or a pruned version answers full, never wrong. The catalog declaresstateDelta: 1. - The extension side caches each list's last versions (
Shell.StateCache):(id, record hash)files under$XDG_CACHE_HOME/<bin>/state/<scope>/lists/<list>/, written temp + rename and content-addressed,Keep(2) versions per list andScopes(8) scopes, the rest deleted.StateCache.Scope(args)adds to the scope (a TUIOS server);StateCache.Fingerprint(args)(StatFingerprint(paths...)) answers an unchanged poll without running the verb, except under--fresh;StateCache.Offturns it all off. MountPageuses it: withPageConfig.FetchFlagsa page'sReloadsends its list hashes and applies the answer (PageView.ApplyState): unchanged touches nothing and skipsOnRows, a delta goes throughList.Patch, full throughSetRows; a list whose hash does not match after applying is fetched again in full, once.PageView.Refreshforgets the hashes. An older extension (nostateDelta) keeps full answers throughFetch.List.Patch(ListPatch{Upsert, At, Remove})(andPatchItems) isSetItemsover the patched rows: kept rows keep their instances, selection and marks, and only removed rows close.SetItemskeeps a table's measured widths when every row draws the same cells.cli.DecodeStateandRowReader.Answer()read a delta answer. BenchmarksBenchmarkStatePollandBenchmarkStateApplycover an 8,000-row poll, unchanged and with one row changed.
Builtin verbs
- Every ochazuke tool's catalog lists the framework's verbs beside the tool's, and some are application verbs (the outline's 14, the chooser's 3), so hosts mounted them as the tool's (
ai-outline,qbt-outline).Operation.Builtinnow marks every operation the framework registers: everythingNewRuntimeandNewModelregister, and what a framework constructor registers later (NewPicker,NewPalette,NewAppearance,grid.Register,markdown.Register,cli.AddCommands). An application's verb is never builtin, even on a framework noun (history.capture-hook). - The catalog's verbs carry
builtin(cli.CatalogVerb.Builtin).CatalogDoc.AppNouns()is what a host mounting a tool's verbs mounts: each noun with only its non-builtin verbs (CatalogNoun.AppVerbs()), nouns left with none dropped. AMountPagelist of a noun's verbs lists only the tool's.
Every list filters
/on a focused list (page lists, tables, catalog lists, the Settings page's section, a list in a modal) opens a query line above the rows; typing keeps the rows whose label or cells hold every word, ignoring case, in list order,N of Mon the right. In thelist_filtermode up/down andctrl+n/ctrl+pmove among the matches (no spill), enter keeps the filter (/edits it,escclears it), esc clears it and selects the row/found, backspace on an empty query leaves,ctrl+uempties it.- Rows are hidden, never removed:
SetItemsandPatchfilter the new rows and keep the selection by id, marks survive,list.applyacts on the marked rows shown, focus landing on a hidden row clears the filter. - An application's own
/wins at any level: the framework's is anapprow (guardlist-filterable), its/ filterhint last on the footer.
Faster updates
Runtime.components()(everyDeliverandPendingCommands) walks an index of the instances that are not list rows instead of sorting every instance, and the list verbs no longer copy every row into their result.BenchmarkUpdateKeyat 16,000 rows: 818 µs to 11 µs a key; nabe's ai page 295 µs to 32 µs.
API changes
-
SettingList("list"): a setting whose value is[]string. settings.json keeps it as a JSON array,settings set NAME '["a","b"]'sets it, andSettings.Strings(name)reads a copy. A value of another shape is refused, as are anEnumand a default that is not a list of strings. -
settings.section {step, name}andsettings.undo. The nouns aresetting-item(edit,add,delete,reset) andsetting.add. The guards aresetting-listandsettings-undo. -
A table whose columns have no titles draws no header (
List.View). -
The page's lists are
__settings/list[/SECTION](were__settings/table[/SECTION]); the__settings/sectionsrail and thesettings-sectionnoun are gone. Item rows are__settings/item/NAME/INDEX. -
Operation.Builtin,Runtime.Builtin(register func())(marks the operationsregisteradded; for framework packages),cli.CatalogVerb.Builtin,CatalogDoc.AppNouns(),CatalogNoun.AppVerbs(). -
list filter --target LIST --query Q(empty clears),list.filter-open|type|erase|keep|clear,list.move {clamp};List.SetFilter,Filter,Filtering,Shown,Height(Lenplus the query line);ListFilterMode.Items/Lenstay every row; a filtered list's state hasfilterandtotaland itsitemsare the rows shown. -
cli.StateDeltaVersion,StateFlags,FormatSince,ParseSince,StateList,RecordHash,ListHash,StateCache,StatFingerprint,DecodeState,RowReader.Answer(),PageConfig.FetchFlags,PageView.ApplyState,PageView.Refresh,PageView.SinceFlags();ochazuke.ListPatch,List.Patch,PatchItems.
Migrating
- Stories or tests that read the old columns (
Setting,Value,Default,Source) or the rail (Sections,__settings/section…) read the tabs, the rows and the description instead. - A host that mounts another tool's catalog verbs (nabe, mtm) mounts
doc.AppNouns()instead of comparing keys against a freshNewRuntime()+NewModel(). A catalog from a tool built before this release has nobuiltin, so every verb reads as the tool's; keep the old check as a fallback until the tools are rebuilt.