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:
- Block types (CalcBlock, TextBlock)
- Document structure with block management
- Dependency tracking between calc blocks
- 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 ¶
- Variables
- func ExchangeRateKey(from, to string) string
- func ExtractStatementReferences(node ast.Node) []string
- func IsRegisteredKey(name string) bool
- func ParseExchangeRateKey(key string) (from, to string, err error)
- type Block
- type BlockNode
- type BlockType
- type CalcBlock
- func (cb *CalcBlock) AddDiagnostic(diag Diagnostic)
- func (cb *CalcBlock) ClearDiagnostics()
- func (cb *CalcBlock) ConvertApplied() []bool
- func (cb *CalcBlock) Dependencies() []string
- func (cb *CalcBlock) Diagnostics() []Diagnostic
- func (cb *CalcBlock) Error() error
- func (cb *CalcBlock) IsDirty() bool
- func (cb *CalcBlock) LastValue() types.Type
- func (cb *CalcBlock) Results() []types.Type
- func (cb *CalcBlock) ScaleExempt() []bool
- func (cb *CalcBlock) SetConvertApplied(applied []bool)
- func (cb *CalcBlock) SetDependencies(deps []string)
- func (cb *CalcBlock) SetDiagnostics(diags []Diagnostic)
- func (cb *CalcBlock) SetDirty(dirty bool)
- func (cb *CalcBlock) SetError(err error)
- func (cb *CalcBlock) SetLastValue(val types.Type)
- func (cb *CalcBlock) SetResults(results []types.Type)
- func (cb *CalcBlock) SetScaleExempt(exempt []bool)
- func (cb *CalcBlock) SetStatements(stmts []ast.Node)
- func (cb *CalcBlock) SetVariables(vars []string)
- func (cb *CalcBlock) Source() []string
- func (cb *CalcBlock) Statements() []ast.Node
- func (cb *CalcBlock) Type() BlockType
- func (cb *CalcBlock) Variables() []string
- type CalendarYearOffset
- type ConvertToConfig
- type DependencyAnalyzer
- type Detector
- type Diagnostic
- type Document
- func (d *Document) ApplyFrontmatter(env EnvironmentWriter) error
- func (d *Document) DeleteBlock(blockID string) (*UpdateResult, error)
- func (d *Document) EnsureFrontmatter() *Frontmatter
- func (d *Document) GetBlock(id string) (*BlockNode, bool)
- func (d *Document) GetBlocks() []*BlockNode
- func (d *Document) GetBlocksInDependencyOrder(blockIDs []string) []string
- func (d *Document) GetFrontmatter() *Frontmatter
- func (d *Document) GetTransitiveDependents(changedVars []string) []string
- func (d *Document) InsertBlock(afterBlockID string, blockType BlockType, source []string) (*UpdateResult, error)
- func (d *Document) ReplaceBlockSource(blockID string, newSource []string) (*UpdateResult, error)
- func (d *Document) SetFrontmatter(fm *Frontmatter)
- type EnvironmentWriter
- type ExtraField
- type FiscalYearConfig
- type Frontmatter
- func (f *Frontmatter) ExchangeKeys() []string
- func (f *Frontmatter) GetExchangeRate(from, to string) (decimal.Decimal, bool)
- func (f *Frontmatter) GlobalKeys() []string
- func (f *Frontmatter) HasExchangeRate(key string) bool
- func (f *Frontmatter) HasGlobal(name string) bool
- func (f *Frontmatter) HasGlobals() bool
- func (f *Frontmatter) HasScale() bool
- func (f *Frontmatter) LineCount() int
- func (f *Frontmatter) Serialize() string
- func (f *Frontmatter) SetExchangeRate(key string, rate decimal.Decimal)
- func (f *Frontmatter) SetGlobal(name, valueExpr string)
- func (f *Frontmatter) SetRawSource(raw string)
- type FrontmatterKeyType
- type MeasurementFrontmatter
- type ParsedGlobals
- type RegisteredKey
- type ScaleConfig
- type TextBlock
- func (tb *TextBlock) AddDiagnostic(diag Diagnostic)
- func (tb *TextBlock) ClearDiagnostics()
- func (tb *TextBlock) ClearInterpolatedSource()
- func (tb *TextBlock) Diagnostics() []Diagnostic
- func (tb *TextBlock) HTML() string
- func (tb *TextBlock) InterpolatedHTMLSourceText() string
- func (tb *TextBlock) InterpolatedSource() []string
- func (tb *TextBlock) InterpolatedSourceText() string
- func (tb *TextBlock) IsDirty() bool
- func (tb *TextBlock) Render() string
- func (tb *TextBlock) SetDirty(dirty bool)
- func (tb *TextBlock) SetHTML(html string)
- func (tb *TextBlock) SetInterpolatedHTMLSource(lines []string)
- func (tb *TextBlock) SetInterpolatedSource(lines []string)
- func (tb *TextBlock) Source() []string
- func (tb *TextBlock) SourceText() string
- func (tb *TextBlock) Type() BlockType
- type UpdateResult
Constants ¶
This section is empty.
Variables ¶
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.
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 ¶
ExchangeRateKey creates a normalized key for looking up exchange rates. Format: "FROM_TO" (e.g., "USD_EUR").
func ExtractStatementReferences ¶
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 ¶
IsRegisteredKey reports whether name is a CalcMark-grammar frontmatter key. Comparison is case-sensitive. Runs in O(|Registry|).
func ParseExchangeRateKey ¶
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 CalcBlock ¶
type CalcBlock struct {
// contains filtered or unexported fields
}
CalcBlock represents one or more consecutive calculation lines. Like a Jupyter code cell.
func NewCalcBlock ¶
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 ¶
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 ¶
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) ScaleExempt ¶
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 ¶
SetConvertApplied sets the per-statement conversion flags.
func (*CalcBlock) SetDependencies ¶
SetDependencies sets the dependencies.
func (*CalcBlock) SetDiagnostics ¶
func (cb *CalcBlock) SetDiagnostics(diags []Diagnostic)
SetDiagnostics sets the structured diagnostics for this block.
func (*CalcBlock) SetLastValue ¶
SetLastValue sets the last evaluated value.
func (*CalcBlock) SetResults ¶
SetResults sets the per-statement evaluation results.
func (*CalcBlock) SetScaleExempt ¶
SetScaleExempt sets the per-statement scale exemption flags.
func (*CalcBlock) SetStatements ¶
SetStatements sets the parsed AST nodes.
func (*CalcBlock) SetVariables ¶
SetVariables sets the variables defined in this block.
func (*CalcBlock) Statements ¶
Statements returns the parsed AST nodes.
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 (*Detector) DetectBlocks ¶
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 ¶
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 ¶
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) GetBlocksInDependencyOrder ¶
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 ¶
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 ¶
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 ¶
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 ¶
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) InterpolatedHTMLSourceText ¶
InterpolatedHTMLSourceText returns the sentinel-wrapped source for HTML rendering. Falls back to InterpolatedSourceText() when no HTML-specific source is set.
func (*TextBlock) InterpolatedSource ¶
InterpolatedSource returns interpolated lines if set, otherwise raw source. All output consumers should call this instead of Source() for display.
func (*TextBlock) InterpolatedSourceText ¶
InterpolatedSourceText returns interpolated source as a single string.
func (*TextBlock) Render ¶
Render converts the markdown source to HTML. This implementation is only available in native Go builds (not WASM).
func (*TextBlock) SetInterpolatedHTMLSource ¶
SetInterpolatedHTMLSource stores sentinel-wrapped lines for HTML rendering.
func (*TextBlock) SetInterpolatedSource ¶
SetInterpolatedSource stores the post-interpolation lines.
func (*TextBlock) SourceText ¶
SourceText returns source as a single string.
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.