mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge remote-tracking branch 'upstream/master' into pr/jerch/3524
This commit is contained in:
@@ -179,7 +179,7 @@ Xterm.js is used in several world-class applications to provide great terminal e
|
||||
- [**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.
|
||||
- [**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.
|
||||
- [**Tess**](https://github.com/SquitchYT/Tess/): Simple Terminal Fully Customizable for Everyone. Discover more at [tessapp.dev](https://tessapp.dev)
|
||||
- [**HashiCorp Nomad**](https://www.nomadproject.io/): A container orchestrator with the ability to connect to remote tasks via a web interface using websockets and xterm.js.
|
||||
- [**TermPair**](https://github.com/cs01/termpair): View and control terminals from your browser with end-to-end encryption
|
||||
- [**gdbgui**](https://github.com/cs01/gdbgui): Browser-based frontend to gdb (gnu debugger)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"SerializeAddon": ["../src/SerializeAddon"]
|
||||
}
|
||||
},
|
||||
"include": ["../**/*", "../../../typings/xterm.d.ts", "../../../out/**/*"],
|
||||
"include": ["../**/*", "../../../typings/xterm.d.ts"],
|
||||
"exclude": ["../../../**/*test.ts", "../../**/*api.ts"],
|
||||
"references": [
|
||||
{ "path": "../../../src/common" },
|
||||
|
||||
@@ -43,6 +43,7 @@ function handleLink(event: MouseEvent, uri: string): void {
|
||||
interface ILinkProviderOptions {
|
||||
hover?(event: MouseEvent, text: string, location: IViewportRange): void;
|
||||
leave?(event: MouseEvent, text: string): void;
|
||||
urlRegex?: RegExp;
|
||||
}
|
||||
|
||||
export class WebLinksAddon implements ITerminalAddon {
|
||||
@@ -62,7 +63,8 @@ export class WebLinksAddon implements ITerminalAddon {
|
||||
|
||||
if (this._useLinkProvider && 'registerLinkProvider' in this._terminal) {
|
||||
const options = this._options as ILinkProviderOptions;
|
||||
this._linkProvider = this._terminal.registerLinkProvider(new WebLinkProvider(this._terminal, strictUrlRegex, this._handler, options));
|
||||
const regex = options.urlRegex || strictUrlRegex;
|
||||
this._linkProvider = this._terminal.registerLinkProvider(new WebLinkProvider(this._terminal, regex, this._handler, options));
|
||||
} else {
|
||||
// TODO: This should be removed eventually
|
||||
const options = this._options as ILinkMatcherOptions;
|
||||
|
||||
@@ -14,8 +14,8 @@ import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { channels, rgba } from 'browser/Color';
|
||||
import { tryDrawCustomChar } from 'browser/renderer/CustomGlyphs';
|
||||
|
||||
// In practice we're probably never going to exhaust a texture this large. For debugging purposes,
|
||||
// however, it can be useful to set this to a really tiny value, to verify that LRU eviction works.
|
||||
// For debugging purposes, it can be useful to set this to a really tiny value,
|
||||
// to verify that LRU eviction works.
|
||||
const TEXTURE_WIDTH = 1024;
|
||||
const TEXTURE_HEIGHT = 1024;
|
||||
|
||||
@@ -463,7 +463,7 @@ export class WebglCharAtlas implements IDisposable {
|
||||
const clippedImageData = this._clipImageData(imageData, this._workBoundingBox);
|
||||
|
||||
// Check if there is enough room in the current row and go to next if needed
|
||||
if (this._currentRowX + this._config.scaledCharWidth > TEXTURE_WIDTH) {
|
||||
if (this._currentRowX + rasterizedGlyph.size.x > TEXTURE_WIDTH) {
|
||||
this._currentRowX = 0;
|
||||
this._currentRowY += this._currentRowHeight;
|
||||
this._currentRowHeight = 0;
|
||||
|
||||
+2
-1
@@ -133,7 +133,8 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
.xterm.xterm-cursor-pointer,
|
||||
.xterm .xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ export class AccessibilityManager extends Disposable {
|
||||
this._accessibilityTreeRoot = document.createElement('div');
|
||||
this._accessibilityTreeRoot.setAttribute('role', 'document');
|
||||
this._accessibilityTreeRoot.classList.add('xterm-accessibility');
|
||||
this._accessibilityTreeRoot.tabIndex = 0;
|
||||
|
||||
this._rowContainer = document.createElement('div');
|
||||
this._rowContainer.setAttribute('role', 'list');
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IBufferService, IUnicodeService } from 'common/services/Services';
|
||||
import { Linkifier } from 'browser/Linkifier';
|
||||
import { MockLogService, MockUnicodeService } from 'common/TestUtils.test';
|
||||
import { IRegisteredLinkMatcher, IMouseZoneManager, IMouseZone } from 'browser/Types';
|
||||
import { IMarker } from 'common/Types';
|
||||
import { IMarker, ITerminalOptions } from 'common/Types';
|
||||
|
||||
const INIT_COLS = 80;
|
||||
const INIT_ROWS = 24;
|
||||
@@ -1501,6 +1501,22 @@ describe('Terminal', () => {
|
||||
assert.deepEqual(markers.map(el => el.line), [-1, -1, 0, 1, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('options', () => {
|
||||
beforeEach(async () => {
|
||||
term = new TestTerminal({});
|
||||
});
|
||||
it('get options', () => {
|
||||
assert.equal(term.options.cols, 80);
|
||||
assert.equal(term.options.rows, 24);
|
||||
});
|
||||
it('set options', async () => {
|
||||
term.options.cols = 40;
|
||||
assert.equal(term.options.cols, 40);
|
||||
term.options.rows = 20;
|
||||
assert.equal(term.options.rows, 20);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class TestLinkifier extends Linkifier {
|
||||
|
||||
+11
-7
@@ -39,7 +39,7 @@ import { MouseZoneManager } from 'browser/MouseZoneManager';
|
||||
import { AccessibilityManager } from './AccessibilityManager';
|
||||
import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider } from 'xterm';
|
||||
import { DomRenderer } from 'browser/renderer/dom/DomRenderer';
|
||||
import { IKeyboardEvent, KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, ScrollSource, IColorEvent, ColorIndex, ColorRequestType } from 'common/Types';
|
||||
import { KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, ScrollSource, IColorEvent, ColorIndex, ColorRequestType } from 'common/Types';
|
||||
import { evaluateKeyboardEvent } from 'common/input/Keyboard';
|
||||
import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter';
|
||||
import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
|
||||
@@ -52,7 +52,6 @@ import { MouseService } from 'browser/services/MouseService';
|
||||
import { Linkifier2 } from 'browser/Linkifier2';
|
||||
import { CoreBrowserService } from 'browser/services/CoreBrowserService';
|
||||
import { CoreTerminal } from 'common/CoreTerminal';
|
||||
import { ITerminalOptions as IInitializedTerminalOptions } from 'common/services/Services';
|
||||
import { color, rgba } from 'browser/Color';
|
||||
import { CharacterJoinerService } from 'browser/services/CharacterJoinerService';
|
||||
import { toRgbString } from 'common/input/XParseColor';
|
||||
@@ -75,9 +74,6 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
|
||||
public browser: IBrowser = Browser as any;
|
||||
|
||||
// TODO: We should remove options once components adopt optionsService
|
||||
public get options(): IInitializedTerminalOptions { return this.optionsService.options; }
|
||||
|
||||
private _customKeyEventHandler: CustomKeyEventHandler | undefined;
|
||||
|
||||
// browser services
|
||||
@@ -576,7 +572,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
this.register(this._mouseZoneManager);
|
||||
this.register(this.onScroll(() => this._mouseZoneManager!.clearAll()));
|
||||
this.linkifier.attachToDom(this.element, this._mouseZoneManager);
|
||||
this.linkifier2.attachToDom(this.element, this._mouseService, this._renderService);
|
||||
this.linkifier2.attachToDom(this.screenElement, this._mouseService, this._renderService);
|
||||
|
||||
// This event listener must be registered aftre MouseZoneManager is created
|
||||
this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.onMouseDown(e)));
|
||||
@@ -1208,6 +1204,10 @@ export class Terminal extends CoreTerminal implements ITerminal {
|
||||
|
||||
this._keyPressHandled = true;
|
||||
|
||||
// The key was handled so clear the dead key state, otherwise certain keystrokes like arrow
|
||||
// keys could be ignored
|
||||
this._unprocessedDeadKey = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1220,11 +1220,15 @@ 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' && !this.optionsService.options.screenReaderMode) {
|
||||
if (ev.data && ev.inputType === 'insertText' && !ev.composed && !this.optionsService.options.screenReaderMode) {
|
||||
if (this._keyPressHandled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The key was handled so clear the dead key state, otherwise certain keystrokes like arrow
|
||||
// keys could be ignored
|
||||
this._unprocessedDeadKey = false;
|
||||
|
||||
const text = ev.data;
|
||||
this.coreService.triggerDataEvent(text, true);
|
||||
|
||||
|
||||
Vendored
-1
@@ -16,7 +16,6 @@ export interface ITerminal extends IPublicTerminal, ICoreTerminal {
|
||||
browser: IBrowser;
|
||||
buffer: IBuffer;
|
||||
viewport: IViewport | undefined;
|
||||
// TODO: We should remove options once components adopt optionsService
|
||||
options: ITerminalOptions;
|
||||
linkifier: ILinkifier;
|
||||
linkifier2: ILinkifier2;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, FontWeight, IModes } from 'xterm';
|
||||
import { Terminal as ITerminalApi, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, FontWeight, IModes } from 'xterm';
|
||||
import { ITerminal } from 'browser/Types';
|
||||
import { Terminal as TerminalCore } from 'browser/Terminal';
|
||||
import * as Strings from 'browser/LocalizableStrings';
|
||||
@@ -12,16 +12,45 @@ import { ParserApi } from 'common/public/ParserApi';
|
||||
import { UnicodeApi } from 'common/public/UnicodeApi';
|
||||
import { AddonManager } from 'common/public/AddonManager';
|
||||
import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi';
|
||||
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: ITerminal;
|
||||
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 = {};
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -90,7 +119,12 @@ export class Terminal implements ITerminalApi {
|
||||
};
|
||||
}
|
||||
public get options(): ITerminalOptions {
|
||||
return this._core.options;
|
||||
return this._publicOptions;
|
||||
}
|
||||
public set options(options: ITerminalOptions) {
|
||||
for (const propName in options) {
|
||||
this._publicOptions[propName] = options[propName];
|
||||
}
|
||||
}
|
||||
public blur(): void {
|
||||
this._core.blur();
|
||||
@@ -216,6 +250,7 @@ export class Terminal implements ITerminalApi {
|
||||
public setOption(key: 'cols' | 'rows', value: number): void;
|
||||
public setOption(key: string, value: any): void;
|
||||
public setOption(key: any, value: any): void {
|
||||
this._checkReadonlyOptions(key);
|
||||
this._core.optionsService.setOption(key, value);
|
||||
}
|
||||
public refresh(start: number, end: number): void {
|
||||
|
||||
@@ -16,7 +16,7 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number
|
||||
cursor: undefined,
|
||||
cursorAccent: undefined,
|
||||
selection: undefined,
|
||||
ansi: colors.ansi
|
||||
ansi: [...colors.ansi]
|
||||
};
|
||||
return {
|
||||
devicePixelRatio: window.devicePixelRatio,
|
||||
|
||||
@@ -122,5 +122,13 @@ describe('SelectionModel', () => {
|
||||
model.selectionEnd = [5, 2];
|
||||
assert.deepEqual(model.finalSelectionEnd, [5, 2]);
|
||||
});
|
||||
it('should not include a trailing EOL when the selection ends at the end of a line', () => {
|
||||
model.selectionStart = [0, 0];
|
||||
model.selectionStartLength = 80;
|
||||
assert.deepEqual(model.finalSelectionEnd, [80, 0]);
|
||||
model.selectionStart = [0, 0];
|
||||
model.selectionStartLength = 160;
|
||||
assert.deepEqual(model.finalSelectionEnd, [80, 1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,6 +79,10 @@ export class SelectionModel {
|
||||
if (!this.selectionEnd || this.areSelectionValuesReversed()) {
|
||||
const startPlusLength = this.selectionStart[0] + this.selectionStartLength;
|
||||
if (startPlusLength > this._bufferService.cols) {
|
||||
// Ensure the trailing EOL isn't included when the selection ends on the right edge
|
||||
if (startPlusLength % this._bufferService.cols === 0) {
|
||||
return [this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols) - 1];
|
||||
}
|
||||
return [startPlusLength % this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols)];
|
||||
}
|
||||
return [startPlusLength, this.selectionStart[1]];
|
||||
|
||||
@@ -176,16 +176,25 @@ export class CharacterJoinerService implements ICharacterJoinerService {
|
||||
// At this point we already know that there is at least one joiner so
|
||||
// we can just pull its value and assign it directly rather than
|
||||
// merging it into an empty array, which incurs unnecessary writes.
|
||||
const joinedRanges: [number, number][] = this._characterJoiners[0].handler(text);
|
||||
let allJoinedRanges: [number, number][] = [];
|
||||
try {
|
||||
allJoinedRanges = this._characterJoiners[0].handler(text);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
for (let i = 1; i < this._characterJoiners.length; i++) {
|
||||
// We merge any overlapping ranges across the different joiners
|
||||
const joinerRanges = this._characterJoiners[i].handler(text);
|
||||
for (let j = 0; j < joinerRanges.length; j++) {
|
||||
CharacterJoinerService._mergeRanges(joinedRanges, joinerRanges[j]);
|
||||
try {
|
||||
const joinerRanges = this._characterJoiners[i].handler(text);
|
||||
for (let j = 0; j < joinerRanges.length; j++) {
|
||||
CharacterJoinerService._mergeRanges(allJoinedRanges, joinerRanges[j]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
this._stringRangesToCellRanges(joinedRanges, lineData, startCol);
|
||||
return joinedRanges;
|
||||
this._stringRangesToCellRanges(allJoinedRanges, lineData, startCol);
|
||||
return allJoinedRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
*/
|
||||
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, ICoreMouseService, IUnicodeService, IDirtyRowService, LogLevelEnum } from 'common/services/Services';
|
||||
import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, ICoreMouseService, IUnicodeService, IDirtyRowService, LogLevelEnum, ITerminalOptions } from 'common/services/Services';
|
||||
import { InstantiationService } from 'common/services/InstantiationService';
|
||||
import { LogService } from 'common/services/LogService';
|
||||
import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService';
|
||||
import { OptionsService } from 'common/services/OptionsService';
|
||||
import { ITerminalOptions, IDisposable, IBufferLine, IAttributeData, ICoreTerminal, IKeyboardEvent, IScrollEvent, ScrollSource } from 'common/Types';
|
||||
import { IDisposable, IBufferLine, IAttributeData, ICoreTerminal, IKeyboardEvent, IScrollEvent, ScrollSource, ITerminalOptions as IPublicTerminalOptions } from 'common/Types';
|
||||
import { CoreService } from 'common/services/CoreService';
|
||||
import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter';
|
||||
import { CoreMouseService } from 'common/services/CoreMouseService';
|
||||
@@ -86,7 +86,12 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
|
||||
public get cols(): number { return this._bufferService.cols; }
|
||||
public get rows(): number { return this._bufferService.rows; }
|
||||
public get buffers(): IBufferSet { return this._bufferService.buffers; }
|
||||
public get options(): ITerminalOptions { return this.optionsService.publicOptions; }
|
||||
public get options(): ITerminalOptions { return this.optionsService.options; }
|
||||
public set options(options: ITerminalOptions) {
|
||||
for (const key in options) {
|
||||
this.optionsService.options[key] = options[key];
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
options: Partial<ITerminalOptions>
|
||||
|
||||
@@ -385,6 +385,56 @@ describe('InputHandler', () => {
|
||||
assert.equal(bufferService.buffer.lines.get(2)!.translateToString(false), Array(bufferService.cols + 1).join(' '));
|
||||
|
||||
});
|
||||
it('eraseInLine reflow', async () => {
|
||||
const bufferService = new MockBufferService(80, 30);
|
||||
const inputHandler = new TestInputHandler(
|
||||
bufferService,
|
||||
new MockCharsetService(),
|
||||
new MockCoreService(),
|
||||
new MockDirtyRowService(),
|
||||
new MockLogService(),
|
||||
new MockOptionsService(),
|
||||
new MockCoreMouseService(),
|
||||
new MockUnicodeService()
|
||||
);
|
||||
|
||||
const resetToBaseState = async (): Promise<void> => {
|
||||
// reset and add a wrapped line
|
||||
bufferService.buffer.y = 0;
|
||||
bufferService.buffer.x = 0;
|
||||
await inputHandler.parseP(Array(bufferService.cols + 1).join('a')); // line 0
|
||||
await inputHandler.parseP(Array(bufferService.cols + 10).join('a')); // line 1 and 2
|
||||
for (let i = 3; i < bufferService.rows; ++i) await inputHandler.parseP(Array(bufferService.cols + 1).join('a'));
|
||||
|
||||
// confirm precondition that line 2 is wrapped
|
||||
assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, true);
|
||||
};
|
||||
|
||||
// params[0] - erase from the cursor through the end of the row.
|
||||
await resetToBaseState();
|
||||
bufferService.buffer.y = 2;
|
||||
bufferService.buffer.x = 40;
|
||||
inputHandler.eraseInLine(Params.fromArray([0]));
|
||||
assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, true);
|
||||
bufferService.buffer.y = 2;
|
||||
bufferService.buffer.x = 0;
|
||||
inputHandler.eraseInLine(Params.fromArray([0]));
|
||||
assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, false);
|
||||
|
||||
// params[1] - erase from the beginning of the line through the cursor
|
||||
await resetToBaseState();
|
||||
bufferService.buffer.y = 2;
|
||||
bufferService.buffer.x = 40;
|
||||
inputHandler.eraseInLine(Params.fromArray([1]));
|
||||
assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, true);
|
||||
|
||||
// params[2] - erase complete line
|
||||
await resetToBaseState();
|
||||
bufferService.buffer.y = 2;
|
||||
bufferService.buffer.x = 40;
|
||||
inputHandler.eraseInLine(Params.fromArray([2]));
|
||||
assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, false);
|
||||
});
|
||||
it('eraseInDisplay', async () => {
|
||||
const bufferService = new MockBufferService(80, 7);
|
||||
const inputHandler = new TestInputHandler(
|
||||
|
||||
@@ -1202,6 +1202,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* @param y row index
|
||||
* @param start first cell index to be erased
|
||||
* @param end end - 1 is last erased cell
|
||||
* @param cleanWrap clear the isWrapped flag
|
||||
*/
|
||||
private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false): void {
|
||||
const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!;
|
||||
@@ -1327,13 +1328,13 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._restrictCursor(this._bufferService.cols);
|
||||
switch (params.params[0]) {
|
||||
case 0:
|
||||
this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols);
|
||||
this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0);
|
||||
break;
|
||||
case 1:
|
||||
this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1);
|
||||
this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1, false);
|
||||
break;
|
||||
case 2:
|
||||
this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols);
|
||||
this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols, true);
|
||||
break;
|
||||
}
|
||||
this._dirtyRowService.markDirty(this._activeBuffer.y);
|
||||
|
||||
@@ -121,16 +121,19 @@ export class MockLogService implements ILogService {
|
||||
export class MockOptionsService implements IOptionsService {
|
||||
public serviceBrand: any;
|
||||
public options: ITerminalOptions = clone(DEFAULT_OPTIONS);
|
||||
public publicOptions: ITerminalOptions = clone(DEFAULT_OPTIONS);
|
||||
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.publicOptions[key] = testOptions[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
public setOptions(options: ITerminalOptions): void {
|
||||
for (const key of Object.keys(options)) {
|
||||
this.options[key] = options[key];
|
||||
}
|
||||
}
|
||||
public setOption<T>(key: string, value: T): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -46,6 +46,7 @@ export interface IKeyboardEvent {
|
||||
ctrlKey: boolean;
|
||||
shiftKey: boolean;
|
||||
metaKey: boolean;
|
||||
/** @deprecated See KeyboardEvent.keyCode */
|
||||
keyCode: number;
|
||||
key: string;
|
||||
type: string;
|
||||
|
||||
@@ -57,17 +57,11 @@ export const DEFAULT_OPTIONS: Readonly<ITerminalOptions> = {
|
||||
|
||||
const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
|
||||
|
||||
/**
|
||||
* The set of options that only have an effect when set in the Terminal constructor.
|
||||
*/
|
||||
const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows'];
|
||||
|
||||
export class OptionsService implements IOptionsService {
|
||||
public serviceBrand: any;
|
||||
|
||||
private _options: ITerminalOptions;
|
||||
public options: ITerminalOptions;
|
||||
public publicOptions: ITerminalOptions;
|
||||
|
||||
private _onOptionChange = new EventEmitter<string>();
|
||||
public get onOptionChange(): IEvent<string> { return this._onOptionChange.event; }
|
||||
@@ -87,11 +81,10 @@ export class OptionsService implements IOptionsService {
|
||||
}
|
||||
|
||||
// set up getters and setters for each option
|
||||
this.options = this._setupOptions(this._options, false);
|
||||
this.publicOptions = this._setupOptions(this._options, true);
|
||||
this.options = this._setupOptions(this._options);
|
||||
}
|
||||
|
||||
private _setupOptions(options: ITerminalOptions, isPublic: boolean): ITerminalOptions {
|
||||
private _setupOptions(options: ITerminalOptions): ITerminalOptions {
|
||||
const copiedOptions = { ... options };
|
||||
for (const propName in copiedOptions) {
|
||||
Object.defineProperty(copiedOptions, propName, {
|
||||
@@ -106,13 +99,6 @@ export class OptionsService implements IOptionsService {
|
||||
throw new Error(`No option with key "${propName}"`);
|
||||
}
|
||||
|
||||
// Throw an error if any constructor only option is modified
|
||||
// from terminal.options
|
||||
// Modifications from anywhere else are allowed
|
||||
if (isPublic && CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) {
|
||||
throw new Error(`Option "${propName}" can only be set in the constructor`);
|
||||
}
|
||||
|
||||
value = this._sanitizeAndValidateOption(propName, value);
|
||||
// Don't fire an option change event if they didn't change
|
||||
if (this._options[propName] !== value) {
|
||||
@@ -126,7 +112,7 @@ export class OptionsService implements IOptionsService {
|
||||
}
|
||||
|
||||
public setOption(key: string, value: any): void {
|
||||
this.publicOptions[key] = value;
|
||||
this.options[key] = value;
|
||||
}
|
||||
|
||||
private _sanitizeAndValidateOption(key: string, value: any): any {
|
||||
@@ -181,6 +167,6 @@ export class OptionsService implements IOptionsService {
|
||||
}
|
||||
|
||||
public getOption(key: string): any {
|
||||
return this.publicOptions[key];
|
||||
return this.options[key];
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user