mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
add addEscHandler
This commit is contained in:
@@ -476,6 +476,13 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._dirtyRowService.markDirty(buffer.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addEscHandler from parser.
|
||||
*/
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._parser.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward addCsiHandler from parser.
|
||||
*/
|
||||
|
||||
@@ -1392,6 +1392,11 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
|
||||
this._customKeyEventHandler = customKeyEventHandler;
|
||||
}
|
||||
|
||||
/** Add handler for ESC escape sequence. See xterm.d.ts for details. */
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._inputHandler.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
|
||||
/** Add handler for CSI escape sequence. See xterm.d.ts for details. */
|
||||
public addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable {
|
||||
return this._inputHandler.addCsiHandler(flag, callback);
|
||||
|
||||
@@ -75,10 +75,13 @@ export class MockTerminal implements ITerminal {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => boolean | void, options?: ILinkMatcherOptions): number {
|
||||
throw new Error('Method not implemented.');
|
||||
|
||||
Vendored
+1
@@ -201,6 +201,7 @@ export interface IPublicTerminal extends IDisposable {
|
||||
open(parent: HTMLElement): void;
|
||||
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable;
|
||||
addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable;
|
||||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
|
||||
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number;
|
||||
deregisterLinkMatcher(matcherId: number): void;
|
||||
|
||||
@@ -1199,6 +1199,57 @@ describe('EscapeSequenceParser', function (): void {
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql([]);
|
||||
});
|
||||
describe('ESC custom handlers', () => {
|
||||
it('prevent fallback', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom - %G']);
|
||||
});
|
||||
it('allow fallback', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return false; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom - %G', 'default - %G']);
|
||||
});
|
||||
it('Multiple custom handlers fallback once', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom2 - %G'); return false; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom2 - %G', 'custom - %G']);
|
||||
});
|
||||
it('Multiple custom handlers no fallback', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
parser2.addEscHandler('%G', () => { esc.push('custom2 - %G'); return true; });
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['custom2 - %G']);
|
||||
});
|
||||
it('Execution order should go from latest handler down to the original', () => {
|
||||
const order: number[] = [];
|
||||
parser2.setEscHandler('%G', () => order.push(1));
|
||||
parser2.addEscHandler('%G', () => { order.push(2); return false; });
|
||||
parser2.addEscHandler('%G', () => { order.push(3); return false; });
|
||||
parse(parser2, '\x1b%G');
|
||||
chai.expect(order).eql([3, 2, 1]);
|
||||
});
|
||||
it('Dispose should work', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
const dispo = parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
dispo.dispose();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['default - %G']);
|
||||
});
|
||||
it('Should not corrupt the parser when dispose is called twice', () => {
|
||||
parser2.setEscHandler('%G', () => esc.push('default - %G'));
|
||||
const dispo = parser2.addEscHandler('%G', () => { esc.push('custom - %G'); return true; });
|
||||
dispo.dispose();
|
||||
dispo.dispose();
|
||||
parse(parser2, INPUT);
|
||||
chai.expect(esc).eql(['default - %G']);
|
||||
});
|
||||
});
|
||||
it('CSI handler', function (): void {
|
||||
parser2.setCsiHandler('m', function (params: IParams, collect: string): void {
|
||||
csi.push(['m', params.toArray(), collect]);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandler, OscFallbackHandler, IOscParser } from 'common/parser/Types';
|
||||
import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandler, OscFallbackHandler, IOscParser, EscHandler } from 'common/parser/Types';
|
||||
import { ParserState, ParserAction } from 'common/parser/Constants';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IDisposable } from 'common/Types';
|
||||
@@ -240,7 +240,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
protected _printHandler: (data: Uint32Array, start: number, end: number) => void;
|
||||
protected _executeHandlers: any;
|
||||
protected _csiHandlers: IHandlerCollection<CsiHandler>;
|
||||
protected _escHandlers: any;
|
||||
protected _escHandlers: IHandlerCollection<EscHandler>;
|
||||
protected _oscParser: IOscParser;
|
||||
protected _dcsHandlers: any;
|
||||
protected _activeDcsHandler: IDcsHandler;
|
||||
@@ -286,7 +286,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
|
||||
public dispose(): void {
|
||||
this._executeHandlers = null;
|
||||
this._escHandlers = null;
|
||||
this._escHandlers = Object.create(null);
|
||||
this._dcsHandlers = null;
|
||||
this._activeDcsHandler = new DcsDummy();
|
||||
this._oscParser.dispose();
|
||||
@@ -335,8 +335,23 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
this._csiHandlerFb = callback;
|
||||
}
|
||||
|
||||
addEscHandler(collectAndFlag: string, callback: EscHandler): IDisposable {
|
||||
if (this._escHandlers[collectAndFlag] === undefined) {
|
||||
this._escHandlers[collectAndFlag] = [];
|
||||
}
|
||||
const handlerList = this._escHandlers[collectAndFlag];
|
||||
handlerList.push(callback);
|
||||
return {
|
||||
dispose: () => {
|
||||
const handlerIndex = handlerList.indexOf(callback);
|
||||
if (handlerIndex !== -1) {
|
||||
handlerList.splice(handlerIndex, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
setEscHandler(collectAndFlag: string, callback: () => void): void {
|
||||
this._escHandlers[collectAndFlag] = callback;
|
||||
this._escHandlers[collectAndFlag] = [callback];
|
||||
}
|
||||
clearEscHandler(collectAndFlag: string): void {
|
||||
if (this._escHandlers[collectAndFlag]) delete this._escHandlers[collectAndFlag];
|
||||
@@ -509,9 +524,18 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP
|
||||
collect += String.fromCharCode(code);
|
||||
break;
|
||||
case ParserAction.ESC_DISPATCH:
|
||||
callback = this._escHandlers[collect + String.fromCharCode(code)];
|
||||
if (callback) callback(collect, code);
|
||||
else this._escHandlerFb(collect, code);
|
||||
const handlersEsc = this._escHandlers[collect + String.fromCharCode(code)];
|
||||
let jj = handlersEsc ? handlersEsc.length - 1 : -1;
|
||||
for (; jj >= 0; jj--) {
|
||||
// undefined or true means success and to stop bubbling
|
||||
if (handlersEsc[jj]() !== false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jj < 0) {
|
||||
this._escHandlerFb(collect, code);
|
||||
}
|
||||
|
||||
this.precedingCodepoint = 0;
|
||||
break;
|
||||
case ParserAction.CLEAR:
|
||||
|
||||
Vendored
+3
-1
@@ -68,6 +68,7 @@ export interface IHandlerCollection<T> {
|
||||
}
|
||||
|
||||
export type CsiHandler = (params: IParams, collect: string) => boolean | void;
|
||||
export type EscHandler = () => boolean | void;
|
||||
|
||||
/**
|
||||
* DCS handler signature for EscapeSequenceParser.
|
||||
@@ -152,15 +153,16 @@ export interface IEscapeSequenceParser extends IDisposable {
|
||||
clearCsiHandler(flag: string): void;
|
||||
setCsiHandlerFallback(callback: (collect: string, params: IParams, flag: number) => void): void;
|
||||
addCsiHandler(flag: string, callback: (params: IParams, collect: string) => boolean): IDisposable;
|
||||
addOscHandler(ident: number, handler: IOscHandler): IDisposable;
|
||||
|
||||
setEscHandler(collectAndFlag: string, callback: () => void): void;
|
||||
clearEscHandler(collectAndFlag: string): void;
|
||||
setEscHandlerFallback(callback: (collect: string, flag: number) => void): void;
|
||||
addEscHandler(collectAndFlag: string, handler: EscHandler): IDisposable;
|
||||
|
||||
setOscHandler(ident: number, handler: IOscHandler): void;
|
||||
clearOscHandler(ident: number): void;
|
||||
setOscHandlerFallback(handler: OscFallbackHandler): void;
|
||||
addOscHandler(ident: number, handler: IOscHandler): IDisposable;
|
||||
|
||||
setDcsHandler(collectAndFlag: string, handler: IDcsHandler): void;
|
||||
clearDcsHandler(collectAndFlag: string): void;
|
||||
|
||||
@@ -60,6 +60,9 @@ export class Terminal implements ITerminalApi {
|
||||
public addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable {
|
||||
return this._core.addCsiHandler(flag, (params: IParams, collect: string) => callback(params.toArray(), collect));
|
||||
}
|
||||
public addEscHandler(collectAndFlag: string, handler: () => boolean): IDisposable {
|
||||
return this._core.addEscHandler(collectAndFlag, handler);
|
||||
}
|
||||
public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
|
||||
return this._core.addOscHandler(ident, callback);
|
||||
}
|
||||
|
||||
@@ -351,6 +351,30 @@ describe('InputHandler Integration Tests', function(): void {
|
||||
assert.deepEqual(await page.evaluate(`(() => _customCsiHandlerParams)();`), [[38, 5, 123], [38, [2, -1, 50, 100, 150]]]);
|
||||
});
|
||||
});
|
||||
describe('addEscHandler', () => {
|
||||
it('should respects return value', async () => {
|
||||
await page.evaluate(`
|
||||
window.term.reset();
|
||||
const _customEscHandlerCallStack = [];
|
||||
const _customEscHandlerA = window.term.addEscHandler('(B', () => {
|
||||
_customEscHandlerCallStack.push('A');
|
||||
return false;
|
||||
});
|
||||
const _customEscHandlerB = window.term.addEscHandler('(B', () => {
|
||||
_customEscHandlerCallStack.push('B');
|
||||
return true;
|
||||
});
|
||||
const _customEscHandlerC = window.term.addEscHandler('(B', () => {
|
||||
_customEscHandlerCallStack.push('C');
|
||||
return false;
|
||||
});
|
||||
`);
|
||||
await page.evaluate(`
|
||||
window.term.write('\x1b(B');
|
||||
`);
|
||||
assert.deepEqual(await page.evaluate(`(() => _customEscHandlerCallStack)();`), ['C', 'B']);
|
||||
});
|
||||
});
|
||||
describe('addOscHandler', () => {
|
||||
it('should respects return value', async () => {
|
||||
await page.evaluate(`
|
||||
|
||||
Vendored
+13
@@ -515,6 +515,19 @@ declare module 'xterm' {
|
||||
*/
|
||||
addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for ESC escape sequences.
|
||||
* @param flag The flag should be a string, which specifies the
|
||||
* collect and the final character (e.g "%G" for default charset selection)
|
||||
* of the ESC sequence.
|
||||
* @param callback The function to handle the escape sequence.
|
||||
* Return true if the sequence was handled; false if
|
||||
* we should try a previous handler (set by addEscHandler or setEscHandler).
|
||||
* The most recently-added handler is tried first.
|
||||
* @return An IDisposable you can call to remove this handler.
|
||||
*/
|
||||
addEscHandler(collect: string, handler: () => boolean): IDisposable;
|
||||
|
||||
/**
|
||||
* Adds a handler for OSC escape sequences.
|
||||
* @param ident The number (first parameter) of the sequence.
|
||||
|
||||
Reference in New Issue
Block a user