diff --git a/src/Buffer.ts b/src/Buffer.ts index 2f1c2e49..286d1311 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -9,7 +9,7 @@ import { EventEmitter } from './common/EventEmitter'; import { IMarker } from 'xterm'; import { BufferLine } from './BufferLine'; import { DEFAULT_COLOR } from './renderer/atlas/Types'; -import { reflowSmallerGetNewLineLengths, reflowLargerGetLinesToRemove } from './BufferReflow'; +import { reflowSmallerGetNewLineLengths, reflowLargerGetLinesToRemove, reflowLargerCreateNewLayout, reflowLargerApplyNewLayout } from './BufferReflow'; export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0); export const CHAR_DATA_ATTR_INDEX = 0; @@ -240,62 +240,28 @@ export class Buffer implements IBuffer { } private _reflowLarger(newCols: number): void { - // TODO: Can toRemove be pulled out into BufferReflow? - - // Gather all BufferLines that need to be removed from the Buffer here so that they can be - // batched up and only committed once const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, newCols); - if (toRemove.length > 0) { - // First iterate through the list and get the actual indexes to use for rows const newLayout: number[] = []; + const countRemoved = reflowLargerCreateNewLayout(this.lines, toRemove, newLayout); + reflowLargerApplyNewLayout(this.lines, newLayout); + this._reflowLargerAdjustViewport(newCols, countRemoved); + } + } - let nextToRemoveIndex = 0; - let nextToRemoveStart = toRemove[nextToRemoveIndex]; - let countRemovedSoFar = 0; - for (let i = 0; i < this.lines.length; i++) { - if (nextToRemoveStart === i) { - const countToRemove = toRemove[++nextToRemoveIndex]; - - // Tell markers that there was a deletion - this.lines.emit('delete', { - index: i - countRemovedSoFar, - amount: countToRemove - } as IDeleteEvent); - - i += countToRemove - 1; - countRemovedSoFar += countToRemove; - nextToRemoveStart = toRemove[++nextToRemoveIndex]; - } else { - newLayout.push(i); - } - } - - // Record original lines so they don't get overridden when we rearrange the list - const newLayoutLines: BufferLine[] = []; - for (let i = 0; i < newLayout.length; i++) { - newLayoutLines.push(this.lines.get(newLayout[i]) as BufferLine); - } - - // Rearrange the list - for (let i = 0; i < newLayoutLines.length; i++) { - this.lines.set(i, newLayoutLines[i]); - } - this.lines.length = newLayout.length; - - // Adjust viewport based on number of items removed - let viewportAdjustments = countRemovedSoFar; - while (viewportAdjustments-- > 0) { - if (this.ybase === 0) { - this.y--; - // Add an extra row at the bottom of the viewport - this.lines.push(new BufferLine(newCols, FILL_CHAR_DATA)); - } else { - if (this.ydisp === this.ybase) { - this.ydisp--; - } - this.ybase--; + private _reflowLargerAdjustViewport(newCols: number, countRemoved: number): void { + // Adjust viewport based on number of items removed + let viewportAdjustments = countRemoved; + while (viewportAdjustments-- > 0) { + if (this.ybase === 0) { + this.y--; + // Add an extra row at the bottom of the viewport + this.lines.push(new BufferLine(newCols, FILL_CHAR_DATA)); + } else { + if (this.ydisp === this.ybase) { + this.ydisp--; } + this.ybase--; } } } diff --git a/src/BufferReflow.ts b/src/BufferReflow.ts index 310443b7..51f83c18 100644 --- a/src/BufferReflow.ts +++ b/src/BufferReflow.ts @@ -4,11 +4,13 @@ */ import { BufferLine } from './BufferLine'; -import { CircularList } from './common/CircularList'; +import { CircularList, IDeleteEvent } from './common/CircularList'; import { IBufferLine } from './Types'; import { FILL_CHAR_DATA } from './Buffer'; export function reflowLargerGetLinesToRemove(lines: CircularList, newCols: number): number[] { + // Gather all BufferLines that need to be removed from the Buffer here so that they can be + // batched up and only committed once const toRemove: number[] = []; for (let y = 0; y < lines.length - 1; y++) { @@ -83,6 +85,45 @@ export function reflowLargerGetLinesToRemove(lines: CircularList, n return toRemove; } +export function reflowLargerCreateNewLayout(lines: CircularList, toRemove: number[], newLayout: number[]): number { + // First iterate through the list and get the actual indexes to use for rows + let nextToRemoveIndex = 0; + let nextToRemoveStart = toRemove[nextToRemoveIndex]; + let countRemovedSoFar = 0; + for (let i = 0; i < lines.length; i++) { + if (nextToRemoveStart === i) { + const countToRemove = toRemove[++nextToRemoveIndex]; + + // Tell markers that there was a deletion + lines.emit('delete', { + index: i - countRemovedSoFar, + amount: countToRemove + } as IDeleteEvent); + + i += countToRemove - 1; + countRemovedSoFar += countToRemove; + nextToRemoveStart = toRemove[++nextToRemoveIndex]; + } else { + newLayout.push(i); + } + } + return countRemovedSoFar; +} + +export function reflowLargerApplyNewLayout(lines: CircularList, newLayout: number[]): void { + // Record original lines so they don't get overridden when we rearrange the list + const newLayoutLines: BufferLine[] = []; + for (let i = 0; i < newLayout.length; i++) { + newLayoutLines.push(lines.get(newLayout[i]) as BufferLine); + } + + // Rearrange the list + for (let i = 0; i < newLayoutLines.length; i++) { + lines.set(i, newLayoutLines[i]); + } + lines.length = newLayout.length; +} + /** * Gets the new line lengths for a given wrapped line. The purpose of this function it to pre- * compute the wrapping points since wide characters may need to be wrapped onto the following line.