mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
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:
+29
-15
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user