tuil
ReferencePackages@mwillbanks/tuil-cellAPI

CellRendererBackend

class exported by @mwillbanks/tuil-cell.

View rawEdit

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

MemberTypeRequiredDescriptionRelated types
id"cell"YesThe id member uses the "cell" contract.
capabilitiesSet<"static" | "json" | "silent" | "cells" | "renderer-application" | "pointer" | "scroll" | "clipboard" | "alternate-screen" | "inline" | "embedded">YesThe capabilities member uses the Set<"static" | "json" | "silent" | "cells" | "renderer-application" | "pointer" | "scroll" | "clipboard" | "alternate-screen" | "inline" | "embedded"> contract.
#acceleratorCellAcceleratorYesThe #accelerator member uses the CellAccelerator contract.CellAccelerator
#acceleratorReadyPromise<void>YesThe #acceleratorReady member uses the Promise<void> contract.
#sequencenumberYesThe #sequence member uses the number contract.
__constructoranyYesThe __constructor member uses the any contract.
render(tree: CellTree, context: RendererContext) => Promise<RendererFrame>YesThe render member uses the (tree: CellTree, context: RendererContext) => Promise<RendererFrame> contract.CellTree
diff(previous: RendererFrame | undefined, current: RendererFrame) => RendererOutputYesThe diff member uses the (previous: RendererFrame | undefined, current: RendererFrame) => RendererOutput contract.
#renderScene(tree: RendererScene, context: RendererContext) => CellFrameYesThe #renderScene member uses the (tree: RendererScene, context: RendererContext) => CellFrame contract.CellFrame
#renderFunction(tree: (buffer: CellBuffer, context: RendererContext) => void | Promise<void>, context: RendererContext) => Promise<CellFrame>YesThe #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.

Source

View the secondary source reference

Package

@mwillbanks/tuil-cell

On this page