Files
Marcos Paulo e8c8c06d1e
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: smart folder model, media time fragments, link card URL guard (MiniMax); specs for 10 more gaps (Codex) and the registry with bloat measurements
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 14:41:26 -03:00

5.5 KiB

Markdown pipe-table formulas (agy gap 15, roadmap 40)

Pure calculation in existing crates/blocks; engine command and current markdown table UI. No new crate/dependency. Bases computed columns stay separate.

Research (2026-10-21; agy claims checked)

agy's Advanced Tables URL is WRONG (404). Correct project: https://github.com/tgrosinger/advanced-tables-obsidian . Its own help says formulas are on the line following a table, evaluated explicitly: https://raw.githubusercontent.com/tgrosinger/advanced-tables-obsidian/main/docs/help.md . Thus agy's =SUM(B1:B5) cells are a requested design, not verified Advanced Tables syntax. Drop Notion spreadsheet-equivalence claim; a database formula property is a different model. No claim of full Excel/Org/Advanced Tables compatibility.

Problem and goal

Small budgets in markdown pipe tables need simple arithmetic without moving into a database. Formula cells remain literal markdown source; Visual mode shows calculated values and exposes formula source on edit. Source/Obsidian retain formulas legibly.

Design decisions

D1 Opt-in syntax and coordinates

Enable only a table immediately followed by <!-- notescraft:table-formulas v1 --> on next line, so existing =... prose is unchanged. Numeric data-row coordinates: A1 is first body row, first column; header and delimiter rows are excluded. Formula cell starts = after whitespace trim; literal text starting = uses inline code. Numbers are finite signed decimal with optional exponent, decimal dot only. Empty referenced cell is 0; nonnumeric text is a typed error, never silently parsed from formatted markup. Grammar: arithmetic + - * /, unary sign, parentheses, cell refs and rectangular ranges only as aggregate args; SUM, AVG, MIN, MAX, COUNT. COUNT counts numeric cells, ignores empty cells, errors on text. AVG/MIN/MAX empty range errors. No dates, strings, scripts, network, external/cross-table refs, implicit locale conversions or volatile functions.

D2 Evaluation and safety

New crates/blocks/src/table_formulas/{mod,parse,eval}.rs accepts cell-source grid, emits per-cell Number or {code,span} error. Dependency graph evaluates once per source change, detects cycles and propagates dependency errors; no recursive traversal without bounds. Caps: 10,000 cells, 1 KiB per formula, 128 AST depth, 100,000 dependency edges/expanded-range visits and 1,000,000 evaluation operations per table. Exceeding cap is explicit error, never truncation. Out-of-grid refs, division by zero, nonfinite arithmetic, unknown function and cycles have stable codes. Display finite numbers with Rust shortest-roundtrip formatting; no promise of exact decimal accounting. Row/column insert/delete preserves formula text verbatim: references are positional and may change result; UI warns before structural edit of enabled table, no hidden Excel-style rewrite.

D3 Commands/UI and source integrity

table.formulas.evaluate {markdown,table_index} -> {cells:[{row,column,value?,error?}],diagnostics} read-only; zero-based table_index, one-based result coordinates. Engine uses shared pure table extraction based on markdown source ranges; UI parser at views/note_view/blocks/table.rs delegates cell splitting to pure module where necessary, preserving existing rendering. No second table interpretation for engine/UI. Read-only Visual evaluation cached by exact table source plus opt-in marker; formula editor always shows original literal. Editing goes through existing NoteEdit, never writes computed values. Header/body rendering exposes localized error tooltip with source span. Marker absent -> exact existing behavior. CSV/export remains raw formula source in v1, visibly documented; no automatic spreadsheet execution export. Engine registry and assistant gate classify evaluate READ.

Acceptance criteria

  1. Opted-in table A1=2, B1=3, C1 = A1*B1, aggregate over a numeric range render correct values while source stays byte-identical.
  2. Marker absent and inline-code =literal cells keep existing rendering and never evaluate.
  3. Cycle, unknown function, text operand, out-of-bounds, division by zero, overflow and every cap return bounded diagnostics without panic.
  4. Unicode text, escaped pipes, code-span pipes, CRLF and short rows produce identical coordinates in command and Visual view.
  5. Changing one literal updates dependent results; unchanged frame performs no reparse/evaluation (counter test).
  6. Editing/undo retains formula syntax, table marker and unrelated bytes; structural edit requires confirmation and preserves refs verbatim.

Open owner questions

  • Q1: approve opt-in comment and A1 body-only coordinates? Proposal yes; explicitly NotesCraft syntax, not Advanced Tables compatibility.
  • Q2: approve finite f64 v1 rather than accounting-grade decimal? New decimal dependency needs owner approval before addition.
  • Q3: approve positional references unchanged on structural edits, or require reference rewrite before release? Proposal warning plus unchanged formulas.

Feature ideas (researched, ranked)

  1. Separate explicit materialize-results command with preview, inspired by Advanced Tables explicit evaluation: https://raw.githubusercontent.com/tgrosinger/advanced-tables-obsidian/main/docs/help.md .
  2. Import Advanced Tables trailing formulas only after a compatibility spec against upstream syntax: https://github.com/tgrosinger/md-advanced-tables/blob/main/docs/formulas.md . URL is linked from verified help; syntax has not been validated for this v1.
  3. Offer Bases computed properties when table grows into a note database: https://obsidian.md/help/bases/syntax .