KEMBAR78
Renderer API · Issue #2005 · xtermjs/xterm.js · GitHub
Skip to content

Renderer API #2005

@Tyriar

Description

@Tyriar

An API for renderers is necessary if we want to include the WebGL renderer as an optional component. A lot of this issue is about refactoring the renderer code to share a lot of the core functionality of all the renderers to make the actual IRenderer API interface slimmer for addons to eventually implement. Here are the sub-goals:

  • Move ColorManager to live under Terminal, pass IColorSet to the renderer
  • Implement the renderer "orchestrator" that does the debouncing/pausing etc. that the current renderers do.
  • Look into whether CharMeasure can live only in the DOM renderer code (canvas renderers can use onOptionsChange)
  • Break renderer dependence on Terminal by passing in relevant objects to handlers Renderer addons will have access to the xterm.js API
  • Expose the renderer API as experimental

API proposal

Note that the inline proposal will change as progress is made.

class Terminal {
  /**
   * Gets or sets the renderer to use for the `Terminal`, the renderer is
   * responsible for displaying all terminal data to the user, including the
   * mouse selection.
   */ 
  renderer: IRenderer;
}

/**
 * An interface that implements a renderer capable of rendering terminal data.
 * Note that if the browser supports `IntersectionObserver` it will not call to
 * render frames when the terminal is completely hidden. The best way to
 * implement this interface is to keep a 
 */
interface IRenderer extends IDisposable {
  /**
   * The dimensions that the renderer will use for things like canvas, cell and
   * character size.
   */
  readonly dimensions: IRenderDimensions;

  /**
   * A method that is called when `window.devicePixelRatio` changes.
   */
  onDevicePixelRatioChange(): void;

  /**
   * A method that is called when the dimenisons of the termnial change.
   */
  onResize(cols: number, rows: number): void;

  /**
   * A method that is called when the terminal loses focus.
   */
  onBlur(): void;

  /**
   * A method that is called when the terminal gains focus.
   */
  onFocus(): void;

  /**
   * A method that is called when the terminal cursor moves, this may be useful
   * for managing the state of a blinking cursor.
   */
  onCursorMove(): void;
  
  /**
   * A method that is called when terminal options change. Note that changes to
   * the theme should be handled with `IRenderer.onThemeChange`.
   */
  onOptionsChange(): void;

  /**
   * A method that is called when the theme changes.
   */
  onThemeChange(colors: IColorSet): void;
  
  /**
   * Clears the viewport.
   */
  clear(): void;

  /**
   * Renders the terminal selection. Depending on the renderer, this method
   * should either render the selection or generate a model to be used when
   * `renderRows` is called, for the latter you must return `true` to guarentee
   * `renderRows` will be called even if no rows have changed.
   * @param start The start of the selection in `[x, y]` format.
   * @param end The end of the selection in `[x, y]` format.
   * @param columnSelectMode Whether column select mode is on, if so the
   * selection should be rendered as a square with start being the top-left
   * corner and end being the bottom-right corner.
   * @returns Whether `renderRows` should be triggered (do this if
   * `renderSelection` only generates a model to render in `renderRows`.
   */
  onSelectionChange(start: [number, number], end: [number, number], columnSelectMode: boolean): boolean;
  
  // TODO: Should buffer be a stripped down view of the world? An iterator? It needs to remain performant.

  /**
   * Renders a range of rows. Calls made to this function are debounced such
   * that they will only be called during an animation frame.
   * @param buffer The terminal buffer on which to render.
   * @param start The first row to render (valid values: `0` to
   * `Terminal.rows - 1`).
   * @param end The last row to render (valid values: `0` to
   * `Terminal.rows - 1`).
   */
  renderRows(buffer: IBuffer, start: number, end: number): void;

  registerCharacterJoiner(handler: CharacterJoinerHandler): number;
  deregisterCharacterJoiner(joinerId: number): boolean;
}

export interface IRenderDimensions {
  canvasWidth: number;
  canvasHeight: number;
  cellWidth: number;
  cellHeight: number;
  scaledCharWidth: number;
  scaledCharHeight: number;
  scaledCellWidth: number;
  scaledCellHeight: number;
  scaledCharLeft: number;
  scaledCharTop: number;
  scaledCanvasWidth: number;
  scaledCanvasHeight: number;
}

Metadata

Metadata

Assignees

Labels

area/apitype/proposalA proposal that needs some discussion before proceeding

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions