-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
hooks for custom control sequences #1813
Changes from 12 commits
4d660de
b689745
0311563
30a667c
8ad2d1b
ffb2708
53fd04a
8ceea11
6351a5b
5af4626
8a5a032
6b65ebd
7173577
9f603a2
a4cc87d
2551a53
d3d3064
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,13 @@ | |
*/ | ||
|
||
import { ParserState, ParserAction, IParsingState, IDcsHandler, IEscapeSequenceParser } from './Types'; | ||
import { IDisposable } from 'xterm'; | ||
import { Disposable } from './common/Lifecycle'; | ||
|
||
interface IHandlerLink extends IDisposable { | ||
nextHandler: IHandlerLink | null; | ||
} | ||
|
||
/** | ||
* Returns an array filled with numbers between the low and high parameters (right exclusive). | ||
* @param low The low number. | ||
|
@@ -41,7 +46,7 @@ export class TransitionTable { | |
* @param action parser action to be done | ||
* @param next next parser state | ||
*/ | ||
add(code: number, state: number, action: number | null, next: number | null): void { | ||
add(code: number, state: number, action: number | null, next: number | null): void { | ||
this.table[state << 8 | code] = ((action | 0) << 4) | ((next === undefined) ? state : next); | ||
} | ||
|
||
|
@@ -303,6 +308,38 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP | |
this._executeHandlerFb = callback; | ||
} | ||
|
||
private _linkHandler(handlers: object[], index: number, newCallback: object): IDisposable { | ||
const newHead: any = newCallback; | ||
newHead.nextHandler = handlers[index] as IHandlerLink; | ||
newHead.dispose = function (): void { | ||
let previous = null; | ||
let cur = handlers[index] as IHandlerLink; | ||
for (; cur && cur.nextHandler; | ||
previous = cur, cur = cur.nextHandler) { | ||
if (cur === newHead) { | ||
if (previous) { previous.nextHandler = cur.nextHandler; } | ||
else { handlers[index] = cur.nextHandler; } | ||
break; | ||
} | ||
} | ||
}; | ||
handlers[index] = newHead; | ||
return newHead; | ||
} | ||
|
||
addCsiHandler(flag: string, callback: (params: number[], collect: string) => boolean): IDisposable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have now a somewhat weird API here:
Since |
||
const index = flag.charCodeAt(0); | ||
const newHead = | ||
(params: number[], collect: string): void => { | ||
if (! callback(params, collect)) { | ||
const next = (newHead as unknown as IHandlerLink).nextHandler; | ||
if (next) { (next as any)(params, collect); } | ||
else { this._csiHandlerFb(collect, params, index); } | ||
} | ||
}; | ||
return this._linkHandler(this._csiHandlers, index, newHead); | ||
} | ||
|
||
setCsiHandler(flag: string, callback: (params: number[], collect: string) => void): void { | ||
this._csiHandlers[flag.charCodeAt(0)] = callback; | ||
} | ||
|
@@ -323,6 +360,17 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP | |
this._escHandlerFb = callback; | ||
} | ||
|
||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable { | ||
const newHead = | ||
(data: string): void => { | ||
if (! callback(data)) { | ||
const next = (newHead as unknown as IHandlerLink).nextHandler; | ||
if (next) { (next as any)(data); } | ||
else { this._oscHandlerFb(ident, data); } | ||
} | ||
}; | ||
return this._linkHandler(this._oscHandlers, ident, newHead); | ||
} | ||
setOscHandler(ident: number, callback: (data: string) => void): void { | ||
this._oscHandlers[ident] = callback; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -492,6 +492,8 @@ export interface IEscapeSequenceParser extends IDisposable { | |
setCsiHandler(flag: string, callback: (params: number[], collect: string) => void): void; | ||
clearCsiHandler(flag: string): void; | ||
setCsiHandlerFallback(callback: (collect: string, params: number[], flag: number) => void): void; | ||
addCsiHandler(flag: string, callback: (params: number[], collect: string) => boolean): IDisposable; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jerch are the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Tyriar, @PerBothner: Not future proof, its still a subject to change, but imho good to go for now. I will address this with one of the typed array transitions to come. |
||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; | ||
|
||
setEscHandler(collectAndFlag: string, callback: () => void): void; | ||
clearEscHandler(collectAndFlag: string): void; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -481,6 +481,31 @@ declare module 'xterm' { | |
*/ | ||
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; | ||
|
||
/** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likely to change with the typed array in the parser (around v3.11): a single char string arg will turn into a number, the string arg is likely to be a typed array itself with start/end offsets (not clear yet whether UTF32 or UTF16 based). |
||
* (EXPERIMENTAL) Adds a handler for CSI escape sequences. | ||
* @param flag The flag should be one-character string, which specifies | ||
* the final character (e.g "m" for SGR) of the CSI sequence. | ||
* @param callback The function to handle the escape sequence. | ||
* The callback is called with the numerical params, | ||
* as well as the special characters (e.g. "$" for DECSCPP). | ||
* Return true if the sequence was handled; false if we should | ||
* try a previous handler (set by addCsiHandler or setCsiHandler). | ||
* The most recently-added handler is tried first. | ||
* @return An IDisposable you can call to remove this handler. | ||
*/ | ||
addCsiHandler(flag: string, callback: (params: number[], collect: string) => boolean): IDisposable; | ||
|
||
/** | ||
* (EXPERIMENTAL) Adds a handler for OSC escape sequences. | ||
* @param ident The number (first parameter) of the sequence. | ||
* @param callback The function to handle the escape sequence. | ||
* The callback is called with OSC data string. | ||
* Return true if the sequence was handled; false if we should | ||
* try a previous handler (set by addOscHandler or setOscHandler). | ||
* The most recently-added handler is tried first. | ||
* @return An IDisposable you can call to remove this handler. | ||
*/ | ||
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; | ||
/** | ||
* (EXPERIMENTAL) Registers a link matcher, allowing custom link patterns to | ||
* be matched and handled. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this still work with cycles, like someone added a handler twice by accident? Also an cycle might prevent the autoclean up by the
.dispose
method, imho the dispose chain of additional handlers should be called there, too.Ah well it creates always a new function object, so cycles should not be an issue (I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it should be ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yupp found no issues with it (handler is recreated anyway).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much cleaner with this management method. 👍