Merge pull request #5504 from Tyriar/onRender_headless

Implement onRender in xterm-headless
This commit is contained in:
Daniel Imms
2025-12-26 11:33:01 -08:00
committed by GitHub
6 changed files with 24 additions and 3 deletions
-2
View File
@@ -126,8 +126,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
public readonly onCursorMove = this._onCursorMove.event;
private readonly _onKey = this._register(new Emitter<{ key: string, domEvent: KeyboardEvent }>());
public readonly onKey = this._onKey.event;
private readonly _onRender = this._register(new Emitter<{ start: number, end: number }>());
public readonly onRender = this._onRender.event;
private readonly _onSelectionChange = this._register(new Emitter<void>());
public readonly onSelectionChange = this._onSelectionChange.event;
private readonly _onTitleChange = this._register(new Emitter<string>());
+2 -1
View File
@@ -65,6 +65,8 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
public readonly onData = this._onData.event;
protected _onLineFeed = this._register(new Emitter<void>());
public readonly onLineFeed = this._onLineFeed.event;
protected readonly _onRender = this._register(new Emitter<{ start: number, end: number }>());
public readonly onRender = this._onRender.event;
private readonly _onResize = this._register(new Emitter<{ cols: number, rows: number }>());
public readonly onResize = this._onResize.event;
protected readonly _onWriteParsed = this._register(new Emitter<void>());
@@ -124,7 +126,6 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
// Register input handler and handle/forward events
this._inputHandler = this._register(new InputHandler(this._bufferService, this._charsetService, this.coreService, this._logService, this.optionsService, this._oscLinkService, this.coreMouseService, this.unicodeService));
this._register(Event.forward(this._inputHandler.onLineFeed, this._onLineFeed));
this._register(this._inputHandler);
// Setup listeners
this._register(Event.forward(this._bufferService.onResize, this._onResize));
+1
View File
@@ -53,6 +53,7 @@ export class Terminal extends CoreTerminal {
this._register(Event.forward(this._inputHandler.onTitleChange, this._onTitleChange));
this._register(Event.forward(this._inputHandler.onA11yChar, this._onA11yCharEmitter));
this._register(Event.forward(this._inputHandler.onA11yTab, this._onA11yTabEmitter));
this._register(Event.forward(Event.map(this._inputHandler.onRequestRefreshRows, e => ({ start: e?.start ?? 0, end: e?.end ?? this.rows - 1 })), this._onRender));
}
/**
+9
View File
@@ -202,6 +202,15 @@ describe('Headless API Tests', function (): void {
strictEqual(callCount, 2);
});
it('onRender', async () => {
const calls: { start: number, end: number }[] = [];
term.onRender(e => calls.push(e));
await writeSync('foo');
deepStrictEqual(calls, [{ start: 0, end: 0 }]);
await writeSync('\n\nbar');
deepStrictEqual(calls, [{ start: 0, end: 0 }, { start: 0, end: 2 }]);
});
it('onScroll', async () => {
term = new Terminal({ rows: 5 });
const calls: number[] = [];
+1
View File
@@ -77,6 +77,7 @@ export class Terminal extends Disposable implements ITerminalApi {
public get onCursorMove(): Event<void> { return this._core.onCursorMove; }
public get onData(): Event<string> { return this._core.onData; }
public get onLineFeed(): Event<void> { return this._core.onLineFeed; }
public get onRender(): Event<{ start: number, end: number }> { return this._core.onRender; }
public get onResize(): Event<{ cols: number, rows: number }> { return this._core.onResize; }
public get onScroll(): Event<number> { return this._core.onScroll; }
public get onTitleChange(): Event<string> { return this._core.onTitleChange; }
+11
View File
@@ -696,6 +696,17 @@ declare module '@xterm/headless' {
*/
onLineFeed: IEvent<void>;
/**
* Adds an event listener for when rows are _requested_ to be rendered. The
* event value contains the start row and end rows of the rendered area
* (ranges from `0` to `Terminal.rows - 1`). This differs from the regular
* xterm.js in that it doesn't actually do any rendering but requests
* rendering from the outside. This is useful for implementing a custom
* renderer on top of xterm-headless.
* @returns an `IDisposable` to stop listening.
*/
onRender: IEvent<{ start: number, end: number }>;
/**
* Adds an event listener for when data has been parsed by the terminal,
* after {@link write} is called. This event is useful to listen for any