Merge branch 'master' into merogge/pixelPerfect

This commit is contained in:
Daniel Imms
2021-08-17 07:15:03 -07:00
committed by GitHub
20 changed files with 1759 additions and 1355 deletions
+23 -24
View File
@@ -267,8 +267,8 @@ export class Terminal extends CoreTerminal implements ITerminal {
* Binds the desired focus behavior on a given terminal object.
*/
private _onTextAreaFocus(ev: KeyboardEvent): void {
if (this._coreService.decPrivateModes.sendFocus) {
this._coreService.triggerDataEvent(C0.ESC + '[I');
if (this.coreService.decPrivateModes.sendFocus) {
this.coreService.triggerDataEvent(C0.ESC + '[I');
}
this.updateCursorStyle(ev);
this.element!.classList.add('focus');
@@ -292,8 +292,8 @@ export class Terminal extends CoreTerminal implements ITerminal {
// screen readers reading it out.
this.textarea!.value = '';
this.refresh(this.buffer.y, this.buffer.y);
if (this._coreService.decPrivateModes.sendFocus) {
this._coreService.triggerDataEvent(C0.ESC + '[O');
if (this.coreService.decPrivateModes.sendFocus) {
this.coreService.triggerDataEvent(C0.ESC + '[O');
}
this.element!.classList.remove('focus');
this._onBlur.fire();
@@ -340,7 +340,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
copyHandler(event, this._selectionService!);
}));
const pasteHandlerWrapper = (event: ClipboardEvent): void => handlePasteEvent(event, this.textarea!, this._coreService);
const pasteHandlerWrapper = (event: ClipboardEvent): void => handlePasteEvent(event, this.textarea!, this.coreService);
this.register(addDisposableDomListener(this.textarea!, 'paste', pasteHandlerWrapper));
this.register(addDisposableDomListener(this.element!, 'paste', pasteHandlerWrapper));
@@ -408,7 +408,6 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.element.classList.add('terminal');
this.element.classList.add('xterm');
this.element.setAttribute('tabindex', '0');
this.element.setAttribute('role', 'document');
parent.appendChild(this.element);
// Performance: Use a document fragment to build the terminal
@@ -526,7 +525,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.onMouseDown(e)));
// apply mouse event classes set by escape codes before terminal was attached
if (this._coreMouseService.areMouseEventsActive) {
if (this.coreMouseService.areMouseEventsActive) {
this._selectionService.disable();
this.element.classList.add('enable-mouse-events');
} else {
@@ -644,7 +643,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
return false;
}
return self._coreMouseService.triggerMouseEvent({
return self.coreMouseService.triggerMouseEvent({
col: pos.x - 33, // FIXME: why -33 here?
row: pos.y - 33,
button: but,
@@ -699,11 +698,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
}
};
this.register(this._coreMouseService.onProtocolChange(events => {
this.register(this.coreMouseService.onProtocolChange(events => {
// apply global changes on events
if (events) {
if (this.optionsService.options.logLevel === 'debug') {
this._logService.debug('Binding to mouse events:', this._coreMouseService.explainEvents(events));
this._logService.debug('Binding to mouse events:', this.coreMouseService.explainEvents(events));
}
this.element!.classList.add('enable-mouse-events');
this._selectionService!.disable();
@@ -746,7 +745,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
}));
// force initial onProtocolChange so we dont miss early mouse requests
this._coreMouseService.activeProtocol = this._coreMouseService.activeProtocol;
this.coreMouseService.activeProtocol = this.coreMouseService.activeProtocol;
/**
* "Always on" event listeners.
@@ -758,7 +757,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
// Don't send the mouse button to the pty if mouse events are disabled or
// if the selection manager is having selection forced (ie. a modifier is
// held).
if (!this._coreMouseService.areMouseEventsActive || this._selectionService!.shouldForceSelection(ev)) {
if (!this.coreMouseService.areMouseEventsActive || this._selectionService!.shouldForceSelection(ev)) {
return;
}
@@ -791,12 +790,12 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
// Construct and send sequences
const sequence = C0.ESC + (this._coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B');
const sequence = C0.ESC + (this.coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B');
let data = '';
for (let i = 0; i < Math.abs(amount); i++) {
data += sequence;
}
this._coreService.triggerDataEvent(data, true);
this.coreService.triggerDataEvent(data, true);
}
return;
}
@@ -812,13 +811,13 @@ export class Terminal extends CoreTerminal implements ITerminal {
}, { passive: false }));
this.register(addDisposableDomListener(el, 'touchstart', (ev: TouchEvent) => {
if (this._coreMouseService.areMouseEventsActive) return;
if (this.coreMouseService.areMouseEventsActive) return;
this.viewport!.onTouchStart(ev);
return this.cancel(ev);
}, { passive: true }));
this.register(addDisposableDomListener(el, 'touchmove', (ev: TouchEvent) => {
if (this._coreMouseService.areMouseEventsActive) return;
if (this.coreMouseService.areMouseEventsActive) return;
if (!this.viewport!.onTouchMove(ev)) {
return this.cancel(ev);
}
@@ -860,8 +859,8 @@ export class Terminal extends CoreTerminal implements ITerminal {
* Display the cursor element
*/
private _showCursor(): void {
if (!this._coreService.isCursorInitialized) {
this._coreService.isCursorInitialized = true;
if (!this.coreService.isCursorInitialized) {
this.coreService.isCursorInitialized = true;
this.refresh(this.buffer.y, this.buffer.y);
}
}
@@ -872,7 +871,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
public paste(data: string): void {
paste(data, this.textarea!, this._coreService);
paste(data, this.textarea!, this.coreService);
}
/**
@@ -1025,7 +1024,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
return false;
}
const result = evaluateKeyboardEvent(event, this._coreService.decPrivateModes.applicationCursorKeys, this.browser.isMac, this.options.macOptionIsMeta);
const result = evaluateKeyboardEvent(event, this.coreService.decPrivateModes.applicationCursorKeys, this.browser.isMac, this.options.macOptionIsMeta);
this.updateCursorStyle(event);
@@ -1061,7 +1060,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._onKey.fire({ key: result.key, domEvent: event });
this._showCursor();
this._coreService.triggerDataEvent(result.key, true);
this.coreService.triggerDataEvent(result.key, true);
// Cancel events when not in screen reader mode so events don't get bubbled up and handled by
// other listeners. When screen reader mode is enabled, this could cause issues if the event
@@ -1138,7 +1137,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._onKey.fire({ key, domEvent: ev });
this._showCursor();
this._coreService.triggerDataEvent(key, true);
this.coreService.triggerDataEvent(key, true);
return true;
}
@@ -1247,12 +1246,12 @@ export class Terminal extends CoreTerminal implements ITerminal {
case WindowsOptionsReportType.GET_WIN_SIZE_PIXELS:
const canvasWidth = this._renderService.dimensions.scaledCanvasWidth.toFixed(0);
const canvasHeight = this._renderService.dimensions.scaledCanvasHeight.toFixed(0);
this._coreService.triggerDataEvent(`${C0.ESC}[4;${canvasHeight};${canvasWidth}t`);
this.coreService.triggerDataEvent(`${C0.ESC}[4;${canvasHeight};${canvasWidth}t`);
break;
case WindowsOptionsReportType.GET_CELL_SIZE_PIXELS:
const cellWidth = this._renderService.dimensions.scaledCellWidth.toFixed(0);
const cellHeight = this._renderService.dimensions.scaledCellHeight.toFixed(0);
this._coreService.triggerDataEvent(`${C0.ESC}[6;${cellHeight};${cellWidth}t`);
this.coreService.triggerDataEvent(`${C0.ESC}[6;${cellHeight};${cellWidth}t`);
break;
}
}
+3 -1
View File
@@ -13,7 +13,7 @@ import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, I
import { Buffer } from 'common/buffer/Buffer';
import * as Browser from 'common/Platform';
import { Terminal } from 'browser/Terminal';
import { IUnicodeService, IOptionsService } from 'common/services/Services';
import { IUnicodeService, IOptionsService, ICoreService, ICoreMouseService } from 'common/services/Services';
import { IFunctionIdentifier, IParams } from 'common/parser/Types';
import { AttributeData } from 'common/buffer/AttributeData';
@@ -43,6 +43,8 @@ export class MockTerminal implements ITerminal {
public onRender!: IEvent<{ start: number, end: number }>;
public onResize!: IEvent<{ cols: number, rows: number }>;
public markers!: IMarker[];
public coreMouseService!: ICoreMouseService;
public coreService!: ICoreService;
public optionsService!: IOptionsService;
public unicodeService!: IUnicodeService;
public addMarker(cursorYOffset: number): IMarker {
+22 -1
View File
@@ -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 } from 'xterm';
import { Terminal as ITerminalApi, ITerminalOptions, 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';
@@ -68,6 +68,27 @@ export class Terminal implements ITerminalApi {
this._checkProposedApi();
return this._core.markers;
}
public get modes(): IModes {
const m = this._core.coreService.decPrivateModes;
let mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any' = 'none';
switch (this._core.coreMouseService.activeProtocol) {
case 'X10': mouseTrackingMode = 'x10'; break;
case 'VT200': mouseTrackingMode = 'vt200'; break;
case 'DRAG': mouseTrackingMode = 'drag'; break;
case 'ANY': mouseTrackingMode = 'any'; break;
}
return {
applicationCursorKeysMode: m.applicationCursorKeys,
applicationKeypadMode: m.applicationKeypad,
bracketedPasteMode: m.bracketedPasteMode,
insertMode: this._core.coreService.modes.insertMode,
mouseTrackingMode: mouseTrackingMode,
originMode: m.origin,
reverseWraparoundMode: m.reverseWraparound,
sendFocusMode: m.sendFocus,
wraparoundMode: m.wraparound
};
}
public blur(): void {
this._core.blur();
}
+11 -11
View File
@@ -47,11 +47,11 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
protected readonly _instantiationService: IInstantiationService;
protected readonly _bufferService: IBufferService;
protected readonly _logService: ILogService;
protected readonly _coreService: ICoreService;
protected readonly _charsetService: ICharsetService;
protected readonly _coreMouseService: ICoreMouseService;
protected readonly _dirtyRowService: IDirtyRowService;
public readonly coreMouseService: ICoreMouseService;
public readonly coreService: ICoreService;
public readonly unicodeService: IUnicodeService;
public readonly optionsService: IOptionsService;
@@ -100,10 +100,10 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
this._instantiationService.setService(IBufferService, this._bufferService);
this._logService = this._instantiationService.createInstance(LogService);
this._instantiationService.setService(ILogService, this._logService);
this._coreService = this.register(this._instantiationService.createInstance(CoreService, () => this.scrollToBottom()));
this._instantiationService.setService(ICoreService, this._coreService);
this._coreMouseService = this._instantiationService.createInstance(CoreMouseService);
this._instantiationService.setService(ICoreMouseService, this._coreMouseService);
this.coreService = this.register(this._instantiationService.createInstance(CoreService, () => this.scrollToBottom()));
this._instantiationService.setService(ICoreService, this.coreService);
this.coreMouseService = this._instantiationService.createInstance(CoreMouseService);
this._instantiationService.setService(ICoreMouseService, this.coreMouseService);
this._dirtyRowService = this._instantiationService.createInstance(DirtyRowService);
this._instantiationService.setService(IDirtyRowService, this._dirtyRowService);
this.unicodeService = this._instantiationService.createInstance(UnicodeService);
@@ -112,14 +112,14 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
this._instantiationService.setService(ICharsetService, this._charsetService);
// Register input handler and handle/forward events
this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this._coreService, this._dirtyRowService, this._logService, this.optionsService, this._coreMouseService, this.unicodeService);
this._inputHandler = new InputHandler(this._bufferService, this._charsetService, this.coreService, this._dirtyRowService, this._logService, this.optionsService, this.coreMouseService, this.unicodeService);
this.register(forwardEvent(this._inputHandler.onLineFeed, this._onLineFeed));
this.register(this._inputHandler);
// Setup listeners
this.register(forwardEvent(this._bufferService.onResize, this._onResize));
this.register(forwardEvent(this._coreService.onData, this._onData));
this.register(forwardEvent(this._coreService.onBinary, this._onBinary));
this.register(forwardEvent(this.coreService.onData, this._onData));
this.register(forwardEvent(this.coreService.onBinary, this._onBinary));
this.register(this.optionsService.onOptionChange(key => this._updateOptions(key)));
this.register(this._bufferService.onScroll(event => {
this._onScroll.fire({ position: this._bufferService.buffer.ydisp, source: ScrollSource.TERMINAL });
@@ -250,8 +250,8 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
this._inputHandler.reset();
this._bufferService.reset();
this._charsetService.reset();
this._coreService.reset();
this._coreMouseService.reset();
this.coreService.reset();
this.coreMouseService.reset();
}
protected _updateOptions(key: string): void {
+3 -1
View File
@@ -7,10 +7,12 @@ import { IFunctionIdentifier, ITerminalOptions as IPublicTerminalOptions } from
import { IEvent, IEventEmitter } from 'common/EventEmitter';
import { IDeleteEvent, IInsertEvent } from 'common/CircularList';
import { IParams } from 'common/parser/Types';
import { IOptionsService, IUnicodeService } from 'common/services/Services';
import { ICoreMouseService, ICoreService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferSet } from 'common/buffer/Types';
export interface ICoreTerminal {
coreMouseService: ICoreMouseService;
coreService: ICoreService;
optionsService: IOptionsService;
unicodeService: IUnicodeService;
buffers: IBufferSet;
+82
View File
@@ -367,6 +367,88 @@ describe('Headless API Tests', function(): void {
});
});
describe('modes', () => {
it('defaults', () => {
deepStrictEqual(term.modes, {
applicationCursorKeysMode: false,
applicationKeypadMode: false,
bracketedPasteMode: false,
insertMode: false,
mouseTrackingMode: 'none',
originMode: false,
reverseWraparoundMode: false,
sendFocusMode: false,
wraparoundMode: true
});
});
it('applicationCursorKeysMode', async () => {
await writeSync('\x1b[?1h');
strictEqual(term.modes.applicationCursorKeysMode, true);
await writeSync('\x1b[?1l');
strictEqual(term.modes.applicationCursorKeysMode, false);
});
it('applicationKeypadMode', async () => {
await writeSync('\x1b[?66h');
strictEqual(term.modes.applicationKeypadMode, true);
await writeSync('\x1b[?66l');
strictEqual(term.modes.applicationKeypadMode, false);
});
it('bracketedPasteMode', async () => {
await writeSync('\x1b[?2004h');
strictEqual(term.modes.bracketedPasteMode, true);
await writeSync('\x1b[?2004l');
strictEqual(term.modes.bracketedPasteMode, false);
});
it('insertMode', async () => {
await writeSync('\x1b[4h');
strictEqual(term.modes.insertMode, true);
await writeSync('\x1b[4l');
strictEqual(term.modes.insertMode, false);
});
it('mouseTrackingMode', async () => {
await writeSync('\x1b[?9h');
strictEqual(term.modes.mouseTrackingMode, 'x10');
await writeSync('\x1b[?9l');
strictEqual(term.modes.mouseTrackingMode, 'none');
await writeSync('\x1b[?1000h');
strictEqual(term.modes.mouseTrackingMode, 'vt200');
await writeSync('\x1b[?1000l');
strictEqual(term.modes.mouseTrackingMode, 'none');
await writeSync('\x1b[?1002h');
strictEqual(term.modes.mouseTrackingMode, 'drag');
await writeSync('\x1b[?1002l');
strictEqual(term.modes.mouseTrackingMode, 'none');
await writeSync('\x1b[?1003h');
strictEqual(term.modes.mouseTrackingMode, 'any');
await writeSync('\x1b[?1003l');
strictEqual(term.modes.mouseTrackingMode, 'none');
});
it('originMode', async () => {
await writeSync('\x1b[?6h');
strictEqual(term.modes.originMode, true);
await writeSync('\x1b[?6l');
strictEqual(term.modes.originMode, false);
});
it('reverseWraparoundMode', async () => {
await writeSync('\x1b[?45h');
strictEqual(term.modes.reverseWraparoundMode, true);
await writeSync('\x1b[?45l');
strictEqual(term.modes.reverseWraparoundMode, false);
});
it('sendFocusMode', async () => {
await writeSync('\x1b[?1004h');
strictEqual(term.modes.sendFocusMode, true);
await writeSync('\x1b[?1004l');
strictEqual(term.modes.sendFocusMode, false);
});
it('wraparoundMode', async () => {
await writeSync('\x1b[?7h');
strictEqual(term.modes.wraparoundMode, true);
await writeSync('\x1b[?7l');
strictEqual(term.modes.wraparoundMode, false);
});
});
it('dispose', async () => {
term.dispose();
strictEqual((term as any)._core._isDisposed, true);
+22 -1
View File
@@ -7,7 +7,7 @@ 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, IParser, ITerminalAddon, ITerminalOptions, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless';
import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, ITerminalOptions, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless';
import { Terminal as TerminalCore } from 'headless/Terminal';
import { AddonManager } from 'common/public/AddonManager';
@@ -61,6 +61,27 @@ export class Terminal implements ITerminalApi {
this._checkProposedApi();
return this._core.markers;
}
public get modes(): IModes {
const m = this._core.coreService.decPrivateModes;
let mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any' = 'none';
switch (this._core.coreMouseService.activeProtocol) {
case 'X10': mouseTrackingMode = 'x10'; break;
case 'VT200': mouseTrackingMode = 'vt200'; break;
case 'DRAG': mouseTrackingMode = 'drag'; break;
case 'ANY': mouseTrackingMode = 'any'; break;
}
return {
applicationCursorKeysMode: m.applicationCursorKeys,
applicationKeypadMode: m.applicationKeypad,
bracketedPasteMode: m.bracketedPasteMode,
insertMode: this._core.coreService.modes.insertMode,
mouseTrackingMode: mouseTrackingMode,
originMode: m.origin,
reverseWraparoundMode: m.reverseWraparound,
sendFocusMode: m.sendFocus,
wraparoundMode: m.wraparound
};
}
public resize(columns: number, rows: number): void {
this._verifyIntegers(columns, rows);
this._core.resize(columns, rows);