Fix various problems with reflow

- No longer reflow lines where the full unwrapped line contains the cursor
- Add guards to prevent y and ybase becoming invalid values

Part of Microsoft/vscode#67364
Fixes #1910
This commit is contained in:
Daniel Imms
2019-01-30 21:47:39 -08:00
parent cc531f1933
commit 33e46682b1
2 changed files with 39 additions and 19 deletions
+29 -15
View File
@@ -3,13 +3,13 @@
* @license MIT
*/
import { CircularList, IInsertEvent, IDeleteEvent } from './common/CircularList';
import { CharData, ITerminal, IBuffer, IBufferLine, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from './Types';
import { EventEmitter } from './common/EventEmitter';
import { IMarker } from 'xterm';
import { BufferLine } from './BufferLine';
import { reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths } from './BufferReflow';
import { CircularList, IDeleteEvent, IInsertEvent } from './common/CircularList';
import { EventEmitter } from './common/EventEmitter';
import { DEFAULT_COLOR } from './renderer/atlas/Types';
import { reflowSmallerGetNewLineLengths, reflowLargerGetLinesToRemove, reflowLargerCreateNewLayout, reflowLargerApplyNewLayout } from './BufferReflow';
import { BufferIndex, CharData, IBuffer, IBufferLine, IBufferStringIterator, IBufferStringIteratorResult, ITerminal } from './Types';
export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
export const CHAR_DATA_ATTR_INDEX = 0;
@@ -212,7 +212,7 @@ export class Buffer implements IBuffer {
this.scrollBottom = newRows - 1;
if (this._hasScrollback) {
this._reflow(newCols);
this._reflow(newCols, newRows);
// Trim the end of the line off if cols shrunk
if (this._cols > newCols) {
@@ -226,7 +226,7 @@ export class Buffer implements IBuffer {
this._rows = newRows;
}
private _reflow(newCols: number): void {
private _reflow(newCols: number, newRows: number): void {
if (this._cols === newCols) {
return;
}
@@ -235,12 +235,12 @@ export class Buffer implements IBuffer {
if (newCols > this._cols) {
this._reflowLarger(newCols);
} else {
this._reflowSmaller(newCols);
this._reflowSmaller(newCols, newRows);
}
}
private _reflowLarger(newCols: number): void {
const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, newCols);
const toRemove: number[] = reflowLargerGetLinesToRemove(this.lines, newCols, this.ybase + this.y);
if (toRemove.length > 0) {
const newLayoutResult = reflowLargerCreateNewLayout(this.lines, toRemove);
reflowLargerApplyNewLayout(this.lines, newLayoutResult.layout);
@@ -253,9 +253,13 @@ export class Buffer implements IBuffer {
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));
if (this.y > 0) {
this.y--;
}
if (this.lines.length < this._rows) {
// 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--;
@@ -265,7 +269,7 @@ export class Buffer implements IBuffer {
}
}
private _reflowSmaller(newCols: number): void {
private _reflowSmaller(newCols: number, newRows: number): void {
// Gather all BufferLines that need to be inserted into the Buffer here so that they can be
// batched up and only committed once
const toInsert = [];
@@ -285,6 +289,13 @@ export class Buffer implements IBuffer {
wrappedLines.unshift(nextLine);
}
// If these lines contain the cursor don't touch them, the program will handle fixing up
// wrapped lines with the cursor
const absoluteY = this.ybase + this.y;
if (absoluteY >= y && absoluteY < y + wrappedLines.length) {
continue;
}
const lastLineLength = wrappedLines[wrappedLines.length - 1].getTrimmedLength();
const destLineLengths = reflowSmallerGetNewLineLengths(wrappedLines, this._cols, newCols);
const linesToAdd = destLineLengths.length - wrappedLines.length;
@@ -357,10 +368,13 @@ export class Buffer implements IBuffer {
this.ydisp++;
}
} else {
if (this.ybase === this.ydisp) {
this.ydisp++;
// Ensure ybase does not exceed its maximum value
if (this.ybase < Math.min(this.lines.maxLength, this.lines.length + countToInsert) - newRows) {
if (this.ybase === this.ydisp) {
this.ydisp++;
}
this.ybase++;
}
this.ybase++;
}
}
}
+10 -4
View File
@@ -3,10 +3,10 @@
* @license MIT
*/
import { FILL_CHAR_DATA } from './Buffer';
import { BufferLine } from './BufferLine';
import { CircularList, IDeleteEvent } from './common/CircularList';
import { IBufferLine } from './Types';
import { FILL_CHAR_DATA } from './Buffer';
export interface INewLayoutResult {
layout: number[];
@@ -19,7 +19,7 @@ export interface INewLayoutResult {
* @param lines The buffer lines.
* @param newCols The columns after resize.
*/
export function reflowLargerGetLinesToRemove(lines: CircularList<IBufferLine>, newCols: number): number[] {
export function reflowLargerGetLinesToRemove(lines: CircularList<IBufferLine>, newCols: number, bufferAbsoluteY: 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[] = [];
@@ -39,6 +39,13 @@ export function reflowLargerGetLinesToRemove(lines: CircularList<IBufferLine>, n
nextLine = lines.get(++i) as BufferLine;
}
// If these lines contain the cursor don't touch them, the program will handle fixing up wrapped
// lines with the cursor
if (bufferAbsoluteY >= y && bufferAbsoluteY < i) {
y += wrappedLines.length - 1;
continue;
}
// Copy buffer data to new locations
let destLineIndex = 0;
let destCol = wrappedLines[destLineIndex].getTrimmedLength();
@@ -64,7 +71,7 @@ export function reflowLargerGetLinesToRemove(lines: CircularList<IBufferLine>, n
}
// Make sure the last cell isn't wide, if it is copy it to the current dest
if (destCol === 0) {
if (destCol === 0 && destLineIndex !== 0) {
if (wrappedLines[destLineIndex - 1].getWidth(newCols - 1) === 2) {
wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[destLineIndex - 1], newCols - 1, destCol++, 1, false);
// Null out the end of the last row
@@ -166,7 +173,6 @@ export function reflowLargerApplyNewLayout(lines: CircularList<IBufferLine>, new
*/
export function reflowSmallerGetNewLineLengths(wrappedLines: BufferLine[], oldCols: number, newCols: number): number[] {
const newLineLengths: number[] = [];
const cellsNeeded = wrappedLines.map(l => l.getTrimmedLength()).reduce((p, c) => p + c);
// Use srcCol and srcLine to find the new wrapping point, use that to get the cellsAvailable and