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):
| Method | Description |
|---|---|
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 method | Description |
|---|---|
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:
| Type | Description |
|---|---|
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 / PrinterCacheItem | The 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: ...} |
DefaultRendererDict | One 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):
| Hook | Description |
|---|---|
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. |