Commit Graph
2835 Commits
Author SHA1 Message Date
Zef Hemel 225cbc2ec3 Fix node.js version to 24.13 2026-02-14 22:17:37 +01:00
Zef Hemel f951d6e74c Merge branch 'main' of github.com:silverbulletmd/silverbullet into to-node 2026-02-14 22:10:42 +01:00
Zef Hemel 02bd8ed362 Migration Deno -> Node.js
* First pass
* Now using vitest for tests
2026-02-14 22:08:35 +01:00
Matouš Jan FialkaandGitHub 3ddfab51e8 [Space Lua] Extend os (#1836) 2026-02-13 20:05:08 +01:00
Matouš Jan FialkaandGitHub e0182b3bb4 [Space Lua] Implement native Lua pattern matching engine (#1838)
* Add Lua *pattern matching engine* (`pattern.ts`) that directly ports
  `lstrlib.c` semantics.

* Integrate the new engine into the `string` API for `find`, `match`,
  `gmatch`, and `gsub` functions.

* Add a pattern test suite (`pattern_test.lua`) covering character
  classes, repetition quantifiers, edge cases as well as error
  conditions.

* Refactor `string_test.lua` to remove duplicated pattern tests that
  are now covered by the pattern test suite.

* Fix `string.rep` separator support.

* Fix `string.sub` index handling.

* Remove the obsolete `string_test2.lua` file.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-02-13 14:18:55 +01:00
Zef Hemel 8592b3add6 Lua snake_case -> camelCase naming in tests 2026-02-12 17:32:28 +01:00
Matouš Jan FialkaandGitHub 4979ac1907 [Space Lua] Rewrite os.date to support UTC mode and strftime specifiers (#1835)
* Aligned with Lua 5.4 `os.date` semantics: `!` prefix selects UTC,
  absent format defaults to `%c`, `*t` returns a table with `isdst`
  only for local time, invalid specifiers raise an error.

* All `strftime` specifiers documented in the Lua 5.4 reference manual
  are supported, including ISO week-based year (`%G`/`%g`/`%V`) and
  composite formats.

* Extensive test suite uses the Go reference timestamp
  `2006-01-02 15:04:05 UTC` (epoch `1136214245`) where every field -
  year, month, day, hour, minute, second — has a distinct value.

  Tests cover UTC and local modes, AM/PM, Sunday edge cases for
  `%u`/`%w`, ISO week-year boundaries, `%%` escaping, `*t` table fields,
  and invalid specifier rejection.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-02-12 17:24:03 +01:00
Zef Hemel 568a3b65ab Lua: string.format: revert map back into for loop 2026-02-12 15:24:35 +01:00
75cc79800f Space Lua: Align numeric/table semantics with Lua, align number formating, optimize loops allocations (#1823)
* Don't know what's going on with the Deno docker image, disabling the deno.lock file for now

* Another try

* Space Lua: Align numeric and table semantics with Lua

This change improves Space Lua compatibility with standard Lua 5.4,
focusing on numeric subtypes and table behavior. The test suite is
extended to lock in the expected semantics and should pass under both
Space Lua and a Lua interpreter.

SUMMARY OF CHANGES
------------------

Tighten Lua compatibility across evaluator and runtime:

- correct metamethod dispatch (`__index`, `__newindex`, `__call`,
  comparison metamethods),

- loop limits,

- raw metamethod lookups.

Rework numeric semantics to preserve Lua **integer** vs **float**
behavior:

- $0$ vs $0.0$ and $-0.0$,

- explicit zero kind representation, and

- updates arithmetic/bitwise coercions accordingly.

Improve parser correctness by rejecting **unary plus** with aligned Lua
errors and better parsing errors reporting.

Fix `stdlib` behavior to match that of Lua:

- `table` function `concat`, `insert`, `remove`, `sort` and `unpack`
  gain metamethod awareness and enforce Lua errors,

- `ipairs` iteration updated to stop on first nil and honor `__index`,

- `tonumber` updated to Luae conversion using `luaToNumberDetailed`,

- `math.modf` return corrected,

- `math.type` accuracy improvements for float/integer and $-0.0$,

- `math.pi` added.

Fix numeric subtypes for `/` and `^` operators so `math.type` matches
Lua results using tagging as well as unary `-`.

Expand test coverage:

- new `metamethods_test.lua` for Lua metamethod/operator semantics,

- extend arithmetic and length tests for zero-kind propagation and
  `rawlen` vs `__len` metamethod,

- Extend `math` test suite to test proper Lua alignment (`math.type` and
  more), and

- update context error expectations for Lua error messages.

RATIONALE
---------

Lua differs from JavaScript by having two numeric subtypes: **integer**
and **float**. Operators depend on the subtype: `+`, `-`, `*`, `//` and
`%` use integer mode when both operands are integers and float mode
otherwise. Bitwise operators require integers and `math.type(x)` reports
"integer" or "float". JavaScript has one numeric primitive type
(`number`) so a plain number value cannot record whether Lua considers
a value to be a float when the value has no fractional part (for example
$2.0$).

Lua also differs from "everything is IEEE 754 double" because the rules
are defined in terms of integer and float subtypes. Float operations
preserve IEEE 754 behavior including `NaN`, infinities and signed zero
($-0.0$) which affects results like $1/0.0$ versus $1/-0.0$. Integer
arithmetic does not preserve $-0$ and collapses it to $0$. Lua integer
arithmetic is exact within its integer range while JavaScript `number`
cannot exactly represent all integers in that range.

Lua numbers are integers or floats. Numeric strings coerce to integer or
float based on _lexical_ form. Each arithmetic operator selects the
result subtype from the operator rules and operand subtypes.  Integer
only operators (bitwise and `//` as integer division) require integer
representability. Mixed arithmetic promotes to float as needed.  Two
operators are **always float** typed: division (`/`) and exponentiation
(`^`) produce floats even if both operands are integers and even if the
numeric value has no fractional part. `math.type` reports that internal
subtype.

Tables are associative arrays and assigning `nil` removes a key. The
length operator `#` uses `__len` metamethod if present otherwise it uses
the raw length rule. `rawlen(table)` ignores `__len`. Without `__len`
Lua defines `#` as some boundary `N` such that `table[N]` is not `nil`
and `table[N+1]` is `nil`. If the table has holes (missing or `nil`
entries in the positive integer key sequence) the boundary may be non
unique so `#` is stable only for proper sequences without holes.

PERFORMANCE NOTES
-----------------

Numeric changes add small checks to preserve Lua integer and float
subtype semantics and avoid allocations except when the subtype would
otherwise be lost.

Some table operations may be slower due to stricter Lua 5.4 behavior
especially around length and sequence boundary handling which currently
requires extra metadata tracking and scans and cannot be avoided without
a completely different internal table representation.

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

* Another try

* Replace `LuaFloatTag` plain objects with boxed Number for float tagging

* Restore pre-merge eval/numeric architecture and fix regressions

This commit restores the original branch architecture.

On top of the restored foundation, float-typed integer results (e.g.
`1.0 + 1.0` = `2.0`, `0.0 // 1.0` = `0.0`) are now correctly tagged via
`makeLuaFloat` so that `tostring` and `math.type` report them as floats.
The *unary minus* fast path for float literals and the `tonumber`
function also preserve float tagging.

Performance regressions from the merge are addressed by avoiding
`Number` boxing for non-integer floats (`3.14` needs no tag — it is
unambiguously float), adding *string key* fast paths in `LuaTable`
`has`/`rawGet`/`rawSet` to skip numeric normalization for the dominant
case, and inlining a `typeof` check in math standard library functions
to avoid function call overhead on plain numbers.

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

* Replace boxed `Number` float tagging with plain tagged objects

* Replace `new Number()` boxing with plain tagged float objects for Lua
  float type tracking.

* Integer-valued floats that need type disambiguation are now
  represented as `{ value: number, isFloat: true }` instead of boxed
  `Number` objects with a symbol property.

* Pre-allocated singletons are used for positive and negative float
  zeros to avoid allocation entirely in common cases.

* Updated all detection, unwrapping, and coercion paths across
  `numeric.ts`, `runtime.ts`, `eval.ts`, `stdlib.ts`, and `stdlib/`
  modules to use the new `isTaggedFloat` type guard.

* Removed all `instanceof Number` checks.

* Deleted the `FloatKind` symbol and eliminated redundant helpers
  `isLuaFloat`, `isFloatTag`, `getZeroBoxKind` and `toPlainNumber` that
  became dead code.

* Simplified `math.type`, `luaToString`, `luaEquals`, `luaTypeName` and
  various other key normalization paths.

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

* Add fast paths in `coerceNumericPair` for tagged float operands

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

* Fix copy/paste typo

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

* Avoid extra `LuaEnv` allocations in "For" and "ForIn" loops

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

* [Space Lua] Reuse loop variable environment in `for` and `for-in` loops

Numeric `for` and generic `for-in` loops allocated a fresh `LuaEnv` on
every iteration to hold loop variables. But this is only necessary when
a closure inside the loop body captures the loop variable.

The optimization uses a two-level check computed at parse time. If no
function definition exists in the loop's subtree, environment reuse is
safe. When a function definition is present a deeper analysis walks the
block to determine whether any function body references the loop
variable names without them being shadowed by its own parameters. When
a closure captures a loop variable the loop fall back to per-iteration
allocation.

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

* [Space Lua] Format numbers using standard Lua rules

Standard Lua formats floats via C `sprintf("%.14g")` (14 significant
digits, scientific notation when shorter, exponent padded to 2 digits,
and a guaranteed `.0` suffix for integer-valued floats).

* Replace the old `luaFormatNumber` with JS `toPrecision(14)`-based
  implementation that reproduces this behavior.

* Integrates it so that `${}` expressions in the UI also display
  numbers correctly.

* Fixes tagged floats (`{ value, isFloat }`) were being stripped by
  `luaValueToJS` or matched as plain objects before reaching the number
  formatter. This caused `${}` expressions to render raw JS numbers.

Examples:

```
- ${tostring(2^63)}
- ${2^63}
- ${(2^63)}
```

All of the the above examples show correct `9.2233720368548e+18` now.

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

* [Space Lua] Fix `string.format` for floats and tagged numbers

Unwrap tagged floats before `printf`, handle `inf`/`-inf`/`-nan` in
`formatDouble`, and fix `%g` producing `0e+00` for zero. Hopefuly it's
enough to gain Lua formatting.

Tests:

```
- ${string.format("%.14g", 0.0)} - `0`
- ${string.format("%.14g", 1.0)} - `1`
- ${string.format("%.14g", 1/3)} - `0.33333333333333`
- ${string.format("%.14g", math.pi)} - `3.1415926535898`
- ${string.format("%.14g", 1e-10)} - `1e-10`
- ${string.format("%.14g", 1e18)} - `1e+18`
- ${string.format("%.14g", 2^63)} - `9.2233720368548e+18`
- ${string.format("%.14g", 2^53)} - `9.007199254741e+15`
- ${string.format("%.14g", 1.7976931348623e+308)} - `1.7976931348623e+308`
- ${string.format("%.14g", 5e-324)} - `4.9406564584125e-324`
- ${string.format("%.14g", 0/0)} - `-nan`
- ${string.format("%.14g", 1/0)} - `inf`
- ${string.format("%.14g", -1/0)} - `-inf`
```

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

* [Space Lua] Add and integrate new `luaFormat` utility and test suite

* Add `luaFormat` string formatting function compatible with Lua, and
  integrate it across the codebase as a replacement for prior formatting
  approaches.

* Add extensive test suite.

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

* Fix check

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

* [Space Lua] Add `%a`/`%A` and `%q` format specifiers to `string.format`

Implement hexadecimal floating-point (`%a`/`%A`) and quoted literal
(`%q`) specifiers.

* Add `%a`/`%A` as IEEE 754 double decomposition with full flag, width
  and precision support.

* Add `%q` as producind valid Lua literals for strings, numbers,
  booleans and nil.

* Use `Math.PI` for `math.pi` to preserve full double precision.

* Remove Deno based test suite and replace it with native Lua test
  suite.

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

* [Space Lua] Add `%p` format specifier to `string.format`

In standard Lua, `%p` formats the internal C heap address of a value,
producing output like `0x55a3bc4e2f10`. It works on tables, functions,
threads, strings, and userdata (GC-ed objects). For `nil`, booleans, and
numbers it returns `(null)`.

In Space Lua, there are no *raw memory addresses* since the runtime is
JavaScript. Instead, `%p` assigns a *stable sequential integer* to each
object via a `WeakMap`, formatted as a 14-digit zero-padded hex value.
The key difference is that identifiers are deterministic and sequential
rather than random-looking heap addresses:

```lua
local t = {}

print(string.format("identifier: %p", t)) -- 0x00000000000001
print(string.format("the same:   %p", t)) -- 0x00000000000001
print(string.format("another:    %p", {}) -- 0x00000000000002
```

For strings, a regular `Map` is used so identical string content always
produces the same identifier.

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

* Revert merge changes to the deno.json

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

* Replace `interface` with `type`

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

* Remove `has_math()` relict function test

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

* Refactor loop to map

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

* Remove `Deno.remove("deno.lock")` weirdness

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

* Refactor: Early return undefined in `astNumberKind` instead of assigning

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

---------

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
Co-authored-by: Zef Hemel <zef@zef.me>
2026-02-12 15:22:12 +01:00
rktjmpandGitHub 9dc6ed2193 Honor openIfExists: true when using Page: From Template command (#1831)
* Improve Page Template option behaviour documentation

* Check pageName == nil or "" when getting page template name from prompt

* Honor `openIfExists: true` when using `Page: From Template` command
2026-02-12 11:18:03 +01:00
Zef Hemel ab9965a629 Revert removal of item's toPos 2026-02-12 11:06:20 +01:00
rktjmpandGitHub 4fdc8c1af5 Vim mode binding collision documentation (#1827) 2026-02-08 15:22:30 +01:00
rktjmpandGitHub 432e7b090d Retain timezone in system.getVersion() date-time (#1828) 2026-02-07 07:08:39 +01:00
Zef Hemel 047f532477 Add date of build with system.getVersion()
Fixes #1817
2026-02-06 16:23:40 +01:00
rktjmpandGitHub 8754b685ba Ensure command keybindings work reliably in any vim-mode (#1821)
When the vim extension is enabled and in "normal" mode, some default
bindings collide with Silverbullets commands (eg: `ctrl-p` - Share,
`ctrl-o` - Open Document, `ctrl-e` - Export, `ctrl-g h` - Home). These
vim bindings are not always functional (they may appear to do nothing
depending on vims state). This gives the impression that Silverbullet is
bugged and wont trigger commands. In "insert" mode, most bindings are
passed through correctly with some exceptions (eg: `ctrl-o`).

By splitting the command keybindings into their own keymap extension and
loading it before the vim extension, we can ensure Silverbullet commands
always trigger.

This does mean some vim bindings are overshadowed, but if a binding
triggers a Silverbullet command, its generally obvious that *something*
happened and the user should be able to recognise why the vim binding
failed and then rebind the command or vim mapping.
2026-02-06 16:12:02 +01:00
rktjmpandGitHub d285288add Support embedding youtube shorts (#1824) 2026-02-06 16:03:06 +01:00
rktjmpandGitHub 2c1cc8ced1 Make any frontmatter <scheme>:// URI's clickable (#1822)
* Make any frontmatter <scheme>:// URI's clickable

http/https links are opened in a new tab/window (via target="_blank"),
other schemes are opened in the current tab, as the browser will prompt
the user to open another application (or do this automatically).

Per https://www.rfc-editor.org/rfc/rfc3986#section-3.1, the scheme must
follow the pattern:

    scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

* Make `mailto:...` strings clickable in frontmatter
2026-02-06 16:01:39 +01:00
Zef Hemel dcf4f126e6 Fix docker builds 2026-02-06 14:49:20 +01:00
Zef Hemel c199aba3d8 Dockerfile tweaks to fix build 2026-02-06 09:24:36 +01:00
Zef Hemel 4647d70164 Deno deno.lock 2026-02-06 09:13:05 +01:00
Zef Hemel 4524bfb14e Bump Deno to 2.6.8 2026-02-06 08:23:37 +01:00
Zef Hemel 2cea80f1de Swap out @luca/esbuild-deno-loader with "official" deno ES build loader (fixes building with Deno 2.6.5+ versions)
- Replaced `@luca/esbuild-deno-loader` with a new `build_deps.ts` file to manage build dependencies.
- Breaking change to plug-compile: --importmap no longer supported, use -c instead to pass in a deno.json (which can include a "import" map).
2026-02-06 08:12:11 +01:00
Zef Hemel 502b636aef Fixes #1815: Changes how index status is tracked
- New check for full indexing completion
- Renamed `hasInitialIndexCompleted` to `hasFullIndexCompleted` for clarity.
- Removed file:initial event (no longer required and not documented for public consumption)

Hopefully doesn't introduce new regressions. Needs testing time "in the field".
2026-02-05 11:20:11 +01:00
Zef Hemel f6d2e37d25 Reduce logging noise 2026-02-05 11:09:05 +01:00
Zef Hemel 40895adc63 Enhance link indexing to support additional link types
* New "type" attribute for links (page, file, url)
* Now indexes external links as well
2026-02-05 09:24:38 +01:00
Zef Hemel 66807fa3bd Addresses some fuzzy search edge cases 2026-02-05 09:20:30 +01:00
Zef Hemel 8712d33b4a Optimize linked tasks query slightly 2026-02-05 09:06:35 +01:00
Zef Hemel 01a14d4e58 Add range attribute to built-in tag schemas 2026-02-05 09:05:57 +01:00
Zef Hemel 0058d1ff31 Handle edge case where index version is > than desired (should still consider the initial index to be completed) 2026-02-05 09:05:22 +01:00
Zef Hemel 9771d3ca58 Fix infinite reindexing
This could occur if two tabs/windows have SilverBullet open but in different versions (with different desiredIndexVersions). Now only triggers a reindex ONLY if the new number is higher (not if it's simply different, as before).
2026-02-05 08:24:12 +01:00
Zef Hemel 81c71bfdd2 Finetuning fuzzy search weights and threshold for improved search accuracy
- Increased weights for various search keys to prioritize more relevant matches.
- Added sorting logic to make sure aspirint pages are sorted last.
2026-02-05 08:18:03 +01:00
Zef Hemel e0d173914f Inline Page Template content on website 2026-02-04 19:25:41 +01:00
Zef Hemel 0f6f06a14f Website docs refactoring (Lua, mostly) 2026-02-04 17:03:55 +01:00
Zef Hemel 140224571e Assign differerent CSS classes to attributes names and value (sb-attribute-name and sb-attribute-value respectively) 2026-02-04 15:29:22 +01:00
Zef Hemel 4c1693714f Make docker build manually triggerable 2026-02-03 16:06:57 +01:00
Zef Hemel 34f34f9347 CHANGELOG fix 2026-02-03 16:02:14 +01:00
Zef Hemel 248abf5aec make fmt 2026-02-03 15:59:54 +01:00
Zef Hemel 0773df31e2 Add validation and error handling for object indexing
- Introduced a new `validate` callback for `tag.define`
- Added `index.validateObjects` API to validate and transform objects before indexing.
- Updated relevant documentation and examples to reflect these changes.
2026-02-03 15:59:04 +01:00
Zef Hemel 3d1e569bd2 Refactor page metadata access in Client class
- Introduced `currentPageMeta` method to encapsulate access to the current page's metadata.
- Updated references to page metadata throughout the codebase to use the new method, improving code readability and maintainability.
- Adjusted related components in the UI and linting logic to utilize the new method for consistency.
2026-02-03 15:57:34 +01:00
Zef Hemel c2f87f259f Fix page template schema 2026-02-03 11:34:00 +01:00
Zef Hemel ed7ccaa216 Schemas for page templates and slash templates 2026-02-03 10:52:18 +01:00
Zef Hemel 7adeb4bd30 CHANGELOG updates 2026-02-03 10:26:26 +01:00
Zef Hemel 6fff01ed3a (Hopefully) further improves sync snapshot handling
Service workers are a bit of a wild west: they can be killed at any time for any reason. This meant that a service worker (and with that a sync cycle) could be killed mid-sync, where files are already synced, but the _snapshot_ has not yet been persisted to the database. These changes persist the snapshot after ever single file sync operation (before: fully sync cycle), removing or at least lowering the chance of this happening. This can be a bit slower, but it's probably worth it.
2026-02-03 09:54:33 +01:00
Zef Hemel 5113a082a9 Remove confusing log message for MQ 2026-02-03 09:51:00 +01:00
Zef Hemel dbf95f7fe2 Fix lint 2026-02-03 09:50:25 +01:00
Zef Hemel 9057702557 Merge Client: Clean into Client: Wipe and remove Client: Clean
Client: Wipe now also deletes redundant other databases.

Related to #1798
2026-02-03 09:48:01 +01:00
Zef Hemel 3b9fb0e944 Merge branch 'main' of github.com:silverbulletmd/silverbullet 2026-02-03 08:56:52 +01:00
Zef Hemel b8b1fb52bb Changes UI progress update logic
Introduced a maximum observed queue size to improve progress percentage calculation, no more "67" fallback value.

Part of #1798
2026-02-03 08:56:41 +01:00
Lajos PappandGitHub 48cef27ce5 fix: undefined SB_PORT in healthcheck (#1812) 2026-02-02 21:50:56 +01:00
Zef Hemel 9667916c9c Adds "Page: Create Under Cursor" command
Command that allows creating a new page based on the wiki link under the
cursor.
2026-02-02 17:00:56 +01:00