Compare commits

...
48 Commits
Author SHA1 Message Date
jerch a11ba0a89c Merge pull request #3365 from jerch/fix_3362
allow cursor to stick at cols in ED/EL
2021-06-11 16:07:10 +02:00
Daniel Imms 2134e050cb Merge branch 'master' into fix_3362 2021-06-11 04:48:33 -07:00
Daniel Imms e2ed603ab8 Merge pull request #3366 from angerson/patch-1
Remove Shellvault
2021-06-10 12:11:44 -07:00
Austin Anderson ff3781a431 Remove Shellvault
Shellvault was shut down a while ago and the link is dead.
2021-06-10 12:01:03 -07:00
Jörg Breitbart 55cd97ec68 remove left over only test clause 2021-06-10 10:42:27 +02:00
Jörg Breitbart 2f0a4fc5c0 allow cursor to stick at cols in ED/EL 2021-06-10 10:35:58 +02:00
Daniel Imms 6dd61f96c0 Merge pull request #3363 from meganrogge/bufferRange
+1 to rangeLength when on a wrapped line to match standard behavior
2021-06-09 06:17:59 -07:00
Megan Rogge fdae61380c Merge branch 'master' into bufferRange 2021-06-08 16:53:28 -05:00
meganrogge 09acb2b5f9 +1 to rangeLength when on a wrapped line to match standard behavior 2021-06-08 14:52:05 -07:00
Daniel Imms 19c9fef8e2 Merge pull request #3361 from xtermjs/dependabot/npm_and_yarn/glob-parent-5.1.2
[Security] Bump glob-parent from 5.1.1 to 5.1.2
2021-06-08 03:26:53 -07:00
dependabot-preview[bot] c335682559 [Security] Bump glob-parent from 5.1.1 to 5.1.2
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2. **This update includes a security fix.**
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-06-08 07:00:20 +00:00
Daniel Imms 96806ee384 Merge pull request #3341 from coderaiser/feature/lint-with-putout
chore: lint using putout
2021-06-04 13:03:30 -07:00
Daniel Imms 096655a3eb Merge branch 'master' into feature/lint-with-putout 2021-06-04 12:39:25 -07:00
Daniel Imms a9788c364d Merge pull request #3360 from Tyriar/eslint_as
Add eslint type assertions rule
2021-06-04 12:29:12 -07:00
Daniel Imms f593d14823 Fix tests, add explanatory comment 2021-06-04 12:21:15 -07:00
coderaiser 6801793547 chore: inc -> prefix -> postfix 2021-06-04 19:37:25 +03:00
Daniel Imms f52d631fa4 Add eslint type assertions rule
Fixes #3359
2021-06-04 06:23:12 -07:00
Daniel Imms ca70d7b6b4 Merge branch 'master' into feature/lint-with-putout 2021-06-04 06:11:52 -07:00
jerch fe1d2f6af1 Merge pull request #3354 from xtermjs/dependabot/npm_and_yarn/ws-7.4.6
Bump ws from 7.4.5 to 7.4.6
2021-05-29 10:41:04 +02:00
dependabot[bot] 64b37ef518 Bump ws from 7.4.5 to 7.4.6
Bumps [ws](https://github.com/websockets/ws) from 7.4.5 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.5...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-29 03:56:37 +00:00
Daniel Imms 654a0a671d Merge pull request #3352 from SquitchYT/master
Add Tess to Readme
2021-05-24 11:56:20 -07:00
Daniel Imms dc1b1b4537 Update README.md 2021-05-24 11:55:53 -07:00
Squitch 579e43c4cc Update README.md 2021-05-24 20:30:33 +02:00
Squitch f8d8288e0e Update README.md 2021-05-24 20:27:07 +02:00
coderaiser ea7f89842a chore: browser: Linkifier: increment 2021-05-17 17:45:35 +03:00
coderaiser 91a79e9dee Merge branch 'master' into feature/lint-with-putout 2021-05-17 17:30:45 +03:00
Daniel Imms a385ab0802 Merge pull request #3344 from silamon/devcontainerupdate
devcontainer: upgrade to node v14.x
2021-05-17 06:32:33 -07:00
Daniel Imms 9175a220be Merge pull request #3345 from tsadarsh/master
Including my project in "Real-World uses" section of README.md
2021-05-17 03:58:40 -07:00
Adarsh TS 0131fc9ebf Update README.md 2021-05-16 09:39:18 +05:30
Simon Lamon c9eab73bd4 devcontainer: upgrade to node v14.x 2021-05-15 16:06:30 +02:00
coderaiser e42e20f776 Merge branch 'master' into feature/lint-with-putout 2021-05-15 01:24:29 +03:00
coderaiser d046e2a77f chore: lint using putout 2021-05-15 01:17:17 +03:00
Daniel Imms 873dd76167 Merge pull request #3337 from LabhanshAgrawal/fonts
Update local fonts query
2021-05-13 08:48:23 -07:00
Labhansh Agrawal 6824d6f4df Merge branch 'master' into fonts 2021-05-13 18:15:46 +05:30
Labhansh Agrawal 74edc6fdd4 Add navigator typing for fonts access 2021-05-13 18:12:07 +05:30
Daniel Imms 99926e67cd Merge pull request #3338 from xtermjs/Tyriar-patch-1
v0.11.1 webgl - types fix
2021-05-13 05:09:59 -07:00
Daniel Imms de712d9b43 v0.11.1 webgl - types fix 2021-05-13 05:09:39 -07:00
Labhansh Agrawal 01f68c50ed Update local fonts query 2021-05-13 12:55:46 +05:30
jerch 840774c034 Merge pull request #3334 from UziTech/patch-2
chore(types): use IEvent from xterm
2021-05-12 11:31:14 +02:00
jerch da898b7efa Merge branch 'master' into patch-2 2021-05-12 11:22:40 +02:00
jerch d4f4e19056 Merge pull request #3330 from jerch/update_dependencies
update package dependencies, switch to node v14
2021-05-12 11:19:43 +02:00
Jörg Breitbart 94ba682b57 Merge branch 'master' into update_dependencies 2021-05-12 11:06:44 +02:00
Jörg Breitbart 8cc6df1f70 upgrade to node v14.x 2021-05-12 10:59:33 +02:00
Tony Brix 7a0b462e7e chore(types): use IEvent from xterm 2021-05-11 20:33:58 -05:00
Jörg Breitbart d229b775ab Merge branch 'master' into update_dependencies 2021-05-10 23:12:29 +02:00
Jörg Breitbart e91d90dbbc switch to 12.x for CI 2021-05-10 23:04:06 +02:00
Jörg Breitbart 8c65fcacb3 flip eslint rule to reflect code base 2021-05-10 22:56:30 +02:00
Jörg Breitbart e55b9fe922 update package dependencies 2021-05-10 22:35:05 +02:00
39 changed files with 1669 additions and 1657 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:10
FROM node:14
# Configure apt
ENV DEBIAN_FRONTEND=noninteractive
+2 -1
View File
@@ -43,10 +43,11 @@
"@typescript-eslint/array-type": [
"warn",
{
"default": "array-simple",
"default": "array",
"readonly": "generic"
}
],
"@typescript-eslint/consistent-type-assertions": "warn",
"@typescript-eslint/consistent-type-definitions": "warn",
"@typescript-eslint/explicit-function-return-type": [
"warn",
+3 -2
View File
@@ -143,7 +143,6 @@ Xterm.js is used in several world-class applications to provide great terminal e
- [**cPanel & WHM**](https://cpanel.com): The hosting platform of choice.
- [**Nutanix**](https://github.com/nutanix): Nutanix Enterprise Cloud uses xterm in the webssh functionality within Nutanix Calm, and is also looking to move our old noserial (termjs) functionality to xterm.js.
- [**SSH Web Client**](https://github.com/roke22/PHP-SSH2-Web-Client): SSH Web Client with PHP.
- [**Shellvault**](https://www.shellvault.io): The cloud-based SSH terminal you can access from anywhere.
- [**Juno**](http://junolab.org/): A flexible Julia IDE, based on Atom.
- [**webssh**](https://github.com/huashengdun/webssh): Web based ssh client.
- [**info-beamer hosted**](https://info-beamer.com): Uses xterm.js to manage digital signage devices from the web dashboard.
@@ -175,7 +174,9 @@ Xterm.js is used in several world-class applications to provide great terminal e
- [**gifcast**](https://dstein64.github.io/gifcast/): Converts an asciinema cast to an animated GIF.
- [**WizardWebssh**](https://gitlab.com/mikeramsey/wizardwebssh): A terminal with Pyqt5 Widget for embedding, which can be used as an ssh client to connect to your ssh servers. It is written in Python, based on tornado, paramiko, and xterm.js.
- [**Wizard Assistant**](https://wizardassistant.com/): Wizard Assistant comes with advanced automation tools, preloaded common and special time-saving commands, and a built-in SSH terminal. Now you can remotely administer, troubleshoot, and analyze any system with ease.
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
- [**ucli**](https://github.com/tsadarsh/ucli): Command Line for everyone :family_man_woman_girl_boy: at [www.ucli.tech](https://www.ucli.tech).
- [**Tess**](https://github.com/SquitchYT/Tess/): Simple Terminal Fully Customizable for Everyone.
- [And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it on our list. Note: Please add any new contributions to the end of the list only.
+1 -1
View File
@@ -20,7 +20,7 @@ export class AttachAddon implements ITerminalAddon {
this._socket = socket;
// always set binary type to arraybuffer, we do not handle blobs
this._socket.binaryType = 'arraybuffer';
this._bidirectional = (options && options.bidirectional === false) ? false : true;
this._bidirectional = !(options && options.bidirectional === false);
}
public activate(terminal: Terminal): void {
+12 -3
View File
@@ -15,6 +15,15 @@ interface IFontMetadata {
blob: () => Promise<Blob>;
}
interface IFontAccessNavigator {
fonts: {
query: () => Promise<IFontMetadata[]>;
};
permissions: {
request?: (permission: { name: string }) => Promise<{state: string}>;
};
}
let fontsPromise: Promise<FontList | Record<string, IFontMetadata[]>> | undefined = undefined;
/**
@@ -28,7 +37,7 @@ export default async function load(fontFamily: string, cacheSize: number): Promi
// Web environment that supports font access API
if (typeof navigator !== 'undefined' && 'fonts' in navigator) {
try {
const status = await (navigator as any).permissions.request?.({
const status = await (navigator as IFontAccessNavigator).permissions.request?.({
name: 'local-fonts'
});
if (status && status.state !== 'granted') {
@@ -44,8 +53,8 @@ export default async function load(fontFamily: string, cacheSize: number): Promi
}
const fonts: Record<string, IFontMetadata[]> = {};
try {
const fontsIterator: AsyncIterableIterator<IFontMetadata> = (navigator as any).fonts.query();
for await (const metadata of fontsIterator) {
const fontsIterator = await (navigator as IFontAccessNavigator).fonts.query();
for (const metadata of fontsIterator) {
if (!fonts.hasOwnProperty(metadata.family)) {
fonts[metadata.family] = [];
}
+1 -1
View File
@@ -394,7 +394,7 @@ export class SearchAddon implements ITerminalAddon {
// If it is not in the viewport then we scroll else it just gets selected
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);
scroll -= Math.floor(terminal.rows / 2);
terminal.scrollLines(scroll);
}
return true;
@@ -35,7 +35,7 @@ perfContext('Terminal: sh -c "dd if=/dev/urandom count=40 bs=1k | hexdump | lolc
chunks.push(data as unknown as Buffer);
length += data.length;
});
await new Promise(resolve => p.on('exit', () => resolve()));
await new Promise<void>(resolve => p.on('exit', () => resolve()));
contentUtf8 = Buffer.concat(chunks, length);
// translate to content string
const buffer = new Uint32Array(contentUtf8.length);
@@ -487,9 +487,9 @@ function newArray<T>(initial: T | ((index: number) => T), count: number): T[] {
const array: T[] = new Array<T>(count);
for (let i = 0; i < array.length; i++) {
if (typeof initial === 'function') {
array[i] = (<(index: number) => T>initial)(i);
array[i] = (initial as (index: number) => T)(i);
} else {
array[i] = <T>initial;
array[i] = initial as T;
}
}
return array;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "xterm-addon-webgl",
"version": "0.11.0",
"version": "0.11.1",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
@@ -263,7 +263,7 @@ export class GlyphRenderer {
// Get attributes from fg (excluding inverse) and resolve inverse by pullibng rgb colors
// from bg. This is needed since the inverse fg color should be based on the original bg
// color, not on the selection color
fg = (fg & ~(Attributes.CM_MASK | Attributes.RGB_MASK | FgFlags.INVERSE));
fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK | FgFlags.INVERSE);
switch (workCell.getBgColorMode()) {
case Attributes.CM_P16:
case Attributes.CM_P256:
+3 -3
View File
@@ -24,9 +24,9 @@ export class WebglAddon implements ITerminalAddon {
throw new Error('Cannot activate WebglAddon before Terminal.open');
}
this._terminal = terminal;
const renderService: IRenderService = (<any>terminal)._core._renderService;
const characterJoinerService: ICharacterJoinerService = (<any>terminal)._core._characterJoinerService;
const colors: IColorSet = (<any>terminal)._core._colorManager.colors;
const renderService: IRenderService = (terminal as any)._core._renderService;
const characterJoinerService: ICharacterJoinerService = (terminal as any)._core._characterJoinerService;
const colors: IColorSet = (terminal as any)._core._colorManager.colors;
this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, this._preserveDrawingBuffer);
this._renderer.onContextLoss(() => this._onContextLoss.fire());
renderService.setRenderer(this._renderer);
@@ -342,7 +342,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
// Flag combined chars with a bit mask so they're easily identifiable
if (chars.length > 1) {
code = code | COMBINED_CHAR_BIT_MASK;
code |= COMBINED_CHAR_BIT_MASK;
}
// Cache the results in the model
+1 -2
View File
@@ -3,8 +3,7 @@
* @license MIT
*/
import { IEvent } from 'node-pty';
import { Terminal, ITerminalAddon } from 'xterm';
import { Terminal, ITerminalAddon, IEvent } from 'xterm';
declare module 'xterm-addon-webgl' {
/**
+7 -7
View File
@@ -10,7 +10,7 @@ jobs:
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- task: YarnInstaller@3
inputs:
@@ -43,7 +43,7 @@ jobs:
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- task: CacheBeta@1
inputs:
@@ -63,7 +63,7 @@ jobs:
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- task: CacheBeta@1
inputs:
@@ -92,7 +92,7 @@ jobs:
displayName: Install required packages
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- task: YarnInstaller@3
inputs:
@@ -111,7 +111,7 @@ jobs:
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- script: yarn --frozen-lockfile
displayName: 'Install dependencies and build'
@@ -128,7 +128,7 @@ jobs:
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- script: yarn --frozen-lockfile
displayName: 'Install dependencies and build'
@@ -151,7 +151,7 @@ jobs:
steps:
- task: NodeTool@0
inputs:
versionSpec: '10.x'
versionSpec: '14.x'
displayName: 'Install Node.js'
- task: YarnInstaller@3
inputs:
+24 -24
View File
@@ -34,37 +34,37 @@
"vtfeatures": "node bin/extract_vtfeatures.js src/**/*.ts src/*.ts"
},
"devDependencies": {
"@types/chai": "^4.2.14",
"@types/chai": "^4.2.18",
"@types/debug": "^4.1.5",
"@types/deep-equal": "^1.0.1",
"@types/glob": "^7.1.3",
"@types/jsdom": "^16.2.5",
"@types/mocha": "^8.0.3",
"@types/node": "^10.17.17",
"@types/jsdom": "^16.2.10",
"@types/mocha": "^8.2.2",
"@types/node": "^14.14.44",
"@types/utf8": "^2.1.6",
"@types/webpack": "^4.41.24",
"@types/ws": "^7.2.9",
"@typescript-eslint/eslint-plugin": "^4.0.0",
"@typescript-eslint/parser": "^3.10.1",
"chai": "^4.2.0",
"deep-equal": "^2.0.4",
"eslint": "^7.12.1",
"@types/webpack": "^5.28.0",
"@types/ws": "^7.4.4",
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/parser": "^4.23.0",
"chai": "^4.3.4",
"deep-equal": "^2.0.5",
"eslint": "^7.26.0",
"express": "^4.17.1",
"express-ws": "^4.0.0",
"glob": "^7.0.5",
"jsdom": "^16.4.0",
"mocha": "^8.2.1",
"mustache": "^4.0.1",
"node-pty": "^0.9.0",
"glob": "^7.1.7",
"jsdom": "^16.5.3",
"mocha": "^8.4.0",
"mustache": "^4.2.0",
"node-pty": "^0.10.1",
"nyc": "^15.1.0",
"playwright": "^1.5.2",
"source-map-loader": "^1.1.2",
"ts-loader": "^8.0.8",
"typescript": "4.0",
"playwright": "^1.11.0",
"source-map-loader": "^2.0.1",
"ts-loader": "^9.1.2",
"typescript": "^4.2.4",
"utf8": "^3.0.0",
"webpack": "^5.4.0",
"webpack-cli": "^4.2.0",
"ws": "^7.3.1",
"xterm-benchmark": "^0.1.3"
"webpack": "^5.37.0",
"webpack-cli": "^4.7.0",
"ws": "^7.4.5",
"xterm-benchmark": "^0.2.1"
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ export class AccessibilityManager extends Disposable {
}
private _onBoundaryFocus(e: FocusEvent, position: BoundaryPosition): void {
const boundaryElement = <HTMLElement>e.target;
const boundaryElement = e.target as HTMLElement;
const beforeBoundaryElement = this._rowElements[position === BoundaryPosition.TOP ? 1 : this._rowElements.length - 2];
// Don't scroll if the buffer top has reached the end in that direction
+2 -2
View File
@@ -17,7 +17,7 @@ describe('ColorManager', () => {
dom = new jsdom.JSDOM('');
window = dom.window;
document = window.document;
(<any>window).HTMLCanvasElement.prototype.getContext = () => ({
(window as any).HTMLCanvasElement.prototype.getContext = () => ({
createLinearGradient(): any {
return null;
},
@@ -36,7 +36,7 @@ describe('ColorManager', () => {
for (const key of Object.keys(cm.colors)) {
if (key !== 'ansi' && key !== 'contrastCache') {
// A #rrggbb or rgba(...)
assert.ok((<any>cm.colors)[key].css.length >= 7);
assert.ok((cm.colors as any)[key].css.length >= 7);
}
}
assert.equal(cm.colors.ansi.length, 256);
+2 -2
View File
@@ -174,7 +174,7 @@ describe('Linkifier', () => {
assert.equal(mouseZoneManager.zones[0].y1, 1);
assert.equal(mouseZoneManager.zones[0].y2, 1);
// Fires done()
mouseZoneManager.zones[0].clickCallback(<any>{});
mouseZoneManager.zones[0].clickCallback({} as any);
}
});
linkifier.linkifyRows();
@@ -210,7 +210,7 @@ describe('Linkifier', () => {
let count = 0;
linkifier.registerLinkMatcher(/test/, () => assert.fail(), {
validationCallback: (url, cb) => {
count += 1;
count++;
if (count === 2) {
done();
}
+3 -1
View File
@@ -89,7 +89,9 @@ export class Linkifier implements ILinkifier {
if (this._rowsTimeoutId) {
clearTimeout(this._rowsTimeoutId);
}
this._rowsTimeoutId = <number><any>setTimeout(() => this._linkifyRows(), Linkifier._timeBeforeLatency);
// Cannot use window.setTimeout since tests need to run in node
this._rowsTimeoutId = setTimeout(() => this._linkifyRows(), Linkifier._timeBeforeLatency) as any as number;
}
/**
+15 -15
View File
@@ -29,10 +29,10 @@ describe('Terminal', () => {
beforeEach(() => {
term = new TestTerminal(termOptions);
term.refresh = () => { };
(<any>term).renderer = new MockRenderer();
(term as any).renderer = new MockRenderer();
term.viewport = new MockViewport();
(<any>term)._compositionHelper = new MockCompositionHelper();
(<any>term).element = {
(term as any)._compositionHelper = new MockCompositionHelper();
(term as any).element = {
classList: {
toggle: () => { },
remove: () => { }
@@ -86,12 +86,12 @@ describe('Terminal', () => {
assert.equal(e.domEvent instanceof Object, true);
done();
});
const evKeyPress = <KeyboardEvent>{
const evKeyPress = {
preventDefault: () => { },
stopPropagation: () => { },
type: 'keypress',
keyCode: 13
};
} as KeyboardEvent;
term.keyPress(evKeyPress);
});
it('should fire a key event after a keydown DOM event', (done) => {
@@ -100,13 +100,13 @@ describe('Terminal', () => {
assert.equal(e.domEvent instanceof Object, true);
done();
});
(<any>term).textarea = { value: '' };
const evKeyDown = <KeyboardEvent>{
(term as any).textarea = { value: '' };
const evKeyDown = {
preventDefault: () => { },
stopPropagation: () => { },
type: 'keydown',
keyCode: 13
};
} as KeyboardEvent;
term.keyDown(evKeyDown);
});
it('should fire the onResize event', (done) => {
@@ -140,18 +140,18 @@ describe('Terminal', () => {
});
describe('attachCustomKeyEventHandler', () => {
const evKeyDown = <KeyboardEvent>{
const evKeyDown = {
preventDefault: () => { },
stopPropagation: () => { },
type: 'keydown',
keyCode: 77
};
const evKeyPress = <KeyboardEvent>{
} as KeyboardEvent;
const evKeyPress = {
preventDefault: () => { },
stopPropagation: () => { },
type: 'keypress',
keyCode: 77
};
} as KeyboardEvent;
beforeEach(() => {
term.clearSelection = () => { };
@@ -374,13 +374,13 @@ describe('Terminal', () => {
describe('keyPress', () => {
it('should scroll down, when a key is pressed and terminal is scrolled up', () => {
const event = <KeyboardEvent>{
const event = {
type: 'keydown',
key: 'a',
keyCode: 65,
preventDefault: () => { },
stopPropagation: () => { }
};
} as KeyboardEvent;
term.buffer.ydisp = 0;
term.buffer.ybase = 40;
@@ -403,7 +403,7 @@ describe('Terminal', () => {
assert.equal(term.buffer.ydisp, startYDisp);
term.scrollLines(-1);
assert.equal(term.buffer.ydisp, startYDisp - 1);
term.keyPress(<KeyboardEvent>{ keyCode: 0 });
term.keyPress({ keyCode: 0 });
assert.equal(term.buffer.ydisp, startYDisp - 1);
});
});
+2 -2
View File
@@ -72,7 +72,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
// private _visualBellTimer: number;
public browser: IBrowser = <any>Browser;
public browser: IBrowser = Browser as any;
// TODO: We should remove options once components adopt optionsService
public get options(): IInitializedTerminalOptions { return this.optionsService.options; }
@@ -601,7 +601,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
let but: CoreMouseButton;
let action: CoreMouseAction | undefined;
switch ((<any>ev).overrideType || ev.type) {
switch ((ev as any).overrideType || ev.type) {
case 'mousemove':
action = CoreMouseAction.MOVE;
if (ev.buttons === undefined) {
+3 -2
View File
@@ -17,6 +17,7 @@ const ROWS = 25;
const TESTFILES = glob.sync('**/escape_sequence_files/*.in', { cwd: path.join(__dirname, '../..')});
const SKIP_FILES = [
't0055-EL.in', // EL/ED handle cursor at cols differently (see #3362)
't0084-CBT.in',
't0101-NLM.in',
't0103-reverse_wrap.in', // not comparable, we deviate from xterm reverse wrap on purpose
@@ -73,7 +74,7 @@ describe('Escape Sequence Files', function(): void {
// register handler to trigger viewport scraping, wait for it to finish
let content = '';
const OSC_CODE = 12345;
await new Promise(resolve => {
await new Promise<void>(resolve => {
customHandler = term.registerOscHandler(OSC_CODE, () => {
// grab terminal viewport content
content = terminalToString(term);
@@ -105,7 +106,7 @@ function formatError(input: string, output: string, expected: string): string {
function addLineNumber(start: number, color: string): (s: string) => string {
let counter = start || 0;
return (s: string): string => {
counter += 1;
counter++;
return '\x1b[33m' + (' ' + counter).slice(-2) + color + s;
};
}
+1 -1
View File
@@ -153,7 +153,7 @@ export class MockTerminal implements ITerminal {
public textarea!: HTMLTextAreaElement;
public rows!: number;
public cols!: number;
public browser: IBrowser = <any>Browser;
public browser: IBrowser = Browser as any;
public writeBuffer!: string[];
public children!: HTMLElement[];
public cursorHidden!: boolean;
+24 -24
View File
@@ -49,7 +49,7 @@ describe('CompositionHelper', () => {
it('Should insert simple characters', (done) => {
// First character 'ㅇ'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent><CompositionEvent>{ data: 'ㅇ' });
compositionHelper.compositionupdate({ data: 'ㅇ' });
textarea.value = 'ㅇ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -57,7 +57,7 @@ describe('CompositionHelper', () => {
assert.equal(handledText, 'ㅇ');
// Second character 'ㅇ'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent><CompositionEvent>{ data: 'ㅇ' });
compositionHelper.compositionupdate({ data: 'ㅇ' });
textarea.value = 'ㅇㅇ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -73,13 +73,13 @@ describe('CompositionHelper', () => {
it('Should insert complex characters', (done) => {
// First character '앙'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'ㅇ' });
compositionHelper.compositionupdate({ data: 'ㅇ' });
textarea.value = 'ㅇ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: '아' });
compositionHelper.compositionupdate({ data: '아' });
textarea.value = '아';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: '앙' });
compositionHelper.compositionupdate({ data: '앙' });
textarea.value = '앙';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -87,13 +87,13 @@ describe('CompositionHelper', () => {
assert.equal(handledText, '앙');
// Second character '앙'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'ㅇ' });
compositionHelper.compositionupdate({ data: 'ㅇ' });
textarea.value = '앙ㅇ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: '아' });
compositionHelper.compositionupdate({ data: '아' });
textarea.value = '앙아';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: '앙' });
compositionHelper.compositionupdate({ data: '앙' });
textarea.value = '앙앙';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -113,19 +113,19 @@ describe('CompositionHelper', () => {
it('Should insert complex characters that change with following character', (done) => {
// First character '아'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'ㅇ' });
compositionHelper.compositionupdate({ data: 'ㅇ' });
textarea.value = 'ㅇ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: '아' });
compositionHelper.compositionupdate({ data: '아' });
textarea.value = '아';
setTimeout(() => { // wait for any textarea updates
// Start second character '아' in first character
compositionHelper.compositionupdate(<CompositionEvent>{ data: '앙' });
compositionHelper.compositionupdate({ data: '앙' });
textarea.value = '앙';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: '아' });
compositionHelper.compositionupdate({ data: '아' });
textarea.value = '아아';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -142,14 +142,14 @@ describe('CompositionHelper', () => {
it('Should insert multi-characters compositions', (done) => {
// First character 'だ'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'd' });
compositionHelper.compositionupdate({ data: 'd' });
textarea.value = 'd';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'だ' });
compositionHelper.compositionupdate({ data: 'だ' });
textarea.value = 'だ';
setTimeout(() => { // wait for any textarea updates
// Second character 'あ'
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'だあ' });
compositionHelper.compositionupdate({ data: 'だあ' });
textarea.value = 'だあ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -165,18 +165,18 @@ describe('CompositionHelper', () => {
it('Should insert multi-character compositions that are converted to other characters with the same length', (done) => {
// First character 'だ'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'd' });
compositionHelper.compositionupdate({ data: 'd' });
textarea.value = 'd';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'だ' });
compositionHelper.compositionupdate({ data: 'だ' });
textarea.value = 'だ';
setTimeout(() => { // wait for any textarea updates
// Second character 'ー'
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'だー' });
compositionHelper.compositionupdate({ data: 'だー' });
textarea.value = 'だー';
setTimeout(() => { // wait for any textarea updates
// Convert to katakana 'ダー'
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'ダー' });
compositionHelper.compositionupdate({ data: 'ダー' });
textarea.value = 'ダー';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -193,18 +193,18 @@ describe('CompositionHelper', () => {
it('Should insert multi-character compositions that are converted to other characters with different lengths', (done) => {
// First character 'い'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'い' });
compositionHelper.compositionupdate({ data: 'い' });
textarea.value = 'い';
setTimeout(() => { // wait for any textarea updates
// Second character 'ま'
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'いm' });
compositionHelper.compositionupdate({ data: 'いm' });
textarea.value = 'いm';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'いま' });
compositionHelper.compositionupdate({ data: 'いま' });
textarea.value = 'いま';
setTimeout(() => { // wait for any textarea updates
// Convert to kanji '今'
compositionHelper.compositionupdate(<CompositionEvent>{ data: '今' });
compositionHelper.compositionupdate({ data: '今' });
textarea.value = '今';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
@@ -221,7 +221,7 @@ describe('CompositionHelper', () => {
it('Should insert non-composition characters input immediately after composition characters', (done) => {
// First character 'ㅇ'
compositionHelper.compositionstart();
compositionHelper.compositionupdate(<CompositionEvent>{ data: 'ㅇ' });
compositionHelper.compositionupdate({ data: 'ㅇ' });
textarea.value = 'ㅇ';
setTimeout(() => { // wait for any textarea updates
compositionHelper.compositionend();
+1 -1
View File
@@ -69,7 +69,7 @@ export class CompositionHelper {
* Handles the compositionupdate event, updating the composition view.
* @param ev The event.
*/
public compositionupdate(ev: CompositionEvent): void {
public compositionupdate(ev: Pick<CompositionEvent, 'data'>): void {
this._compositionView.textContent = ev.data;
this.updateCompositionElements();
setTimeout(() => {
+1 -1
View File
@@ -31,7 +31,7 @@ export class AddonManager implements IDisposable {
};
this._addons.push(loadedAddon);
instance.dispose = () => this._wrappedAddonDispose(loadedAddon);
instance.activate(<any>terminal);
instance.activate(terminal as any);
}
private _wrappedAddonDispose(loadedAddon: ILoadedAddon): void {
+1 -1
View File
@@ -280,7 +280,7 @@ class BufferLineApiView implements IBufferLineApi {
}
if (cell) {
this._line.loadCell(x, <ICellData>cell);
this._line.loadCell(x, cell as ICellData);
return cell;
}
return this._line.loadCell(x, new CellData());
+1 -1
View File
@@ -10,7 +10,7 @@ import { ITerminalOptions } from 'common/services/Services';
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, options: ITerminalOptions, colors: IColorSet): ICharAtlasConfig {
// null out some fields that don't matter
const clonedColors = <IPartialColorSet>{
const clonedColors: IPartialColorSet = {
foreground: colors.foreground,
background: colors.background,
cursor: undefined,
+1 -1
View File
@@ -387,7 +387,7 @@ export class DomRenderer extends Disposable implements IRenderer {
if (!row) {
return;
}
const span = <HTMLElement>row.children[x];
const span = row.children[x] as HTMLElement;
if (span) {
span.style.textDecoration = enabled ? 'underline' : 'none';
}
@@ -270,7 +270,7 @@ function lineData(data: IPartialLineData[]): IBufferLine {
const tline = new BufferLine(0);
for (let i = 0; i < data.length; ++i) {
const line = data[i][0];
const attr = <number>(data[i][1] || 0);
const attr = (data[i][1] || 0) as number;
const offset = tline.length;
tline.resize(tline.length + line.split('').length, CellData.fromCharData([0, '', 0, 0]));
line.split('').map((char, idx) => tline.setCell(idx + offset, CellData.fromCharData([attr, char, 1, char.charCodeAt(0)])));
+2 -2
View File
@@ -133,8 +133,8 @@ export class SelectionService extends Disposable implements ISelectionService {
super();
// Init listeners
this._mouseMoveListener = event => this._onMouseMove(<MouseEvent>event);
this._mouseUpListener = event => this._onMouseUp(<MouseEvent>event);
this._mouseMoveListener = event => this._onMouseMove(event as MouseEvent);
this._mouseUpListener = event => this._onMouseUp(event as MouseEvent);
this._coreService.onUserInput(() => {
if (this.hasSelection) {
this.clearSelection();
+1 -1
View File
@@ -13,7 +13,7 @@ export class SoundService implements ISoundService {
public static get audioContext(): AudioContext | null {
if (!SoundService._audioContext) {
const audioContextCtor: typeof AudioContext = (<any>window).AudioContext || (<any>window).webkitAudioContext;
const audioContextCtor: typeof AudioContext = (window as any).AudioContext || (window as any).webkitAudioContext;
if (!audioContextCtor) {
console.warn('Web Audio API is not supported by this browser. Consider upgrading to the latest version');
return null;
+1 -1
View File
@@ -16,7 +16,7 @@ export function clone<T>(val: T, depth: number = 5): T {
for (const key in val) {
// Recursively clone eack item unless we're at the maximum depth
clonedObject[key] = depth <= 1 ? val[key] : (val[key] ? clone(val[key], depth - 1) : val[key]);
clonedObject[key] = depth <= 1 ? val[key] : (val[key] && clone(val[key], depth - 1));
}
return clonedObject as T;
+91 -5
View File
@@ -77,7 +77,7 @@ describe('InputHandler', () => {
optionsService.options.scrollback = 1;
bufferService.reset();
});
it('SL (scrollLeft)', async () => {
it('SL (scrollLeft)', () => {
inputHandler.parseP('12345'.repeat(6));
inputHandler.parseP('\x1b[ @');
assert.deepEqual(getLines(bufferService, 6), ['12345', '2345', '2345', '2345', '2345', '2345']);
@@ -86,7 +86,7 @@ describe('InputHandler', () => {
inputHandler.parseP('\x1b[2 @');
assert.deepEqual(getLines(bufferService, 6), ['12345', '5', '5', '5', '5', '5']);
});
it('SR (scrollRight)', async () => {
it('SR (scrollRight)', () => {
inputHandler.parseP('12345'.repeat(6));
inputHandler.parseP('\x1b[ A');
assert.deepEqual(getLines(bufferService, 6), ['12345', ' 1234', ' 1234', ' 1234', ' 1234', ' 1234']);
@@ -95,7 +95,7 @@ describe('InputHandler', () => {
inputHandler.parseP('\x1b[2 A');
assert.deepEqual(getLines(bufferService, 6), ['12345', ' 1', ' 1', ' 1', ' 1', ' 1']);
});
it('insertColumns (DECIC)', async () => {
it('insertColumns (DECIC)', () => {
inputHandler.parseP('12345'.repeat(6));
inputHandler.parseP('\x1b[3;3H');
inputHandler.parseP('\x1b[\'}');
@@ -111,7 +111,7 @@ describe('InputHandler', () => {
inputHandler.parseP('\x1b[2\'}');
assert.deepEqual(getLines(bufferService, 6), ['12345', '12 3', '12 3', '12 3', '12 3', '12 3']);
});
it('deleteColumns (DECDC)', async () => {
it('deleteColumns (DECDC)', () => {
inputHandler.parseP('12345'.repeat(6));
inputHandler.parseP('\x1b[3;3H');
inputHandler.parseP('\x1b[\'~');
@@ -137,7 +137,7 @@ describe('InputHandler', () => {
bufferService.reset();
});
describe('reverseWraparound set', () => {
it('should not reverse outside of scroll margins', async () => {
it('should not reverse outside of scroll margins', () => {
// prepare buffer content
inputHandler.parseP('#####abcdefghijklmnopqrstuvwxy');
assert.deepEqual(getLines(bufferService, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', 'uvwxy']);
@@ -1913,6 +1913,92 @@ describe('InputHandler', () => {
});
});
});
// issue #3362 and #2979
describe('EL/ED cursor at buffer.cols', () => {
beforeEach(() => {
bufferService.resize(10, 5);
});
describe('cursor should stay at cols / does not overflow', () => {
it('EL0', async () => {
await inputHandler.parseP('##########\x1b[0K');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['#'.repeat(10), '', '', '', '']);
});
it('EL1', async () => {
await inputHandler.parseP('##########\x1b[1K');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
});
it('EL2', async () => {
await inputHandler.parseP('##########\x1b[2K');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
});
it('ED0', async () => {
await inputHandler.parseP('##########\x1b[0J');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['#'.repeat(10), '', '', '', '']);
});
it('ED1', async () => {
await inputHandler.parseP('##########\x1b[1J');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
});
it('ED2', async () => {
await inputHandler.parseP('##########\x1b[2J');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
});
it('ED3', async () => {
await inputHandler.parseP('##########\x1b[3J');
assert.equal(bufferService.buffer.x, 10);
assert.deepEqual(getLines(bufferService), ['#'.repeat(10), '', '', '', '']);
});
});
describe('following sequence keeps working', () => {
// sequences to test (cursor related ones)
const SEQ = [
/* ICH */ '\x1b[10@',
/* SL */ '\x1b[10 @',
/* CUU */ '\x1b[10A',
/* SR */ '\x1b[10 A',
/* CUD */ '\x1b[10B',
/* CUF */ '\x1b[10C',
/* CUB */ '\x1b[10D',
/* CNL */ '\x1b[10E',
/* CPL */ '\x1b[10F',
/* CHA */ '\x1b[10G',
/* CUP */ '\x1b[10;10H',
/* CHT */ '\x1b[10I',
/* IL */ '\x1b[10L',
/* DL */ '\x1b[10M',
/* DCH */ '\x1b[10P',
/* SU */ '\x1b[10S',
/* SD */ '\x1b[10T',
/* ECH */ '\x1b[10X',
/* CBT */ '\x1b[10Z',
/* HPA */ '\x1b[10`',
/* HPR */ '\x1b[10a',
/* REP */ '\x1b[10b',
/* VPA */ '\x1b[10d',
/* VPR */ '\x1b[10e',
/* HVP */ '\x1b[10;10f',
/* TBC */ '\x1b[0g',
/* SCOSC */ '\x1b[s',
/* DECIC */ '\x1b[10\'}',
/* DECDC */ '\x1b[10\'~'
];
it('cursor never advances beyond cols', async () => {
for (const seq of SEQ) {
await inputHandler.parseP('##########\x1b[2J' + seq);
assert.equal(bufferService.buffer.x <= bufferService.cols, true);
inputHandler.reset();
bufferService.reset();
}
});
});
});
});
+2 -2
View File
@@ -1247,7 +1247,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* @vt: #P[Protection attributes are not supported.] CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Currently the same as ED."
*/
public eraseInDisplay(params: IParams): boolean {
this._restrictCursor();
this._restrictCursor(this._bufferService.cols);
let j;
switch (params.params[0]) {
case 0:
@@ -1319,7 +1319,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* @vt: #P[Protection attributes are not supported.] CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Currently the same as EL."
*/
public eraseInLine(params: IParams): boolean {
this._restrictCursor();
this._restrictCursor(this._bufferService.cols);
switch (params.params[0]) {
case 0:
this._eraseInBufferLine(this._bufferService.buffer.y, this._bufferService.buffer.x, this._bufferService.cols);
+1 -1
View File
@@ -125,7 +125,7 @@ export class MockOptionsService implements IOptionsService {
constructor(testOptions?: IPartialTerminalOptions) {
if (testOptions) {
for (const key of Object.keys(testOptions)) {
this.options[key] = (<any>testOptions)[key];
this.options[key] = (testOptions as any)[key];
}
}
}
+2 -2
View File
@@ -16,10 +16,10 @@ describe('BufferRange', () => {
assert.throws(() => getRangeLength(createRange(1, 3, 1, 1), 0));
});
it('should get range multiple lines', () => {
assert.equal(getRangeLength(createRange(1, 1, 4, 5), 5), 23);
assert.equal(getRangeLength(createRange(1, 1, 4, 5), 5), 24);
});
it('should get range for end line right after start line', () => {
assert.equal(getRangeLength(createRange(1, 1, 7, 2), 5), 11);
assert.equal(getRangeLength(createRange(1, 1, 7, 2), 5), 12);
});
});
});
+2 -5
View File
@@ -5,12 +5,9 @@
import { IBufferRange } from 'xterm';
export function getRangeLength(range: IBufferRange, cols: number): number {
if (range.start.y === range.end.y) {
return range.end.x - range.start.x + 1;
}
export function getRangeLength(range: IBufferRange, bufferCols: number): number {
if (range.start.y > range.end.y) {
throw new Error(`Buffer range end (${range.end.x}, ${range.end.y}) cannot be before start (${range.start.x}, ${range.start.y})`);
}
return cols * (range.end.y - range.start.y - 1) + cols - range.start.x + range.end.x;
return bufferCols * (range.end.y - range.start.y) + (range.end.x - range.start.x + 1);
}
+1447 -1531
View File
File diff suppressed because it is too large Load Diff