提交 d59c6186 编写于 作者: D Daniel Imms

Add unit test for link handler

Ideally there would be an integration test as well but currently it's not
possible as there's no extension API to activate links within the terminal
上级 bff2692f
......@@ -60,7 +60,7 @@ const CUSTOM_LINK_PRIORITY = -1;
/** Lowest */
const LOCAL_LINK_PRIORITY = -2;
export type XtermLinkMatcherHandler = (event: MouseEvent, link: string) => boolean | void;
export type XtermLinkMatcherHandler = (event: MouseEvent, link: string) => Promise<void>;
export type XtermLinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void;
interface IPath {
......@@ -77,6 +77,9 @@ export class TerminalLinkHandler extends DisposableStore {
private readonly _leaveCallback: () => void;
private _hasBeforeHandleLinkListeners = false;
protected static _LINK_INTERCEPT_THRESHOLD = LINK_INTERCEPT_THRESHOLD;
public static readonly LINK_INTERCEPT_THRESHOLD = TerminalLinkHandler._LINK_INTERCEPT_THRESHOLD;
private readonly _onBeforeHandleLink = this.add(new Emitter<ITerminalBeforeHandleLinkEvent>({
onFirstListenerAdd: () => this._hasBeforeHandleLinkListeners = true,
onLastListenerRemove: () => this._hasBeforeHandleLinkListeners = false
......@@ -227,8 +230,8 @@ export class TerminalLinkHandler extends DisposableStore {
this._xterm.registerLinkMatcher(this._gitDiffPostImagePattern, wrappedHandler, options);
}
private _wrapLinkHandler(handler: (link: string) => void): XtermLinkMatcherHandler {
return (event: MouseEvent, link: string) => {
protected _wrapLinkHandler(handler: (link: string) => void): XtermLinkMatcherHandler {
return async (event: MouseEvent, link: string) => {
// Prevent default electron link handling so Alt+Click mode works normally
event.preventDefault();
// Require correct modifier on click
......@@ -238,12 +241,12 @@ export class TerminalLinkHandler extends DisposableStore {
// Allow the link to be intercepted if there are listeners
if (this._hasBeforeHandleLinkListeners) {
new Promise<boolean>(r => {
const wasHandled = await new Promise<boolean>(r => {
const timeoutId = setTimeout(() => {
canceled = true;
this._logService.error('An extension intecepted a terminal link but did not return');
r(false);
}, LINK_INTERCEPT_THRESHOLD);
}, TerminalLinkHandler.LINK_INTERCEPT_THRESHOLD);
let canceled = false;
const resolve = (handled: boolean) => {
if (!canceled) {
......@@ -252,11 +255,10 @@ export class TerminalLinkHandler extends DisposableStore {
}
};
this._onBeforeHandleLink.fire({ link, resolve });
}).then(wasHandled => {
if (!wasHandled) {
handler(link);
}
});
if (!wasHandled) {
handler(link);
}
return;
}
......@@ -307,7 +309,7 @@ export class TerminalLinkHandler extends DisposableStore {
this._openerService.open(url, { allowTunneling: !!(this._processManager && this._processManager.remoteAuthority) });
}
private _isLinkActivationModifierDown(event: MouseEvent): boolean {
protected _isLinkActivationModifierDown(event: MouseEvent): boolean {
const editorConf = this._configurationService.getValue<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor');
if (editorConf.multiCursorModifier === 'ctrlCmd') {
return !!event.altKey;
......
......@@ -5,11 +5,12 @@
import * as assert from 'assert';
import { OperatingSystem } from 'vs/base/common/platform';
import { TerminalLinkHandler, LineColumnInfo } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
import { TerminalLinkHandler, LineColumnInfo, XtermLinkMatcherHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
import * as strings from 'vs/base/common/strings';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { Event } from 'vs/base/common/event';
import { ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
class TestTerminalLinkHandler extends TerminalLinkHandler {
public get localLinkRegex(): RegExp {
......@@ -24,6 +25,13 @@ class TestTerminalLinkHandler extends TerminalLinkHandler {
public preprocessPath(link: string): string | null {
return this._preprocessPath(link);
}
protected _isLinkActivationModifierDown(event: MouseEvent): boolean {
return true;
}
public wrapLinkHandler(handler: (link: string) => void): XtermLinkMatcherHandler {
TerminalLinkHandler._LINK_INTERCEPT_THRESHOLD = 0;
return this._wrapLinkHandler(handler);
}
}
class TestXterm {
......@@ -302,4 +310,35 @@ suite('Workbench - TerminalLinkHandler', () => {
assert.equal(linkHandler.gitDiffLinkPostImageRegex.test('+++ /dev/null'), false);
assert.equal(linkHandler.gitDiffLinkPostImageRegex.test('+++ /dev/null '), false);
});
suite.only('wrapLinkHandler', () => {
const nullMouseEvent: any = Object.freeze({ preventDefault: () => { } });
test('should allow intercepting of links with onBeforeHandleLink', async () => {
const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any, testConfigHelper, null!, null!, new TestConfigurationService(), new MockTerminalInstanceService(), null!, null!);
linkHandler.onBeforeHandleLink(e => {
if (e.link === 'https://www.microsoft.com') {
intercepted = true;
e.resolve(true);
}
e.resolve(false);
});
const wrappedHandler = linkHandler.wrapLinkHandler(() => defaultHandled = true);
let defaultHandled = false;
let intercepted = false;
await wrappedHandler(nullMouseEvent, 'https://www.visualstudio.com');
assert.equal(intercepted, false);
assert.equal(defaultHandled, true);
defaultHandled = false;
intercepted = false;
await wrappedHandler(nullMouseEvent, 'https://www.microsoft.com');
assert.equal(intercepted, true);
assert.equal(defaultHandled, false);
});
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册