document cross-sheet references

This commit is contained in:
Horizontal42 2026-07-02 05:43:33 +03:00
parent 90c19e343f
commit 26a6bc283b
4 changed files with 59 additions and 0 deletions

View file

@ -113,6 +113,30 @@ snapshot price) plus the mirror list in `src-tauri/src/main.rs`.
- The registry is rebuilt never; extensions mutate it (add phrases/functions)
at startup.
## Cross-sheet references
`@Sheet.key` is lexed directly in `lexer.ts` (not through the phrase
registry — sheet titles are arbitrary user text, not vocabulary), producing
an `xref` lexeme carrying `{ sheet, key }`. The engine only knows how to
*ask* for a value: `EvalCtx.resolveXRef?.(sheet, key)` returns
`{ ok: true; value } | { ok: false; reason }`; when no resolver is supplied
(tests, extensions, `evaluateExpression`) an xref is simply unresolved.
Unresolved xrefs throw `XRefError` internally, caught in
`SumEngine.evaluateDocument` and surfaced as `LineResult.error` (rendered as
`#ref?` in the results column) — every other evaluation error still resolves
to a silent blank line, unchanged.
The engine has no concept of "other sheets" — that lives entirely in
`src/workspace.ts`. `Workspace` reads all sheet texts from the app's
in-memory `data.contents`, caches each sheet's exports (its assigned
variables, `total`, `last`) after first evaluating it, and invalidates a
sheet's cache plus every transitive dependent (found via a text scan for
`@Name.`) when it's edited or rates refresh. `Workspace.evaluateSheet(id,
text)` pushes `id` onto a resolving-stack for the duration of the call, so a
sheet that references itself — directly or through another sheet — hits an
already-on-the-stack check and resolves to `circular reference` instead of
recursing forever.
## UI notes
- CodeMirror injects its base theme at runtime *after* `app.css`, so anything

View file

@ -111,6 +111,29 @@ src-tauri/
- Реестр не пересобирается никогда; расширения мутируют его (добавляют фразы/функции)
при запуске.
## Ссылки между листами
`@Sheet.key` лексится напрямую в `lexer.ts` (не через реестр фраз — названия
листов это произвольный текст пользователя, а не словарь), давая лексему
`xref` с `{ sheet, key }`. Движок умеет только *спросить* значение:
`EvalCtx.resolveXRef?.(sheet, key)` возвращает
`{ ok: true; value } | { ok: false; reason }`; без резолвера (тесты,
расширения, `evaluateExpression`) ссылка просто не резолвится. Нерешённые
ссылки бросают `XRefError` внутри, он ловится в `SumEngine.evaluateDocument`
и превращается в `LineResult.error` (рисуется как `#ref?` в колонке
результатов) — все прочие ошибки вычисления по-прежнему тихо дают пустую
строку, это не изменилось.
Движок не знает про "другие листы" — это целиком живёт в `src/workspace.ts`.
`Workspace` читает тексты всех листов из `data.contents` приложения,
кэширует экспорт каждого листа (его присвоенные переменные, `total`, `last`)
после первого вычисления, и сбрасывает кэш листа плюс всех его транзитивных
зависимых (находятся сканированием текста на `@Name.`) при правке листа или
обновлении курсов. `Workspace.evaluateSheet(id, text)` кладёт `id` в стек
резолвинга на всё время вызова, поэтому лист, ссылающийся сам на себя —
напрямую или через другой лист — сразу натыкается на проверку "уже в
стеке" и получает `circular reference` вместо бесконечной рекурсии.
## Особенности UI
- CodeMirror встраивает свою базовую тему во время выполнения *после* `app.css`,

View file

@ -88,6 +88,12 @@ plus `in fraction` (0.75 → 3/4) and `in roman` (2026 → MMXXVI).
`//` comments. The status bar always shows the sheet total; select a few lines
to see just their sum. Add `chart` at the end of a block to draw a sparkline.
**Cross-sheet references** — pull a value from another sheet with `@`:
`@Budget.total`, `@Budget.rent`, `@[Trip to Lisbon].food`. A sheet made of
nothing but references becomes a live dashboard:
`@Assets.total - @Debts.total`. Give the source sheet a fixed name (not an
auto-derived one) so the reference doesn't break when its first line changes.
## Handy things
- **Ctrl+Alt+N** (configurable — the settings field records keys you press)

View file

@ -85,6 +85,12 @@ AAPL в USD → $213.55
выдели несколько строк — увидишь их сумму. Добавь `график` в конце блока чтобы
нарисовать спарклайн.
**Ссылки между листами** — тяни значение из другого листа через `@`:
`@Бюджет.total`, `@Бюджет.аренда`, `@[Поездка в Лиссабон].еда`. Лист из одних
ссылок становится живым дашбордом: `@Активы.total - @Долги.total`. Дай листу-
источнику постоянное имя (не автоматическое), иначе ссылка сломается при
правке первой строки.
## Удобные мелочи
- **Ctrl+Alt+N** (настраивается — поле в настройках записывает нажатые клавиши)