printer: The Printer

The core module that renders document trees into typeset output: Printer (the registry of concepts and renderers), PrinterComponent (the component executing two-phase rendering), PrinterRenderer (the renderer protocol), and the types of the preprocessing products. The preprocessing mechanism itself is explained in tutorial chapters 4 and 6.

Printer

Printer is the entry object of the output side, and also the keeper of all concept definitions (the editor queries concepts through it). Like EditorCore, it is constructed once at startup and shared from then on. Its four constructor arguments appeared in tutorial chapter 3:

new Printer(
    first_class_concepts: FirstClassConcept[],
    second_class_concepts: SecondClassConcept[],
    renderers: RendererDict,            // {group: {first-concept name: PrinterRenderer}, ...}
    default_renderers: DefaultRendererDict, // one default renderer per node kind
)

Its methods fall into four groups: dynamic registration (the add_ family, for appending concepts and renderers at runtime), lookup of concepts and renderers (the get_ family), parameter processing (process_parameters), and the entry point of preprocessing (preprocess, normally invoked by the printer component rather than by hand):

MethodDescription
add_first_concept(x) / add_second_concept(x) / add_renderer(type, name, renderer)Register concepts and renderers dynamically after construction
get_first_concept(type, name) / get_second_concept(type, name)Concept lookup by name
get_node_first_concept(node) / get_node_second_concept(node)Resolve a node's concepts starting from the node
get_renderer(type, name?) / get_node_renderer(node)Renderer lookup; falls back to the default renderers
process_parameters(node)Produce the processed form of a node's parameters: apply second-class overrides, evaluate function-typed parameters, strip the type wrappers
preprocess({root, init_env?})Preprocess the whole tree; returns the four products [environment, per-node contexts, per-node parameters, cache]
preprocess_init()Async initialization: runs each renderer's init (preloading data, for example); returns a Promise

PrinterComponent

The printer's React component (a class component), responsible for running preprocessing and rendering. Normally used through its wrapper DefaultPrinterComponent (see the defaults page).

interface PrinterComponentProps {
    printer: Printer
    root: AbstractNode
    init_env?: Env                        // initial environment for preprocessing; rarely needed
    onUpdateCache?: (cache: PrinterCache) => void  // hands out the cache after each preprocessing pass
}
Instance methodDescription
scroll_to(path) / scroll_to_idx(idx)Scroll to a node; click-to-jump for references is built on this
get_ref(path) / get_ref_from_idx(idx) / bind_ref(path)Obtain or bind the DOM element corresponding to a node
preprocess(params?) / update()Trigger preprocessing or a refresh manually

PrinterRenderer: the renderer protocol

A printer renderer is an instance of the PrinterRenderer class, which splits a renderer into phase functions:

new PrinterRenderer<NodeType>({
    init?: () => Promise<void>,            // one-off asynchronous preparation
    enter?: PrinterEnterFunction<NodeType>, // called when preprocessing enters the node
    exit?: PrinterExitFunction<NodeType>,   // called when preprocessing leaves the node
    renderer: PrinterRenderFunction<NodeType>,          // the render-phase React component
    renderer_as_property?: PrinterRenderFunction<NodeType>, // abstract nodes only: used when rendered as a property
})

The signatures of the phase functions:

// Preprocessing phase, called per node in document order.
// Mutate env and context in place.
type PrinterEnterFunction<NT> = (
    node: Readonly<NT>, path: Readonly<number[]>,
    parameters: Readonly<ProcessedParameterList>,
    env_draft: Env, context_draft: Context,
) => void

// Called when leaving a node. Returns a pair: the content to write into the
// cache, and whether processing is finished (false requests another
// preprocessing iteration).
type PrinterExitFunction<NT> = (same arguments as above) => [PrinterCacheItem, boolean]

// Render phase: an ordinary React component.
interface PrinterRenderFunctionProps<NT> {
    node: NT
    context: Context                       // the conclusions preprocessing left for this node
    parameters: {[key: string]: any}       // the processed parameters
    children?: React.ReactNode             // the rendered children; be sure to output them
}

Writing enter and exit by hand is the low-level path. Everyday development uses the factory functions of the default implementation together with contexters; the factories wire the contexter hooks into these two positions for you (see tutorial chapter 6).

Types of the preprocessing products

The four products of preprocessing (the environment, the per-node contexts, the per-node parameters, the cache) each have a type name of their own. They come up constantly when writing renderers and contexters, so they are worth learning alongside tutorial chapter 6:

TypeDescription
Env{[key]: any}. The global environment of a preprocessing pass; each contexter occupies its own slot under its own key.
Context{[key]: any}. The conclusions preprocessing leaves for a single node, readable by that node at render time.
ProcessedParameterList{[key]: any}. Processed parameters; the values are plain values.
PrinterCache / PrinterCacheItemThe cache table indexed by node idx. The return values of exit collect here; it is readable from anywhere, which makes it the home of information meant for others, such as reference names.
RendererDict{group: {name: PrinterRenderer}, inline: ..., structure: ..., support: ..., abstract: ...}
DefaultRendererDictOne default PrinterRenderer per node kind (seven kinds)

Render-context hooks

Inside printer render functions, a set of hooks gives access to the whole printing scene (provided by the PrinterGlobalInfo React context):

HookDescription
usePrinter() / usePrinterGlobalInfo()The printer's global information
usePrinterRoot()The root currently being rendered
usePrinterComponent()The PrinterComponent instance, for calling scroll_to_idx and similar methods
usePrinterAllEnv() / usePrinterAllContexts() / usePrinterAllParameters() / usePrinterAllCaches()All the preprocessing products. For displaying references, caches is the one used most: look up the reference name by the target idx.