Commit Graph

4 Commits

Author SHA1 Message Date
evan 772618ef89 feat(json): JSON for apps through vendored lua-cjson
lua-cjson decodes straight onto the Lua stack, so a response costs its
text plus the table it becomes rather than a document in between, and it
brings the encode half that a C tokenizer would have left to write here.

It is a module rather than a global: a global namespace is a contract a
firmware implements, and nothing about this needs a provider. Registering
into package.preload also puts it ahead of the SD-card searcher, so an
implementation cannot be shadowed, and an app that never requires it
never pays for the module.

Depth is capped at 32 through the module's own knobs rather than by
patching the vendored source. Decoding recurses on the C stack and
upstream defaults to 1000, which assumes a server rather than a FreeRTOS
task.
2026-08-05 16:41:51 -04:00
evan b9f7c9347c refactor(api)!: declare callbacks as classes an app composes
The runtime has always called fields on the table main.lua returns, but
@lua-global declared them as loose functions, so the stubs type-checked
something that does not exist and read as "define a global".

Callbacks are now @lua-app blocks that generate a class: App for the core
contract, TouchHandlers and ButtonHandlers beside the namespaces they belong
to. An app composes what it implements:

  ---@class PaintApp : App, TouchHandlers

Names follow the rest of the surface: onTouchDown rather than on_touch_down,
with the field names the runtime looks up renamed to match. @lua-field carries
the plain fields (home, data) that were prose in a preamble before.
2026-08-05 10:42:01 -04:00
evan 75b3a2c490 refactor(api)!: one namespace per feature, screen split out
Namespaces were shared across features: `settings` was written by core, the
panel and touch, and `input` by touch and buttons. That made "does this
firmware implement the whole feature?" a question no pointer could answer.

Each namespace now belongs to exactly one feature or to core, so a feature is
a provider pointer and the compiler validates completeness:

  gui, node       -> screen, tree, under the screen feature
  settings        -> screen (rotation, theme), sys (timezone),
                     touch (calibration)
  input           -> touch, buttons

Runtime::open() no longer requires a GuiProvider; a firmware without one runs
with no screen/tree globals and reports sys.hasFeature("screen") false.
Rotation is one value again: GuiProvider::setRotation applies and persists, so
an app rotating the panel transiently puts the old value back itself.
2026-08-05 10:26:38 -04:00
evan 95fa512047 initial commit 2026-08-03 17:46:14 -04:00