Merge remote-tracking branch 'ups/master' into 1994_buffer_api
This commit is contained in:
+8
-3
@@ -21,7 +21,12 @@ jobs:
|
|||||||
displayName: 'Install dependencies and build'
|
displayName: 'Install dependencies and build'
|
||||||
- script: |
|
- script: |
|
||||||
yarn mocha
|
yarn mocha
|
||||||
displayName: 'Test'
|
displayName: 'Unit tests'
|
||||||
|
- script: |
|
||||||
|
yarn start &
|
||||||
|
sleep 5
|
||||||
|
yarn test-api --headless
|
||||||
|
displayName: 'Integration tests'
|
||||||
- script: |
|
- script: |
|
||||||
yarn lint
|
yarn lint
|
||||||
displayName: 'Lint'
|
displayName: 'Lint'
|
||||||
@@ -39,7 +44,7 @@ jobs:
|
|||||||
displayName: 'Install dependencies and build'
|
displayName: 'Install dependencies and build'
|
||||||
- script: |
|
- script: |
|
||||||
yarn mocha
|
yarn mocha
|
||||||
displayName: 'Test'
|
displayName: 'Unit tests'
|
||||||
- script: |
|
- script: |
|
||||||
yarn lint
|
yarn lint
|
||||||
displayName: 'Lint'
|
displayName: 'Lint'
|
||||||
@@ -62,7 +67,7 @@ jobs:
|
|||||||
displayName: 'Install dependencies and build'
|
displayName: 'Install dependencies and build'
|
||||||
- script: |
|
- script: |
|
||||||
yarn mocha
|
yarn mocha
|
||||||
displayName: 'Test'
|
displayName: 'Unit tests'
|
||||||
- script: |
|
- script: |
|
||||||
yarn lint
|
yarn lint
|
||||||
displayName: 'Lint'
|
displayName: 'Lint'
|
||||||
|
|||||||
+2
-2
@@ -39,7 +39,7 @@ function getNextBetaVersion() {
|
|||||||
}
|
}
|
||||||
const tag = 'beta';
|
const tag = 'beta';
|
||||||
const stableVersion = packageJson.version.split('.');
|
const stableVersion = packageJson.version.split('.');
|
||||||
const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.${stableVersion[2]}`;
|
const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`;
|
||||||
const publishedVersions = getPublishedVersions(nextStableVersion, tag);
|
const publishedVersions = getPublishedVersions(nextStableVersion, tag);
|
||||||
if (publishedVersions.length === 0) {
|
if (publishedVersions.length === 0) {
|
||||||
return `${nextStableVersion}-${tag}1`;
|
return `${nextStableVersion}-${tag}1`;
|
||||||
@@ -54,7 +54,7 @@ function getNextBetaVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPublishedVersions(version, tag) {
|
function getPublishedVersions(version, tag) {
|
||||||
const versionsProcess = cp.spawnSync('npm', ['view', 'xterm', 'versions', '--json']);
|
const versionsProcess = cp.spawnSync('npm', ['view', packageJson.name, 'versions', '--json']);
|
||||||
const versionsJson = JSON.parse(versionsProcess.stdout);
|
const versionsJson = JSON.parse(versionsProcess.stdout);
|
||||||
if (tag) {
|
if (tag) {
|
||||||
return versionsJson.filter(v => !v.search(new RegExp(`${version}-${tag}[0-9]+`)));
|
return versionsJson.filter(v => !v.search(new RegExp(`${version}-${tag}[0-9]+`)));
|
||||||
|
|||||||
+7
-3
@@ -21,6 +21,7 @@ import { Terminal as TerminalType, ITerminalOptions } from 'xterm';
|
|||||||
|
|
||||||
export interface IWindowWithTerminal extends Window {
|
export interface IWindowWithTerminal extends Window {
|
||||||
term: TerminalType;
|
term: TerminalType;
|
||||||
|
Terminal?: typeof TerminalType;
|
||||||
}
|
}
|
||||||
declare let window: IWindowWithTerminal;
|
declare let window: IWindowWithTerminal;
|
||||||
|
|
||||||
@@ -57,8 +58,6 @@ function getSearchOptions(): ISearchOptions {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createTerminal();
|
|
||||||
|
|
||||||
const disposeRecreateButtonHandler = () => {
|
const disposeRecreateButtonHandler = () => {
|
||||||
// If the terminal exists dispose of it, otherwise recreate it
|
// If the terminal exists dispose of it, otherwise recreate it
|
||||||
if (term) {
|
if (term) {
|
||||||
@@ -74,7 +73,12 @@ const disposeRecreateButtonHandler = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler);
|
if (document.location.pathname === '/test') {
|
||||||
|
window.Terminal = Terminal;
|
||||||
|
} else {
|
||||||
|
createTerminal();
|
||||||
|
document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler);
|
||||||
|
}
|
||||||
|
|
||||||
function createTerminal(): void {
|
function createTerminal(): void {
|
||||||
// Clean terminal
|
// Clean terminal
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ function startServer() {
|
|||||||
res.sendFile(__dirname + '/index.html');
|
res.sendFile(__dirname + '/index.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/test', function(req, res){
|
||||||
|
res.sendFile(__dirname + '/test.html');
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/style.css', function(req, res){
|
app.get('/style.css', function(req, res){
|
||||||
res.sendFile(__dirname + '/style.css');
|
res.sendFile(__dirname + '/style.css');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>xterm.js integration test fixture</title>
|
||||||
|
<link rel="stylesheet" href="/src/xterm.css" />
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="terminal-container"></div>
|
||||||
|
<script src="dist/client-bundle.js" defer ></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -21,7 +21,7 @@ namespace constructor {
|
|||||||
'disableStdin': false,
|
'disableStdin': false,
|
||||||
'rows': 1,
|
'rows': 1,
|
||||||
'scrollback': 10,
|
'scrollback': 10,
|
||||||
'tabStopWidth': 2,
|
'tabStopWidth': 2
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,8 +119,8 @@ namespace methods_core {
|
|||||||
const t: Terminal = new Terminal();
|
const t: Terminal = new Terminal();
|
||||||
t.attachCustomKeyEventHandler((e: KeyboardEvent) => true);
|
t.attachCustomKeyEventHandler((e: KeyboardEvent) => true);
|
||||||
t.attachCustomKeyEventHandler((e: KeyboardEvent) => false);
|
t.attachCustomKeyEventHandler((e: KeyboardEvent) => false);
|
||||||
const d1: IDisposable = t.addCsiHandler("x",
|
const d1: IDisposable = t.addCsiHandler('x',
|
||||||
(params: number[], collect: string): boolean => params[0]===1);
|
(params: number[], collect: string): boolean => params[0] === 1);
|
||||||
d1.dispose();
|
d1.dispose();
|
||||||
const d2: IDisposable = t.addOscHandler(199,
|
const d2: IDisposable = t.addOscHandler(199,
|
||||||
(data: string): boolean => true);
|
(data: string): boolean => true);
|
||||||
@@ -155,6 +155,7 @@ namespace methods_core {
|
|||||||
const r25: string = t.getOption('fontWeightBold');
|
const r25: string = t.getOption('fontWeightBold');
|
||||||
const r26: boolean = t.getOption('allowTransparency');
|
const r26: boolean = t.getOption('allowTransparency');
|
||||||
const r27: boolean = t.getOption('rightClickSelectsWord');
|
const r27: boolean = t.getOption('rightClickSelectsWord');
|
||||||
|
const r28: boolean = t.getOption('windowsMode');
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const t: Terminal = new Terminal();
|
const t: Terminal = new Terminal();
|
||||||
@@ -177,6 +178,7 @@ namespace methods_core {
|
|||||||
t.setOption('useFlowControl', true);
|
t.setOption('useFlowControl', true);
|
||||||
t.setOption('allowTransparency', true);
|
t.setOption('allowTransparency', true);
|
||||||
t.setOption('visualBell', true);
|
t.setOption('visualBell', true);
|
||||||
|
t.setOption('windowsMode', true);
|
||||||
t.setOption('colors', ['a', 'b']);
|
t.setOption('colors', ['a', 'b']);
|
||||||
t.setOption('letterSpacing', 1);
|
t.setOption('letterSpacing', 1);
|
||||||
t.setOption('cols', 1);
|
t.setOption('cols', 1);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"@types/jsdom": "11.0.1",
|
"@types/jsdom": "11.0.1",
|
||||||
"@types/mocha": "^2.2.33",
|
"@types/mocha": "^2.2.33",
|
||||||
"@types/node": "6.0.108",
|
"@types/node": "6.0.108",
|
||||||
|
"@types/puppeteer": "^1.12.4",
|
||||||
"@types/webpack": "^4.4.11",
|
"@types/webpack": "^4.4.11",
|
||||||
"browserify": "^13.3.0",
|
"browserify": "^13.3.0",
|
||||||
"chai": "3.5.0",
|
"chai": "3.5.0",
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
"node-pty": "0.7.6",
|
"node-pty": "0.7.6",
|
||||||
"nodemon": "1.10.2",
|
"nodemon": "1.10.2",
|
||||||
"nyc": "^11.8.0",
|
"nyc": "^11.8.0",
|
||||||
|
"puppeteer": "^1.15.0",
|
||||||
"sorcery": "^0.10.0",
|
"sorcery": "^0.10.0",
|
||||||
"source-map-loader": "^0.2.4",
|
"source-map-loader": "^0.2.4",
|
||||||
"ts-loader": "^4.5.0",
|
"ts-loader": "^4.5.0",
|
||||||
@@ -54,6 +56,7 @@
|
|||||||
"test-debug": "node --inspect-brk node_modules/.bin/gulp test",
|
"test-debug": "node --inspect-brk node_modules/.bin/gulp test",
|
||||||
"test-suite": "gulp mocha-suite --test",
|
"test-suite": "gulp mocha-suite --test",
|
||||||
"test-coverage": "nyc -x gulpfile.js -x '**/*test*' npm run mocha",
|
"test-coverage": "nyc -x gulpfile.js -x '**/*test*' npm run mocha",
|
||||||
|
"test-api": "mocha \"**/*.api.js\"",
|
||||||
"mocha": "gulp test",
|
"mocha": "gulp test",
|
||||||
"prebuild": "tsc -b ./src/tsconfig.all.json",
|
"prebuild": "tsc -b ./src/tsconfig.all.json",
|
||||||
"build": "gulp build",
|
"build": "gulp build",
|
||||||
|
|||||||
+2
-2
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
import { assert, expect } from 'chai';
|
import { assert, expect } from 'chai';
|
||||||
import { ITerminal } from './Types';
|
import { ITerminal } from './Types';
|
||||||
import { Buffer, DEFAULT_ATTR_DATA } from './Buffer';
|
import { Buffer } from './Buffer';
|
||||||
import { CircularList } from './common/CircularList';
|
import { CircularList } from './common/CircularList';
|
||||||
import { MockTerminal, TestTerminal } from './TestUtils.test';
|
import { MockTerminal, TestTerminal } from './TestUtils.test';
|
||||||
import { BufferLine, CellData } from './BufferLine';
|
import { BufferLine, CellData, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
const INIT_COLS = 80;
|
const INIT_COLS = 80;
|
||||||
const INIT_ROWS = 24;
|
const INIT_ROWS = 24;
|
||||||
|
|||||||
+4
-30
@@ -4,42 +4,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CircularList, IInsertEvent } from './common/CircularList';
|
import { CircularList, IInsertEvent } from './common/CircularList';
|
||||||
import { ITerminal, IBuffer, IBufferLine, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult, ICellData, IAttributeData } from './Types';
|
import { ITerminal, IBuffer, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from './Types';
|
||||||
|
import { IBufferLine, ICellData, IAttributeData } from './core/Types';
|
||||||
import { IMarker } from 'xterm';
|
import { IMarker } from 'xterm';
|
||||||
import { BufferLine, CellData, AttributeData } from './BufferLine';
|
import { BufferLine, CellData, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||||
import { reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths, getWrappedLineTrimmedLength } from './BufferReflow';
|
import { reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths, getWrappedLineTrimmedLength } from './BufferReflow';
|
||||||
import { DEFAULT_COLOR } from './renderer/atlas/Types';
|
|
||||||
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
||||||
import { Disposable } from '../lib/common/Lifecycle';
|
import { Disposable } from './common/Lifecycle';
|
||||||
|
|
||||||
export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
|
|
||||||
|
|
||||||
export const DEFAULT_ATTR_DATA = new AttributeData();
|
|
||||||
|
|
||||||
export const CHAR_DATA_ATTR_INDEX = 0;
|
|
||||||
export const CHAR_DATA_CHAR_INDEX = 1;
|
|
||||||
export const CHAR_DATA_WIDTH_INDEX = 2;
|
|
||||||
export const CHAR_DATA_CODE_INDEX = 3;
|
|
||||||
export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
|
export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
|
||||||
|
|
||||||
/**
|
|
||||||
* Null cell - a real empty cell (containing nothing).
|
|
||||||
* Note that code should always be 0 for a null cell as
|
|
||||||
* several test condition of the buffer line rely on this.
|
|
||||||
*/
|
|
||||||
export const NULL_CELL_CHAR = '';
|
|
||||||
export const NULL_CELL_WIDTH = 1;
|
|
||||||
export const NULL_CELL_CODE = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whitespace cell.
|
|
||||||
* This is meant as a replacement for empty cells when needed
|
|
||||||
* during rendering lines to preserve correct aligment.
|
|
||||||
*/
|
|
||||||
export const WHITESPACE_CELL_CHAR = ' ';
|
|
||||||
export const WHITESPACE_CELL_WIDTH = 1;
|
|
||||||
export const WHITESPACE_CELL_CODE = 32;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a terminal buffer (an internal state of the terminal), where the
|
* This class represents a terminal buffer (an internal state of the terminal), where the
|
||||||
* following information is stored (in high-level):
|
* following information is stored (in high-level):
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { BufferLine } from './BufferLine';
|
import { BufferLine, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './core/buffer/BufferLine';
|
||||||
import { reflowSmallerGetNewLineLengths } from './BufferReflow';
|
import { reflowSmallerGetNewLineLengths } from './BufferReflow';
|
||||||
import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Buffer';
|
|
||||||
|
|
||||||
describe('BufferReflow', () => {
|
describe('BufferReflow', () => {
|
||||||
describe('reflowSmallerGetNewLineLengths', () => {
|
describe('reflowSmallerGetNewLineLengths', () => {
|
||||||
|
|||||||
+2
-2
@@ -3,9 +3,9 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BufferLine } from './BufferLine';
|
import { BufferLine } from './core/buffer/BufferLine';
|
||||||
import { CircularList } from './common/CircularList';
|
import { CircularList } from './common/CircularList';
|
||||||
import { IBufferLine, ICellData } from './Types';
|
import { IBufferLine, ICellData } from './core/Types';
|
||||||
|
|
||||||
export interface INewLayoutResult {
|
export interface INewLayoutResult {
|
||||||
layout: number[];
|
layout: number[];
|
||||||
|
|||||||
+2
-1
@@ -3,7 +3,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ITerminal, IBufferSet, IAttributeData, IBuffer } from './Types';
|
import { ITerminal, IBufferSet, IBuffer } from './Types';
|
||||||
|
import { IAttributeData } from './core/Types';
|
||||||
import { Buffer } from './Buffer';
|
import { Buffer } from './Buffer';
|
||||||
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import { TestTerminal } from './TestUtils.test';
|
|||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { getStringCellWidth, wcwidth } from './CharWidth';
|
import { getStringCellWidth, wcwidth } from './CharWidth';
|
||||||
import { IBuffer } from './Types';
|
import { IBuffer } from './Types';
|
||||||
import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from './Buffer';
|
import { CellData, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from './core/buffer/BufferLine';
|
||||||
import { CellData } from './BufferLine';
|
|
||||||
|
|
||||||
|
|
||||||
describe('getStringCellWidth', function(): void {
|
describe('getStringCellWidth', function(): void {
|
||||||
|
|||||||
@@ -6,10 +6,9 @@
|
|||||||
import { assert, expect } from 'chai';
|
import { assert, expect } from 'chai';
|
||||||
import { InputHandler } from './InputHandler';
|
import { InputHandler } from './InputHandler';
|
||||||
import { MockInputHandlingTerminal, TestTerminal } from './TestUtils.test';
|
import { MockInputHandlingTerminal, TestTerminal } from './TestUtils.test';
|
||||||
import { DEFAULT_ATTR_DATA } from './Buffer';
|
|
||||||
import { Terminal } from './Terminal';
|
import { Terminal } from './Terminal';
|
||||||
import { IBufferLine } from './Types';
|
import { IBufferLine } from './core/Types';
|
||||||
import { CellData, Attributes, AttributeData } from './BufferLine';
|
import { CellData, Attributes, AttributeData, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
describe('InputHandler', () => {
|
describe('InputHandler', () => {
|
||||||
describe('save and restore cursor', () => {
|
describe('save and restore cursor', () => {
|
||||||
|
|||||||
+1
-2
@@ -7,14 +7,13 @@
|
|||||||
import { IInputHandler, IDcsHandler, IEscapeSequenceParser, IInputHandlingTerminal } from './Types';
|
import { IInputHandler, IDcsHandler, IEscapeSequenceParser, IInputHandlingTerminal } from './Types';
|
||||||
import { C0, C1 } from './common/data/EscapeSequences';
|
import { C0, C1 } from './common/data/EscapeSequences';
|
||||||
import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets';
|
import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets';
|
||||||
import { NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR_DATA } from './Buffer';
|
|
||||||
import { wcwidth } from './CharWidth';
|
import { wcwidth } from './CharWidth';
|
||||||
import { EscapeSequenceParser } from './EscapeSequenceParser';
|
import { EscapeSequenceParser } from './EscapeSequenceParser';
|
||||||
import { IDisposable } from 'xterm';
|
import { IDisposable } from 'xterm';
|
||||||
import { Disposable } from './common/Lifecycle';
|
import { Disposable } from './common/Lifecycle';
|
||||||
import { concat } from './common/TypedArrayUtils';
|
import { concat } from './common/TypedArrayUtils';
|
||||||
import { StringToUtf32, stringFromCodePoint, utf32ToString } from './core/input/TextDecoder';
|
import { StringToUtf32, stringFromCodePoint, utf32ToString } from './core/input/TextDecoder';
|
||||||
import { CellData, Attributes, FgFlags, BgFlags, AttributeData } from './BufferLine';
|
import { CellData, Attributes, FgFlags, BgFlags, AttributeData, NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||||
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,11 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { IMouseZoneManager, IMouseZone, ILinkMatcher, ITerminal, IBufferLine } from './Types';
|
import { IMouseZoneManager, IMouseZone, ILinkMatcher, ITerminal } from './Types';
|
||||||
|
import { IBufferLine } from './core/Types';
|
||||||
import { Linkifier } from './Linkifier';
|
import { Linkifier } from './Linkifier';
|
||||||
import { MockBuffer, MockTerminal, TestTerminal } from './TestUtils.test';
|
import { MockBuffer, MockTerminal, TestTerminal } from './TestUtils.test';
|
||||||
import { CircularList } from './common/CircularList';
|
import { CircularList } from './common/CircularList';
|
||||||
import { BufferLine, CellData } from './BufferLine';
|
import { BufferLine, CellData } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
class TestLinkifier extends Linkifier {
|
class TestLinkifier extends Linkifier {
|
||||||
constructor(terminal: ITerminal) {
|
constructor(terminal: ITerminal) {
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import { CharMeasure } from './CharMeasure';
|
|||||||
import { SelectionManager, SelectionMode } from './SelectionManager';
|
import { SelectionManager, SelectionMode } from './SelectionManager';
|
||||||
import { SelectionModel } from './SelectionModel';
|
import { SelectionModel } from './SelectionModel';
|
||||||
import { BufferSet } from './BufferSet';
|
import { BufferSet } from './BufferSet';
|
||||||
import { ITerminal, IBuffer, IBufferLine } from './Types';
|
import { ITerminal, IBuffer } from './Types';
|
||||||
|
import { IBufferLine } from './core/Types';
|
||||||
import { MockTerminal } from './TestUtils.test';
|
import { MockTerminal } from './TestUtils.test';
|
||||||
import { BufferLine, CellData } from './BufferLine';
|
import { BufferLine, CellData } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
class TestMockTerminal extends MockTerminal {
|
class TestMockTerminal extends MockTerminal {
|
||||||
emit(event: string, data: any): void {}
|
emit(event: string, data: any): void {}
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ITerminal, ISelectionManager, IBuffer, IBufferLine, ISelectionRedrawRequestEvent } from './Types';
|
import { ITerminal, ISelectionManager, IBuffer, ISelectionRedrawRequestEvent } from './Types';
|
||||||
|
import { IBufferLine } from './core/Types';
|
||||||
import { MouseHelper } from './MouseHelper';
|
import { MouseHelper } from './MouseHelper';
|
||||||
import * as Browser from './common/Platform';
|
import * as Browser from './common/Platform';
|
||||||
import { CharMeasure } from './CharMeasure';
|
import { CharMeasure } from './CharMeasure';
|
||||||
import { SelectionModel } from './SelectionModel';
|
import { SelectionModel } from './SelectionModel';
|
||||||
import { AltClickHandler } from './handlers/AltClickHandler';
|
import { AltClickHandler } from './handlers/AltClickHandler';
|
||||||
import { CellData } from './BufferLine';
|
import { CellData } from './core/buffer/BufferLine';
|
||||||
import { IDisposable } from 'xterm';
|
import { IDisposable } from 'xterm';
|
||||||
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
||||||
|
|
||||||
@@ -245,6 +246,7 @@ export class SelectionManager implements ISelectionManager {
|
|||||||
this._model.clearSelection();
|
this._model.clearSelection();
|
||||||
this._removeMouseDownListeners();
|
this._removeMouseDownListeners();
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
this._onSelectionChange.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import * as pty from 'node-pty';
|
|||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { Terminal } from './Terminal';
|
import { Terminal } from './Terminal';
|
||||||
import { Terminal as PublicTerminal } from './public/Terminal';
|
import { Terminal as PublicTerminal } from './public/Terminal';
|
||||||
import { WHITESPACE_CELL_CHAR } from './Buffer';
|
|
||||||
import { IViewport } from './Types';
|
import { IViewport } from './Types';
|
||||||
import { CellData } from './BufferLine';
|
import { CellData, WHITESPACE_CELL_CHAR } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
class TestTerminal extends Terminal {
|
class TestTerminal extends Terminal {
|
||||||
innerWrite(): void { this._innerWrite(); }
|
innerWrite(): void { this._innerWrite(); }
|
||||||
@@ -79,35 +78,6 @@ function terminalToString(term: Terminal): string {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('API tests', () => {
|
|
||||||
let api: PublicTerminal;
|
|
||||||
let core: TestTerminal;
|
|
||||||
|
|
||||||
// expect files need terminal at 80x25!
|
|
||||||
const INIT_COLS = 80;
|
|
||||||
const INIT_ROWS = 25;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
api = new PublicTerminal({ cols: INIT_COLS, rows: INIT_ROWS });
|
|
||||||
core = (api as any)._core;
|
|
||||||
core.innerWrite = () => (core as any)._innerWrite();
|
|
||||||
core.refresh = () => {};
|
|
||||||
core.viewport = <IViewport>{
|
|
||||||
syncScrollArea: () => {}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('buffer', () => {
|
|
||||||
it('IBufferLine.getLine', () => {
|
|
||||||
core.writeBuffer.push('abc\n\rdef');
|
|
||||||
core.innerWrite();
|
|
||||||
assert.equal(api.buffer.length, INIT_ROWS);
|
|
||||||
assert.equal(api.buffer.getLine(0).translateToString(true), 'abc');
|
|
||||||
assert.equal(api.buffer.getLine(1).translateToString(true), 'def');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Skip tests on Windows since pty.open isn't supported
|
// Skip tests on Windows since pty.open isn't supported
|
||||||
if (os.platform() !== 'win32') {
|
if (os.platform() !== 'win32') {
|
||||||
const consoleLog = console.log;
|
const consoleLog = console.log;
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
import { assert, expect } from 'chai';
|
import { assert, expect } from 'chai';
|
||||||
import { Terminal } from './Terminal';
|
import { Terminal } from './Terminal';
|
||||||
import { MockViewport, MockCompositionHelper, MockRenderer } from './TestUtils.test';
|
import { MockViewport, MockCompositionHelper, MockRenderer } from './TestUtils.test';
|
||||||
import { DEFAULT_ATTR_DATA } from './Buffer';
|
import { CellData, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||||
import { CellData } from './BufferLine';
|
|
||||||
|
|
||||||
const INIT_COLS = 80;
|
const INIT_COLS = 80;
|
||||||
const INIT_ROWS = 24;
|
const INIT_ROWS = 24;
|
||||||
|
|||||||
+4
-4
@@ -21,10 +21,10 @@
|
|||||||
* http://linux.die.net/man/7/urxvt
|
* http://linux.die.net/man/7/urxvt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharacterJoinerHandler, IBufferLine, IAttributeData, IMouseZoneManager } from './Types';
|
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharacterJoinerHandler, IMouseZoneManager } from './Types';
|
||||||
import { IRenderer } from './renderer/Types';
|
import { IRenderer } from './renderer/Types';
|
||||||
import { BufferSet } from './BufferSet';
|
import { BufferSet } from './BufferSet';
|
||||||
import { Buffer, MAX_BUFFER_SIZE, DEFAULT_ATTR_DATA } from './Buffer';
|
import { Buffer, MAX_BUFFER_SIZE } from './Buffer';
|
||||||
import { CompositionHelper } from './CompositionHelper';
|
import { CompositionHelper } from './CompositionHelper';
|
||||||
import { EventEmitter } from './common/EventEmitter';
|
import { EventEmitter } from './common/EventEmitter';
|
||||||
import { Viewport } from './Viewport';
|
import { Viewport } from './Viewport';
|
||||||
@@ -48,10 +48,10 @@ import { removeTerminalFromCache } from './renderer/atlas/CharAtlasCache';
|
|||||||
import { DomRenderer } from './renderer/dom/DomRenderer';
|
import { DomRenderer } from './renderer/dom/DomRenderer';
|
||||||
import { IKeyboardEvent } from './common/Types';
|
import { IKeyboardEvent } from './common/Types';
|
||||||
import { evaluateKeyboardEvent } from './core/input/Keyboard';
|
import { evaluateKeyboardEvent } from './core/input/Keyboard';
|
||||||
import { KeyboardResultType, ICharset } from './core/Types';
|
import { KeyboardResultType, ICharset, IBufferLine, IAttributeData } from './core/Types';
|
||||||
import { clone } from './common/Clone';
|
import { clone } from './common/Clone';
|
||||||
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
import { EventEmitter2, IEvent } from './common/EventEmitter2';
|
||||||
import { Attributes } from './BufferLine';
|
import { Attributes, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine';
|
||||||
import { applyWindowsMode } from './WindowsMode';
|
import { applyWindowsMode } from './WindowsMode';
|
||||||
|
|
||||||
// Let it work inside Node.js for automated testing purposes.
|
// Let it work inside Node.js for automated testing purposes.
|
||||||
|
|||||||
@@ -4,13 +4,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IColorSet, IRenderer, IRenderDimensions, IColorManager } from './renderer/Types';
|
import { IColorSet, IRenderer, IRenderDimensions, IColorManager } from './renderer/Types';
|
||||||
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuffer, IBufferSet, IBrowser, ICharMeasure, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions, CharacterJoinerHandler, IBufferLine, IBufferStringIterator, ICellData, IAttributeData } from './Types';
|
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuffer, IBufferSet, IBrowser, ICharMeasure, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions, CharacterJoinerHandler, IBufferStringIterator } from './Types';
|
||||||
|
import { IBufferLine, ICellData, IAttributeData } from './core/Types';
|
||||||
import { ICircularList, XtermListener } from './common/Types';
|
import { ICircularList, XtermListener } from './common/Types';
|
||||||
import { Buffer } from './Buffer';
|
import { Buffer } from './Buffer';
|
||||||
import * as Browser from './common/Platform';
|
import * as Browser from './common/Platform';
|
||||||
import { ITheme, IDisposable, IMarker, IEvent } from 'xterm';
|
import { ITheme, IDisposable, IMarker, IEvent } from 'xterm';
|
||||||
import { Terminal } from './Terminal';
|
import { Terminal } from './Terminal';
|
||||||
import { AttributeData } from './BufferLine';
|
import { AttributeData } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
export class TestTerminal extends Terminal {
|
export class TestTerminal extends Terminal {
|
||||||
writeSync(data: string): void {
|
writeSync(data: string): void {
|
||||||
|
|||||||
+1
-81
@@ -5,13 +5,12 @@
|
|||||||
|
|
||||||
import { ITerminalOptions as IPublicTerminalOptions, IEventEmitter, IDisposable, IMarker } from 'xterm';
|
import { ITerminalOptions as IPublicTerminalOptions, IEventEmitter, IDisposable, IMarker } from 'xterm';
|
||||||
import { IColorSet, IRenderer } from './renderer/Types';
|
import { IColorSet, IRenderer } from './renderer/Types';
|
||||||
import { ICharset } from './core/Types';
|
import { ICharset, IAttributeData, ICellData, IBufferLine, CharData } from './core/Types';
|
||||||
import { ICircularList } from './common/Types';
|
import { ICircularList } from './common/Types';
|
||||||
import { IEvent } from './common/EventEmitter2';
|
import { IEvent } from './common/EventEmitter2';
|
||||||
|
|
||||||
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
|
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
|
||||||
|
|
||||||
export type CharData = [number, string, number, number];
|
|
||||||
export type LineData = CharData[];
|
export type LineData = CharData[];
|
||||||
|
|
||||||
export type LinkMatcherHandler = (event: MouseEvent, uri: string) => void;
|
export type LinkMatcherHandler = (event: MouseEvent, uri: string) => void;
|
||||||
@@ -573,85 +572,6 @@ export interface IEscapeSequenceParser extends IDisposable {
|
|||||||
clearErrorHandler(): void;
|
clearErrorHandler(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** RGB color type */
|
|
||||||
export type IColorRGB = [number, number, number];
|
|
||||||
|
|
||||||
/** Attribute data */
|
|
||||||
export interface IAttributeData {
|
|
||||||
fg: number;
|
|
||||||
bg: number;
|
|
||||||
|
|
||||||
clone(): IAttributeData;
|
|
||||||
|
|
||||||
// flags
|
|
||||||
isInverse(): number;
|
|
||||||
isBold(): number;
|
|
||||||
isUnderline(): number;
|
|
||||||
isBlink(): number;
|
|
||||||
isInvisible(): number;
|
|
||||||
isItalic(): number;
|
|
||||||
isDim(): number;
|
|
||||||
|
|
||||||
// color modes
|
|
||||||
getFgColorMode(): number;
|
|
||||||
getBgColorMode(): number;
|
|
||||||
isFgRGB(): boolean;
|
|
||||||
isBgRGB(): boolean;
|
|
||||||
isFgPalette(): boolean;
|
|
||||||
isBgPalette(): boolean;
|
|
||||||
isFgDefault(): boolean;
|
|
||||||
isBgDefault(): boolean;
|
|
||||||
|
|
||||||
// colors
|
|
||||||
getFgColor(): number;
|
|
||||||
getBgColor(): number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Cell data */
|
|
||||||
export interface ICellData extends IAttributeData {
|
|
||||||
content: number;
|
|
||||||
combinedData: string;
|
|
||||||
isCombined(): number;
|
|
||||||
getWidth(): number;
|
|
||||||
getChars(): string;
|
|
||||||
getCode(): number;
|
|
||||||
setFromCharData(value: CharData): void;
|
|
||||||
getAsCharData(): CharData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for a line in the terminal buffer.
|
|
||||||
*/
|
|
||||||
export interface IBufferLine {
|
|
||||||
length: number;
|
|
||||||
isWrapped: boolean;
|
|
||||||
get(index: number): CharData;
|
|
||||||
set(index: number, value: CharData): void;
|
|
||||||
loadCell(index: number, cell: ICellData): ICellData;
|
|
||||||
setCell(index: number, cell: ICellData): void;
|
|
||||||
setCellFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number): void;
|
|
||||||
addCodepointToCell(index: number, codePoint: number): void;
|
|
||||||
insertCells(pos: number, n: number, ch: ICellData): void;
|
|
||||||
deleteCells(pos: number, n: number, fill: ICellData): void;
|
|
||||||
replaceCells(start: number, end: number, fill: ICellData): void;
|
|
||||||
resize(cols: number, fill: ICellData): void;
|
|
||||||
fill(fillCellData: ICellData): void;
|
|
||||||
copyFrom(line: IBufferLine): void;
|
|
||||||
clone(): IBufferLine;
|
|
||||||
getTrimmedLength(): number;
|
|
||||||
translateToString(trimRight?: boolean, startCol?: number, endCol?: number): string;
|
|
||||||
|
|
||||||
/* direct access to cell attrs */
|
|
||||||
getWidth(index: number): number;
|
|
||||||
hasWidth(index: number): number;
|
|
||||||
getFg(index: number): number;
|
|
||||||
getBg(index: number): number;
|
|
||||||
hasContent(index: number): number;
|
|
||||||
getCodePoint(index: number): number;
|
|
||||||
isCombined(index: number): number;
|
|
||||||
getString(index: number): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMouseZoneManager extends IDisposable {
|
export interface IMouseZoneManager extends IDisposable {
|
||||||
add(zone: IMouseZone): void;
|
add(zone: IMouseZone): void;
|
||||||
clearAll(start?: number, end?: number): void;
|
clearAll(start?: number, end?: number): void;
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { IDisposable } from 'xterm';
|
import { IDisposable } from 'xterm';
|
||||||
import { ITerminal } from './Types';
|
import { ITerminal } from './Types';
|
||||||
import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CODE } from './Buffer';
|
import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CODE } from './core/buffer/BufferLine';
|
||||||
|
|
||||||
export function applyWindowsMode(terminal: ITerminal): IDisposable {
|
export function applyWindowsMode(terminal: ITerminal): IDisposable {
|
||||||
// Winpty does not support wraparound mode which means that lines will never
|
// Winpty does not support wraparound mode which means that lines will never
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
import { IEvent, EventEmitter2 } from './EventEmitter2';
|
import { IEvent, EventEmitter2 } from './EventEmitter2';
|
||||||
import { IDeleteEvent, IInsertEvent } from './CircularList';
|
import { IDeleteEvent, IInsertEvent } from './CircularList';
|
||||||
|
|
||||||
|
export const DEFAULT_COLOR = 256;
|
||||||
|
|
||||||
export interface IDisposable {
|
export interface IDisposable {
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,3 +19,82 @@ export interface IKeyboardResult {
|
|||||||
export interface ICharset {
|
export interface ICharset {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CharData = [number, string, number, number];
|
||||||
|
export type IColorRGB = [number, number, number];
|
||||||
|
|
||||||
|
/** Attribute data */
|
||||||
|
export interface IAttributeData {
|
||||||
|
fg: number;
|
||||||
|
bg: number;
|
||||||
|
|
||||||
|
clone(): IAttributeData;
|
||||||
|
|
||||||
|
// flags
|
||||||
|
isInverse(): number;
|
||||||
|
isBold(): number;
|
||||||
|
isUnderline(): number;
|
||||||
|
isBlink(): number;
|
||||||
|
isInvisible(): number;
|
||||||
|
isItalic(): number;
|
||||||
|
isDim(): number;
|
||||||
|
|
||||||
|
// color modes
|
||||||
|
getFgColorMode(): number;
|
||||||
|
getBgColorMode(): number;
|
||||||
|
isFgRGB(): boolean;
|
||||||
|
isBgRGB(): boolean;
|
||||||
|
isFgPalette(): boolean;
|
||||||
|
isBgPalette(): boolean;
|
||||||
|
isFgDefault(): boolean;
|
||||||
|
isBgDefault(): boolean;
|
||||||
|
|
||||||
|
// colors
|
||||||
|
getFgColor(): number;
|
||||||
|
getBgColor(): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cell data */
|
||||||
|
export interface ICellData extends IAttributeData {
|
||||||
|
content: number;
|
||||||
|
combinedData: string;
|
||||||
|
isCombined(): number;
|
||||||
|
getWidth(): number;
|
||||||
|
getChars(): string;
|
||||||
|
getCode(): number;
|
||||||
|
setFromCharData(value: CharData): void;
|
||||||
|
getAsCharData(): CharData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a line in the terminal buffer.
|
||||||
|
*/
|
||||||
|
export interface IBufferLine {
|
||||||
|
length: number;
|
||||||
|
isWrapped: boolean;
|
||||||
|
get(index: number): CharData;
|
||||||
|
set(index: number, value: CharData): void;
|
||||||
|
loadCell(index: number, cell: ICellData): ICellData;
|
||||||
|
setCell(index: number, cell: ICellData): void;
|
||||||
|
setCellFromCodePoint(index: number, codePoint: number, width: number, fg: number, bg: number): void;
|
||||||
|
addCodepointToCell(index: number, codePoint: number): void;
|
||||||
|
insertCells(pos: number, n: number, ch: ICellData): void;
|
||||||
|
deleteCells(pos: number, n: number, fill: ICellData): void;
|
||||||
|
replaceCells(start: number, end: number, fill: ICellData): void;
|
||||||
|
resize(cols: number, fill: ICellData): void;
|
||||||
|
fill(fillCellData: ICellData): void;
|
||||||
|
copyFrom(line: IBufferLine): void;
|
||||||
|
clone(): IBufferLine;
|
||||||
|
getTrimmedLength(): number;
|
||||||
|
translateToString(trimRight?: boolean, startCol?: number, endCol?: number): string;
|
||||||
|
|
||||||
|
/* direct access to cell attrs */
|
||||||
|
getWidth(index: number): number;
|
||||||
|
hasWidth(index: number): number;
|
||||||
|
getFg(index: number): number;
|
||||||
|
getBg(index: number): number;
|
||||||
|
hasContent(index: number): number;
|
||||||
|
getCodePoint(index: number): number;
|
||||||
|
isCombined(index: number): number;
|
||||||
|
getString(index: number): string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import { BufferLine, CellData, Content } from './BufferLine';
|
import { BufferLine, CellData, Content, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR } from './BufferLine';
|
||||||
import { CharData, IBufferLine } from './Types';
|
import { CharData, IBufferLine } from '../Types';
|
||||||
import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR } from './Buffer';
|
|
||||||
|
|
||||||
|
|
||||||
class TestBufferLine extends BufferLine {
|
class TestBufferLine extends BufferLine {
|
||||||
public get combined(): {[index: number]: string} {
|
public get combined(): {[index: number]: string} {
|
||||||
@@ -57,7 +55,7 @@ describe('BufferLine', function(): void {
|
|||||||
chai.expect(line.length).equals(10);
|
chai.expect(line.length).equals(10);
|
||||||
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
||||||
chai.expect(line.isWrapped).equals(false);
|
chai.expect(line.isWrapped).equals(false);
|
||||||
line = new TestBufferLine(10, null, true);
|
line = new TestBufferLine(10, undefined, true);
|
||||||
chai.expect(line.length).equals(10);
|
chai.expect(line.length).equals(10);
|
||||||
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
||||||
chai.expect(line.isWrapped).equals(true);
|
chai.expect(line.isWrapped).equals(true);
|
||||||
@@ -127,7 +125,7 @@ describe('BufferLine', function(): void {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('clone', function(): void {
|
it('clone', function(): void {
|
||||||
const line = new TestBufferLine(5, null, true);
|
const line = new TestBufferLine(5, undefined, true);
|
||||||
line.setCell(0, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
line.setCell(0, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
line.setCell(1, CellData.fromCharData([2, 'b', 0, 'b'.charCodeAt(0)]));
|
line.setCell(1, CellData.fromCharData([2, 'b', 0, 'b'.charCodeAt(0)]));
|
||||||
line.setCell(2, CellData.fromCharData([3, 'c', 0, 'c'.charCodeAt(0)]));
|
line.setCell(2, CellData.fromCharData([3, 'c', 0, 'c'.charCodeAt(0)]));
|
||||||
@@ -167,27 +165,27 @@ describe('BufferLine', function(): void {
|
|||||||
it('enlarge(false)', function(): void {
|
it('enlarge(false)', function(): void {
|
||||||
const line = new TestBufferLine(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
const line = new TestBufferLine(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
||||||
line.resize(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
line.resize(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
chai.expect(line.toArray()).eql((Array(10) as any).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
});
|
});
|
||||||
it('enlarge(true)', function(): void {
|
it('enlarge(true)', function(): void {
|
||||||
const line = new TestBufferLine(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
const line = new TestBufferLine(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
||||||
line.resize(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
line.resize(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
chai.expect(line.toArray()).eql((Array(10) as any).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
});
|
});
|
||||||
it('shrink(true) - should apply new size', function(): void {
|
it('shrink(true) - should apply new size', function(): void {
|
||||||
const line = new TestBufferLine(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
const line = new TestBufferLine(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
||||||
line.resize(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
line.resize(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
chai.expect(line.toArray()).eql(Array(5).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
chai.expect(line.toArray()).eql((Array(5) as any).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
});
|
});
|
||||||
it('shrink to 0 length', function(): void {
|
it('shrink to 0 length', function(): void {
|
||||||
const line = new TestBufferLine(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
const line = new TestBufferLine(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
||||||
line.resize(0, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
line.resize(0, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
chai.expect(line.toArray()).eql(Array(0).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
chai.expect(line.toArray()).eql((Array(0) as any).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
});
|
});
|
||||||
it('should remove combining data on replaced cells after shrinking then enlarging', () => {
|
it('should remove combining data on replaced cells after shrinking then enlarging', () => {
|
||||||
const line = new TestBufferLine(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
const line = new TestBufferLine(10, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]), false);
|
||||||
line.set(2, [ null, '😁', 1, '😁'.charCodeAt(0) ]);
|
line.set(2, [ 0, '😁', 1, '😁'.charCodeAt(0) ]);
|
||||||
line.set(9, [ null, '😁', 1, '😁'.charCodeAt(0) ]);
|
line.set(9, [ 0, '😁', 1, '😁'.charCodeAt(0) ]);
|
||||||
chai.expect(line.translateToString()).eql('aa😁aaaaaa😁');
|
chai.expect(line.translateToString()).eql('aa😁aaaaaa😁');
|
||||||
chai.expect(Object.keys(line.combined).length).eql(2);
|
chai.expect(Object.keys(line.combined).length).eql(2);
|
||||||
line.resize(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
line.resize(5, CellData.fromCharData([1, 'a', 0, 'a'.charCodeAt(0)]));
|
||||||
@@ -224,7 +222,7 @@ describe('BufferLine', function(): void {
|
|||||||
const line = new TestBufferLine(10, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]), false);
|
const line = new TestBufferLine(10, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]), false);
|
||||||
line.setCell(0, CellData.fromCharData([1, 'a', 1, 'a'.charCodeAt(0)]));
|
line.setCell(0, CellData.fromCharData([1, 'a', 1, 'a'.charCodeAt(0)]));
|
||||||
line.setCell(2, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
line.setCell(2, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
||||||
line.setCell(3, CellData.fromCharData([0, '', 0, undefined]));
|
line.setCell(3, CellData.fromCharData([0, '', 0, 0]));
|
||||||
chai.expect(line.getTrimmedLength()).equal(4); // also counts null cell after fullwidth
|
chai.expect(line.getTrimmedLength()).equal(4); // also counts null cell after fullwidth
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -284,11 +282,11 @@ describe('BufferLine', function(): void {
|
|||||||
const line = new TestBufferLine(10, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]), false);
|
const line = new TestBufferLine(10, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]), false);
|
||||||
line.setCell(0, CellData.fromCharData([1, 'a', 1, 'a'.charCodeAt(0)]));
|
line.setCell(0, CellData.fromCharData([1, 'a', 1, 'a'.charCodeAt(0)]));
|
||||||
line.setCell(2, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
line.setCell(2, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
||||||
line.setCell(3, CellData.fromCharData([0, '', 0, undefined]));
|
line.setCell(3, CellData.fromCharData([0, '', 0, 0]));
|
||||||
line.setCell(5, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
line.setCell(5, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
||||||
line.setCell(6, CellData.fromCharData([0, '', 0, undefined]));
|
line.setCell(6, CellData.fromCharData([0, '', 0, 0]));
|
||||||
line.setCell(7, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
line.setCell(7, CellData.fromCharData([1, '1', 2, '1'.charCodeAt(0)]));
|
||||||
line.setCell(8, CellData.fromCharData([0, '', 0, undefined]));
|
line.setCell(8, CellData.fromCharData([0, '', 0, 0]));
|
||||||
chai.expect(line.translateToString(false)).equal('a 1 11 ');
|
chai.expect(line.translateToString(false)).equal('a 1 11 ');
|
||||||
chai.expect(line.translateToString(true)).equal('a 1 11');
|
chai.expect(line.translateToString(true)).equal('a 1 11');
|
||||||
chai.expect(line.translateToString(false, 0, 7)).equal('a 1 1');
|
chai.expect(line.translateToString(false, 0, 7)).equal('a 1 1');
|
||||||
@@ -2,10 +2,34 @@
|
|||||||
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
import { CharData, IBufferLine, ICellData, IColorRGB, IAttributeData } from './Types';
|
import { CharData, IBufferLine, ICellData, IColorRGB, IAttributeData } from '../Types';
|
||||||
import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, WHITESPACE_CELL_CHAR, CHAR_DATA_ATTR_INDEX } from './Buffer';
|
import { stringFromCodePoint } from '../input/TextDecoder';
|
||||||
import { stringFromCodePoint } from './core/input/TextDecoder';
|
import { DEFAULT_COLOR } from '../../common/Types';
|
||||||
|
|
||||||
|
export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
|
||||||
|
|
||||||
|
export const CHAR_DATA_ATTR_INDEX = 0;
|
||||||
|
export const CHAR_DATA_CHAR_INDEX = 1;
|
||||||
|
export const CHAR_DATA_WIDTH_INDEX = 2;
|
||||||
|
export const CHAR_DATA_CODE_INDEX = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Null cell - a real empty cell (containing nothing).
|
||||||
|
* Note that code should always be 0 for a null cell as
|
||||||
|
* several test condition of the buffer line rely on this.
|
||||||
|
*/
|
||||||
|
export const NULL_CELL_CHAR = '';
|
||||||
|
export const NULL_CELL_WIDTH = 1;
|
||||||
|
export const NULL_CELL_CODE = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whitespace cell.
|
||||||
|
* This is meant as a replacement for empty cells when needed
|
||||||
|
* during rendering lines to preserve correct aligment.
|
||||||
|
*/
|
||||||
|
export const WHITESPACE_CELL_CHAR = ' ';
|
||||||
|
export const WHITESPACE_CELL_WIDTH = 1;
|
||||||
|
export const WHITESPACE_CELL_CODE = 32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* buffer memory layout:
|
* buffer memory layout:
|
||||||
@@ -193,6 +217,8 @@ export class AttributeData implements IAttributeData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_ATTR_DATA = new AttributeData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CellData - represents a single Cell in the terminal buffer.
|
* CellData - represents a single Cell in the terminal buffer.
|
||||||
*/
|
*/
|
||||||
@@ -299,17 +325,15 @@ export class CellData extends AttributeData implements ICellData {
|
|||||||
* memory allocs / GC pressure can be greatly reduced by reusing the CellData object.
|
* memory allocs / GC pressure can be greatly reduced by reusing the CellData object.
|
||||||
*/
|
*/
|
||||||
export class BufferLine implements IBufferLine {
|
export class BufferLine implements IBufferLine {
|
||||||
protected _data: Uint32Array | null = null;
|
protected _data: Uint32Array;
|
||||||
protected _combined: {[index: number]: string} = {};
|
protected _combined: {[index: number]: string} = {};
|
||||||
public length: number;
|
public length: number;
|
||||||
|
|
||||||
constructor(cols: number, fillCellData?: ICellData, public isWrapped: boolean = false) {
|
constructor(cols: number, fillCellData?: ICellData, public isWrapped: boolean = false) {
|
||||||
if (cols) {
|
this._data = new Uint32Array(cols * CELL_SIZE);
|
||||||
this._data = new Uint32Array(cols * CELL_SIZE);
|
const cell = fillCellData || CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
||||||
const cell = fillCellData || CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
for (let i = 0; i < cols; ++i) {
|
||||||
for (let i = 0; i < cols; ++i) {
|
this.setCell(i, cell);
|
||||||
this.setCell(i, cell);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.length = cols;
|
this.length = cols;
|
||||||
}
|
}
|
||||||
@@ -547,7 +571,7 @@ export class BufferLine implements IBufferLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._data = null;
|
this._data = new Uint32Array(0);
|
||||||
this._combined = {};
|
this._combined = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ITerminal, IBufferLine } from '../Types';
|
import { ITerminal } from '../Types';
|
||||||
|
import { IBufferLine } from '../core/Types';
|
||||||
import { ICircularList } from '../common/Types';
|
import { ICircularList } from '../common/Types';
|
||||||
import { C0 } from '../common/data/EscapeSequences';
|
import { C0 } from '../common/data/EscapeSequences';
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as puppeteer from 'puppeteer';
|
||||||
|
import { assert } from 'chai';
|
||||||
|
import { ITerminalOptions } from '../Types';
|
||||||
|
|
||||||
|
const APP = 'http://127.0.0.1:3000/test';
|
||||||
|
|
||||||
|
let browser: puppeteer.Browser;
|
||||||
|
let page: puppeteer.Page;
|
||||||
|
const width = 800;
|
||||||
|
const height = 600;
|
||||||
|
|
||||||
|
describe('API Integration Tests', () => {
|
||||||
|
before(async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
browser = await puppeteer.launch({
|
||||||
|
headless: process.argv.indexOf('--headless') !== -1,
|
||||||
|
slowMo: 80,
|
||||||
|
args: [`--window-size=${width},${height}`]
|
||||||
|
});
|
||||||
|
page = (await browser.pages())[0];
|
||||||
|
await page.setViewport({ width, height });
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await page.goto(APP);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Default options', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
assert.equal(await page.evaluate(`window.term.cols`), 80);
|
||||||
|
assert.equal(await page.evaluate(`window.term.rows`), 24);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('write', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.term.write('foo');
|
||||||
|
window.term.write('bar');
|
||||||
|
`);
|
||||||
|
assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(0, true)`), 'foobar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('writeln', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.term.writeln('foo');
|
||||||
|
window.term.writeln('bar');
|
||||||
|
`);
|
||||||
|
assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(0, true)`), 'foo');
|
||||||
|
assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(1, true)`), 'bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clear', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal({ rows: 5 });
|
||||||
|
await page.evaluate(`
|
||||||
|
window.term.write('test0');
|
||||||
|
for (let i = 1; i < 10; i++) {
|
||||||
|
window.term.write('\\n\\rtest' + i);
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
await page.evaluate(`window.term.clear()`);
|
||||||
|
assert.equal(await page.evaluate(`window.term._core.buffer.lines.length`), '5');
|
||||||
|
assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(0, true)`), 'test9');
|
||||||
|
for (let i = 1; i < 5; i++) {
|
||||||
|
assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(${i}, true)`), '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getOption, setOption', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
assert.equal(await page.evaluate(`window.term.getOption('rendererType')`), 'canvas');
|
||||||
|
await page.evaluate(`window.term.setOption('rendererType', 'dom')`);
|
||||||
|
assert.equal(await page.evaluate(`window.term.getOption('rendererType')`), 'dom');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('selection', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal({ rows: 5 });
|
||||||
|
await page.evaluate(`window.term.write('\\n\\nfoo\\n\\n\\rbar\\n\\n\\rbaz')`);
|
||||||
|
assert.equal(await page.evaluate(`window.term.hasSelection()`), false);
|
||||||
|
assert.equal(await page.evaluate(`window.term.getSelection()`), '');
|
||||||
|
await page.evaluate(`window.term.selectAll()`);
|
||||||
|
assert.equal(await page.evaluate(`window.term.hasSelection()`), true);
|
||||||
|
assert.equal(await page.evaluate(`window.term.getSelection()`), '\n\nfoo\n\nbar\n\nbaz');
|
||||||
|
await page.evaluate(`window.term.clearSelection()`);
|
||||||
|
assert.equal(await page.evaluate(`window.term.hasSelection()`), false);
|
||||||
|
assert.equal(await page.evaluate(`window.term.getSelection()`), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('focus, blur', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
assert.equal(await page.evaluate(`document.activeElement.className`), '');
|
||||||
|
await page.evaluate(`window.term.focus()`);
|
||||||
|
assert.equal(await page.evaluate(`document.activeElement.className`), 'xterm-helper-textarea');
|
||||||
|
await page.evaluate(`window.term.blur()`);
|
||||||
|
assert.equal(await page.evaluate(`document.activeElement.className`), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Events', () => {
|
||||||
|
it('onCursorMove', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.callCount = 0;
|
||||||
|
window.term.onCursorMove(e => window.callCount++);
|
||||||
|
window.term.write('foo');
|
||||||
|
`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 1);
|
||||||
|
await page.evaluate(`window.term.write('bar')`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onData', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.term.onData(e => calls.push(e));
|
||||||
|
`);
|
||||||
|
await page.type('.xterm-helper-textarea', 'foo');
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), ['f', 'o', 'o']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onKey', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.term.onKey(e => calls.push(e.key));
|
||||||
|
`);
|
||||||
|
await page.type('.xterm-helper-textarea', 'foo');
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), ['f', 'o', 'o']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onLineFeed', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.callCount = 0;
|
||||||
|
window.term.onLineFeed(() => callCount++);
|
||||||
|
window.term.writeln('foo');
|
||||||
|
`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 1);
|
||||||
|
await page.evaluate(`window.term.writeln('bar')`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onScroll', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal({ rows: 5 });
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.term.onScroll(e => window.calls.push(e));
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
window.term.writeln('foo');
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), []);
|
||||||
|
await page.evaluate(`window.term.writeln('bar')`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), [1]);
|
||||||
|
await page.evaluate(`window.term.writeln('baz')`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), [1, 2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onSelectionChange', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.callCount = 0;
|
||||||
|
window.term.onSelectionChange(() => window.callCount++);
|
||||||
|
`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 0);
|
||||||
|
await page.evaluate(`window.term.selectAll()`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 1);
|
||||||
|
await page.evaluate(`window.term.clearSelection()`);
|
||||||
|
assert.equal(await page.evaluate(`window.callCount`), 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onRender', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.term.onRender(e => window.calls.push([e.start, e.end]));
|
||||||
|
`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), []);
|
||||||
|
await page.evaluate(`window.term.write('foo')`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), [[0, 0]]);
|
||||||
|
await page.evaluate(`window.term.write('bar\\n\\nbaz')`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), [[0, 0], [0, 2]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onResize', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.term.onResize(e => window.calls.push([e.cols, e.rows]));
|
||||||
|
`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), []);
|
||||||
|
await page.evaluate(`window.term.resize(10, 5)`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), [[10, 5]]);
|
||||||
|
await page.evaluate(`window.term.resize(20, 15)`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), [[10, 5], [20, 15]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('onTitleChange', async function(): Promise<any> {
|
||||||
|
this.timeout(10000);
|
||||||
|
await openTerminal();
|
||||||
|
await page.evaluate(`
|
||||||
|
window.calls = [];
|
||||||
|
window.term.onTitleChange(e => window.calls.push(e));
|
||||||
|
`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), []);
|
||||||
|
await page.evaluate(`window.term.write('\\x1b]2;foo\\x9c')`);
|
||||||
|
assert.deepEqual(await page.evaluate(`window.calls`), ['foo']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
|
||||||
|
await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`);
|
||||||
|
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
|
||||||
|
if (options.rendererType === 'dom') {
|
||||||
|
await page.waitForSelector('.xterm-rows');
|
||||||
|
} else {
|
||||||
|
await page.waitForSelector('.xterm-text-layer');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IRenderLayer, IColorSet, IRenderDimensions } from './Types';
|
import { IRenderLayer, IColorSet, IRenderDimensions } from './Types';
|
||||||
import { ITerminal, ICellData } from '../Types';
|
import { ITerminal } from '../Types';
|
||||||
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier, DEFAULT_COLOR } from './atlas/Types';
|
import { ICellData } from '../core/Types';
|
||||||
|
import { DEFAULT_COLOR } from '../common/Types';
|
||||||
|
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier } from './atlas/Types';
|
||||||
import BaseCharAtlas from './atlas/BaseCharAtlas';
|
import BaseCharAtlas from './atlas/BaseCharAtlas';
|
||||||
import { acquireCharAtlas } from './atlas/CharAtlasCache';
|
import { acquireCharAtlas } from './atlas/CharAtlasCache';
|
||||||
import { CellData, AttributeData } from '../BufferLine';
|
import { CellData, AttributeData, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../core/buffer/BufferLine';
|
||||||
import { WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../Buffer';
|
|
||||||
import { JoinedCellData } from './CharacterJoinerRegistry';
|
|
||||||
|
|
||||||
export abstract class BaseRenderLayer implements IRenderLayer {
|
export abstract class BaseRenderLayer implements IRenderLayer {
|
||||||
private _canvas: HTMLCanvasElement;
|
private _canvas: HTMLCanvasElement;
|
||||||
@@ -263,9 +263,9 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
|||||||
|
|
||||||
// skip cache right away if we draw in RGB
|
// skip cache right away if we draw in RGB
|
||||||
// Note: to avoid bad runtime JoinedCellData will be skipped
|
// Note: to avoid bad runtime JoinedCellData will be skipped
|
||||||
// in the cache handler (atlasDidDraw == false) itself and
|
// in the cache handler itself (atlasDidDraw == false) and
|
||||||
// fall through to uncached later down below
|
// fall through to uncached later down below
|
||||||
if (cell.isFgRGB() || cell.isBgRGB() || cell instanceof JoinedCellData) {
|
if (cell.isFgRGB() || cell.isBgRGB()) {
|
||||||
this._drawUncachedChars(terminal, cell, x, y);
|
this._drawUncachedChars(terminal, cell, x, y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
|
||||||
import { MockTerminal, MockBuffer } from '../TestUtils.test';
|
import { MockTerminal, MockBuffer } from '../TestUtils.test';
|
||||||
@@ -5,8 +10,8 @@ import { CircularList } from '../common/CircularList';
|
|||||||
|
|
||||||
import { ICharacterJoinerRegistry } from './Types';
|
import { ICharacterJoinerRegistry } from './Types';
|
||||||
import { CharacterJoinerRegistry } from './CharacterJoinerRegistry';
|
import { CharacterJoinerRegistry } from './CharacterJoinerRegistry';
|
||||||
import { BufferLine, CellData } from '../BufferLine';
|
import { BufferLine, CellData } from '../core/buffer/BufferLine';
|
||||||
import { IBufferLine } from '../Types';
|
import { IBufferLine } from '../core/Types';
|
||||||
|
|
||||||
describe('CharacterJoinerRegistry', () => {
|
describe('CharacterJoinerRegistry', () => {
|
||||||
let registry: ICharacterJoinerRegistry;
|
let registry: ICharacterJoinerRegistry;
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { ITerminal, IBufferLine, ICellData, CharData } from '../Types';
|
/**
|
||||||
|
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ITerminal } from '../Types';
|
||||||
|
import { IBufferLine, ICellData, CharData } from '../core/Types';
|
||||||
import { ICharacterJoinerRegistry, ICharacterJoiner } from './Types';
|
import { ICharacterJoinerRegistry, ICharacterJoiner } from './Types';
|
||||||
import { CellData, Content, AttributeData } from '../BufferLine';
|
import { CellData, Content, AttributeData, WHITESPACE_CELL_CHAR } from '../core/buffer/BufferLine';
|
||||||
import { WHITESPACE_CELL_CHAR } from '../Buffer';
|
|
||||||
|
|
||||||
export class JoinedCellData extends AttributeData implements ICellData {
|
export class JoinedCellData extends AttributeData implements ICellData {
|
||||||
private _width: number;
|
private _width: number;
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
|
|
||||||
import { IColorSet, IRenderDimensions } from './Types';
|
import { IColorSet, IRenderDimensions } from './Types';
|
||||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||||
import { ITerminal, ICellData } from '../Types';
|
import { ITerminal } from '../Types';
|
||||||
import { CellData } from '../BufferLine';
|
import { ICellData } from '../core/Types';
|
||||||
|
import { CellData } from '../core/buffer/BufferLine';
|
||||||
|
|
||||||
interface ICursorState {
|
interface ICursorState {
|
||||||
x: number;
|
x: number;
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { NULL_CELL_CODE } from '../Buffer';
|
|
||||||
import { IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
|
import { IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
|
||||||
import { CharData, ITerminal, ICellData } from '../Types';
|
import { ITerminal } from '../Types';
|
||||||
|
import { CharData, ICellData } from '../core/Types';
|
||||||
import { GridCache } from './GridCache';
|
import { GridCache } from './GridCache';
|
||||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||||
import { CellData, AttributeData, Content } from '../BufferLine';
|
import { CellData, AttributeData, Content, NULL_CELL_CODE } from '../core/buffer/BufferLine';
|
||||||
import { JoinedCellData } from './CharacterJoinerRegistry';
|
import { JoinedCellData } from './CharacterJoinerRegistry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
import { ITerminal } from '../../Types';
|
import { ITerminal } from '../../Types';
|
||||||
import { IColorSet } from '../Types';
|
import { IColorSet } from '../Types';
|
||||||
import { DEFAULT_COLOR, ICharAtlasConfig } from './Types';
|
import { ICharAtlasConfig } from './Types';
|
||||||
|
import { DEFAULT_COLOR } from '../../common/Types';
|
||||||
|
|
||||||
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {
|
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {
|
||||||
// null out some fields that don't matter
|
// null out some fields that don't matter
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DIM_OPACITY, IGlyphIdentifier, DEFAULT_COLOR, ICharAtlasConfig, CHAR_ATLAS_CELL_SPACING } from './Types';
|
import { DIM_OPACITY, IGlyphIdentifier, ICharAtlasConfig, CHAR_ATLAS_CELL_SPACING } from './Types';
|
||||||
import { generateStaticCharAtlasTexture } from './CharAtlasGenerator';
|
import { generateStaticCharAtlasTexture } from './CharAtlasGenerator';
|
||||||
import BaseCharAtlas from './BaseCharAtlas';
|
import BaseCharAtlas from './BaseCharAtlas';
|
||||||
import { is256Color } from './CharAtlasUtils';
|
import { is256Color } from './CharAtlasUtils';
|
||||||
|
import { DEFAULT_COLOR } from '../../common/Types';
|
||||||
|
|
||||||
export default class StaticCharAtlas extends BaseCharAtlas {
|
export default class StaticCharAtlas extends BaseCharAtlas {
|
||||||
private _texture: HTMLCanvasElement | ImageBitmap;
|
private _texture: HTMLCanvasElement | ImageBitmap;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
import { FontWeight } from 'xterm';
|
import { FontWeight } from 'xterm';
|
||||||
import { IColorSet } from '../Types';
|
import { IColorSet } from '../Types';
|
||||||
|
|
||||||
export const DEFAULT_COLOR = 256;
|
|
||||||
export const INVERTED_DEFAULT_COLOR = 257;
|
export const INVERTED_DEFAULT_COLOR = 257;
|
||||||
export const DIM_OPACITY = 0.5;
|
export const DIM_OPACITY = 0.5;
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _updateDimensions(): void {
|
private _updateDimensions(): void {
|
||||||
this.dimensions.scaledCharWidth = Math.floor(this._terminal.charMeasure.width * window.devicePixelRatio);
|
this.dimensions.scaledCharWidth = this._terminal.charMeasure.width * window.devicePixelRatio;
|
||||||
this.dimensions.scaledCharHeight = Math.ceil(this._terminal.charMeasure.height * window.devicePixelRatio);
|
this.dimensions.scaledCharHeight = Math.ceil(this._terminal.charMeasure.height * window.devicePixelRatio);
|
||||||
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing);
|
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing);
|
||||||
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight);
|
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight);
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
import jsdom = require('jsdom');
|
import jsdom = require('jsdom');
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { DomRendererRowFactory } from './DomRendererRowFactory';
|
import { DomRendererRowFactory } from './DomRendererRowFactory';
|
||||||
import { DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR_DATA } from '../../Buffer';
|
import { BufferLine, CellData, FgFlags, BgFlags, Attributes, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, DEFAULT_ATTR_DATA } from '../../core/buffer/BufferLine';
|
||||||
import { BufferLine, CellData, FgFlags, BgFlags, Attributes } from '../../BufferLine';
|
import { ITerminalOptions } from '../../Types';
|
||||||
import { IBufferLine, ITerminalOptions } from '../../Types';
|
import { IBufferLine } from '../../core/Types';
|
||||||
|
|
||||||
describe('DomRendererRowFactory', () => {
|
describe('DomRendererRowFactory', () => {
|
||||||
let dom: jsdom.JSDOM;
|
let dom: jsdom.JSDOM;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../Buffer';
|
import { ITerminalOptions } from '../../Types';
|
||||||
import { IBufferLine, ITerminalOptions } from '../../Types';
|
import { IBufferLine } from '../../core/Types';
|
||||||
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
||||||
import { CellData, AttributeData } from '../../BufferLine';
|
import { CellData, AttributeData, NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../core/buffer/BufferLine';
|
||||||
|
|
||||||
export const BOLD_CLASS = 'xterm-bold';
|
export const BOLD_CLASS = 'xterm-bold';
|
||||||
export const DIM_CLASS = 'xterm-dim';
|
export const DIM_CLASS = 'xterm-dim';
|
||||||
|
|||||||
Vendored
+2
-2
@@ -754,7 +754,7 @@ declare module 'xterm' {
|
|||||||
* Retrieves an option's value from the terminal.
|
* Retrieves an option's value from the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
*/
|
*/
|
||||||
getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean;
|
getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean;
|
||||||
/**
|
/**
|
||||||
* Retrieves an option's value from the terminal.
|
* Retrieves an option's value from the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
@@ -805,7 +805,7 @@ declare module 'xterm' {
|
|||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
* @param value The option value.
|
* @param value The option value.
|
||||||
*/
|
*/
|
||||||
setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void;
|
setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void;
|
||||||
/**
|
/**
|
||||||
* Sets an option on the terminal.
|
* Sets an option on the terminal.
|
||||||
* @param key The option key.
|
* @param key The option key.
|
||||||
|
|||||||
Reference in New Issue
Block a user