Commit Graph
3038 Commits
Author SHA1 Message Date
Zef Hemel a16eebd902 More safetey in overriding default template files in non-empty spaces 2026-03-20 12:28:29 +01:00
Matouš Jan FialkaandGitHub baeb688ddc Fix: template.each returns nil on empty results (#1899)
* Fix: `template.each` returns nil on empty results

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix typo

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-19 16:26:32 +01:00
Matouš Jan FialkaandGitHub 9170627d27 Add tests for aggregates and few useful aggregates (#1897)
* [LIQ] Add more tests for builtin aggregates

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* [LIQ] Add `first`, `last`, `mode` and `median` aggregates and `group_concat` alias

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-19 12:34:58 +01:00
Matouš Jan FialkaandGitHub 6cbb61c7db [LIQ] Add new aggregate functions, aliases, and queryable aggregate registry (#1891)
* [LIQ] Add new aggregate functions, aliases, and queryable aggregate registry

* Extend with 13 new built-in aggregates: `product`, `string_agg`,
  `yaml_agg`, `json_agg`, `bit_and`, `bit_or`, `bit_xor`, `bool_and`,
  `bool_or`, `stddev_pop`, `stddev_samp`, `var_pop` and `var_samp`.

* Introduce `aggregate.alias` API allowing users to define custom
  aliases for any aggregate. Standard aliases (`every`, `std`, `stddev`
  and `variance`) are now defined via this API rather than hardcoded.

* Add `index.aggregates` queryable collection so users can discover
  all available aggregates directly from LIQ queries.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix config pass through query path so custom aggregates work

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Preserve `LuaTable`/`LuaFunction` values in aggregate config storage

`config.set` uses `LuaNativeJSFunction` which calls `luaValueToJS` on
all arguments. This converted the aggregate `LuaTable` to a plain JS
object and wrapped `LuaFunction` callbacks in JS functions that also
converted their returned values via `luaValueToJS`. The result was that
state returned by initialize (a `LuaTable`) got converted to a plain JS
object before being passed to `iterate`. Therefor Lua operations like
`table.insert` on that were failing because they expected a `LuaTable`
and not a plain JS array.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix formatting

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Improve aggregate functions descriptions, fix `sum` divergence

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Align `product` with `sum`

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: extract `alias` from `LuaTable` via `rawGet` in `aggregates()` registry

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Rename `alias` in `aggregates()` to `target` for clarity

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Add a null guard at the top of `jsToLuaValue`

This preserves `null`/`undefined` as-is (both map to Lua nil) and
prevents them from falling through to the `typeof` "object" branch.

For this PR it means that null `target` in our `aggregates` entries will
correctly show as empty/`nil` in query results rather than `{}`.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Documentation reflects recent changes

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: make `sum`/`product` return null on empty input; stop `LIQ_NULL` leaks

* `sum(`) and` product(`) now return null when no rows match (matching
  Postgres semantics) instead of returning 0 and 1 respectively.

* Query result columns that hold null are internally preserved using
  a `LIQ_NULL` sentinel so that column keys survive in `LuaTable`
  storage.  This sentinel was leaking into Lua code as "userdata"
  through three read paths:

  * `luaIndexValue`: `rawGet` returned the sentinel directly to Lua when
    accessing table fields,

  * `rawget` (stdlib): the builtin `rawget` function exposed the
    sentinel without converting it back to `nil`,

  * `createAugmentedEnv`: string interpolation unpacked table values via
    `rawGet` into local variables, making the sentinel visible in
    template expressions like `${var}`.

  All three now convert `LIQ_NULL` to `nil` at the read boundary,
  keeping the sentinel internal to table storage where it belongs.

* Update affected test expectations accordingly.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Remove duplicated LIQ_NULL hazard, add guard for all builtin aggregate `iterate`s

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: `array_agg` preserves NULL positions

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Add symbol guard to `json_agg`

`JSON.stringify(Symbol(...))` in an array produces null by accident.
That is a JS implementation detail we **MUST NOT** rely on. Explicit
null push makes intent clear and avoids surprises if the `Symbol`
representation ever changes.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Add symbol guard to `yaml_agg` (ditto)

`js-yaml` has no knowledge of the `LIQ_NULL` symbol. Passing null makes
it emit YAML null (or `~`), which is the correct YAML representation of
a missing value and matches standard `json_agg`/`yaml_agg`
NULL-inclusion semantics.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Add intra-aggregate ordering null guards

Without this, `LIQ_NULL` sort keys would fall through to `valA < valB`
which is always false for `Symbol`s which is breaking the `nulls
first`/`nulls last` contract...

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Ditto, but for `order by` null comparisons

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Guard `luaTypeName`, `luaTypeOf` and `luaToString` against `LIQ_NULL` sentinel

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Guard presentation layer against `LIQ_NULL` sentinel leaking as visible text

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix: Evaluate extra args per-item in `executeAggregate`; add new aggregates

Extra arguments (2nd, 3rd, etc.) to aggregate functions were evaluated
against the outer query environment where the object variable is not
bound. This caused multi-argument aggregates like `covar_samp(data.y,
data.x)` to fail with nil reference errors. This commit addresses this
by evaluating extra args per-item inside the iterate loop using the item
environment so all arguments resolve correctly.

We also add few common aggregates:

- `covar_pop`, `covar_samp`, `corr`: population/sample covariance and
  correlation coefficient using online co-moment algorithm.

- `quantile(value, q, method)`: general quantile with interpolation
  methods: lower, higher, nearest, midpoint and default linear.

- `percentile_cont(value, q)`: continuous percentile (linear)

- `percentile_disc(value, q)`: discrete percentile (lower)

Note: `percentile_cont` and `percentile_disc` share the `quantile`
implementation through `ctx.name` at initialize time.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Update docs

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Make the ordering for quantile aggregates explicit

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Update docs

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Improve docs

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-19 09:37:09 +01:00
Zef Hemel 18f4806aca Fix SB_READ_ONLY docs 2026-03-19 07:34:19 +01:00
Brett AnthoineandGitHub 4045e92887 Fix: unwrap multi-return values in PropertyAccess and method calls (#1895) 2026-03-18 21:05:03 +01:00
Joshua BrunnerandGitHub 6aad7cff43 fix: allow colons in SB_USER password (#1893) 2026-03-18 18:40:44 +01:00
Matouš Jan FialkaandGitHub 8f7e525812 Fix mobile tasks, annoying caret jumping and empty widgets on navigation (#1890) 2026-03-17 22:16:58 +01:00
Matouš Jan FialkaandGitHub 4db49239a4 Fix extended task state widget click behavior in widgets (#1889)
* Fix extended task state widget click behavior in widgets

* Add mouse click handler on extended task state span to prevent
  CodeMirror from moving selection to widget source on normal click

* Let `Alt+Click` pass to parent div for the "cursor to source" behavior
  matching simple checkbox `Alt+Click` behavior

* Skip state cycling on `Alt+Click`

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Prevent task state corruption from concurrent cycling on mobile

On mobile, rapid taps on an enhanced task state (e.g. `[PLANNED]`) could
fire multiple events before the first `taskCycleAtPos` completed.  Add
a reentrancy guard to `taskCycleAtPos` so concurrent calls are dropped.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-17 13:55:47 +01:00
Zef Hemel e456100b5b No new logs fix 2026-03-17 11:25:10 +01:00
Zef Hemel 10c95bcba5 Runtime API: Clean up lock file on chrome hard-kill 2026-03-17 11:09:01 +01:00
Zef Hemel 587b27fbd9 Runtime API: Make logs already available before client is fully
initialized
2026-03-17 11:01:25 +01:00
Zef Hemel 63b71f1689 Disable integration tests on github 2026-03-17 10:22:16 +01:00
Zef Hemel d04c69e74e Tests files for integration tests 2026-03-17 10:06:51 +01:00
Zef Hemel 50a483ad3d Merge branch 'remote-cli' 2026-03-17 09:57:34 +01:00
Zef Hemel b15b57059e Merge branch 'main' of github.com:silverbulletmd/silverbullet 2026-03-17 09:57:29 +01:00
Zef Hemel c04d7c332f First pass at "Remote API" (see docs)
Note: this is highly experimental and will likely change in the future.
2026-03-17 09:57:08 +01:00
SigmabroandGitHub dd4c154eff fix(client): append file input to body to fix iOS Safari upload dialog (#1886) 2026-03-15 20:45:18 +01:00
Zef Hemel efe70a77dd Tauri detection (future) 2026-03-15 08:02:51 +01:00
Brett AnthoineandGitHub 356bc82986 Add optional stdin to shell syscall (#1885) 2026-03-14 20:55:11 +01:00
Matouš Jan FialkaandGitHub a01b91b707 Resove merge conflict (#1884)
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-13 16:30:17 +01:00
Zef Hemel 4a411b224d Unrelated code slipped in 2026-03-13 14:58:02 +01:00
Zef Hemel fc2228be1a Make sync requests not blow up when service worker is not activated 2026-03-13 14:54:01 +01:00
Matouš Jan FialkaandGitHub 6d52350640 Fix extended task rendering in widgets (#1882)
* Fix extended task rendering in widgets

This patch addresses several issues.

1. Extended tasks like `[PLANNED]` or `[TODO]` were not rendering
   correctly when generated via widgets. The HTML renderer was producing
   plain text without brackets or proper styling, while simple `[x]`
   tasks worked fine.  The fix produces the same DOM structure as
   CodeMirror producing coherent styling everywhere.

2. Widget checkboxes are not interactive now. Since widget tasks have no
   backing state handler clicking them only caused a misleading visual
   toggle with no effect. The `disabled` attribute prevents this
   confusion and the dimmed appearanceit signals to the user that the
   checkbox is read-only in this context which is the truth.

To see it in action try the following Markdown snippet in SilverBullet:

```
- [x] #foo [att: i]
- [PLANNED] bar #bar [att: i]

${'- [x] #foo [att: i]\n- [PLANNED] bar #bar [att: i]'}
```

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Revert and just prevent widget checkboxes from toggling visually

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Support custom task states in widgets and indexer

Custom task states like `[PLANNED]` or `[IN PROGRESS]` now render
correctly in *widgets*, matching the same DOM structure as CodeMirror
uses in the editor. Widget-rendered tasks that reference a real task
(via `page@pos`) are fully interactive — clicking an extended state
cycles it through the configured states and updates the source task.
Tasks without a reference are disabled to prevent misleading visual
feedback.

The task indexer now respects the `done` flag on custom states defined
via `taskState.define`, so queries like `where not t.done` correctly
exclude tasks in states marked as done. Previously only the built-in
simple tasks (`- [x]` or `- [X]`) states were treated as completed. The
`Task: Remove Completed` command already handled custom done states and
continues to work unchanged.

State cycling now preserves the definition order from `taskState.define`
calls instead of sorting alphabetically. A new `order` field allows
explicit control over the cycle sequence. Without it, states cycle in
definition order. With it, states are sorted by the `order` field value.
This gives users full control over the progression, for example:

    PLANNED --> IN PROGRESS --> FINISHED

The `taskState.define` API now validates its input against a schema:
`name` (string, required), `done` (boolean, optional), and `order`
(number, optional).

The `expandMarkdown` no longer injects "fake" `page@pos` references into
tasks rendered via `widget.markdownBlock` or `widget.new` which was
causing broken links and unwanted interactivity on static task content.

The `task:stateChange` event is dispatched when toggling tasks from
widgets, ensuring Lua listeners (such as some custom completed timestamp
management) fire correctly regardless of where the toggle originates.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-13 13:32:26 +01:00
Zef Hemel 19d3328647 lint fixes 2026-03-13 09:24:52 +01:00
Zef Hemel 702c75cc9c CHANGELOG updates 2026-03-13 09:17:43 +01:00
Zef Hemel f6308c788c Adds back "lock" button on mobile
This can be used to toggle between read-only mode, useful for mobile
users that are primarily navigating, not editing
2026-03-13 09:14:52 +01:00
Zef Hemel b60496f30e Move forward/backward action buttons to drop-down on mobile 2026-03-13 08:39:20 +01:00
Zef Hemel e841d1f24d CHANGELOG updates 2026-03-13 08:36:28 +01:00
Zef Hemel 3aea9a8112 Fixes #1872 2026-03-13 08:32:04 +01:00
Zef Hemel 9581433cd3 Fixes #212: adds footnote support
Based on https://www.markdownlang.com/extended/footnotes.html

* Both "official" [^1] and [^1]: def
* And inline ^[My foot note]

Features:
* Properly parsed in markdown parser
* Syntax highlighting
* Live Preview to ... when on-hover preview of content, on-click moves
  cursor to definition
* Reference completion
* Invalid references are marked
2026-03-13 08:28:43 +01:00
Zef Hemel 4bb258ca71 Fix regression: transclusions were no longer treatin wikilinks as
absolute
2026-03-12 20:08:43 +01:00
Zef Hemel 2dd2c9b929 Fix "No such header #boot" errors in PWA mode 2026-03-12 15:08:38 +01:00
Zef Hemel 1a5c7fdfc6 Update website CONFIG with individual actionButton.define calls 2026-03-12 14:57:13 +01:00
Zef Hemel 1b0ba027b3 Add standalone option to action buttons
When `standalone` is set to true, this action button will only appear in
"standalone PWA" mode (e.g. home-screen mobile apps, or installed PWA on
desktop). Useful to e.g. only show forward and backward buttons. These
forward and backward buttons are now also added to the default action
button config.
2026-03-12 14:51:31 +01:00
Zef Hemel 6bc12bc00f Add support for opting out action buttons from the drop down on mobile
+ by default making the page picker opt out
2026-03-12 14:27:20 +01:00
Zef Hemel dbcef9e8aa Fix: make sure Edit buttons work even for Lua expressions and code
widgets whose bodies appear multiple times in the same page (previously
always jumped to first).
2026-03-12 14:13:18 +01:00
Matouš Jan FialkaandGitHub 1f7a4d7d66 Fix attribute rendering (#1880)
* Fix table row parser

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Remove all `{[command button]}` remnants

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Render `Attribute` nodes in HTML like CodeMirror does

This patch

- ensures always render `Attribute`,
- produces `sb-attribute` span with sub-spans matching CodeMirror DOM,
- removee `preserveAttributes` from Markdown render options and callers.

Finally the attributes looks the same everywhere (table, text, widget).

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-12 13:50:09 +01:00
Matouš Jan FialkaandGitHub b83c1e03d2 Fix Markdown table rendering and remove deprecated command button remnants (#1879)
* Fix table row parser

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Remove all `{[command button]}` remnants

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Add tests

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

* Fix extended task rendering in case of following EoL

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-12 13:46:48 +01:00
Zef HemelandGitHub 3df11ccf3d Implements custom markdown syntax extensions (EXPERIMENTAL) (#1881)
Alternative implemention of #1727
2026-03-12 13:40:20 +01:00
Zef HemelandGitHub 84136c7ed6 Merge pull request #1878 from mjf/liq-implement-offset 2026-03-11 19:44:04 +01:00
Matouš Jan FialkaandGitHub fea7e5a508 Merge branch 'main' into liq-implement-offset 2026-03-11 18:49:29 +01:00
Zef HemelandGitHub f898c44196 Merge pull request #1877 from mjf/liq-implement-order-by-for-aggregates
[LIQ] Implement `order by` for aggregates
2026-03-11 16:54:07 +01:00
Matouš Jan FialkaandGitHub 9104231132 Merge branch 'silverbulletmd:main' into liq-implement-offset 2026-03-11 15:23:16 +01:00
Matouš Jan Fialka 9522437941 [LIQ] Website: Improve general syntax description
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-11 15:17:06 +01:00
Zef Hemel 1beb13a134 Fix: regression where multi-line markdown results from Lua directives
would _always_ be rendered as inline.

Added back the old heuristic check.
2026-03-11 14:55:02 +01:00
Zef Hemel 0ac8172185 Fix CI 2026-03-11 14:40:57 +01:00
Zef Hemel e799d30c63 Some more build cleanup 2026-03-11 14:28:45 +01:00
Matouš Jan Fialka 5205ab5154 [LIQ] Implement offset (4: add tests)
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-11 11:47:11 +01:00
Matouš Jan Fialka 11a5fb1a5a Merge branch 'main' into liq-implement-offset 2026-03-11 11:38:52 +01:00