Skip to content

Conversation

@jim-lake
Copy link

Add a onRowChange event so that watchers can do efficient inspection of buffer changes.

Copy link
Member

@Tyriar Tyriar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have plans to add this, the way we're handling similar things in VS Code are by tracking onCursorMove/onData/onLineFeed and then checking the buffer's cursor position.

@Tyriar Tyriar closed this Dec 20, 2025
@jim-lake
Copy link
Author

The goal is to expose the _onRequestRefreshRows, so you can write a renderer on top of headless, like a real renderer would in regular xterm.js. The specific fire that is very useful in rendering is actually for a scroll event:

this._onRequestRefreshRows.fire({
start: Math.min(viewportStart, this._bufferService.rows - 1),
end: Math.min(viewportEnd, this._bufferService.rows - 1)
});

This event provides just what you need to for render on headless. onLineFeed and onCursorMove didn't definitely give me this fire every time the buffer scrolls.

@Tyriar Tyriar reopened this Dec 20, 2025
public get onWriteParsed(): Event<void> { return this._core.onWriteParsed; }
public get onRowChange(): Event<{ start: number, end: number }> {
this._checkProposedApi();
return Event.map(this._core.onRowChange, e => ({ start: e.start, end: e.end }));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to avoid Event.map here if possible, now sure why this would be needed?

public get onTitleChange(): Event<string> { return this._core.onTitleChange; }
public get onWriteParsed(): Event<void> { return this._core.onWriteParsed; }
public get onRowChange(): Event<{ start: number, end: number }> {
this._checkProposedApi();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can skip making it proposed since it's so simple

public loadAddon(addon: ITerminalAddon): void {
// TODO: This could cause issues if the addon calls renderer apis
this._addonManager.loadAddon(this as any, addon);
this._addonManager.loadAddon(this as any, addon as any);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this needed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The typescript compiler was complaining because the interfaces on headless and regular are different. I'm not sure why it ever worked without an as cast.

Comment on lines +58 to +62
this._register(this._inputHandler.onRequestRefreshRows(e => {
if (e) {
this._onRowChange.fire({ start: e.start, end: e.end });
}
}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the event also fire undefined? I think that means every row needs to be updated?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't love the might be undefined or might be an object as the event spec, and I never needed the undefined case so I thought it made the API cleaner. If I remember right another event gets fired on full repaint so its redundant. I'm indifferent to changing the interface to { start, end}|undefined.

Comment on lines +751 to +756
/**
* Adds an event listener for when buffer rows change during parsing. The event
* value contains the range of rows that changed.
* @returns an `IDisposable` to stop listening.
*/
onRowChange: IEvent<{ start: number, end: number }>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add to xterm.d.ts as xterm-headless is a subset of that

Comment on lines +752 to +753
* Adds an event listener for when buffer rows change during parsing. The event
* value contains the range of rows that changed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Adds an event listener for when buffer rows change during parsing. The event
* value contains the range of rows that changed.
* Adds an event listener for when buffer rows change during parsing. The
* event value contains the range of rows that changed. This is particularly
* useful when implementing a custom renderer.

* value contains the range of rows that changed.
* @returns an `IDisposable` to stop listening.
*/
onRowChange: IEvent<{ start: number, end: number }>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if instead xterm-headless should just forward onRequestRefreshRows to the existing onRender? Would that accomplish what you're after?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants