document

package
v2.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package document defines the CalcMark document structure with blocks.

A CalcMark document consists of blocks: - CalcBlock: 1+ consecutive calculation lines (like Jupyter code cell) - TextBlock: markdown text (like Jupyter markdown cell)

Block boundaries: - 2 consecutive empty lines (\n\n\n) = hard boundary between blocks - 1 empty line (\n\n) = soft boundary (stays within current block)

Package document provides the CalcMark document model with blocks.

This package implements a higher-level document abstraction that manages mixed markdown and calculation content as a structured collection of blocks.

Architecture

Key components:

  1. Block types (CalcBlock, TextBlock)
  2. Document structure with block management
  3. Dependency tracking between calc blocks
  4. Incremental evaluation for editors

Block Types

CalcBlock: calculation code

block := &CalcBlock{}
block.AppendLine("x = 5")
block.AppendLine("y = x + 3")

TextBlock: markdown or prose

block := &TextBlock{}
block.AppendLine("# My Document")
block.AppendLine("Some text here")

Document Model

Documents manage blocks in order:

doc := document.NewDocument()
calcBlock := &CalcBlock{}
calcBlock.AppendLine("total = 100")
doc.AppendBlock(calcBlock)

textBlock := &TextBlock{}
textBlock.AppendLine("# Results")
doc.AppendBlock(textBlock)

Incremental Evaluation

The document model supports incremental updates for interactive editors:

// Initial evaluation
doc.Evaluate()

// User edits a block
doc.ReplaceBlockSource(blockID, []string{"total = 200"})

// Re-evaluate only affected blocks
doc.EvaluateBlock(blockID)

Dependency Tracking

The document tracks dependencies between blocks to enable smart re-evaluation. When a block changes, only dependent blocks are re-evaluated.

Line Detection

Automatic detection of calculation vs markdown:

detector := document.NewDetector()
blockType := detector.DetectLine("x = 5")  // CalcBlock
blockType = detector.DetectLine("# Title") // TextBlock

Use Cases

This package is designed for:

  • Interactive markdown editors with live calculation
  • Document processing pipelines
  • Static site generators with embedded calculations
  • Notebook-style interfaces

Performance

Document operations are optimized for incremental updates. Evaluation complexity is O(affected blocks) not O(total blocks).

Package document provides document structure and parsing for CalcMark.

Package document provides document structure and parsing for CalcMark.

Package document provides document structure and parsing for CalcMark.

Index

Constants

This section is empty.

Variables

View Source
var ErrFrontmatterUnclosed = fmt.Errorf("frontmatter not closed: missing closing '---' delimiter")

ErrFrontmatterUnclosed is returned by ParseFrontmatter when a document starts with an opening `---` fence but no matching closing fence is present. Along with this error, ParseFrontmatter returns the full source as the remaining body so interactive callers (editors, LSPs) can render in-progress content instead of erroring out.

Strict callers (like NewDocument) may continue to treat this as fatal. Lenient callers should check `errors.Is(err, ErrFrontmatterUnclosed)` and use the returned source.

View Source
var Registry = []RegisteredKey{
	{
		Name: "exchange",
		Type: FrontmatterKeyMapStringDecimal,
		Doc:  "Currency exchange rates as 'FROM_TO' -> rate (e.g., 'USD_EUR': 0.92 means 1 USD = 0.92 EUR). Used by currency conversion expressions in the document.",
	},
	{
		Name: "globals",
		Type: FrontmatterKeyMapStringString,
		Doc:  "User-defined variables as name -> CalcMark expression string. Each value is parsed as a CalcMark expression and made available throughout the document.",
	},
	{
		Name: "scale",
		Type: FrontmatterKeyStruct,
		Doc:  "Document-level scale transform. Either a positive number (factor only) or a map with 'factor' and optional 'unit_categories' to restrict which categories scale.",
	},
	{
		Name:       "convert_to",
		Type:       FrontmatterKeyEnumString,
		Doc:        "Document-level unit system conversion. Either the string 'si' or 'imperial', or a map with 'system' and optional 'unit_categories' to restrict which categories convert.",
		EnumValues: []string{"si", "imperial"},
	},
	{
		Name: "measurement",
		Type: FrontmatterKeyStruct,
		Doc:  "Disambiguates ambiguous unit names. Map with axis keys 'volume' (us|imperial), 'mass' (standard|troy), 'ton' (short|long|metric), and optional 'strict' boolean controlling formatter annotation.",
	},
	{
		Name: "fiscal_year_starts",
		Type: FrontmatterKeyStruct,
		Doc:  "Anchors fiscal-period expressions (FQ1, FY26, 'this fiscal quarter') to a calendar start. String value naming a month, optionally with a day (e.g., 'July', 'October 1').",
	},
	{
		Name:       "calendar_year_offset",
		Type:       FrontmatterKeyEnumString,
		Doc:        "Selects which calendar year a fiscal-year label refers to. 'before' (default) — FY label = year FY ends in (Australian government year, US tax year, most companies). 'after' — FY label = year FY starts in (some companies). Has no effect when fiscal_year_starts is January.",
		EnumValues: []string{"before", "after"},
	},
}

Registry lists every CalcMark-grammar frontmatter key recognized by ParseFrontmatter. Non-registered top-level keys are preserved verbatim in Frontmatter.Extra and carry no CalcMark semantics.

Complexity note: lookup helpers walk this slice linearly. With ~6 entries this is faster than a map and keeps the data trivially inspectable. If the registry grows past ~50 entries, consider an auxiliary map index.

Functions

func ExchangeRateKey

func ExchangeRateKey(from, to string) string

ExchangeRateKey creates a normalized key for looking up exchange rates. Format: "FROM_TO" (e.g., "USD_EUR").

func ExtractStatementReferences

func ExtractStatementReferences(node ast.Node) []string

ExtractStatementReferences returns the sorted set of variable names referenced by a single AST statement. For assignments, only RHS references are included (the defined variable is excluded by extractIdentifiers). Returns nil for a nil node. O(n) time where n is the number of AST nodes in the statement.

func IsRegisteredKey

func IsRegisteredKey(name string) bool

IsRegisteredKey reports whether name is a CalcMark-grammar frontmatter key. Comparison is case-sensitive. Runs in O(|Registry|).

func ParseExchangeRateKey

func ParseExchangeRateKey(key string) (from, to string, err error)

ParseExchangeRateKey splits a key like "USD_EUR" into (from, to) parts. Returns an error if the key format is invalid. Currency codes must be exactly 3 ASCII letters (ISO 4217 format, e.g., USD, EUR, GBP).

Types

type Block

type Block interface {
	// Type returns the block type.
	Type() BlockType

	// Source returns the raw source lines.
	Source() []string

	// IsDirty returns true if the block needs re-evaluation/rendering.
	IsDirty() bool

	// SetDirty marks the block as needing update.
	SetDirty(bool)
}

Block represents a content block in a CalcMark document.

type BlockNode

type BlockNode struct {
	ID    string // UUID (session-ephemeral)
	Block Block  // Underlying block (CalcBlock or TextBlock)
}

BlockNode wraps a Block with metadata for incremental updates.

type BlockType

type BlockType int

BlockType identifies the type of block.

const (
	// BlockCalculation represents consecutive calculation lines.
	BlockCalculation BlockType = iota
	// BlockText represents markdown text.
	BlockText
)

func (BlockType) String

func (bt BlockType) String() string

type CalcBlock

type CalcBlock struct {
	// contains filtered or unexported fields
}

CalcBlock represents one or more consecutive calculation lines. Like a Jupyter code cell.

func NewCalcBlock

func NewCalcBlock(source []string) *CalcBlock

NewCalcBlock creates a new calculation block.

func (*CalcBlock) AddDiagnostic

func (cb *CalcBlock) AddDiagnostic(diag Diagnostic)

AddDiagnostic adds a single diagnostic to this block.

func (*CalcBlock) ClearDiagnostics

func (cb *CalcBlock) ClearDiagnostics()

ClearDiagnostics removes all diagnostics from this block.

func (*CalcBlock) ConvertApplied

func (cb *CalcBlock) ConvertApplied() []bool

ConvertApplied returns the per-statement conversion flags. A true value at index i means convert_to actually changed the unit for statement i (detected by comparing units before and after Apply).

func (*CalcBlock) Dependencies

func (cb *CalcBlock) Dependencies() []string

Dependencies returns variables referenced from other blocks.

func (*CalcBlock) Diagnostics

func (cb *CalcBlock) Diagnostics() []Diagnostic

Diagnostics returns structured errors/warnings with position info.

func (*CalcBlock) Error

func (cb *CalcBlock) Error() error

Error returns any evaluation error.

func (*CalcBlock) IsDirty

func (cb *CalcBlock) IsDirty() bool

func (*CalcBlock) LastValue

func (cb *CalcBlock) LastValue() types.Type

LastValue returns the value of the last statement in the block.

func (*CalcBlock) Results

func (cb *CalcBlock) Results() []types.Type

Results returns all per-statement evaluation results.

func (*CalcBlock) ScaleExempt

func (cb *CalcBlock) ScaleExempt() []bool

ScaleExempt returns the per-statement scale exemption flags. A true value at index i means statement i references @scale and should not be scaled (to prevent double-scaling).

func (*CalcBlock) SetConvertApplied

func (cb *CalcBlock) SetConvertApplied(applied []bool)

SetConvertApplied sets the per-statement conversion flags.

func (*CalcBlock) SetDependencies

func (cb *CalcBlock) SetDependencies(deps []string)

SetDependencies sets the dependencies.

func (*CalcBlock) SetDiagnostics

func (cb *CalcBlock) SetDiagnostics(diags []Diagnostic)

SetDiagnostics sets the structured diagnostics for this block.

func (*CalcBlock) SetDirty

func (cb *CalcBlock) SetDirty(dirty bool)

func (*CalcBlock) SetError

func (cb *CalcBlock) SetError(err error)

SetError sets the evaluation error.

func (*CalcBlock) SetLastValue

func (cb *CalcBlock) SetLastValue(val types.Type)

SetLastValue sets the last evaluated value.

func (*CalcBlock) SetResults

func (cb *CalcBlock) SetResults(results []types.Type)

SetResults sets the per-statement evaluation results.

func (*CalcBlock) SetScaleExempt

func (cb *CalcBlock) SetScaleExempt(exempt []bool)

SetScaleExempt sets the per-statement scale exemption flags.

func (*CalcBlock) SetStatements

func (cb *CalcBlock) SetStatements(stmts []ast.Node)

SetStatements sets the parsed AST nodes.

func (*CalcBlock) SetVariables

func (cb *CalcBlock) SetVariables(vars []string)

SetVariables sets the variables defined in this block.

func (*CalcBlock) Source

func (cb *CalcBlock) Source() []string

func (*CalcBlock) Statements

func (cb *CalcBlock) Statements() []ast.Node

Statements returns the parsed AST nodes.

func (*CalcBlock) Type

func (cb *CalcBlock) Type() BlockType

func (*CalcBlock) Variables

func (cb *CalcBlock) Variables() []string

Variables returns variables defined in this block.

type CalendarYearOffset

type CalendarYearOffset int

CalendarYearOffset enumerates the FY-label conventions a document can declare via the `calendar_year_offset` frontmatter key.

const (
	// CalendarYearOffsetBefore is the default. The FY label corresponds
	// to the calendar year the FY ENDS in.
	CalendarYearOffsetBefore CalendarYearOffset = iota
	// CalendarYearOffsetAfter labels by the calendar year the FY
	// STARTS in.
	CalendarYearOffsetAfter
)

type ConvertToConfig

type ConvertToConfig struct {
	System         string   // "si" or "imperial"
	UnitCategories []string // empty = all
}

ConvertToConfig configures the document-level unit system conversion. When present, eligible quantities are converted to the target measurement system. UnitCategories restricts conversion to specific categories (empty = all).

type DependencyAnalyzer

type DependencyAnalyzer struct{}

DependencyAnalyzer extracts variable dependencies from CalcBlocks.

func NewDependencyAnalyzer

func NewDependencyAnalyzer() *DependencyAnalyzer

NewDependencyAnalyzer creates a new dependency analyzer.

func (*DependencyAnalyzer) AnalyzeBlock

func (da *DependencyAnalyzer) AnalyzeBlock(block *CalcBlock) error

AnalyzeBlock parses a CalcBlock and extracts: - Variables defined (from assignments) - Variables referenced (from expressions)

type Detector

type Detector struct {
	// contains filtered or unexported fields
}

Detector analyzes source text and splits it into blocks.

func NewDetector

func NewDetector() *Detector

NewDetector creates a new block detector.

func (*Detector) DetectBlocks

func (d *Detector) DetectBlocks(source string) ([]Block, error)

DetectBlocks splits source into blocks using these rules: - 2 consecutive empty lines = block boundary - 1 empty line = part of current block - Calculations vs text determined by parsing each line

Unicode-aware: handles all line terminators (LF, CRLF, CR, U+2028, U+2029).

func (*Detector) IsCalculation

func (d *Detector) IsCalculation(line string) (bool, error)

IsCalculation checks if a line is a valid calculation. The approach: if a line parses successfully as a calculation, it's a calculation. If it fails to parse, it's text (markdown).

Returns (true, nil) for valid calculation lines. Returns (false, nil) for text lines (including invalid syntax - treated as markdown).

This is the public API for determining line type. Used by the TUI to decide how to render lines in the preview pane.

type Diagnostic

type Diagnostic struct {
	BlockID   string
	Severity  string // "error", "warning", "hint"
	Code      string
	Message   string
	Detailed  string // Detailed explanation with context and guidance (from semantic checker)
	Line      int    // 1-indexed line number within the block (for block-internal lookups)
	Column    int    // 1-indexed column number
	DocLine   int    // 1-indexed document-absolute line number (0 if unknown)
	EndLine   int    // 1-indexed end line (0 if unknown — falls back to start line)
	EndColumn int    // 1-indexed end column (0 if unknown — falls back to end-of-line)
}

Diagnostic represents a validation issue with source position info.

type Document

type Document struct {
	// contains filtered or unexported fields
}

Document represents a CalcMark document with incremental evaluation. Tracks blocks, dependencies, and provides efficient change propagation.

Note: Document is a pure data structure and does NOT contain interpreter state. The impl/document.Evaluator is responsible for evaluation with its own environment.

func NewDocument

func NewDocument(source string) (*Document, error)

NewDocument creates a new document from CalcMark source and eagerly parses it.

func (*Document) ApplyFrontmatter

func (d *Document) ApplyFrontmatter(env EnvironmentWriter) error

ApplyFrontmatter injects frontmatter values (exchange rates, globals) into the given environment. This should be called before evaluation. The env parameter must implement EnvironmentWriter (e.g., *interpreter.Environment).

func (*Document) DeleteBlock

func (d *Document) DeleteBlock(blockID string) (*UpdateResult, error)

DeleteBlock removes a block and updates dependents.

func (*Document) EnsureFrontmatter

func (d *Document) EnsureFrontmatter() *Frontmatter

EnsureFrontmatter returns the frontmatter, creating an empty one if nil.

func (*Document) GetBlock

func (d *Document) GetBlock(id string) (*BlockNode, bool)

GetBlock returns a block by ID.

func (*Document) GetBlocks

func (d *Document) GetBlocks() []*BlockNode

GetBlocks returns all blocks in order.

func (*Document) GetBlocksInDependencyOrder

func (d *Document) GetBlocksInDependencyOrder(blockIDs []string) []string

GetBlocksInDependencyOrder returns block IDs sorted so that dependencies come before dependents. This is a topological sort based on the dependency graph. Useful for evaluating blocks in the correct order after a change.

func (*Document) GetFrontmatter

func (d *Document) GetFrontmatter() *Frontmatter

GetFrontmatter returns the document's frontmatter (may be nil).

func (*Document) GetTransitiveDependents

func (d *Document) GetTransitiveDependents(changedVars []string) []string

GetTransitiveDependents returns all block IDs that transitively depend on any of the given variables. This follows the dependency chain: if a→b→c, changing 'a' returns blocks containing 'b' AND 'c'.

This is the key API for reactive UIs: when a variable changes, call this to get the minimal set of blocks that need re-evaluation.

func (*Document) InsertBlock

func (d *Document) InsertBlock(afterBlockID string, blockType BlockType, source []string) (*UpdateResult, error)

InsertBlock inserts a new block after the specified block ID.

func (*Document) ReplaceBlockSource

func (d *Document) ReplaceBlockSource(blockID string, newSource []string) (*UpdateResult, error)

ReplaceBlockSource replaces the source of a block and propagates changes. Returns only the affected block IDs for efficient UI updates.

func (*Document) SetFrontmatter

func (d *Document) SetFrontmatter(fm *Frontmatter)

SetFrontmatter replaces the document's frontmatter.

type EnvironmentWriter

type EnvironmentWriter interface {
	Set(name string, value types.Type)
	SetExchangeRate(from, to string, rate decimal.Decimal)
}

EnvironmentWriter can receive frontmatter values during evaluation. This interface is implemented by impl/interpreter.Environment. It decouples the spec/document package from the impl/interpreter package.

type ExtraField

type ExtraField struct {
	Key   string
	Value any // string, int, float64, []any, map[string]any
}

ExtraField holds a non-CalcMark frontmatter key-value pair.

type FiscalYearConfig

type FiscalYearConfig struct {
	Month int // 1-12 (January-December)
	Day   int // 1-31 (defaults to 1 if not specified)
}

FiscalYearConfig holds the fiscal year start month and optional day.

type Frontmatter

type Frontmatter struct {
	// Exchange contains currency exchange rates as "FROM_TO" -> rate.
	// Example: "USD_EUR" -> 0.92 means 1 USD = 0.92 EUR
	Exchange map[string]decimal.Decimal

	// Globals contains user-defined variables as name -> expression string.
	// Values are CalcMark expressions that will be parsed and evaluated.
	// Example: "base_date" -> "Jan 15 2025", "tax_rate" -> "0.32"
	Globals map[string]string

	// Scale is the document-level scale transform (nil if not present).
	Scale *ScaleConfig

	// ConvertTo is the document-level unit system conversion (nil if not present).
	ConvertTo *ConvertToConfig

	// Measurement configures how ambiguous unit names are interpreted (nil if not present).
	Measurement *MeasurementFrontmatter

	// FiscalYearStarts configures the start of the fiscal year (nil if not set).
	// When set, fiscal expressions (FQ1, FY26, "this fiscal quarter") resolve relative
	// to this configuration. When nil, fiscal expressions produce an error diagnostic.
	FiscalYearStarts *FiscalYearConfig

	// CalendarYearOffset selects which calendar year an FY label refers
	// to. CalendarYearOffsetBefore (default) labels by the calendar
	// year the FY ENDS in (matches the Australian government year,
	// the US tax year, and most companies). CalendarYearOffsetAfter
	// labels by the calendar year the FY STARTS in. Only has effect
	// when FiscalYearStarts is non-nil and the start month is not
	// January.
	CalendarYearOffset CalendarYearOffset

	// Extra contains non-CalcMark frontmatter keys (e.g., title, author)
	// preserved in document order. Values are the raw YAML-parsed types
	// (string, int, float64, []any, map[string]any).
	Extra []ExtraField

	// KeyRanges maps each top-level frontmatter key (registered or Extra) to
	// the source range covering its key+value YAML block. Lines and columns are
	// 1-based, matching ast.Position convention (see spec/ast/position.go).
	// The range starts at the key identifier and ends at the last byte of its
	// value (for mappings/sequences, the last byte of the deepest child).
	//
	// Absent keys are simply not present in the map. Use the
	// `r, ok := fm.KeyRanges[key]` idiom; a returned zero-value ast.Range from a
	// missing key is indistinguishable from one explicitly stored as zero.
	//
	// Lines are document-relative: line 1 is the opening "---" fence and the
	// first key sits on line 2 in a typical frontmatter.
	KeyRanges map[string]ast.Range
	// contains filtered or unexported fields
}

Frontmatter represents structured metadata at the start of a CalcMark document. It is delimited by --- markers and contains YAML content.

Reserved keys (CalcMark grammar):

  • exchange: Currency conversion rates
  • scale: Document-level quantity scaling
  • convert_to: Document-level unit system conversion

User-defined variables go under 'globals':

---
exchange:
  USD_EUR: 0.92
scale: 4
convert_to: imperial
globals:
  base_date: Jan 15 2025
  tax_rate: 0.32
---

func ParseFrontmatter

func ParseFrontmatter(source string) (*Frontmatter, string, error)

ParseFrontmatter extracts YAML frontmatter from the beginning of a document. Returns the parsed frontmatter, the remaining source (without frontmatter), and any error.

Frontmatter must:

  • Start at line 1 with exactly "---"
  • End with a line containing exactly "---"
  • Contain valid YAML between the delimiters
  • Unknown top-level keys are silently ignored; only CalcMark keys are processed (exchange, globals, scale, convert_to)

If no frontmatter is present, returns (nil, source, nil).

If the opening fence is found but the closing fence is missing, returns (nil, source, ErrFrontmatterUnclosed). The full source is returned as body so lenient callers can render in-progress content.

func (*Frontmatter) ExchangeKeys

func (f *Frontmatter) ExchangeKeys() []string

ExchangeKeys returns exchange rate keys in insertion order. Falls back to sorted keys for backward compatibility when frontmatter is created via struct literals rather than ParseFrontmatter or SetExchangeRate.

func (*Frontmatter) GetExchangeRate

func (f *Frontmatter) GetExchangeRate(from, to string) (decimal.Decimal, bool)

GetExchangeRate looks up the rate to convert from one currency to another. Returns the rate and true if found, or zero and false if not defined.

func (*Frontmatter) GlobalKeys

func (f *Frontmatter) GlobalKeys() []string

GlobalKeys returns global variable names in insertion order. Falls back to sorted keys for backward compatibility when frontmatter is created via struct literals rather than ParseFrontmatter or SetGlobal.

func (*Frontmatter) HasExchangeRate

func (f *Frontmatter) HasExchangeRate(key string) bool

HasExchangeRate returns true if the exchange rate is defined in frontmatter.

func (*Frontmatter) HasGlobal

func (f *Frontmatter) HasGlobal(name string) bool

HasGlobal returns true if the global variable is defined in frontmatter.

func (*Frontmatter) HasGlobals

func (f *Frontmatter) HasGlobals() bool

HasGlobals returns true if any globals are defined in frontmatter.

func (*Frontmatter) HasScale

func (f *Frontmatter) HasScale() bool

HasScale returns true if a scale directive is defined in frontmatter.

func (*Frontmatter) LineCount

func (f *Frontmatter) LineCount() int

LineCount returns the number of source lines occupied by the frontmatter (including both --- delimiters). Returns 0 if no frontmatter is present.

func (*Frontmatter) Serialize

func (f *Frontmatter) Serialize() string

Serialize returns the frontmatter as a YAML string with --- delimiters. If the frontmatter has no content (no exchange rates, no globals), returns "". When rawSource is available (from parsing), the original text is preserved to support natural editing (Enter, whitespace, etc.) in the TUI editor.

func (*Frontmatter) SetExchangeRate

func (f *Frontmatter) SetExchangeRate(key string, rate decimal.Decimal)

SetExchangeRate sets an exchange rate. The key should be in FROM_TO format.

func (*Frontmatter) SetGlobal

func (f *Frontmatter) SetGlobal(name, valueExpr string)

SetGlobal sets a global variable value. The valueExpr is stored as the raw expression string for serialization.

func (*Frontmatter) SetRawSource

func (f *Frontmatter) SetRawSource(raw string)

SetRawSource replaces the serialized frontmatter text (including --- delimiters and trailing newline) without re-parsing YAML. This allows the TUI editor to preserve user-typed text even when intermediate edits produce invalid YAML. Parsed data (Globals, Exchange) remains unchanged until a valid parse succeeds.

type FrontmatterKeyType

type FrontmatterKeyType int

FrontmatterKeyType describes the value shape a registered CalcMark frontmatter key accepts. It exists so tooling (LSP completion, hover, semantic diagnostics) can describe and validate keys uniformly without special-casing each one.

const (
	// FrontmatterKeyMapStringDecimal: map of string -> decimal.Decimal.
	// Used by `exchange` (e.g., "USD_EUR" -> 0.92).
	FrontmatterKeyMapStringDecimal FrontmatterKeyType = iota

	// FrontmatterKeyMapStringString: map of string -> string.
	// Used by `globals` (variable name -> CalcMark expression source).
	FrontmatterKeyMapStringString

	// FrontmatterKeyEnumString: a string drawn from a fixed set of values.
	// EnumValues lists the accepted values in canonical order.
	FrontmatterKeyEnumString

	// FrontmatterKeyStruct: a structured value (typically a YAML map with
	// known sub-keys). Sub-key shape is documented in the registered key's
	// Doc string and enforced by the key's parser.
	FrontmatterKeyStruct
)

func (FrontmatterKeyType) String

func (t FrontmatterKeyType) String() string

String returns a stable, human-readable label for the key type. Useful for diagnostics and tooling output.

type MeasurementFrontmatter

type MeasurementFrontmatter struct {
	units.MeasurementConfig

	// Strict controls whether the formatter annotates bare ambiguous units in output.
	// nil = use config default (true), true = annotate, false = pass through.
	Strict *bool
}

MeasurementFrontmatter wraps units.MeasurementConfig with an optional Strict flag that controls formatter annotation of bare ambiguous units.

type ParsedGlobals

type ParsedGlobals struct {
	Values map[string]types.Type
}

ParsedGlobals contains parsed global variable values ready for injection into the interpreter environment.

func ParseGlobals

func ParseGlobals(rawGlobals map[string]string) (*ParsedGlobals, error)

ParseGlobals parses the raw string values from frontmatter into typed CalcMark values. Only literal values are allowed (no expressions or calculations):

  • Numbers: 42, 3.14, 1.5K, 25%
  • Quantities: 10 meters, 5 kg, 100 MB
  • Currencies: $100, 50 EUR
  • Dates: Jan 15 2025, today
  • Durations: 5 days, 2 weeks
  • Booleans: true, false
  • Rates: 100 MB/s, $50/hour

Returns an error if any value cannot be parsed or is not a literal.

func ParseGlobalsOrdered

func ParseGlobalsOrdered(rawGlobals map[string]string, keys []string) (*ParsedGlobals, error)

ParseGlobalsOrdered parses globals in the specified key order. This ensures variables are processed in document order (frontmatter order).

type RegisteredKey

type RegisteredKey struct {
	// Name is the YAML key as it appears in document frontmatter.
	// Comparison is case-sensitive.
	Name string

	// Type describes the accepted value shape.
	Type FrontmatterKeyType

	// Doc is a 1-2 sentence description of what the key configures.
	// It is the source of truth for hover text in tooling (LSP).
	Doc string

	// EnumValues lists accepted values when Type == FrontmatterKeyEnumString.
	// Empty for all other types. Order is canonical (preferred form first).
	EnumValues []string
}

RegisteredKey describes a single CalcMark-specific frontmatter key. All CalcMark grammar keys (those that ParseFrontmatter recognizes and validates beyond YAML decoding) are listed in the Registry.

func LookupKey

func LookupKey(name string) (RegisteredKey, bool)

LookupKey returns the RegisteredKey with the given name, if any. Comparison is case-sensitive. Runs in O(|Registry|).

type ScaleConfig

type ScaleConfig struct {
	Factor         decimal.Decimal
	UnitCategories []string // empty = nothing scales
}

ScaleConfig configures the document-level scale transform. When present, eligible quantities are multiplied by Factor. UnitCategories lists the categories to scale (empty = nothing scales).

type TextBlock

type TextBlock struct {
	// contains filtered or unexported fields
}

TextBlock represents markdown text. Like a Jupyter markdown cell.

func NewTextBlock

func NewTextBlock(source []string) *TextBlock

NewTextBlock creates a new text block.

func (*TextBlock) AddDiagnostic

func (tb *TextBlock) AddDiagnostic(diag Diagnostic)

AddDiagnostic adds a single diagnostic to this text block.

func (*TextBlock) ClearDiagnostics

func (tb *TextBlock) ClearDiagnostics()

ClearDiagnostics removes all diagnostics from this text block.

func (*TextBlock) ClearInterpolatedSource

func (tb *TextBlock) ClearInterpolatedSource()

ClearInterpolatedSource resets interpolation (e.g., when source changes).

func (*TextBlock) Diagnostics

func (tb *TextBlock) Diagnostics() []Diagnostic

Diagnostics returns warnings for this text block.

func (*TextBlock) HTML

func (tb *TextBlock) HTML() string

HTML returns the rendered HTML.

func (*TextBlock) InterpolatedHTMLSourceText

func (tb *TextBlock) InterpolatedHTMLSourceText() string

InterpolatedHTMLSourceText returns the sentinel-wrapped source for HTML rendering. Falls back to InterpolatedSourceText() when no HTML-specific source is set.

func (*TextBlock) InterpolatedSource

func (tb *TextBlock) InterpolatedSource() []string

InterpolatedSource returns interpolated lines if set, otherwise raw source. All output consumers should call this instead of Source() for display.

func (*TextBlock) InterpolatedSourceText

func (tb *TextBlock) InterpolatedSourceText() string

InterpolatedSourceText returns interpolated source as a single string.

func (*TextBlock) IsDirty

func (tb *TextBlock) IsDirty() bool

func (*TextBlock) Render

func (tb *TextBlock) Render() string

Render converts the markdown source to HTML. This implementation is only available in native Go builds (not WASM).

func (*TextBlock) SetDirty

func (tb *TextBlock) SetDirty(dirty bool)

func (*TextBlock) SetHTML

func (tb *TextBlock) SetHTML(html string)

SetHTML sets the rendered HTML.

func (*TextBlock) SetInterpolatedHTMLSource

func (tb *TextBlock) SetInterpolatedHTMLSource(lines []string)

SetInterpolatedHTMLSource stores sentinel-wrapped lines for HTML rendering.

func (*TextBlock) SetInterpolatedSource

func (tb *TextBlock) SetInterpolatedSource(lines []string)

SetInterpolatedSource stores the post-interpolation lines.

func (*TextBlock) Source

func (tb *TextBlock) Source() []string

func (*TextBlock) SourceText

func (tb *TextBlock) SourceText() string

SourceText returns source as a single string.

func (*TextBlock) Type

func (tb *TextBlock) Type() BlockType

type UpdateResult

type UpdateResult struct {
	// ModifiedBlockID is the block that was directly modified
	ModifiedBlockID string

	// AffectedBlockIDs are all blocks that need UI updates
	// (includes modified block + dependents)
	AffectedBlockIDs []string

	// Diagnostics from semantic validation
	Diagnostics []Diagnostic
}

UpdateResult contains information about what changed in the document.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL