Files
plainleaf/client/space_lua
Matouš Jan Fialka 2aaa797bda Improve Lua Widget Rendering
Lua `${...}` expression results are rendered using two parallel paths:

- **HTML path** (display path) for visual display in the editor and
- **Markdown path** (copy path) for the *copy button* output.

Every Lua value is classified as one of:

- **Scalar:** number, string, boolean, or `nil`
- **Empty table:** `{}`
- **Array:** a `LuaTable` with only sequential integer keys (no string keys)
- **Array of tables:** an array where every element is a `LuaTable`
- **Record:** a `LuaTable` with any string key (may also have integer keys)

Scalars are rendered as inline Markdown - wiki links, tags, bold, and
other inline syntax are resolved, `nil` renders as `<span data-empty>`.

Empty tables render as `<table data-table-empty>`.

An array of tables renders as a multi-row `<table>`. Column headers
are the union of all element keys. Each cell value recurses through
the same classification.

An array of scalars (or a mix of scalars and tables) renders as `<ul>`
with one `<li>` per element. Each item value recurses.

A record renders as a single-row `<table>` with one column per key.
Cell values recurse.

Every `<td>` carries `data-table-cell-type` and optionally
`data-table-cell-empty`.  Every `<li>` carries `data-list-item-type` and
optionally `data-list-item-empty`.  The outermost element carries
`data-type`.  These attributes allow CSS styling of rendered widgets.

Nesting is **unlimited**. Tables inside cells, lists inside cells,
tables inside list items all render correctly in HTML.

Scalars render as plain text. Lua `nil` renders as `nil`. Empty tables
render as `*(empty table)*`.

An array of tables renders as a pipe-delimited Markdown table. Nested
values in cells are rendered as Lua literals via `toStringAsync()`
(e.g. `{1, 2, 3}` or `{a = 1}`), since Markdown table cells cannot
contain block-level content.

An array of scalars renders as a Markdown list (`- item`). When a list
item is itself multi-line (a sublist) it uses an empty bullet with
two-space indented content on the next line:

```
- 1
- 2
-
  - nested 1
  - nested 2
```

Nested tables or arrays **beyond the first list nesting** level are
rendered as Lua literals.

A record renders as a single-row Markdown table.

Column headers follow the order returned by `LuaTable.keys`: string keys
in their insertion order, followed by integer keys in ascending order.
For example, `{a = 1, b = 2, 3, d = 4}` produces columns `a
| b | d | 1`. This is consequence of `LuaTable` storing string keys
and the array part separately (for performance).

Arrays mixing plain scalars and record-like tables (e.g.  `{1, 2, 3,
{a=3}}`) were previously rendered as a single flat table due to an
internal JS conversion (`toJS`). They now render as a list, with record
elements shown as nested tables - which more accurately reflects their
Lua structure. This is the only divergence from the original
presentation.

To restore the old tabular layout, wrap all elements as records with
a consistent key:

```lua
-- Before (was a flat table, now a list with nested table):
${{1, 2, 3, {a=3}}}

-- After (explicit records, renders as a table):
${{{value=1}, {value=2}, {value=3}, {a=3}}}
```

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-09 11:45:04 +01:00
..