Skip to content
4 changes: 2 additions & 2 deletions addons/xterm-addon-attach/src/AttachAddon.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('AttachAddon', () => {
const server = new WebSocket.Server({ port });
server.on('connection', socket => socket.send('foo'));
await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
await pollFor(page, `window.term.buffer.getLine(0).translateToString(true)`, 'foo');
await pollFor(page, `window.term.buffer.active.getLine(0).translateToString(true)`, 'foo');
server.close();
});

Expand All @@ -47,7 +47,7 @@ describe('AttachAddon', () => {
const data = new Uint8Array([102, 111, 111]);
server.on('connection', socket => socket.send(data));
await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
await pollFor(page, `window.term.buffer.getLine(0).translateToString(true)`, 'foo');
await pollFor(page, `window.term.buffer.active.getLine(0).translateToString(true)`, 'foo');
server.close();
});
});
8 changes: 4 additions & 4 deletions addons/xterm-addon-search/src/SearchAddon.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('Search Tests', function(): void {
await page.evaluate(`window.term.writeln('package.jsonc\\n')`);
await writeSync(page, 'package.json pack package.lock');
await page.evaluate(`window.search.findPrevious('pack', {incremental: true})`);
let line: string = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
let line: string = await page.evaluate(`window.term.buffer.active.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
let selectionPosition: { startColumn: number, startRow: number, endColumn: number, endRow: number } = await page.evaluate(`window.term.getSelectionPosition()`);
// We look further ahead in the line to ensure that pack was selected from package.lock
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 8), 'package.lock');
Expand All @@ -69,15 +69,15 @@ describe('Search Tests', function(): void {
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 3), 'package.json');
await page.evaluate(`window.search.findPrevious('package.jsonc', {incremental: true})`);
// We have to reevaluate line because it should have switched starting rows at this point
line = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
line = await page.evaluate(`window.term.buffer.active.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`);
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn), 'package.jsonc');
});
it('Incremental Find Next', async () => {
await page.evaluate(`window.term.writeln('package.lock pack package.json package.ups\\n')`);
await writeSync(page, 'package.jsonc');
await page.evaluate(`window.search.findNext('pack', {incremental: true})`);
let line: string = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
let line: string = await page.evaluate(`window.term.buffer.active.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
let selectionPosition: { startColumn: number, startRow: number, endColumn: number, endRow: number } = await page.evaluate(`window.term.getSelectionPosition()`);
// We look further ahead in the line to ensure that pack was selected from package.lock
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 8), 'package.lock');
Expand All @@ -86,7 +86,7 @@ describe('Search Tests', function(): void {
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 3), 'package.json');
await page.evaluate(`window.search.findNext('package.jsonc', {incremental: true})`);
// We have to reevaluate line because it should have switched starting rows at this point
line = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
line = await page.evaluate(`window.term.buffer.active.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`);
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn), 'package.jsonc');
});
Expand Down
22 changes: 11 additions & 11 deletions addons/xterm-addon-search/src/SearchAddon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class SearchAddon implements ITerminalAddon {
// Search from startRow + 1 to end
if (!result) {

for (let y = startRow + 1; y < this._terminal.buffer.baseY + this._terminal.rows; y++) {
for (let y = startRow + 1; y < this._terminal.buffer.active.baseY + this._terminal.rows; y++) {
searchPosition.startRow = y;
searchPosition.startCol = 0;
// If the current line is wrapped line, increase index of column to ignore the previous scan
Expand Down Expand Up @@ -135,7 +135,7 @@ export class SearchAddon implements ITerminalAddon {
}

const isReverseSearch = true;
let startRow = this._terminal.buffer.baseY + this._terminal.rows;
let startRow = this._terminal.buffer.active.baseY + this._terminal.rows;
let startCol = this._terminal.cols;
let result: ISearchResult | undefined;
const incremental = searchOptions ? searchOptions.incremental : false;
Expand Down Expand Up @@ -174,8 +174,8 @@ export class SearchAddon implements ITerminalAddon {
}
}
// If we hit the top and didn't search from the very bottom wrap back down
if (!result && startRow !== (this._terminal.buffer.baseY + this._terminal.rows)) {
for (let y = (this._terminal.buffer.baseY + this._terminal.rows); y > startRow; y--) {
if (!result && startRow !== (this._terminal.buffer.active.baseY + this._terminal.rows)) {
for (let y = (this._terminal.buffer.active.baseY + this._terminal.rows); y > startRow; y--) {
searchPosition.startRow = y;
result = this._findInLine(term, searchPosition, searchOptions, isReverseSearch);
if (result) {
Expand All @@ -197,7 +197,7 @@ export class SearchAddon implements ITerminalAddon {
private _initLinesCache(): void {
const terminal = this._terminal!;
if (!this._linesCache) {
this._linesCache = new Array(terminal.buffer.length);
this._linesCache = new Array(terminal.buffer.active.length);
this._cursorMoveListener = terminal.onCursorMove(() => this._destroyLinesCache());
this._resizeListener = terminal.onResize(() => this._destroyLinesCache());
}
Expand Down Expand Up @@ -249,7 +249,7 @@ export class SearchAddon implements ITerminalAddon {
const col = searchPosition.startCol;

// Ignore wrapped lines, only consider on unwrapped line (first row of command string).
const firstLine = terminal.buffer.getLine(row);
const firstLine = terminal.buffer.active.getLine(row);
if (firstLine && firstLine.isWrapped) {
if (isReverseSearch) {
searchPosition.startCol += terminal.cols;
Expand Down Expand Up @@ -311,7 +311,7 @@ export class SearchAddon implements ITerminalAddon {
return;
}

const line = terminal.buffer.getLine(row);
const line = terminal.buffer.active.getLine(row);

if (line) {
for (let i = 0; i < resultIndex; i++) {
Expand Down Expand Up @@ -354,9 +354,9 @@ export class SearchAddon implements ITerminalAddon {
let lineWrapsToNext: boolean;

do {
const nextLine = terminal.buffer.getLine(lineIndex + 1);
const nextLine = terminal.buffer.active.getLine(lineIndex + 1);
lineWrapsToNext = nextLine ? nextLine.isWrapped : false;
const line = terminal.buffer.getLine(lineIndex);
const line = terminal.buffer.active.getLine(lineIndex);
if (!line) {
break;
}
Expand All @@ -380,8 +380,8 @@ export class SearchAddon implements ITerminalAddon {
}
terminal.select(result.col, result.row, result.term.length);
// If it is not in the viewport then we scroll else it just gets selected
if (result.row >= (terminal.buffer.viewportY + terminal.rows) || result.row < terminal.buffer.viewportY) {
let scroll = result.row - terminal.buffer.viewportY;
if (result.row >= (terminal.buffer.active.viewportY + terminal.rows) || result.row < terminal.buffer.active.viewportY) {
let scroll = result.row - terminal.buffer.active.viewportY;
scroll = scroll - Math.floor(terminal.rows / 2);
terminal.scrollLines(scroll);
}
Expand Down
4 changes: 2 additions & 2 deletions addons/xterm-addon-serialize/src/SerializeAddon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ export class SerializeAddon implements ITerminalAddon {
throw new Error('Cannot use addon until it has been loaded');
}

const maxRows = this._terminal.buffer.length;
const handler = new StringSerializeHandler(this._terminal.buffer);
const maxRows = this._terminal.buffer.active.length;
const handler = new StringSerializeHandler(this._terminal.buffer.active);

rows = (rows === undefined) ? maxRows : constrain(rows, 0, maxRows);

Expand Down
6 changes: 3 additions & 3 deletions addons/xterm-addon-web-links/src/WebLinkProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class LinkComputer {
let prevLinesToWrap: boolean;

do {
const line = terminal.buffer.getLine(lineIndex);
const line = terminal.buffer.active.getLine(lineIndex);
if (!line) {
break;
}
Expand All @@ -99,9 +99,9 @@ export class LinkComputer {
const startLineIndex = lineIndex;

do {
const nextLine = terminal.buffer.getLine(lineIndex + 1);
const nextLine = terminal.buffer.active.getLine(lineIndex + 1);
lineWrapsToNext = nextLine ? nextLine.isWrapped : false;
const line = terminal.buffer.getLine(lineIndex);
const line = terminal.buffer.active.getLine(lineIndex);
if (!line) {
break;
}
Expand Down
4 changes: 2 additions & 2 deletions addons/xterm-addon-webgl/src/GlyphRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export class GlyphRenderer {

private _updateSelectionRange(startCol: number, endCol: number, y: number, model: IRenderModel, bg: number): void {
const terminal = this._terminal;
const row = y + terminal.buffer.viewportY;
const row = y + terminal.buffer.active.viewportY;
let line: IBufferLine | undefined;
for (let x = startCol; x < endCol; x++) {
const offset = (y * this._terminal.cols + x) * RENDER_MODEL_INDICIES_PER_CELL;
Expand Down Expand Up @@ -281,7 +281,7 @@ export class GlyphRenderer {
}
if (code & COMBINED_CHAR_BIT_MASK) {
if (!line) {
line = terminal.buffer.getLine(row);
line = terminal.buffer.active.getLine(row);
}
const chars = line!.getCell(x)!.getChars();
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg, chars);
Expand Down
4 changes: 2 additions & 2 deletions addons/xterm-addon-webgl/src/WebglRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
}

// Translate from buffer position to viewport position
const viewportStartRow = start[1] - terminal.buffer.viewportY;
const viewportEndRow = end[1] - terminal.buffer.viewportY;
const viewportStartRow = start[1] - terminal.buffer.active.viewportY;
const viewportEndRow = end[1] - terminal.buffer.active.viewportY;
const viewportCappedStartRow = Math.max(viewportStartRow, 0);
const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1);

Expand Down
12 changes: 6 additions & 6 deletions addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ export class CursorRenderLayer extends BaseRenderLayer {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.pause();
}
this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.cursorY, end: terminal.buffer.cursorY });
this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.active.cursorY, end: terminal.buffer.active.cursorY });
}

public onFocus(terminal: Terminal): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.resume(terminal);
} else {
this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.cursorY, end: terminal.buffer.cursorY });
this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.active.cursorY, end: terminal.buffer.active.cursorY });
}
}

Expand All @@ -100,7 +100,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
}
// Request a refresh from the terminal as management of rendering is being
// moved back to the terminal
this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.cursorY, end: terminal.buffer.cursorY });
this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.active.cursorY, end: terminal.buffer.active.cursorY });
}

public onCursorMove(terminal: Terminal): void {
Expand All @@ -125,11 +125,11 @@ export class CursorRenderLayer extends BaseRenderLayer {
return;
}

const cursorY = terminal.buffer.baseY + terminal.buffer.cursorY;
const viewportRelativeCursorY = cursorY - terminal.buffer.viewportY;
const cursorY = terminal.buffer.active.baseY + terminal.buffer.active.cursorY;
const viewportRelativeCursorY = cursorY - terminal.buffer.active.viewportY;

// in case cursor.x == cols adjust visual cursor to cols - 1
const cursorX = Math.min(terminal.buffer.cursorX, terminal.cols - 1);
const cursorX = Math.min(terminal.buffer.active.cursorX, terminal.cols - 1);

// Don't draw the cursor if it's off-screen
if (viewportRelativeCursorY < 0 || viewportRelativeCursorY >= terminal.rows) {
Expand Down
42 changes: 37 additions & 5 deletions src/public/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
* @license MIT
*/

import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, IParser, IFunctionIdentifier, ILinkProvider, IUnicodeHandling, IUnicodeVersionProvider } from 'xterm';
import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, IParser, IFunctionIdentifier, ILinkProvider, IUnicodeHandling, IUnicodeVersionProvider } from 'xterm';
import { ITerminal } from '../Types';
import { IBufferLine, ICellData } from 'common/Types';
import { IBuffer } from 'common/buffer/Types';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { CellData } from 'common/buffer/CellData';
import { Terminal as TerminalCore } from '../Terminal';
import * as Strings from '../browser/LocalizableStrings';
import { IEvent } from 'common/EventEmitter';
import { IEvent, EventEmitter } from 'common/EventEmitter';
import { AddonManager } from './AddonManager';
import { IParams } from 'common/parser/Types';

Expand Down Expand Up @@ -48,7 +48,7 @@ export class Terminal implements ITerminalApi {
public get textarea(): HTMLTextAreaElement | undefined { return this._core.textarea; }
public get rows(): number { return this._core.rows; }
public get cols(): number { return this._core.cols; }
public get buffer(): IBufferApi { return new BufferApiView(this._core.buffer); }
public get buffer(): IBufferNamespaceApi { return new BufferNamespaceApi(this._core.buffers); }
public get markers(): ReadonlyArray<IMarker> { return this._core.markers; }
public blur(): void {
this._core.blur();
Expand Down Expand Up @@ -193,7 +193,15 @@ export class Terminal implements ITerminalApi {
}

class BufferApiView implements IBufferApi {
constructor(private _buffer: IBuffer) { }
constructor(
private _buffer: IBuffer,
public readonly type: 'normal' | 'alternate'
) { }

public init(buffer: IBuffer): BufferApiView {
this._buffer = buffer;
return this;
}

public get cursorY(): number { return this._buffer.y; }
public get cursorX(): number { return this._buffer.x; }
Expand All @@ -210,6 +218,30 @@ class BufferApiView implements IBufferApi {
public getNullCell(): IBufferCellApi { return new CellData(); }
}

class BufferNamespaceApi implements IBufferNamespaceApi {
private _normal: BufferApiView;
private _alternate: BufferApiView;
private _onBufferChange = new EventEmitter<IBufferApi>();
public get onBufferChange(): IEvent<IBufferApi> { return this._onBufferChange.event; }

constructor(private _buffers: IBufferSet) {
this._normal = new BufferApiView(this._buffers.normal, 'normal');
this._alternate = new BufferApiView(this._buffers.alt, 'alternate');
this._buffers.onBufferActivate(() => this._onBufferChange.fire(this.active));
}
public get active(): IBufferApi {
if (this._buffers.active === this._buffers.normal) { return this.normal; }
if (this._buffers.active === this._buffers.alt) { return this.alternate; }
throw new Error('Active buffer is neither normal nor alternate');
}
public get normal(): IBufferApi {
return this._normal.init(this._buffers.normal);
}
public get alternate(): IBufferApi {
return this._alternate.init(this._buffers.alt);
}
}

class BufferLineApiView implements IBufferLineApi {
constructor(private _line: IBufferLine) { }

Expand Down
2 changes: 1 addition & 1 deletion test/api/CharWidth.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async function sumWidths(start: number, end: number, sentinel: string): Promise<
await page.evaluate(`
(function() {
window.result = 0;
const buffer = window.term.buffer;
const buffer = window.term.buffer.active;
for (let i = ${start}; i < ${end}; i++) {
const line = buffer.getLine(i);
let j = 0;
Expand Down
18 changes: 9 additions & 9 deletions test/api/InputHandler.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ describe('InputHandler Integration Tests', function(): void {
window.term.reset()
window.term.write('1\\n2\\n3\\n4\\n5${fixture}\x1b[3J')
`);
await pollFor(page, () => page.evaluate(`window.term.buffer.length`), 5);
await pollFor(page, () => page.evaluate(`window.term.buffer.active.length`), 5);
await pollFor(page, () => getLinesAsArray(5), [' 4', ' 5', 'abc', 'def', 'ghi']);
});

Expand Down Expand Up @@ -193,7 +193,7 @@ describe('InputHandler Integration Tests', function(): void {
window.term.reset()
window.term.write('1\\n2\\n3\\n4\\n5${fixture}\x1b[?3J')
`);
await pollFor(page, () => page.evaluate(`window.term.buffer.length`), 5);
await pollFor(page, () => page.evaluate(`window.term.buffer.active.length`), 5);
await pollFor(page, () => getLinesAsArray(5), [' 4', ' 5', 'abc', 'def', 'ghi']);
});

Expand Down Expand Up @@ -239,7 +239,7 @@ describe('InputHandler Integration Tests', function(): void {
it('Report Cursor Position (CPR) - CSI 6 n', async function(): Promise<any> {
await page.evaluate(`window.term.write('\\n\\nfoo')`);
await pollFor(page, () => page.evaluate(`
[window.term.buffer.cursorY, window.term.buffer.cursorX]
[window.term.buffer.active.cursorY, window.term.buffer.active.cursorX]
`), [2, 3]);
await page.evaluate(`
window.term.onData(e => window.result = e);
Expand All @@ -251,7 +251,7 @@ describe('InputHandler Integration Tests', function(): void {
it('Report Cursor Position (DECXCPR) - CSI ? 6 n', async function(): Promise<any> {
await page.evaluate(`window.term.write('\\n\\nfoo')`);
await pollFor(page, () => page.evaluate(`
[window.term.buffer.cursorY, window.term.buffer.cursorX]
[window.term.buffer.active.cursorY, window.term.buffer.active.cursorX]
`), [2, 3]);
await page.evaluate(`
window.term.onData(e => window.result = e);
Expand Down Expand Up @@ -409,7 +409,7 @@ describe('InputHandler Integration Tests', function(): void {
async function getLinesAsArray(count: number, start: number = 0): Promise<string[]> {
let text = '';
for (let i = start; i < start + count; i++) {
text += `window.term.buffer.getLine(${i}).translateToString(true), `;
text += `window.term.buffer.active.getLine(${i}).translateToString(true),`;
}
return await page.evaluate(`[${text}]`);
}
Expand All @@ -429,10 +429,10 @@ async function simulatePaste(text: string): Promise<string> {

async function getCursor(): Promise<{ col: number, row: number }> {
return page.evaluate(`
(function() {
return { col: term.buffer.cursorX, row: term.buffer.cursorY };
})();
`);
(function() {
return {col: term.buffer.active.cursorX, row: term.buffer.active.cursorY};
})();
`);
}

async function getDimensions(): Promise<any> {
Expand Down
Loading