aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-26 10:54:12 +0100
committereunhhu <[email protected]>2026-09-26 10:54:12 +0100
commitb230b70252f09cf3425a8b4b959b3dfd72075b31 (patch)
tree6ddae95ead87fa1905e133dbabf0f2d6a595efde /prototypes
parentd58e1d29cc3cbd5f1c9b271c0b7e25b9962fad4f (diff)
downloadpure-b230b70252f09cf3425a8b4b959b3dfd72075b31.tar.gz
pure-b230b70252f09cf3425a8b4b959b3dfd72075b31.zip
Let a host point an index at an item
pure_app_point moves an index state to an item, as a user pointing at a row would: an event with no handler, saved like a key event, joining the burst when saving is deferred; past the last item it is not_found. A host learns which index to move from the view that shows it: pure_module_position gives the state behind a number view that is just `at.position`. An interface can so turn a click on a list row into its focus without any code in the app.
Diffstat (limited to 'prototypes')
-rw-r--r--prototypes/connections/module.c20
-rw-r--r--prototypes/connections/module.h7
-rw-r--r--prototypes/connections/test-module.c32
3 files changed, 58 insertions, 1 deletions
diff --git a/prototypes/connections/module.c b/prototypes/connections/module.c
index ebb746f..5e2b98f 100644
--- a/prototypes/connections/module.c
+++ b/prototypes/connections/module.c
@@ -522,6 +522,13 @@ int pure_module_view(const PureModule *m, const char *name) {
return -1;
}
+int pure_module_position(const PureModule *m, uint32_t view) {
+ if (view >= m->views || m->view_type[view] != PURE_VIEW_NUM || m->view_table[view]) return -1;
+ const PureBlock *block = &m->view_code[view];
+ const PureOp *code = &m->code[block->start];
+ return block->length == 2 && code[0].op == PURE_OP_INDEX_LOAD && code[1].op == PURE_OP_INDEX_NUM ? (int)code[0].arg : -1;
+}
+
int pure_module_column(const PureModule *m, uint32_t table, const char *name) {
for (uint32_t i = 0; i < m->views; ++i)
if (m->view_table[i] == table + 1 && !strcmp(m->view_names[i], name)) return (int)i;
@@ -1121,6 +1128,19 @@ PureResult pure_app_input(PureApp *app, uint32_t input, PureEdge edge) {
return dispatch(app, 1 + 2 * input + (edge == PURE_EDGE_UP), &ev);
}
+PureResult pure_app_point(PureApp *app, uint32_t state, size_t position) {
+ const PureModule *m = app->module;
+ pure_app_finish(app);
+ if (state >= m->states || m->state_type[state] != PURE_STATE_INDEX) return PURE_INVALID;
+ if (position >= pure_list_count(app->lists[m->state_ref[state]])) return PURE_NOT_FOUND;
+ open_burst(app); /* what a failed save returns to */
+ app->fault = PURE_FAULT_NONE;
+ app->fault_pc = UINT32_MAX;
+ app->values[state] = (double)position;
+ ++app->events;
+ return app->deferred ? PURE_OK : pure_app_save(app);
+}
+
PureResult pure_app_text(PureApp *app, uint32_t input, PureSpan text) {
pure_app_finish(app);
if (input >= app->module->inputs || app->module->input[input].kind != PURE_KIND_TEXT ||
diff --git a/prototypes/connections/module.h b/prototypes/connections/module.h
index c9fb606..16b755c 100644
--- a/prototypes/connections/module.h
+++ b/prototypes/connections/module.h
@@ -106,6 +106,9 @@ int pure_module_state(const PureModule *, const char *name);
int pure_module_input(const PureModule *, const char *name);
int pure_module_view(const PureModule *, const char *name);
int pure_module_column(const PureModule *, uint32_t table, const char *name);
+/* The index state a number view shows as its position (a view that is just
+ * `at.position`), or -1: what a host moves with pure_app_point. */
+int pure_module_position(const PureModule *, uint32_t view);
/* Keyed collections live in a data host (for example the tree store). One
* event opens at most one document, the message's key, at its current
@@ -189,6 +192,10 @@ bool pure_app_defer(PureApp *, bool deferred);
void pure_app_stop(PureApp *);
PureResult pure_app_frame(PureApp *);
PureResult pure_app_input(PureApp *, uint32_t input, PureEdge);
+/* Point an index state at the item at position (0 first), as a user pointing
+ * at a row: an event with no handler, saved like a key event. NOT_FOUND past
+ * the last item, INVALID for a state that is not an index. */
+PureResult pure_app_point(PureApp *, uint32_t state, size_t position);
/* Deliver committed text (for example from an input method). Not UTF-8: invalid. */
PureResult pure_app_text(PureApp *, uint32_t input, PureSpan text);
/* Deliver a message. base is the revision the sender edited, or -1 for none;
diff --git a/prototypes/connections/test-module.c b/prototypes/connections/test-module.c
index 6f48bc8..b0666fe 100644
--- a/prototypes/connections/test-module.c
+++ b/prototypes/connections/test-module.c
@@ -1714,6 +1714,35 @@ static void deferred(void) {
deferred_messages();
}
+/* A host points at an item: the index a view shows as its position moves
+ * there, as an event with no handler, saved like a key event; deferred, it
+ * joins the burst and a failed save undoes it with the rest. */
+static void pointing(void) {
+ CHECK(load(list_spec, &module_a) == PURE_OK);
+ CHECK(pure_module_position(&module_a, 1) == 2); /* position = at.position */
+ CHECK(pure_module_position(&module_a, 0) == -1 && pure_module_position(&module_a, 2) == -1 &&
+ pure_module_position(&module_a, 3) == -1 && pure_module_position(&module_a, 99) == -1);
+ char path[] = "/tmp/pure-point-XXXXXX";
+ CHECK(mkdtemp(path) && pure_store_init(path) == PURE_OK);
+ PureApp app;
+ CHECK(pure_app_start(&app, &module_a, pure_tree_data(path)) == PURE_OK);
+ CHECK(pure_app_point(&app, 2, 0) == PURE_NOT_FOUND); /* nothing to point at */
+ for (int i = 0; i < 3; ++i) CHECK(pure_app_text(&app, 0, (PureSpan){(const unsigned char *)"a", 1}) == PURE_OK);
+ uint64_t events = app.events;
+ CHECK(app.values[2] == 2 && pure_app_point(&app, 2, 0) == PURE_OK && app.values[2] == 0 && app.events == events + 1);
+ CHECK(pure_app_point(&app, 2, 3) == PURE_NOT_FOUND && app.values[2] == 0);
+ CHECK(pure_app_point(&app, 0, 1) == PURE_INVALID && pure_app_point(&app, 1, 1) == PURE_INVALID); /* a number, a list */
+ CHECK(pure_app_point(&app, 2, 1) == PURE_OK);
+ pure_app_stop(&app);
+ CHECK(pure_app_start(&app, &module_a, pure_tree_data(path)) == PURE_OK && app.values[2] == 1);
+ CHECK(pure_app_defer(&app, true) && pure_app_point(&app, 2, 2) == PURE_OK && app.open && app.values[2] == 2);
+ CHECK(pure_app_save(&app) == PURE_OK);
+ pure_app_stop(&app);
+ CHECK(pure_app_start(&app, &module_a, pure_tree_data(path)) == PURE_OK && app.values[2] == 2);
+ pure_app_stop(&app);
+ remove_store(path);
+}
+
int main(void) {
behaviour();
faults();
@@ -1724,12 +1753,13 @@ int main(void) {
texts();
text_mutations();
lists();
+ pointing();
list_mutations();
tables();
table_mutations();
stored_states();
deferred();
printf("{\"sizeof_module\":%zu,\"sizeof_app\":%zu}\n", sizeof(PureModule), sizeof(PureApp));
- puts("{\"module_tests\":\"verified-load-atomic-events-faults-signed-zero-if-else-replace-by-name-rejections-mutations-messages-documents-typed-verification-text-cursors-utf8-views-rollback-replace-lists-indices-undo-migration-joins-tables-columns-pick-slide-stored-equivalence-crashes-frames-messages-migration-deferred-bursts\"}");
+ puts("{\"module_tests\":\"verified-load-atomic-events-faults-signed-zero-if-else-replace-by-name-rejections-mutations-messages-documents-typed-verification-text-cursors-utf8-views-rollback-replace-lists-indices-undo-migration-joins-tables-columns-pick-slide-stored-equivalence-crashes-frames-messages-migration-deferred-bursts-pointing\"}");
return 0;
}