mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
@@ -521,7 +521,13 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
const wraparoundMode = this._coreService.decPrivateModes.wraparound;
|
||||
const insertMode = this._coreService.modes.insertMode;
|
||||
const curAttr = this._curAttrData;
|
||||
let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!;
|
||||
let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y);
|
||||
|
||||
// Defensive check: bufferRow can be undefined if a resize occurred mid-write due to async
|
||||
// scheduling gaps in WriteBuffer. See https://github.com/xtermjs/xterm.js/issues/5597
|
||||
if (!bufferRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._dirtyRowTracker.markDirty(this._activeBuffer.y);
|
||||
|
||||
@@ -586,7 +592,10 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = true;
|
||||
}
|
||||
// row changed, get it again
|
||||
bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!;
|
||||
bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y);
|
||||
if (!bufferRow) {
|
||||
return;
|
||||
}
|
||||
if (oldWidth > 0 && bufferRow instanceof BufferLine) {
|
||||
// Combining character widens 1 column to 2.
|
||||
// Move old character to next line.
|
||||
|
||||
@@ -264,6 +264,13 @@ export class Buffer implements IBuffer {
|
||||
this._cols = newCols;
|
||||
this._rows = newRows;
|
||||
|
||||
// Ensure the cursor position invariant: ybase + y must be within buffer bounds
|
||||
// This can be violated during reflow or when shrinking rows
|
||||
if (this.lines.length > 0) {
|
||||
const maxY = Math.max(0, this.lines.length - this.ybase - 1);
|
||||
this.y = Math.min(this.y, maxY);
|
||||
}
|
||||
|
||||
this._memoryCleanupQueue.clear();
|
||||
// schedule memory cleanup only, if more than 10% of the lines are affected
|
||||
if (dirtyMemoryLines > 0.1 * this.lines.length) {
|
||||
|
||||
@@ -402,6 +402,16 @@ test.describe('API Integration Tests', () => {
|
||||
await pollFor(ctx.page, `window.calls`, [[10, 5], [20, 15]]);
|
||||
});
|
||||
|
||||
test('resize during write should not throw', async () => {
|
||||
await openTerminal(ctx, { rows: 50, cols: 80 });
|
||||
const largeData = 'x'.repeat(10000);
|
||||
await ctx.proxy.write(largeData);
|
||||
await ctx.proxy.resize(80, 10);
|
||||
await ctx.proxy.write(largeData);
|
||||
await ctx.proxy.resize(80, 5);
|
||||
await ctx.proxy.write(largeData);
|
||||
});
|
||||
|
||||
test('onTitleChange', async () => {
|
||||
await openTerminal(ctx);
|
||||
await ctx.page.evaluate(`
|
||||
|
||||
Reference in New Issue
Block a user