CellRendererBackend
class exported by @mwillbanks/tuil-cell.
class
Public class exported by @mwillbanks/tuil-cell.
export class CellRendererBackend implements RendererBackend<CellTree> {
readonly id = "cell";
readonly capabilities = new Set([
"cells",
"renderer-application",
"pointer",
"scroll",
"clipboard",
"alternate-screen",
"inline",
"static",
"json",
"silent",
"embedded",
] as const);
#accelerator = typescriptCellAccelerator;
readonly #acceleratorReady: Promise<void>;
#sequence = 0;
constructor(options: CellRendererBackendOptions = {}) {
const configured = options.accelerator ?? typescriptCellAccelerator;
this.#acceleratorReady = Promise.resolve(
typeof configured === "function" ? configured() : configured,
).then((accelerator) => {
this.#accelerator = accelerator;
});
}
async render(
tree: CellTree,
context: RendererContext,
): Promise<RendererFrame> {
await this.#acceleratorReady;
if (context.signal.aborted) throw context.signal.reason;
const projected =
typeof tree === "function"
? await this.#renderFunction(tree, context)
: "lines" in tree
? this.#renderScene(tree, context)
: "kind" in tree
? composeCellScene(
tree,
context.capabilities.width,
context.capabilities.height,
context.layout,
)
: tree;
const frame = normalizeCellFrame(
projected,
context.capabilities.hyperlinks,
);
return Object.freeze({
width: frame.width,
height: frame.height,
sequence: ++this.#sequence,
timestamp: performance.now(),
mode: context.mode,
payload: frame,
cursor: frame.cursor,
});
}
diff(
previous: RendererFrame | undefined,
current: RendererFrame,
): RendererOutput {
const mode = current.mode ?? "interactive";
if (mode === "interactive") {
return this.#accelerator.diff(
previous?.payload as CellFrame | undefined,
current.payload as CellFrame,
);
}
return encodeCellOutput(
current.payload as CellFrame,
mode === "json" ? "json" : mode === "silent" ? "silent" : "static",
previous?.payload as CellFrame | undefined,
);
}
#renderScene(tree: RendererScene, context: RendererContext): CellFrame {
const scene = normalizeRendererScene(
tree,
context.capabilities.width,
context.capabilities.height,
context.capabilities.hyperlinks,
);
const buffer = new CellBuffer(
context.capabilities.width,
context.capabilities.height,
);
for (const [index, line] of scene.lines.entries()) {
if (index >= buffer.height) break;
const runs = scene.styledLines?.[index];
if (!runs || runs.length === 0) {
buffer.write(0, index, line);
continue;
}
let column = 0;
for (const run of runs) {
column = buffer.write(
column,
index,
run.text,
rendererCellStyle(run.style, run.link),
);
}
}
buffer.setCursor(scene.cursor);
return Object.freeze({ ...buffer.frame(), semantics: scene.semantics });
}
async #renderFunction(
tree: (
buffer: CellBuffer,
context: RendererContext,
) => void | Promise<void>,
context: RendererContext,
): Promise<CellFrame> {
const buffer = new CellBuffer(
context.capabilities.width,
context.capabilities.height,
);
await tree(buffer, context);
if (context.signal.aborted) throw context.signal.reason;
return buffer.frame();
}
}Members
| Member | Type | Required | Description | Related types |
|---|---|---|---|---|
id | "cell" | Yes | The id member uses the "cell" contract. | — |
capabilities | Set<"static" | "json" | "silent" | "cells" | "renderer-application" | "pointer" | "scroll" | "clipboard" | "alternate-screen" | "inline" | "embedded"> | Yes | The capabilities member uses the Set<"static" | "json" | "silent" | "cells" | "renderer-application" | "pointer" | "scroll" | "clipboard" | "alternate-screen" | "inline" | "embedded"> contract. | — |
#accelerator | CellAccelerator | Yes | The #accelerator member uses the CellAccelerator contract. | CellAccelerator |
#acceleratorReady | Promise<void> | Yes | The #acceleratorReady member uses the Promise<void> contract. | — |
#sequence | number | Yes | The #sequence member uses the number contract. | — |
__constructor | any | Yes | The __constructor member uses the any contract. | — |
render | (tree: CellTree, context: RendererContext) => Promise<RendererFrame> | Yes | The render member uses the (tree: CellTree, context: RendererContext) => Promise<RendererFrame> contract. | CellTree |
diff | (previous: RendererFrame | undefined, current: RendererFrame) => RendererOutput | Yes | The diff member uses the (previous: RendererFrame | undefined, current: RendererFrame) => RendererOutput contract. | — |
#renderScene | (tree: RendererScene, context: RendererContext) => CellFrame | Yes | The #renderScene member uses the (tree: RendererScene, context: RendererContext) => CellFrame contract. | CellFrame |
#renderFunction | (tree: (buffer: CellBuffer, context: RendererContext) => void | Promise<void>, context: RendererContext) => Promise<CellFrame> | Yes | The #renderFunction member uses the (tree: (buffer: CellBuffer, context: RendererContext) => void | Promise<void>, context: RendererContext) => Promise<CellFrame> contract. | CellBuffer, CellFrame |
Parameters
This declaration has no public members.
Returns
This declaration does not return a value.
Throws
No thrown errors are documented for this declaration.
Related types
Source
View the secondary source reference