Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BufferLine rewrite [WIP] #4928

Open
wants to merge 69 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
bf4e359
Experimental re-design of BufferLine.
PerBothner Jul 13, 2023
8df267f
Improve new BuferLine implementation.
PerBothner Jul 18, 2023
8d87caa
Merge branch 'master' into buffer-cell-cursor
PerBothner Aug 18, 2023
7f2107a
New implementations of translateToString and getTrimmedLength.
PerBothner Aug 18, 2023
d13d98c
Change some small access functions and tweak documentation+comments.
PerBothner Aug 18, 2023
ede649f
Add debugging functions _showData and getText.
PerBothner Aug 18, 2023
7659c9f
More work on BufferLine re-write.
PerBothner Aug 29, 2023
8de51e9
Add some comments to document IBuffer fields.
PerBothner Sep 8, 2023
231ae07
Merge remote-tracking branch 'upstream/master' into buffer-cell-cursor
PerBothner Sep 8, 2023
ae9ac1d
Merge remote-tracking branch 'upstream/master' into buffer-cell-cursor
PerBothner Sep 18, 2023
3b516f6
Start re-vamping BufferLine re-implementation
PerBothner Sep 27, 2023
6998d1e
Remove setCluster function. Fix thinko.
PerBothner Oct 4, 2023
9a2027b
Change setCellFromCodePoint API and rename to setCellFromCodepoint
PerBothner Sep 26, 2023
9cca703
Extract guts of loadCell into new moveToColumn function.
PerBothner Oct 5, 2023
5983a0c
Get webgl renderer working again (as well as it did before).
PerBothner Oct 6, 2023
68e7631
Remove old buffer DataKind values
PerBothner Oct 6, 2023
71bdedd
Revert canvas and webgl renderers to old API
PerBothner Oct 6, 2023
38fd0dc
Change LineBuffer.setAttributes to take an IAttributeData
PerBothner Oct 7, 2023
6d32c99
new method LineBuffer.insertText
PerBothner Oct 13, 2023
1636425
New help method deleteCellsOnly.
PerBothner Oct 16, 2023
e66a006
implement setCellFromCodepoint for new BufferLine
PerBothner Oct 20, 2023
dd1eea0
More BufferLine cleanup
PerBothner Oct 21, 2023
8d1b31b
Allow choice of either NewBufferLine or OldBufferLine
PerBothner Oct 21, 2023
79ed24f
Basic support for window resize.
PerBothner Nov 2, 2023
d0dfa2a
Merge branch 'master' into buffer-cell-cursor
PerBothner Nov 5, 2023
b01f827
Get rid of some no-longer-used stuff in CellData.
PerBothner Nov 5, 2023
a3020a7
Incomplete re-write of line-wrapping model.
PerBothner Nov 16, 2023
733093e
Basic reflow handling on window-width changes.
PerBothner Nov 23, 2023
ed1b672
_showData debug helper: Don't use hex for counts.
PerBothner Nov 24, 2023
43c8e43
Adjust buffer.y on window resize.
PerBothner Nov 24, 2023
214a820
New eraseCells function. Other fixes.
PerBothner Nov 27, 2023
41db1f2
Various fixes.
PerBothner Nov 29, 2023
632187f
Add logOutput, a debug hook for Terminal.write.
PerBothner Dec 1, 2023
7f2fc37
Fixes to scrolling and line wrapping.
PerBothner Dec 1, 2023
0deb617
Make erase work better.
PerBothner Dec 3, 2023
cfdfb06
Make background color erase (BCE) work
PerBothner Dec 7, 2023
795c388
Fix to scroll handling
PerBothner Dec 7, 2023
2baf3a8
Implement insertCells.
PerBothner Dec 8, 2023
dbc1080
Fix a bunch of lint issues
PerBothner Dec 9, 2023
63d36d5
Add "newBufferLine" option.
PerBothner Dec 10, 2023
040666b
Fix to setting of newBufferLine option
PerBothner Dec 11, 2023
97910e3
Improved logic to update cursor position on resize
PerBothner Dec 17, 2023
cd360f2
Change reflow to be lazy
PerBothner Dec 26, 2023
dc07f28
Merge remote-tracking branch 'upstream/master' into buffer-cell-cursor
PerBothner Dec 26, 2023
33a0054
Fix preInsert when position is in SKIP_SPACES or after end.
PerBothner Dec 28, 2023
0b08b16
Fix bugs from playwright: translateToString and ICH
PerBothner Dec 28, 2023
d09fbc3
Merge branch 'master' into buffer-cell-cursor
PerBothner Dec 29, 2023
6eee37b
Fix testsuite errors when newBufferLine is false
PerBothner Dec 29, 2023
a8aab00
More Lint fixes.
PerBothner Dec 29, 2023
a2c26d6
Merge branch 'master' into buffer-cell-cursor
PerBothner Dec 30, 2023
845d202
Fix translateToString.
PerBothner Dec 31, 2023
da51666
More reflow fixes, including handling saved cursor.
PerBothner Jan 6, 2024
e2da6d5
Testsuite-based fixes and cleanups.
PerBothner Jan 13, 2024
2d2c027
FixImplement extended-attribute handling in deleteCellsOnly.
PerBothner Jan 14, 2024
10719a0
Fixes for extended attributes and setWrapped for test-cases.
PerBothner Jan 22, 2024
c5685bb
More polishing and testsuite fixes.
PerBothner Jan 25, 2024
e0b62dd
Change preInsert to reduce duplicated style entries
PerBothner Jan 26, 2024
f86d308
Merge branch 'xtermjs:master' into buffer-cell-cursor
PerBothner Jan 26, 2024
bc57c28
Adjust showRow and showDataRow.
PerBothner Feb 25, 2024
9aaf516
Fixes mostly related to wrapped lines with wide characters
PerBothner Feb 29, 2024
b25427f
Fixes to Buffer.setWrapped
PerBothner Feb 29, 2024
b351bd1
Merge branch 'master' into buffer-cell-cursor
PerBothner Feb 29, 2024
1d6de8e
Merge branch 'xtermjs:master' into buffer-cell-cursor
PerBothner Jun 9, 2024
f92e6df
Merge branch 'master' into buffer-cell-cursor
PerBothner Jul 25, 2024
8b23f24
Remove 2 unused fields.
PerBothner Aug 5, 2024
544800a
Merge branch 'master' into buffer-cell-cursor
PerBothner Aug 5, 2024
5313b49
Revert "Remove 2 unused fields."
PerBothner Aug 7, 2024
e4d0a68
Merge branch 'master' into buffer-cell-cursor
PerBothner Sep 21, 2024
973ec45
Provide basic implementation of NewBufferLine.resize
PerBothner Oct 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/browser/TestUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ export class MockBuffer implements IBuffer {
public addMarker(y: number): IMarker {
throw new Error('Method not implemented.');
}
public splitLine(row: number, col: number): void {
throw new Error('Method not implemented.');
}
public isCursorInViewport!: boolean;
public lines!: ICircularList<IBufferLine>;
public ydisp!: number;
Expand All @@ -240,6 +243,9 @@ export class MockBuffer implements IBuffer {
public getWrappedRangeForLine(y: number): { first: number, last: number } {
return Buffer.prototype.getWrappedRangeForLine.apply(this, arguments as any);
}
public reflowRegion(startRow: number, endRow: number, maxRows: number): boolean {
throw new Error('Method not implemented.');
}
public nextStop(x?: number): number {
throw new Error('Method not implemented.');
}
Expand All @@ -264,6 +270,9 @@ export class MockBuffer implements IBuffer {
public clearAllMarkers(): void {
throw new Error('Method not implemented.');
}
public setWrapped(row: number, value: boolean): void {
throw new Error('Method not implemented.');
}
}

export class MockRenderer implements IRenderer {
Expand Down
9 changes: 9 additions & 0 deletions src/browser/public/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class Terminal extends Disposable implements ITerminalApi {
private _parser: IParser | undefined;
private _buffer: BufferNamespaceApi | undefined;
private _publicOptions: Required<ITerminalOptions>;
public logOutput: boolean = false;

constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions) {
super();
Expand Down Expand Up @@ -224,6 +225,14 @@ export class Terminal extends Disposable implements ITerminalApi {
this._core.clear();
}
public write(data: string | Uint8Array, callback?: () => void): void {
if (this.logOutput && data instanceof Uint8Array) {
const thisAny = this as any;
if (! thisAny._decoder) {
thisAny._decoder = new TextDecoder(); // label = "utf-8");
}
const str = thisAny._decoder.decode(data, { stream:true });
console.log('write: '+JSON.stringify(str));
}
this._core.write(data, callback);
}
public writeln(data: string | Uint8Array, callback?: () => void): void {
Expand Down
8 changes: 4 additions & 4 deletions src/browser/renderer/dom/DomRendererRowFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ describe('DomRendererRowFactory', () => {
});

it('should handle BCE correctly', () => {
const nullCell = lineData.loadCell(0, new CellData());
const nullCell = CellData.fromChar(' ');
nullCell.bg = Attributes.CM_P16 | 1;
lineData.setCell(2, nullCell);
nullCell.bg = Attributes.CM_P16 | 2;
Expand All @@ -418,7 +418,7 @@ describe('DomRendererRowFactory', () => {
});

it('should handle BCE for multiple cells', () => {
const nullCell = lineData.loadCell(0, new CellData());
const nullCell = CellData.fromChar(' ');
nullCell.bg = Attributes.CM_P16 | 1;
lineData.setCell(0, nullCell);
let spans = rowFactory.createRow(lineData, 0, false, undefined, undefined, 0, false, 5, EMPTY_WIDTH, -1, -1);
Expand Down Expand Up @@ -451,7 +451,7 @@ describe('DomRendererRowFactory', () => {
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, '€', 1, '€'.charCodeAt(0)]));
lineData.setCell(2, CellData.fromCharData([DEFAULT_ATTR, 'c', 1, 'c'.charCodeAt(0)]));
lineData.setCell(3, CellData.fromCharData([DEFAULT_ATTR, '語', 2, 'c'.charCodeAt(0)]));
lineData.setCell(4, CellData.fromCharData([DEFAULT_ATTR, '𝄞', 1, 'c'.charCodeAt(0)]));
lineData.setCell(5, CellData.fromCharData([DEFAULT_ATTR, '𝄞', 1, 'c'.charCodeAt(0)]));
const spans = rowFactory.createRow(lineData, 0, false, undefined, undefined, 0, false, 5, EMPTY_WIDTH, -1, -1);
assert.equal(extractHtml(spans),
'<span>a</span><span style="letter-spacing: 3px;">€</span><span>c語</span><span style="letter-spacing: -2px;">𝄞</span>'
Expand Down Expand Up @@ -502,7 +502,7 @@ describe('DomRendererRowFactory', () => {
}

function createEmptyLineData(cols: number): IBufferLine {
const lineData = new BufferLine(cols);
const lineData = BufferLine.make(cols);
for (let i = 0; i < cols; i++) {
lineData.setCell(i, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]));
}
Expand Down
14 changes: 7 additions & 7 deletions src/browser/renderer/dom/DomRendererRowFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { CellData } from 'common/buffer/CellData';
import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { channels, color } from 'common/Color';
import { ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { JoinedCellData } from 'browser/services/CharacterJoinerService';
import { treatGlyphAsBackgroundColor } from 'browser/renderer/shared/RendererUtils';
import { AttributeData } from 'common/buffer/AttributeData';
import { WidthCache } from 'browser/renderer/dom/WidthCache';
Expand Down Expand Up @@ -44,7 +43,7 @@ export class DomRendererRowFactory {

constructor(
private readonly _document: Document,
@ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService,
@ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService, // FIXME remove
@IOptionsService private readonly _optionsService: IOptionsService,
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService,
@ICoreService private readonly _coreService: ICoreService,
Expand All @@ -71,9 +70,9 @@ export class DomRendererRowFactory {
linkStart: number,
linkEnd: number
): HTMLSpanElement[] {
const cell = this._workCell;

const elements: HTMLSpanElement[] = [];
const joinedRanges = this._characterJoinerService.getJoinedCharacters(row);
const colors = this._themeService.colors;

let lineLength = lineData.getNoBgTrimmedLength();
Expand All @@ -97,21 +96,21 @@ export class DomRendererRowFactory {

for (let x = 0; x < lineLength; x++) {
lineData.loadCell(x, this._workCell);
let width = this._workCell.getWidth();
const width = this._workCell.getWidth();

// The character to the left is a wide character, drawing is owned by the char at x-1
if (width === 0) {
continue;
}

// If true, indicates that the current character(s) to draw were joined.
let isJoined = false;
let lastCharX = x;
const isJoined = false;
const lastCharX = x;

// Process any joined character ranges as needed. Because of how the
// ranges are produced, we know that they are valid for the characters
// and attributes of our input.
let cell = this._workCell;
/*
if (joinedRanges.length > 0 && x === joinedRanges[0][0]) {
isJoined = true;
const range = joinedRanges.shift()!;
Expand All @@ -130,6 +129,7 @@ export class DomRendererRowFactory {
// Recalculate width
width = cell.getWidth();
}
*/

const isInSelection = this._isCellInSelection(x, row);
const isCursorCell = isCursorRow && x === cursorX;
Expand Down
4 changes: 2 additions & 2 deletions src/browser/services/CharacterJoinerService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('CharacterJoinerService', () => {
lines.set(2, lineData([['a -> b -', 0xFFFFFFFF], ['> c -> d', 0]]));

lines.set(3, lineData([['no joined ranges']]));
lines.set(4, new BufferLine(0));
lines.set(4, BufferLine.make(0));
lines.set(5, lineData([['a', 0x11111111], [' -> b -> c -> '], ['d', 0x22222222]]));
const line6 = lineData([['wi']]);
line6.resize(line6.length + 1, CellData.fromCharData([0, '¥', 2, '¥'.charCodeAt(0)]));
Expand Down Expand Up @@ -267,7 +267,7 @@ describe('CharacterJoinerService', () => {
type IPartialLineData = ([string] | [string, number]);

function lineData(data: IPartialLineData[]): IBufferLine {
const tline = new BufferLine(0);
const tline = BufferLine.make(0);
for (let i = 0; i < data.length; ++i) {
const line = data[i][0];
const attr = (data[i][1] || 0) as number;
Expand Down
1 change: 1 addition & 0 deletions src/browser/services/CharacterJoinerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CellData } from 'common/buffer/CellData';
import { IBufferService } from 'common/services/Services';
import { ICharacterJoinerService } from 'browser/services/Services';

// FIXME should probably just use plain CellData
export class JoinedCellData extends AttributeData implements ICellData {
private _width: number;
// .content carries no meaning for joined CellData, simply nullify it
Expand Down
18 changes: 9 additions & 9 deletions src/browser/services/SelectionService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ describe('SelectionService', () => {
});

function stringToRow(text: string): IBufferLine {
const result = new BufferLine(text.length);
const result = BufferLine.make(text.length);
for (let i = 0; i < text.length; i++) {
result.setCell(i, CellData.fromCharData([0, text.charAt(i), 1, text.charCodeAt(i)]));
}
return result;
}

function stringArrayToRow(chars: string[]): IBufferLine {
const line = new BufferLine(chars.length);
const line = BufferLine.make(chars.length);
chars.map((c, idx) => line.setCell(idx, CellData.fromCharData([0, c, 1, c.charCodeAt(0)])));
return line;
}
Expand Down Expand Up @@ -118,7 +118,7 @@ describe('SelectionService', () => {
[0, 'o', 1, 'o'.charCodeAt(0)],
[0, 'o', 1, 'o'.charCodeAt(0)]
];
const line = new BufferLine(data.length);
const line = BufferLine.make(data.length);
for (let i = 0; i < data.length; ++i) line.setCell(i, CellData.fromCharData(data[i]));
buffer.lines.set(0, line);
// Ensure wide characters take up 2 columns
Expand Down Expand Up @@ -193,7 +193,7 @@ describe('SelectionService', () => {
it('should expand upwards or downards for wrapped lines', () => {
buffer.lines.set(0, stringToRow(' foo'));
buffer.lines.set(1, stringToRow('bar '));
buffer.lines.get(1)!.isWrapped = true;
buffer.setWrapped(1, true);
selectionService.selectWordAt([1, 1]);
assert.equal(selectionService.selectionText, 'foobar');
selectionService.model.clearSelection();
Expand All @@ -207,10 +207,10 @@ describe('SelectionService', () => {
buffer.lines.set(2, stringToRow('bbbbbbbbbbbbbbbbbbbb'));
buffer.lines.set(3, stringToRow('cccccccccccccccccccc'));
buffer.lines.set(4, stringToRow('bar '));
buffer.lines.get(1)!.isWrapped = true;
buffer.lines.get(2)!.isWrapped = true;
buffer.lines.get(3)!.isWrapped = true;
buffer.lines.get(4)!.isWrapped = true;
buffer.setWrapped(1, true);
buffer.setWrapped(2, true);
buffer.setWrapped(3, true);
buffer.setWrapped(4, true);
selectionService.selectWordAt([18, 0]);
assert.equal(selectionService.selectionText, expectedText);
selectionService.model.clearSelection();
Expand Down Expand Up @@ -349,8 +349,8 @@ describe('SelectionService', () => {
it('should select the entire wrapped line', () => {
buffer.lines.set(0, stringToRow('foo'));
const line2 = stringToRow('bar');
line2.isWrapped = true;
buffer.lines.set(1, line2);
buffer.setWrapped(1, true);
selectionService.selectLineAt(0);
assert.equal(selectionService.selectionText, 'foobar', 'The selected text is correct');
assert.deepEqual(selectionService.model.selectionStart, [0, 0]);
Expand Down
4 changes: 2 additions & 2 deletions src/browser/services/SelectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ export class SelectionService extends Disposable implements ISelectionService {
}

// Expand the string in both directions until a space is hit
while (startCol > 0 && startIndex > 0 && !this._isCharWordSeparator(bufferLine.loadCell(startCol - 1, this._workCell))) {
while (startCol > 0 && startIndex > 0 && !this._isCharWordSeparator(bufferLine.loadCell(startCol - 1, this._workCell) as CellData)) {
bufferLine.loadCell(startCol - 1, this._workCell);
const length = this._workCell.getChars().length;
if (this._workCell.getWidth() === 0) {
Expand All @@ -880,7 +880,7 @@ export class SelectionService extends Disposable implements ISelectionService {
startIndex--;
startCol--;
}
while (endCol < bufferLine.length && endIndex + 1 < line.length && !this._isCharWordSeparator(bufferLine.loadCell(endCol + 1, this._workCell))) {
while (endCol < bufferLine.length && endIndex + 1 < line.length && !this._isCharWordSeparator(bufferLine.loadCell(endCol + 1, this._workCell) as CellData)) {
bufferLine.loadCell(endCol + 1, this._workCell);
const length = this._workCell.getChars().length;
if (this._workCell.getWidth() === 2) {
Expand Down
30 changes: 15 additions & 15 deletions src/common/InputHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,18 +452,16 @@
);

// fill display with a's
for (let i = 0; i < bufferService.rows; ++i) await inputHandler.parseP(Array(bufferService.cols + 1).join('a'));
const a_repeat_cols = Array(bufferService.cols + 1).join('a');

Check warning on line 455 in src/common/InputHandler.test.ts

View workflow job for this annotation

GitHub Actions / lint

Variable name `a_repeat_cols` must match one of the following formats: camelCase, UPPER_CASE
for (let i = 0; i < bufferService.rows; ++i) await inputHandler.parseP(a_repeat_cols);

// params [0] - right and below erase
bufferService.buffer.y = 5;
bufferService.buffer.x = 40;
inputHandler.eraseInDisplay(Params.fromArray([0]));
assert.deepEqual(termContent(bufferService, false), [
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
a_repeat_cols, a_repeat_cols, a_repeat_cols,
a_repeat_cols, a_repeat_cols,
Array(40 + 1).join('a') + Array(bufferService.cols - 40 + 1).join(' '),
Array(bufferService.cols + 1).join(' ')
]);
Expand Down Expand Up @@ -1885,17 +1883,19 @@
assert.equal(cell.isUnderlineColorDefault(), false);

// eAttrs in buffer pos 0 and 1 should be the same object
assert.equal(
(bufferService.buffer!.lines.get(0)! as any)._extendedAttrs[0],
(bufferService.buffer!.lines.get(0)! as any)._extendedAttrs[1]
);
const line0 = bufferService.buffer!.lines.get(0)!;
line0.loadCell(0, cell);
const ext0 = cell.extended;
line0.loadCell(1, cell);
const ext1 = cell.extended;
assert.equal(ext0, ext1);
// should not have written eAttr for pos 2 in the buffer
assert.equal((bufferService.buffer!.lines.get(0)! as any)._extendedAttrs[2], undefined);
line0.loadCell(2, cell);
assert.isFalse(cell.hasExtendedAttrs() !== 0);
// eAttrs in buffer pos 1 and pos 3 must be different objs
assert.notEqual(
(bufferService.buffer!.lines.get(0)! as any)._extendedAttrs[1],
(bufferService.buffer!.lines.get(0)! as any)._extendedAttrs[3]
);
line0.loadCell(3, cell);
const ext3 = cell.extended;
assert.notEqual(ext1, ext3);
});
});
describe('DECSTR', () => {
Expand Down
Loading
Loading