Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3261beaea | ||
|
|
345b8d910b | ||
|
|
922ee7c48d | ||
|
|
131e11b52b | ||
|
|
5a3e0612a7 | ||
|
|
b246318090 | ||
|
|
d807bdac5e | ||
|
|
1695baa5b0 | ||
|
|
c71252cd23 | ||
|
|
6c18b7f2cc | ||
|
|
5e77ad5cb4 | ||
|
|
e1578813a7 | ||
|
|
21811cb37d | ||
|
|
265227edcb | ||
|
|
1d3c1964f9 | ||
|
|
58b7a4a2d7 | ||
|
|
a6b0734fe8 | ||
|
|
55cd34c7a5 | ||
|
|
0e8aeebedb | ||
|
|
1c4d41db86 | ||
|
|
63c281e405 | ||
|
|
f03d0858cc | ||
|
|
8bdeb14bc6 | ||
|
|
ad7fe8f881 | ||
|
|
1dcc1d1baf | ||
|
|
0029bc3b42 | ||
|
|
0b73a8d469 | ||
|
|
3a2b97e0f7 | ||
|
|
9bcc98beb9 | ||
|
|
1fb11707a5 | ||
|
|
84548d5d7b | ||
|
|
6f666f56c1 | ||
|
|
2866977941 | ||
|
|
c087592e2c | ||
|
|
65182176b9 | ||
|
|
c8123d911e | ||
|
|
cacda99707 | ||
|
|
bac4eba35e | ||
|
|
625df61489 | ||
|
|
ccca58bb95 | ||
|
|
9557b9132b | ||
|
|
d6d540e748 |
Vendored
+4
-1
@@ -11,7 +11,10 @@
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"group": "test",
|
||||
"group":{
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
|
||||
@@ -185,7 +185,10 @@ Xterm.js is used in several world-class applications to provide great terminal e
|
||||
- [**gdbgui**](https://github.com/cs01/gdbgui): Browser-based frontend to gdb (gnu debugger)
|
||||
- [**goormIDE**](https://ide.goorm.io/): Run almost every programming languages with real-time collaboration, live pair programming, and built-in messenger.
|
||||
- [**FleetDeck**](https://fleetdeck.io): Remote desktop & virtual terminal
|
||||
- [And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
|
||||
- [**OpenSumi**](https://github.com/opensumi/core): A framework helps you quickly build Cloud or Desktop IDE products.
|
||||
- [**KubeSail**](https://kubesail.com): The Self-Hosting Company - uses xterm to allow users to exec into kubernetes pods and build github apps
|
||||
- [**WiTTY**](https://github.com/syssecfsu/witty): Web-based interactive terminal emulator that allows users to easily record, share, and replay console sessions.
|
||||
- [And much more...](https://github.com/xtermjs/xterm.js/network/dependents?package_id=UGFja2FnZS0xNjYzMjc4OQ%3D%3D)
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"types": "typings/xterm-addon-attach.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"types": "typings/xterm-addon-fit.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xterm-addon-ligatures",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"description": "Add support for programming ligatures to xterm.js",
|
||||
"author": {
|
||||
"name": "The xterm.js authors",
|
||||
@@ -25,14 +25,14 @@
|
||||
"keywords": [
|
||||
"font",
|
||||
"ligature",
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js",
|
||||
"terminal"
|
||||
"xterm.js"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"font-finder": "^1.1.0",
|
||||
"font-ligatures": "^1.4.0"
|
||||
"font-ligatures": "^1.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/sinon": "^5.0.1",
|
||||
|
||||
@@ -67,9 +67,9 @@ fd-slicer@~1.1.0:
|
||||
pend "~1.2.0"
|
||||
|
||||
follow-redirects@^1.14.0:
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e"
|
||||
integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw==
|
||||
version "1.14.7"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
|
||||
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
|
||||
|
||||
font-finder@^1.0.3:
|
||||
version "1.0.4"
|
||||
@@ -86,10 +86,10 @@ font-finder@^1.1.0:
|
||||
get-system-fonts "^2.0.0"
|
||||
promise-stream-reader "^1.0.1"
|
||||
|
||||
font-ligatures@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/font-ligatures/-/font-ligatures-1.4.0.tgz#6a7b370d96be1358dddfad67830e82fbfd59e6dc"
|
||||
integrity sha512-n7DFnnEpJ0NrVoLqZIL4tMGVs+CnFwQc92m80LWyrbgAFO4x234+t2/H9o4eOYA1eh6ta9dZAEEsJAwsBdNezA==
|
||||
font-ligatures@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/font-ligatures/-/font-ligatures-1.4.1.tgz#e8c9df7cf6bee80c0cca4a9a578618c7b1f5d8de"
|
||||
integrity sha512-7W6zlfyhvCqShZ5ReUWqmSd9vBaUudW0Hxis+tqUjtHhsPU+L3Grf8mcZAtCiXHTzorhwdRTId2WeH/88gdFkw==
|
||||
dependencies:
|
||||
font-finder "^1.0.3"
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"types": "typings/xterm-addon-search.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"types": "typings/xterm-addon-serialize.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"types": "typings/xterm-addon-unicode11.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xterm-addon-web-links",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"author": {
|
||||
"name": "The xterm.js authors",
|
||||
"url": "https://xtermjs.org/"
|
||||
@@ -9,6 +9,11 @@
|
||||
"types": "typings/xterm-addon-web-links.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
@@ -10,7 +10,7 @@ const protocolClause = '(https?:\\/\\/)';
|
||||
const domainCharacterSet = '[\\da-z\\.-]+';
|
||||
const negatedDomainCharacterSet = '[^\\da-z\\.-]+';
|
||||
const domainBodyClause = '(' + domainCharacterSet + ')';
|
||||
const tldClause = '([a-z\\.]{2,6})';
|
||||
const tldClause = '([a-z\\.]{2,18})';
|
||||
const ipClause = '((\\d{1,3}\\.){3}\\d{1,3})';
|
||||
const localHostClause = '(localhost)';
|
||||
const portClause = '(:\\d{1,5})';
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
"types": "typings/xterm-addon-webgl.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"terminal",
|
||||
"webgl",
|
||||
"xterm",
|
||||
"xterm.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p .",
|
||||
"prepackage": "npm run build",
|
||||
|
||||
+18
-17
@@ -105,22 +105,23 @@ jobs:
|
||||
- script: xvfb-run --auto-servernum -- bash -c "yarn test-api-firefox --headless --forbid-only"
|
||||
displayName: 'Integration tests (Firefox)'
|
||||
|
||||
- job: macOS_IntegrationTests
|
||||
pool:
|
||||
vmImage: 'macOS-10.15'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '14.x'
|
||||
displayName: 'Install Node.js'
|
||||
- script: yarn --frozen-lockfile
|
||||
displayName: 'Install dependencies and build'
|
||||
- script: yarn test-api-chromium --headless --forbid-only
|
||||
displayName: 'Integration tests (Chromium)'
|
||||
- script: yarn test-api-firefox --headless --forbid-only
|
||||
displayName: 'Integration tests (Firefox)'
|
||||
- script: yarn test-api-webkit --headless --forbid-only
|
||||
displayName: 'Integration tests (Webkit)'
|
||||
# Integration tests are too flaky on macOS https://github.com/xtermjs/xterm.js/issues/3590
|
||||
# - job: macOS_IntegrationTests
|
||||
# pool:
|
||||
# vmImage: 'macOS-10.15'
|
||||
# steps:
|
||||
# - task: NodeTool@0
|
||||
# inputs:
|
||||
# versionSpec: '14.x'
|
||||
# displayName: 'Install Node.js'
|
||||
# - script: yarn --frozen-lockfile
|
||||
# displayName: 'Install dependencies and build'
|
||||
# - script: yarn test-api-chromium --headless --forbid-only
|
||||
# displayName: 'Integration tests (Chromium)'
|
||||
# - script: yarn test-api-firefox --headless --forbid-only
|
||||
# displayName: 'Integration tests (Firefox)'
|
||||
# - script: yarn test-api-webkit --headless --forbid-only
|
||||
# displayName: 'Integration tests (Webkit)'
|
||||
|
||||
- job: Windows_IntegrationTests
|
||||
pool:
|
||||
@@ -143,7 +144,7 @@ jobs:
|
||||
- macOS
|
||||
- Windows
|
||||
- Linux_IntegrationTests
|
||||
- macOS_IntegrationTests
|
||||
# - macOS_IntegrationTests
|
||||
- Windows_IntegrationTests
|
||||
condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['FORCE_RELEASE'], 'true')))
|
||||
pool:
|
||||
|
||||
+16
-1
@@ -1,12 +1,27 @@
|
||||
{
|
||||
"name": "xterm",
|
||||
"description": "Full xterm terminal, in your browser",
|
||||
"version": "4.16.0",
|
||||
"version": "4.17.0",
|
||||
"main": "lib/xterm.js",
|
||||
"style": "css/xterm.css",
|
||||
"types": "typings/xterm.d.ts",
|
||||
"repository": "https://github.com/xtermjs/xterm.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"cli",
|
||||
"command-line",
|
||||
"console",
|
||||
"pty",
|
||||
"shell",
|
||||
"ssh",
|
||||
"styles",
|
||||
"terminal-emulator",
|
||||
"terminal",
|
||||
"tty",
|
||||
"vt100",
|
||||
"webgl",
|
||||
"xterm"
|
||||
],
|
||||
"scripts": {
|
||||
"prepackage": "npm run build",
|
||||
"package": "webpack",
|
||||
|
||||
@@ -150,7 +150,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
|
||||
}
|
||||
|
||||
// Restart the tooltip timeout
|
||||
this._tooltipTimeout = window.setTimeout(() => this._onTooltip(e), this._optionsService.options.linkTooltipHoverDuration);
|
||||
this._tooltipTimeout = window.setTimeout(() => this._onTooltip(e), this._optionsService.rawOptions.linkTooltipHoverDuration);
|
||||
}
|
||||
|
||||
private _onTooltip(e: MouseEvent): void {
|
||||
|
||||
@@ -298,7 +298,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
this.viewport?.syncScrollArea();
|
||||
break;
|
||||
case 'screenReaderMode':
|
||||
if (this.optionsService.options.screenReaderMode) {
|
||||
if (this.optionsService.rawOptions.screenReaderMode) {
|
||||
if (!this._accessibilityManager && this._renderService) {
|
||||
this._accessibilityManager = new AccessibilityManager(this, this._renderService);
|
||||
}
|
||||
@@ -309,7 +309,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
break;
|
||||
case 'tabStopWidth': this.buffers.setupTabStops(); break;
|
||||
case 'theme':
|
||||
this._setTheme(this.optionsService.options.theme);
|
||||
this._setTheme(this.optionsService.rawOptions.theme);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -753,7 +753,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
this.register(this.coreMouseService.onProtocolChange(events => {
|
||||
// apply global changes on events
|
||||
if (events) {
|
||||
if (this.optionsService.options.logLevel === 'debug') {
|
||||
if (this.optionsService.rawOptions.logLevel === 'debug') {
|
||||
this._logService.debug('Binding to mouse events:', this.coreMouseService.explainEvents(events));
|
||||
}
|
||||
this.element!.classList.add('enable-mouse-events');
|
||||
@@ -1125,7 +1125,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
// other listeners. When screen reader mode is enabled, this could cause issues if the event
|
||||
// is handled at a higher level, this is a compromise in order to echo keys to the screen
|
||||
// reader.
|
||||
if (!this.optionsService.options.screenReaderMode) {
|
||||
if (!this.optionsService.rawOptions.screenReaderMode) {
|
||||
return this.cancel(event, true);
|
||||
}
|
||||
|
||||
@@ -1220,7 +1220,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
protected _inputEvent(ev: InputEvent): boolean {
|
||||
// Only support emoji IMEs when screen reader mode is disabled as the event must bubble up to
|
||||
// support reading out character input which can doubling up input characters
|
||||
if (ev.data && ev.inputType === 'insertText' && !ev.composed && !this.optionsService.options.screenReaderMode) {
|
||||
if (ev.data && ev.inputType === 'insertText' && !ev.composed && !this.optionsService.rawOptions.screenReaderMode) {
|
||||
if (this._keyPressHandled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ export class Viewport extends Disposable implements IViewport {
|
||||
}
|
||||
|
||||
// Update scroll bar width
|
||||
if (this._optionsService.options.scrollback === 0) {
|
||||
if (this._optionsService.rawOptions.scrollback === 0) {
|
||||
this.scrollBarWidth = 0;
|
||||
} else {
|
||||
this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH;
|
||||
@@ -153,7 +153,7 @@ export class Viewport extends Disposable implements IViewport {
|
||||
}
|
||||
|
||||
// If the scroll bar visibility changed
|
||||
if (this._lastHadScrollBar !== (this._optionsService.options.scrollback > 0)) {
|
||||
if (this._lastHadScrollBar !== (this._optionsService.rawOptions.scrollback > 0)) {
|
||||
this._refresh(immediate);
|
||||
}
|
||||
}
|
||||
@@ -259,15 +259,15 @@ export class Viewport extends Disposable implements IViewport {
|
||||
}
|
||||
|
||||
private _applyScrollModifier(amount: number, ev: WheelEvent): number {
|
||||
const modifier = this._optionsService.options.fastScrollModifier;
|
||||
const modifier = this._optionsService.rawOptions.fastScrollModifier;
|
||||
// Multiply the scroll speed when the modifier is down
|
||||
if ((modifier === 'alt' && ev.altKey) ||
|
||||
(modifier === 'ctrl' && ev.ctrlKey) ||
|
||||
(modifier === 'shift' && ev.shiftKey)) {
|
||||
return amount * this._optionsService.options.fastScrollSensitivity * this._optionsService.options.scrollSensitivity;
|
||||
return amount * this._optionsService.rawOptions.fastScrollSensitivity * this._optionsService.rawOptions.scrollSensitivity;
|
||||
}
|
||||
|
||||
return amount * this._optionsService.options.scrollSensitivity;
|
||||
return amount * this._optionsService.rawOptions.scrollSensitivity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,8 +217,8 @@ export class CompositionHelper {
|
||||
this._compositionView.style.top = cursorTop + 'px';
|
||||
this._compositionView.style.height = cellHeight + 'px';
|
||||
this._compositionView.style.lineHeight = cellHeight + 'px';
|
||||
this._compositionView.style.fontFamily = this._optionsService.options.fontFamily;
|
||||
this._compositionView.style.fontSize = this._optionsService.options.fontSize + 'px';
|
||||
this._compositionView.style.fontFamily = this._optionsService.rawOptions.fontFamily;
|
||||
this._compositionView.style.fontSize = this._optionsService.rawOptions.fontSize + 'px';
|
||||
// Sync the textarea to the exact position of the composition view so the IME knows where the
|
||||
// text is.
|
||||
const compositionViewBounds = this._compositionView.getBoundingClientRect();
|
||||
|
||||
@@ -30,17 +30,21 @@ export class Terminal implements ITerminalApi {
|
||||
this._core = new TerminalCore(options);
|
||||
this._addonManager = new AddonManager();
|
||||
|
||||
this._publicOptions = {};
|
||||
this._publicOptions = { ... this._core.options };
|
||||
const getter = (propName: string): any => {
|
||||
return this._core.options[propName];
|
||||
};
|
||||
const setter = (propName: string, value: any): void => {
|
||||
this._checkReadonlyOptions(propName);
|
||||
this._core.options[propName] = value;
|
||||
};
|
||||
|
||||
for (const propName in this._core.options) {
|
||||
Object.defineProperty(this._publicOptions, propName, {
|
||||
get: () => {
|
||||
return this._core.options[propName];
|
||||
},
|
||||
set: (value: any) => {
|
||||
this._checkReadonlyOptions(propName);
|
||||
this._core.options[propName] = value;
|
||||
}
|
||||
});
|
||||
const desc = {
|
||||
get: getter.bind(this, propName),
|
||||
set: setter.bind(this, propName)
|
||||
};
|
||||
Object.defineProperty(this._publicOptions, propName, desc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +58,7 @@ export class Terminal implements ITerminalApi {
|
||||
}
|
||||
|
||||
private _checkProposedApi(): void {
|
||||
if (!this._core.optionsService.options.allowProposedApi) {
|
||||
if (!this._core.optionsService.rawOptions.allowProposedApi) {
|
||||
throw new Error('You must set the allowProposedApi option to true to use proposed API');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
this._charAtlas = acquireCharAtlas(this._optionsService.options, this._rendererId, colorSet, this._scaledCharWidth, this._scaledCharHeight);
|
||||
this._charAtlas = acquireCharAtlas(this._optionsService.rawOptions, this._rendererId, colorSet, this._scaledCharWidth, this._scaledCharHeight);
|
||||
this._charAtlas.warmUp();
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
|
||||
// Draw custom characters if applicable
|
||||
let drawSuccess = false;
|
||||
if (this._optionsService.options.customGlyphs !== false) {
|
||||
if (this._optionsService.rawOptions.customGlyphs !== false) {
|
||||
drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight);
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
fg = (cell.isFgDefault()) ? DEFAULT_COLOR : cell.getFgColor();
|
||||
}
|
||||
|
||||
const drawInBrightColor = this._optionsService.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8;
|
||||
const drawInBrightColor = this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && fg < 8;
|
||||
|
||||
fg += drawInBrightColor ? 8 : 0;
|
||||
this._currentGlyphIdentifier.chars = cell.getChars() || WHITESPACE_CELL_CHAR;
|
||||
@@ -356,7 +356,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getBgColor()).join(',')})`;
|
||||
} else {
|
||||
let bg = cell.getBgColor();
|
||||
if (this._optionsService.options.drawBoldTextInBrightColors && cell.isBold() && bg < 8) {
|
||||
if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && bg < 8) {
|
||||
bg += 8;
|
||||
}
|
||||
this._ctx.fillStyle = this._colors.ansi[bg].css;
|
||||
@@ -370,7 +370,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`;
|
||||
} else {
|
||||
let fg = cell.getFgColor();
|
||||
if (this._optionsService.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
|
||||
if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
this._ctx.fillStyle = this._colors.ansi[fg].css;
|
||||
@@ -386,7 +386,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
|
||||
// Draw custom characters if applicable
|
||||
let drawSuccess = false;
|
||||
if (this._optionsService.options.customGlyphs !== false) {
|
||||
if (this._optionsService.rawOptions.customGlyphs !== false) {
|
||||
drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight);
|
||||
}
|
||||
|
||||
@@ -421,14 +421,14 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
* @param isBold If we should use the bold fontWeight.
|
||||
*/
|
||||
protected _getFont(isBold: boolean, isItalic: boolean): string {
|
||||
const fontWeight = isBold ? this._optionsService.options.fontWeightBold : this._optionsService.options.fontWeight;
|
||||
const fontWeight = isBold ? this._optionsService.rawOptions.fontWeightBold : this._optionsService.rawOptions.fontWeight;
|
||||
const fontStyle = isItalic ? 'italic' : '';
|
||||
|
||||
return `${fontStyle} ${fontWeight} ${this._optionsService.options.fontSize * window.devicePixelRatio}px ${this._optionsService.options.fontFamily}`;
|
||||
return `${fontStyle} ${fontWeight} ${this._optionsService.rawOptions.fontSize * window.devicePixelRatio}px ${this._optionsService.rawOptions.fontFamily}`;
|
||||
}
|
||||
|
||||
private _getContrastColor(cell: CellData): IColor | undefined {
|
||||
if (this._optionsService.options.minimumContrastRatio === 1) {
|
||||
if (this._optionsService.rawOptions.minimumContrastRatio === 1) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
|
||||
const bgRgba = this._resolveBackgroundRgba(bgColorMode, bgColor, isInverse);
|
||||
const fgRgba = this._resolveForegroundRgba(fgColorMode, fgColor, isInverse, isBold);
|
||||
const result = rgba.ensureContrastRatio(bgRgba, fgRgba, this._optionsService.options.minimumContrastRatio);
|
||||
const result = rgba.ensureContrastRatio(bgRgba, fgRgba, this._optionsService.rawOptions.minimumContrastRatio);
|
||||
|
||||
if (!result) {
|
||||
this._colors.contrastCache.setColor(cell.bg, cell.fg, null);
|
||||
@@ -495,7 +495,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
switch (fgColorMode) {
|
||||
case Attributes.CM_P16:
|
||||
case Attributes.CM_P256:
|
||||
if (this._optionsService.options.drawBoldTextInBrightColors && bold && fgColor < 8) {
|
||||
if (this._optionsService.rawOptions.drawBoldTextInBrightColors && bold && fgColor < 8) {
|
||||
fgColor += 8;
|
||||
}
|
||||
return this._colors.ansi[fgColor].rgba;
|
||||
|
||||
@@ -94,7 +94,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
|
||||
}
|
||||
|
||||
public onOptionsChanged(): void {
|
||||
if (this._optionsService.options.cursorBlink) {
|
||||
if (this._optionsService.rawOptions.cursorBlink) {
|
||||
if (!this._cursorBlinkStateManager) {
|
||||
this._cursorBlinkStateManager = new CursorBlinkStateManager(this._coreBrowserService.isFocused, () => {
|
||||
this._render(true);
|
||||
@@ -148,7 +148,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
|
||||
this._clearCursor();
|
||||
this._ctx.save();
|
||||
this._ctx.fillStyle = this._colors.cursor.css;
|
||||
const cursorStyle = this._optionsService.options.cursorStyle;
|
||||
const cursorStyle = this._optionsService.rawOptions.cursorStyle;
|
||||
if (cursorStyle && cursorStyle !== 'block') {
|
||||
this._cursorRenderers[cursorStyle](cursorX, viewportRelativeCursorY, this._cell);
|
||||
} else {
|
||||
@@ -174,7 +174,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
|
||||
if (this._state.x === cursorX &&
|
||||
this._state.y === viewportRelativeCursorY &&
|
||||
this._state.isFocused === this._coreBrowserService.isFocused &&
|
||||
this._state.style === this._optionsService.options.cursorStyle &&
|
||||
this._state.style === this._optionsService.rawOptions.cursorStyle &&
|
||||
this._state.width === this._cell.getWidth()) {
|
||||
return;
|
||||
}
|
||||
@@ -182,13 +182,13 @@ export class CursorRenderLayer extends BaseRenderLayer {
|
||||
}
|
||||
|
||||
this._ctx.save();
|
||||
this._cursorRenderers[this._optionsService.options.cursorStyle || 'block'](cursorX, viewportRelativeCursorY, this._cell);
|
||||
this._cursorRenderers[this._optionsService.rawOptions.cursorStyle || 'block'](cursorX, viewportRelativeCursorY, this._cell);
|
||||
this._ctx.restore();
|
||||
|
||||
this._state.x = cursorX;
|
||||
this._state.y = viewportRelativeCursorY;
|
||||
this._state.isFocused = false;
|
||||
this._state.style = this._optionsService.options.cursorStyle;
|
||||
this._state.style = this._optionsService.rawOptions.cursorStyle;
|
||||
this._state.width = this._cell.getWidth();
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
|
||||
private _renderBarCursor(x: number, y: number, cell: ICellData): void {
|
||||
this._ctx.save();
|
||||
this._ctx.fillStyle = this._colors.cursor.css;
|
||||
this._fillLeftLineAtCell(x, y, this._optionsService.options.cursorWidth);
|
||||
this._fillLeftLineAtCell(x, y, this._optionsService.rawOptions.cursorWidth);
|
||||
this._ctx.restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
@IOptionsService private readonly _optionsService: IOptionsService
|
||||
) {
|
||||
super();
|
||||
const allowTransparency = this._optionsService.options.allowTransparency;
|
||||
const allowTransparency = this._optionsService.rawOptions.allowTransparency;
|
||||
this._renderLayers = [
|
||||
instantiationService.createInstance(TextRenderLayer, this._screenElement, 0, this._colors, allowTransparency, this._id),
|
||||
instantiationService.createInstance(SelectionRenderLayer, this._screenElement, 1, this._colors, this._id),
|
||||
@@ -178,18 +178,18 @@ export class Renderer extends Disposable implements IRenderer {
|
||||
// will be floored because since lineHeight can never be lower then 1, there
|
||||
// is a guarentee that the scaled line height will always be larger than
|
||||
// scaled char height.
|
||||
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.options.lineHeight);
|
||||
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.rawOptions.lineHeight);
|
||||
|
||||
// Calculate the y coordinate within a cell that text should draw from in
|
||||
// order to draw in the center of a cell.
|
||||
this.dimensions.scaledCharTop = this._optionsService.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2);
|
||||
this.dimensions.scaledCharTop = this._optionsService.rawOptions.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2);
|
||||
|
||||
// Calculate the scaled cell width, taking the letterSpacing into account.
|
||||
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.options.letterSpacing);
|
||||
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.rawOptions.letterSpacing);
|
||||
|
||||
// Calculate the x coordinate with a cell that text should draw from in
|
||||
// order to draw in the center of a cell.
|
||||
this.dimensions.scaledCharLeft = Math.floor(this._optionsService.options.letterSpacing / 2);
|
||||
this.dimensions.scaledCharLeft = Math.floor(this._optionsService.rawOptions.letterSpacing / 2);
|
||||
|
||||
// Recalculate the canvas dimensions; scaled* define the actual number of
|
||||
// pixel in the canvas
|
||||
|
||||
@@ -225,7 +225,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getBgColor()).join(',')})`;
|
||||
} else {
|
||||
let bg = cell.getBgColor();
|
||||
if (this._optionsService.options.drawBoldTextInBrightColors && cell.isBold() && bg < 8) {
|
||||
if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && bg < 8) {
|
||||
bg += 8;
|
||||
}
|
||||
this._ctx.fillStyle = this._colors.ansi[bg].css;
|
||||
@@ -237,7 +237,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`;
|
||||
} else {
|
||||
let fg = cell.getFgColor();
|
||||
if (this._optionsService.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
|
||||
if (this._optionsService.rawOptions.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
|
||||
fg += 8;
|
||||
}
|
||||
this._ctx.fillStyle = this._colors.ansi[fg].css;
|
||||
@@ -271,7 +271,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
}
|
||||
|
||||
public onOptionsChanged(): void {
|
||||
this._setTransparency(this._optionsService.options.allowTransparency);
|
||||
this._setTransparency(this._optionsService.rawOptions.allowTransparency);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { isFirefox } from 'common/Platform';
|
||||
import { isFirefox, isLegacyEdge } from 'common/Platform';
|
||||
|
||||
export const INVERTED_DEFAULT_COLOR = 257;
|
||||
export const DIM_OPACITY = 0.5;
|
||||
// The text baseline is set conditionally by browser. Using 'ideographic' for Firefox would
|
||||
// The text baseline is set conditionally by browser. Using 'ideographic' for Firefox or Legacy Edge would
|
||||
// result in truncated text (Issue 3353). Using 'bottom' for Chrome would result in slightly
|
||||
// unaligned Powerline fonts (PR 3356#issuecomment-850928179).
|
||||
export const TEXT_BASELINE: CanvasTextBaseline = isFirefox ? 'bottom' : 'ideographic';
|
||||
export const TEXT_BASELINE: CanvasTextBaseline = isFirefox || isLegacyEdge ? 'bottom' : 'ideographic';
|
||||
|
||||
export const CHAR_ATLAS_CELL_SPACING = 1;
|
||||
|
||||
@@ -107,8 +107,8 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
private _updateDimensions(): void {
|
||||
this.dimensions.scaledCharWidth = this._charSizeService.width * window.devicePixelRatio;
|
||||
this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * window.devicePixelRatio);
|
||||
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.options.letterSpacing);
|
||||
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.options.lineHeight);
|
||||
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.rawOptions.letterSpacing);
|
||||
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.rawOptions.lineHeight);
|
||||
this.dimensions.scaledCharLeft = 0;
|
||||
this.dimensions.scaledCharTop = 0;
|
||||
this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._bufferService.cols;
|
||||
@@ -161,16 +161,16 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
let styles =
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +
|
||||
` color: ${this._colors.foreground.css};` +
|
||||
` font-family: ${this._optionsService.options.fontFamily};` +
|
||||
` font-size: ${this._optionsService.options.fontSize}px;` +
|
||||
` font-family: ${this._optionsService.rawOptions.fontFamily};` +
|
||||
` font-size: ${this._optionsService.rawOptions.fontSize}px;` +
|
||||
`}`;
|
||||
// Text styles
|
||||
styles +=
|
||||
`${this._terminalSelector} span:not(.${BOLD_CLASS}) {` +
|
||||
` font-weight: ${this._optionsService.options.fontWeight};` +
|
||||
` font-weight: ${this._optionsService.rawOptions.fontWeight};` +
|
||||
`}` +
|
||||
`${this._terminalSelector} span.${BOLD_CLASS} {` +
|
||||
` font-weight: ${this._optionsService.options.fontWeightBold};` +
|
||||
` font-weight: ${this._optionsService.rawOptions.fontWeightBold};` +
|
||||
`}` +
|
||||
`${this._terminalSelector} span.${ITALIC_CLASS} {` +
|
||||
` font-style: italic;` +
|
||||
@@ -210,7 +210,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
` color: ${this._colors.cursorAccent.css};` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BAR_CLASS} {` +
|
||||
` box-shadow: ${this._optionsService.options.cursorWidth}px 0 0 ${this._colors.cursor.css} inset;` +
|
||||
` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${this._colors.cursor.css} inset;` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_UNDERLINE_CLASS} {` +
|
||||
` box-shadow: 0 -1px 0 ${this._colors.cursor.css} inset;` +
|
||||
@@ -356,7 +356,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
public renderRows(start: number, end: number): void {
|
||||
const cursorAbsoluteY = this._bufferService.buffer.ybase + this._bufferService.buffer.y;
|
||||
const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1);
|
||||
const cursorBlink = this._optionsService.options.cursorBlink;
|
||||
const cursorBlink = this._optionsService.rawOptions.cursorBlink;
|
||||
|
||||
for (let y = start; y <= end; y++) {
|
||||
const rowElement = this._rowElements[y];
|
||||
@@ -364,7 +364,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
||||
|
||||
const row = y + this._bufferService.buffer.ydisp;
|
||||
const lineData = this._bufferService.buffer.lines.get(row);
|
||||
const cursorStyle = this._optionsService.options.cursorStyle;
|
||||
const cursorStyle = this._optionsService.rawOptions.cursorStyle;
|
||||
rowElement.appendChild(this._rowFactory.createRow(lineData!, row, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, this._bufferService.cols));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ export class DomRendererRowFactory {
|
||||
switch (fgColorMode) {
|
||||
case Attributes.CM_P16:
|
||||
case Attributes.CM_P256:
|
||||
if (cell.isBold() && fg < 8 && this._optionsService.options.drawBoldTextInBrightColors) {
|
||||
if (cell.isBold() && fg < 8 && this._optionsService.rawOptions.drawBoldTextInBrightColors) {
|
||||
fg += 8;
|
||||
}
|
||||
if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.ansi[fg])) {
|
||||
@@ -225,7 +225,7 @@ export class DomRendererRowFactory {
|
||||
}
|
||||
|
||||
private _applyMinimumContrast(element: HTMLElement, bg: IColor, fg: IColor): boolean {
|
||||
if (this._optionsService.options.minimumContrastRatio === 1) {
|
||||
if (this._optionsService.rawOptions.minimumContrastRatio === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ export class DomRendererRowFactory {
|
||||
|
||||
// Calculate and store in cache
|
||||
if (adjustedColor === undefined) {
|
||||
adjustedColor = color.ensureContrastRatio(bg, fg, this._optionsService.options.minimumContrastRatio);
|
||||
adjustedColor = color.ensureContrastRatio(bg, fg, this._optionsService.rawOptions.minimumContrastRatio);
|
||||
this._colors.contrastCache.setColor(this._workCell.bg, this._workCell.fg, adjustedColor ?? null);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ class DomMeasureStrategy implements IMeasureStrategy {
|
||||
}
|
||||
|
||||
public measure(): IReadonlyMeasureResult {
|
||||
this._measureElement.style.fontFamily = this._optionsService.options.fontFamily;
|
||||
this._measureElement.style.fontSize = `${this._optionsService.options.fontSize}px`;
|
||||
this._measureElement.style.fontFamily = this._optionsService.rawOptions.fontFamily;
|
||||
this._measureElement.style.fontSize = `${this._optionsService.rawOptions.fontSize}px`;
|
||||
|
||||
// Note that this triggers a synchronous layout
|
||||
const geometry = this._measureElement.getBoundingClientRect();
|
||||
|
||||
@@ -414,7 +414,7 @@ export class SelectionService extends Disposable implements ISelectionService {
|
||||
*/
|
||||
public shouldForceSelection(event: MouseEvent): boolean {
|
||||
if (Browser.isMac) {
|
||||
return event.altKey && this._optionsService.options.macOptionClickForcesSelection;
|
||||
return event.altKey && this._optionsService.rawOptions.macOptionClickForcesSelection;
|
||||
}
|
||||
|
||||
return event.shiftKey;
|
||||
@@ -567,7 +567,7 @@ export class SelectionService extends Disposable implements ISelectionService {
|
||||
* @param event the mouse or keyboard event
|
||||
*/
|
||||
public shouldColumnSelect(event: KeyboardEvent | MouseEvent): boolean {
|
||||
return event.altKey && !(Browser.isMac && this._optionsService.options.macOptionClickForcesSelection);
|
||||
return event.altKey && !(Browser.isMac && this._optionsService.rawOptions.macOptionClickForcesSelection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -993,7 +993,7 @@ export class SelectionService extends Disposable implements ISelectionService {
|
||||
if (cell.getWidth() === 0) {
|
||||
return false;
|
||||
}
|
||||
return this._optionsService.options.wordSeparator.indexOf(cell.getChars()) >= 0;
|
||||
return this._optionsService.rawOptions.wordSeparator.indexOf(cell.getChars()) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ export class SoundService implements ISoundService {
|
||||
return;
|
||||
}
|
||||
const bellAudioSource = ctx.createBufferSource();
|
||||
ctx.decodeAudioData(this._base64ToArrayBuffer(this._removeMimeType(this._optionsService.options.bellSound)), (buffer) => {
|
||||
ctx.decodeAudioData(this._base64ToArrayBuffer(this._removeMimeType(this._optionsService.rawOptions.bellSound)), (buffer) => {
|
||||
bellAudioSource.buffer = buffer;
|
||||
bellAudioSource.connect(ctx.destination);
|
||||
bellAudioSource.start(0);
|
||||
|
||||
@@ -247,7 +247,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
|
||||
}
|
||||
|
||||
protected _setup(): void {
|
||||
if (this.optionsService.options.windowsMode) {
|
||||
if (this.optionsService.rawOptions.windowsMode) {
|
||||
this._enableWindowsMode();
|
||||
}
|
||||
}
|
||||
@@ -267,7 +267,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
|
||||
this.buffers.resize(this.cols, this.rows);
|
||||
break;
|
||||
case 'windowsMode':
|
||||
if (this.optionsService.options.windowsMode) {
|
||||
if (this.optionsService.rawOptions.windowsMode) {
|
||||
this._enableWindowsMode();
|
||||
} else {
|
||||
this._windowsMode?.dispose();
|
||||
|
||||
+10
-10
@@ -177,8 +177,8 @@ class DECRQSS implements IDcsHandler {
|
||||
break;
|
||||
case ' q': // DECSCUSR
|
||||
const STYLES: { [key: string]: number } = { 'block': 2, 'underline': 4, 'bar': 6 };
|
||||
let style = STYLES[this._optionsService.options.cursorStyle];
|
||||
style -= this._optionsService.options.cursorBlink ? 1 : 0;
|
||||
let style = STYLES[this._optionsService.rawOptions.cursorStyle];
|
||||
style -= this._optionsService.rawOptions.cursorBlink ? 1 : 0;
|
||||
this._coreService.triggerDataEvent(`${C0.ESC}P1$r${style} q${C0.ESC}\\`);
|
||||
break;
|
||||
default:
|
||||
@@ -603,7 +603,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
let code: number;
|
||||
let chWidth: number;
|
||||
const charset = this._charsetService.charset;
|
||||
const screenReaderMode = this._optionsService.options.screenReaderMode;
|
||||
const screenReaderMode = this._optionsService.rawOptions.screenReaderMode;
|
||||
const cols = this._bufferService.cols;
|
||||
const wraparoundMode = this._coreService.decPrivateModes.wraparound;
|
||||
const insertMode = this._coreService.modes.insertMode;
|
||||
@@ -745,7 +745,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
if (id.final === 't' && !id.prefix && !id.intermediates) {
|
||||
// security: always check whether window option is allowed
|
||||
return this._parser.registerCsiHandler(id, params => {
|
||||
if (!paramToWindowOption(params.params[0], this._optionsService.options.windowOptions)) {
|
||||
if (!paramToWindowOption(params.params[0], this._optionsService.rawOptions.windowOptions)) {
|
||||
return true;
|
||||
}
|
||||
return callback(params);
|
||||
@@ -800,7 +800,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
*/
|
||||
public lineFeed(): boolean {
|
||||
this._dirtyRowService.markDirty(this._activeBuffer.y);
|
||||
if (this._optionsService.options.convertEol) {
|
||||
if (this._optionsService.rawOptions.convertEol) {
|
||||
this._activeBuffer.x = 0;
|
||||
}
|
||||
this._activeBuffer.y++;
|
||||
@@ -904,7 +904,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
}
|
||||
const originalX = this._activeBuffer.x;
|
||||
this._activeBuffer.x = this._activeBuffer.nextStop();
|
||||
if (this._optionsService.options.screenReaderMode) {
|
||||
if (this._optionsService.rawOptions.screenReaderMode) {
|
||||
this._onA11yTab.fire(this._activeBuffer.x - originalX);
|
||||
}
|
||||
return true;
|
||||
@@ -1763,7 +1763,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* @param term The terminal name to evaluate
|
||||
*/
|
||||
private _is(term: string): boolean {
|
||||
return (this._optionsService.options.termName + '').indexOf(term) === 0;
|
||||
return (this._optionsService.rawOptions.termName + '').indexOf(term) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1929,7 +1929,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* This is only active if 'SetWinLines' (24) is enabled
|
||||
* through `options.windowsOptions`.
|
||||
*/
|
||||
if (this._optionsService.options.windowOptions.setWinLines) {
|
||||
if (this._optionsService.rawOptions.windowOptions.setWinLines) {
|
||||
this._bufferService.resize(132, this._bufferService.rows);
|
||||
this._onRequestReset.fire();
|
||||
}
|
||||
@@ -2163,7 +2163,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* This is only active if 'SetWinLines' (24) is enabled
|
||||
* through `options.windowsOptions`.
|
||||
*/
|
||||
if (this._optionsService.options.windowOptions.setWinLines) {
|
||||
if (this._optionsService.rawOptions.windowOptions.setWinLines) {
|
||||
this._bufferService.resize(80, this._bufferService.rows);
|
||||
this._onRequestReset.fire();
|
||||
}
|
||||
@@ -2740,7 +2740,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* Ps >= 24 not implemented
|
||||
*/
|
||||
public windowOptions(params: IParams): boolean {
|
||||
if (!paramToWindowOption(params.params[0], this._optionsService.options.windowOptions)) {
|
||||
if (!paramToWindowOption(params.params[0], this._optionsService.rawOptions.windowOptions)) {
|
||||
return true;
|
||||
}
|
||||
const second = (params.length > 1) ? params.params[1] : 0;
|
||||
|
||||
@@ -18,6 +18,7 @@ const userAgent = (isNode) ? 'node' : navigator.userAgent;
|
||||
const platform = (isNode) ? 'node' : navigator.platform;
|
||||
|
||||
export const isFirefox = userAgent.includes('Firefox');
|
||||
export const isLegacyEdge = userAgent.includes('Edge');
|
||||
export const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);
|
||||
|
||||
// Find the users platform. We use this to interpret the meta key
|
||||
|
||||
@@ -120,12 +120,13 @@ export class MockLogService implements ILogService {
|
||||
|
||||
export class MockOptionsService implements IOptionsService {
|
||||
public serviceBrand: any;
|
||||
public options: ITerminalOptions = clone(DEFAULT_OPTIONS);
|
||||
public readonly rawOptions: ITerminalOptions = clone(DEFAULT_OPTIONS);
|
||||
public options: ITerminalOptions = this.rawOptions;
|
||||
public onOptionChange: IEvent<string> = new EventEmitter<string>().event;
|
||||
constructor(testOptions?: Partial<ITerminalOptions>) {
|
||||
if (testOptions) {
|
||||
for (const key of Object.keys(testOptions)) {
|
||||
this.options[key] = testOptions[key];
|
||||
this.rawOptions[key] = testOptions[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ export class Buffer implements IBuffer {
|
||||
return rows;
|
||||
}
|
||||
|
||||
const correctBufferLength = rows + this._optionsService.options.scrollback;
|
||||
const correctBufferLength = rows + this._optionsService.rawOptions.scrollback;
|
||||
|
||||
return correctBufferLength > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : correctBufferLength;
|
||||
}
|
||||
@@ -172,7 +172,7 @@ export class Buffer implements IBuffer {
|
||||
if (this._rows < newRows) {
|
||||
for (let y = this._rows; y < newRows; y++) {
|
||||
if (this.lines.length < newRows + this.ybase) {
|
||||
if (this._optionsService.options.windowsMode) {
|
||||
if (this._optionsService.rawOptions.windowsMode) {
|
||||
// Just add the new missing rows on Windows as conpty reprints the screen with it's
|
||||
// view of the world. Once a line enters scrollback for conpty it remains there
|
||||
this.lines.push(new BufferLine(newCols, nullCell));
|
||||
@@ -252,7 +252,7 @@ export class Buffer implements IBuffer {
|
||||
}
|
||||
|
||||
private get _isReflowEnabled(): boolean {
|
||||
return this._hasScrollback && !this._optionsService.options.windowsMode;
|
||||
return this._hasScrollback && !this._optionsService.rawOptions.windowsMode;
|
||||
}
|
||||
|
||||
private _reflow(newCols: number, newRows: number): void {
|
||||
@@ -367,6 +367,11 @@ export class Buffer implements IBuffer {
|
||||
let srcCol = lastLineLength;
|
||||
while (srcLineIndex >= 0) {
|
||||
const cellsToCopy = Math.min(srcCol, destCol);
|
||||
if (wrappedLines[destLineIndex] === undefined) {
|
||||
// Sanity check that the line exists, this has been known to fail for an unknown reason
|
||||
// which would stop the reflow from happening if an exception would throw.
|
||||
break;
|
||||
}
|
||||
wrappedLines[destLineIndex].copyCellsFrom(wrappedLines[srcLineIndex], srcCol - cellsToCopy, destCol - cellsToCopy, cellsToCopy, true);
|
||||
destCol -= cellsToCopy;
|
||||
if (destCol === 0) {
|
||||
@@ -550,7 +555,7 @@ export class Buffer implements IBuffer {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
for (; i < this._cols; i += this._optionsService.options.tabStopWidth) {
|
||||
for (; i < this._cols; i += this._optionsService.rawOptions.tabStopWidth) {
|
||||
this.tabs[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ export class BufferService extends Disposable implements IBufferService {
|
||||
@IOptionsService private _optionsService: IOptionsService
|
||||
) {
|
||||
super();
|
||||
this.cols = Math.max(_optionsService.options.cols || 0, MINIMUM_COLS);
|
||||
this.rows = Math.max(_optionsService.options.rows || 0, MINIMUM_ROWS);
|
||||
this.cols = Math.max(_optionsService.rawOptions.cols || 0, MINIMUM_COLS);
|
||||
this.rows = Math.max(_optionsService.rawOptions.rows || 0, MINIMUM_ROWS);
|
||||
this.buffers = new BufferSet(_optionsService, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ export class CoreService extends Disposable implements ICoreService {
|
||||
|
||||
public triggerDataEvent(data: string, wasUserInput: boolean = false): void {
|
||||
// Prevents all events to pty process if stdin is disabled
|
||||
if (this._optionsService.options.disableStdin) {
|
||||
if (this._optionsService.rawOptions.disableStdin) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export class CoreService extends Disposable implements ICoreService {
|
||||
}
|
||||
|
||||
public triggerBinaryEvent(data: string): void {
|
||||
if (this._optionsService.options.disableStdin) {
|
||||
if (this._optionsService.rawOptions.disableStdin) {
|
||||
return;
|
||||
}
|
||||
this._logService.debug(`sending binary "${data}"`, () => data.split('').map(e => e.charCodeAt(0)));
|
||||
|
||||
@@ -46,7 +46,7 @@ export class LogService implements ILogService {
|
||||
}
|
||||
|
||||
private _updateLogLevel(): void {
|
||||
this.logLevel = optionsKeyToLogLevel[this._optionsService.options.logLevel];
|
||||
this.logLevel = optionsKeyToLogLevel[this._optionsService.rawOptions.logLevel];
|
||||
}
|
||||
|
||||
private _evalLazyOptionalParams(optionalParams: any[]): void {
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('OptionsService', () => {
|
||||
describe('constructor', () => {
|
||||
const originalError = console.error;
|
||||
beforeEach(() => {
|
||||
console.error = () => {};
|
||||
console.error = () => { };
|
||||
});
|
||||
afterEach(() => {
|
||||
console.error = originalError;
|
||||
@@ -26,7 +26,11 @@ describe('OptionsService', () => {
|
||||
assert.equal(optionsService.getOption('cols'), 80);
|
||||
});
|
||||
it('uses default value if invalid constructor option value passed', () => {
|
||||
assert.equal(new OptionsService({tabStopWidth: 0}).getOption('tabStopWidth'), DEFAULT_OPTIONS.tabStopWidth);
|
||||
assert.equal(new OptionsService({ tabStopWidth: 0 }).getOption('tabStopWidth'), DEFAULT_OPTIONS.tabStopWidth);
|
||||
});
|
||||
it('object.keys return the correct number of options', () => {
|
||||
const optionsService = new OptionsService({ cols: 80, rows: 25 });
|
||||
assert.notEqual(Object.keys(optionsService.options).length, 0);
|
||||
});
|
||||
});
|
||||
describe('setOption', () => {
|
||||
|
||||
@@ -60,7 +60,7 @@ const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '1
|
||||
export class OptionsService implements IOptionsService {
|
||||
public serviceBrand: any;
|
||||
|
||||
private _options: ITerminalOptions;
|
||||
public readonly rawOptions: ITerminalOptions;
|
||||
public options: ITerminalOptions;
|
||||
|
||||
private _onOptionChange = new EventEmitter<string>();
|
||||
@@ -68,12 +68,12 @@ export class OptionsService implements IOptionsService {
|
||||
|
||||
constructor(options: Partial<ITerminalOptions>) {
|
||||
// set the default value of each option
|
||||
this._options = { ...DEFAULT_OPTIONS };
|
||||
const defaultOptions = { ...DEFAULT_OPTIONS };
|
||||
for (const key in options) {
|
||||
if (key in this._options) {
|
||||
if (key in defaultOptions) {
|
||||
try {
|
||||
const newValue = options[key];
|
||||
this._options[key] = this._sanitizeAndValidateOption(key, newValue);
|
||||
defaultOptions[key] = this._sanitizeAndValidateOption(key, newValue);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -81,34 +81,39 @@ export class OptionsService implements IOptionsService {
|
||||
}
|
||||
|
||||
// set up getters and setters for each option
|
||||
this.options = this._setupOptions(this._options);
|
||||
this.rawOptions = defaultOptions;
|
||||
this.options = { ... defaultOptions };
|
||||
this._setupOptions();
|
||||
}
|
||||
|
||||
private _setupOptions(options: ITerminalOptions): ITerminalOptions {
|
||||
const copiedOptions = { ... options };
|
||||
for (const propName in copiedOptions) {
|
||||
Object.defineProperty(copiedOptions, propName, {
|
||||
get: () => {
|
||||
if (!(propName in DEFAULT_OPTIONS)) {
|
||||
throw new Error(`No option with key "${propName}"`);
|
||||
}
|
||||
return this._options[propName];
|
||||
},
|
||||
set: (value: any) => {
|
||||
if (!(propName in DEFAULT_OPTIONS)) {
|
||||
throw new Error(`No option with key "${propName}"`);
|
||||
}
|
||||
private _setupOptions(): void {
|
||||
const getter = (propName: string): any => {
|
||||
if (!(propName in DEFAULT_OPTIONS)) {
|
||||
throw new Error(`No option with key "${propName}"`);
|
||||
}
|
||||
return this.rawOptions[propName];
|
||||
};
|
||||
|
||||
value = this._sanitizeAndValidateOption(propName, value);
|
||||
// Don't fire an option change event if they didn't change
|
||||
if (this._options[propName] !== value) {
|
||||
this._options[propName] = value;
|
||||
this._onOptionChange.fire(propName);
|
||||
}
|
||||
}
|
||||
});
|
||||
const setter = (propName: string, value: any): void => {
|
||||
if (!(propName in DEFAULT_OPTIONS)) {
|
||||
throw new Error(`No option with key "${propName}"`);
|
||||
}
|
||||
|
||||
value = this._sanitizeAndValidateOption(propName, value);
|
||||
// Don't fire an option change event if they didn't change
|
||||
if (this.rawOptions[propName] !== value) {
|
||||
this.rawOptions[propName] = value;
|
||||
this._onOptionChange.fire(propName);
|
||||
}
|
||||
};
|
||||
|
||||
for (const propName in this.rawOptions) {
|
||||
const desc = {
|
||||
get: getter.bind(this, propName),
|
||||
set: setter.bind(this, propName)
|
||||
};
|
||||
Object.defineProperty(this.options, propName, desc);
|
||||
}
|
||||
return copiedOptions;
|
||||
}
|
||||
|
||||
public setOption(key: string, value: any): void {
|
||||
|
||||
@@ -188,6 +188,12 @@ export const IOptionsService = createDecorator<IOptionsService>('OptionsService'
|
||||
export interface IOptionsService {
|
||||
serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Read only access to the raw options object, this is an internal-only fast path for accessing
|
||||
* single options without any validation as we trust TypeScript to enforce correct usage
|
||||
* internally.
|
||||
*/
|
||||
readonly rawOptions: Readonly<ITerminalOptions>;
|
||||
readonly options: ITerminalOptions;
|
||||
|
||||
readonly onOptionChange: IEvent<string>;
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
import { deepStrictEqual, strictEqual, throws } from 'assert';
|
||||
import { Terminal } from 'headless/public/Terminal';
|
||||
import { ITerminalOptions } from 'xterm-headless';
|
||||
|
||||
let term: Terminal;
|
||||
|
||||
describe('Headless API Tests', function(): void {
|
||||
describe('Headless API Tests', function (): void {
|
||||
beforeEach(() => {
|
||||
// Create default terminal to be used by most tests
|
||||
term = new Terminal();
|
||||
@@ -119,13 +120,43 @@ describe('Headless API Tests', function(): void {
|
||||
strictEqual(term.getOption('scrollback'), 50);
|
||||
});
|
||||
|
||||
describe('options', () => {
|
||||
const termOptions = {
|
||||
cols: 80,
|
||||
rows: 24
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
term = new Terminal(termOptions);
|
||||
});
|
||||
it('get options', () => {
|
||||
const options: ITerminalOptions = term.options;
|
||||
strictEqual(options.cols, 80);
|
||||
strictEqual(options.rows, 24);
|
||||
});
|
||||
it('set options', async () => {
|
||||
const options: ITerminalOptions = term.options;
|
||||
throws(() => options.cols = 40);
|
||||
throws(() => options.rows = 20);
|
||||
term.options.scrollback = 1;
|
||||
strictEqual(term.options.scrollback, 1);
|
||||
term.options= {
|
||||
fontSize: 12,
|
||||
fontFamily: 'Arial'
|
||||
};
|
||||
strictEqual(term.options.fontSize, 12);
|
||||
strictEqual(term.options.fontFamily, 'Arial');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('loadAddon', () => {
|
||||
it('constructor', async () => {
|
||||
term = new Terminal({ cols: 5 });
|
||||
let cols = 0;
|
||||
term.loadAddon({
|
||||
activate: (t) => cols = t.cols,
|
||||
dispose: () => {}
|
||||
dispose: () => { }
|
||||
});
|
||||
strictEqual(cols, 5);
|
||||
});
|
||||
@@ -133,7 +164,7 @@ describe('Headless API Tests', function(): void {
|
||||
it('dispose (addon)', async () => {
|
||||
let disposeCalled = false;
|
||||
const addon = {
|
||||
activate: () => {},
|
||||
activate: () => { },
|
||||
dispose: () => disposeCalled = true
|
||||
};
|
||||
term.loadAddon(addon);
|
||||
@@ -145,7 +176,7 @@ describe('Headless API Tests', function(): void {
|
||||
it('dispose (terminal)', async () => {
|
||||
let disposeCalled = false;
|
||||
term.loadAddon({
|
||||
activate: () => {},
|
||||
activate: () => { },
|
||||
dispose: () => disposeCalled = true
|
||||
});
|
||||
strictEqual(disposeCalled, false);
|
||||
|
||||
@@ -7,19 +7,61 @@ import { IEvent } from 'common/EventEmitter';
|
||||
import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi';
|
||||
import { ParserApi } from 'common/public/ParserApi';
|
||||
import { UnicodeApi } from 'common/public/UnicodeApi';
|
||||
import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, ITerminalOptions, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless';
|
||||
import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless';
|
||||
import { Terminal as TerminalCore } from 'headless/Terminal';
|
||||
import { AddonManager } from 'common/public/AddonManager';
|
||||
import { ITerminalOptions } from 'common/Types';
|
||||
|
||||
/**
|
||||
* The set of options that only have an effect when set in the Terminal constructor.
|
||||
*/
|
||||
const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows'];
|
||||
|
||||
export class Terminal implements ITerminalApi {
|
||||
private _core: TerminalCore;
|
||||
private _addonManager: AddonManager;
|
||||
private _parser: IParser | undefined;
|
||||
private _buffer: BufferNamespaceApi | undefined;
|
||||
private _publicOptions: ITerminalOptions;
|
||||
|
||||
constructor(options?: ITerminalOptions) {
|
||||
this._core = new TerminalCore(options);
|
||||
this._addonManager = new AddonManager();
|
||||
|
||||
this._publicOptions = { ... this._core.options };
|
||||
const getter = (propName: string): any => {
|
||||
return this._core.options[propName];
|
||||
};
|
||||
const setter = (propName: string, value: any): void => {
|
||||
this._checkReadonlyOptions(propName);
|
||||
this._core.options[propName] = value;
|
||||
};
|
||||
|
||||
for (const propName in this._core.options) {
|
||||
Object.defineProperty(this._publicOptions, propName, {
|
||||
get: () => {
|
||||
return this._core.options[propName];
|
||||
},
|
||||
set: (value: any) => {
|
||||
this._checkReadonlyOptions(propName);
|
||||
this._core.options[propName] = value;
|
||||
}
|
||||
});
|
||||
const desc = {
|
||||
get: getter.bind(this, propName),
|
||||
set: setter.bind(this, propName)
|
||||
};
|
||||
Object.defineProperty(this._publicOptions, propName, desc);
|
||||
}
|
||||
}
|
||||
|
||||
private _checkReadonlyOptions(propName: string): void {
|
||||
// Throw an error if any constructor only option is modified
|
||||
// from terminal.options
|
||||
// Modifications from anywhere else are allowed
|
||||
if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) {
|
||||
throw new Error(`Option "${propName}" can only be set in the constructor`);
|
||||
}
|
||||
}
|
||||
|
||||
private _checkProposedApi(): void {
|
||||
@@ -82,6 +124,14 @@ export class Terminal implements ITerminalApi {
|
||||
wraparoundMode: m.wraparound
|
||||
};
|
||||
}
|
||||
public get options(): ITerminalOptions {
|
||||
return this._publicOptions;
|
||||
}
|
||||
public set options(options: ITerminalOptions) {
|
||||
for (const propName in options) {
|
||||
this._publicOptions[propName] = options[propName];
|
||||
}
|
||||
}
|
||||
public resize(columns: number, rows: number): void {
|
||||
this._verifyIntegers(columns, rows);
|
||||
this._core.resize(columns, rows);
|
||||
|
||||
@@ -189,6 +189,10 @@ describe('API Integration Tests', function(): void {
|
||||
assert.equal(await page.evaluate(`window.term.options.fontSize`), 30);
|
||||
assert.equal(await page.evaluate(`window.term.options.fontFamily`), 'Arial');
|
||||
});
|
||||
it('object.keys return the correct number of options', async () => {
|
||||
await openTerminal(page);
|
||||
assert.notEqual(await page.evaluate(`Object.keys(window.term.options).length`), 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderer', () => {
|
||||
|
||||
Vendored
+23
@@ -534,6 +534,29 @@ declare module 'xterm-headless' {
|
||||
*/
|
||||
readonly modes: IModes;
|
||||
|
||||
/**
|
||||
* Gets or sets the terminal options. This supports setting multiple options.
|
||||
*
|
||||
* @example Get a single option
|
||||
* ```typescript
|
||||
* console.log(terminal.options.fontSize);
|
||||
* ```
|
||||
*
|
||||
* @example Set a single option
|
||||
* ```typescript
|
||||
* terminal.options.fontSize = 12;
|
||||
* ```
|
||||
*
|
||||
* @example Set multiple options
|
||||
* ```typescript
|
||||
* terminal.options = {
|
||||
* fontSize: 12,
|
||||
* fontFamily: 'Arial',
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
options: ITerminalOptions;
|
||||
|
||||
/**
|
||||
* Natural language strings that can be localized.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user