Merge from vscode 099a7622e6e90dbcc226e428d4e35a72cb19ecbc (#9646)

* Merge from vscode 099a7622e6e90dbcc226e428d4e35a72cb19ecbc

* fix strict
This commit is contained in:
Anthony Dresser
2020-03-16 23:16:40 -07:00
committed by GitHub
parent 81e1b9a434
commit a53b78c0c8
170 changed files with 2601 additions and 2026 deletions

View File

@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction } from 'vs/platform/quickinput/common/quickAccess';
import { IQuickPickSeparator, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
import { IPickerQuickAccessItem, PickerQuickAccessProvider, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { matchesFuzzy } from 'vs/base/common/filters';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ICommandService } from 'vs/platform/commands/common/commands';
@@ -22,6 +22,12 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
super(TerminalQuickAccessProvider.PREFIX);
}
protected configure(picker: IQuickPick<IPickerQuickAccessItem>): void {
// Allow to open terminals in background without closing picker
picker.canAcceptInBackground = true;
}
protected getPicks(filter: string): Array<IPickerQuickAccessItem | IQuickPickSeparator> {
const terminalPicks: Array<IPickerQuickAccessItem | IQuickPickSeparator> = [];
@@ -60,9 +66,9 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider<IPick
return TriggerAction.NO_ACTION;
},
accept: () => {
accept: (keyMod, event) => {
this.terminalService.setActiveInstance(terminal);
this.terminalService.showPanel(true);
this.terminalService.showPanel(!event.inBackground);
}
});
}

View File

@@ -294,8 +294,8 @@ configurationRegistry.registerConfiguration({
type: 'boolean',
default: true
},
'terminal.integrated.allowMenubarMnemonics': {
markdownDescription: nls.localize('terminal.integrated.allowMenubarMnemonics', "Whether to allow menubar mnemonics (eg. alt+f) to trigger the open the menubar. Note that this will cause all alt keystrokes will skip the shell when true."),
'terminal.integrated.allowMnemonics': {
markdownDescription: nls.localize('terminal.integrated.allowMnemonics', "Whether to allow menubar mnemonics (eg. alt+f) to trigger the open the menubar. Note that this will cause all alt keystrokes will skip the shell when true."),
type: 'boolean',
default: false
},

View File

@@ -131,6 +131,14 @@ export interface ITerminalService {
findNext(): void;
findPrevious(): void;
/**
* Link handlers can be registered here to allow intercepting links clicked in the terminal.
* When a link is clicked, the link will be considered handled when the first interceptor
* resolves with true. It will be considered not handled when _all_ link handlers resolve with
* false, or 3 seconds have elapsed.
*/
addLinkHandler(key: string, callback: TerminalLinkHandlerCallback): IDisposable;
selectDefaultWindowsShell(): Promise<void>;
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
@@ -179,6 +187,18 @@ export enum WindowsShellType {
}
export type TerminalShellType = WindowsShellType | undefined;
export const LINK_INTERCEPT_THRESHOLD = 3000;
export interface ITerminalBeforeHandleLinkEvent {
terminal?: ITerminalInstance;
/** The text of the link */
link: string;
/** Call with whether the link was handled by the interceptor */
resolve(wasHandled: boolean): void;
}
export type TerminalLinkHandlerCallback = (e: ITerminalBeforeHandleLinkEvent) => Promise<boolean>;
export interface ITerminalInstance {
/**
* The ID of the terminal instance, this is an arbitrary number only used to identify the
@@ -240,6 +260,11 @@ export interface ITerminalInstance {
*/
onExit: Event<number | undefined>;
/**
* Attach a listener to intercept and handle link clicks in the terminal.
*/
onBeforeHandleLink: Event<ITerminalBeforeHandleLinkEvent>;
readonly exitCode: number | undefined;
processReady: Promise<void>;

View File

@@ -30,7 +30,7 @@ import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGR
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { ITerminalInstanceService, ITerminalInstance, TerminalShellType } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalInstance, TerminalShellType, ITerminalBeforeHandleLinkEvent } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm';
import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
@@ -272,6 +272,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
public get onMaximumDimensionsChanged(): Event<void> { return this._onMaximumDimensionsChanged.event; }
private readonly _onFocus = new Emitter<ITerminalInstance>();
public get onFocus(): Event<ITerminalInstance> { return this._onFocus.event; }
private readonly _onBeforeHandleLink = new Emitter<ITerminalBeforeHandleLinkEvent>();
public get onBeforeHandleLink(): Event<ITerminalBeforeHandleLinkEvent> { return this._onBeforeHandleLink.event; }
public constructor(
private readonly _terminalFocusContextKey: IContextKey<boolean>,
@@ -523,6 +525,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
});
}
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, xterm, this._processManager, this._configHelper);
this._linkHandler.onBeforeHandleLink(e => {
e.terminal = this;
this._onBeforeHandleLink.fire(e);
});
});
this._commandTrackerAddon = new CommandTrackerAddon();
@@ -615,7 +621,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
// Skip processing by xterm.js of keyboard events that match menu bar mnemonics
if (this._configHelper.config.allowMenubarMnemonics && event.altKey) {
if (this._configHelper.config.allowMnemonics && event.altKey) {
return false;
}

View File

@@ -16,9 +16,11 @@ import { IFileService } from 'vs/platform/files/common/files';
import { Terminal, ILinkMatcherOptions, IViewportRange } from 'xterm';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { posix, win32 } from 'vs/base/common/path';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalBeforeHandleLinkEvent, LINK_INTERCEPT_THRESHOLD } from 'vs/workbench/contrib/terminal/browser/terminal';
import { OperatingSystem, isMacintosh } from 'vs/base/common/platform';
import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
import { Emitter, Event } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
const pathPrefix = '(\\.\\.?|\\~)';
const pathSeparatorClause = '\\/';
@@ -58,7 +60,7 @@ const CUSTOM_LINK_PRIORITY = -1;
/** Lowest */
const LOCAL_LINK_PRIORITY = -2;
export type XtermLinkMatcherHandler = (event: MouseEvent, uri: string) => boolean | void;
export type XtermLinkMatcherHandler = (event: MouseEvent, link: string) => Promise<void>;
export type XtermLinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void;
interface IPath {
@@ -66,14 +68,28 @@ interface IPath {
normalize(path: string): string;
}
export class TerminalLinkHandler {
private readonly _hoverDisposables = new DisposableStore();
export class TerminalLinkHandler extends DisposableStore {
private _widgetManager: TerminalWidgetManager | undefined;
private _processCwd: string | undefined;
private _gitDiffPreImagePattern: RegExp;
private _gitDiffPostImagePattern: RegExp;
private readonly _tooltipCallback: (event: MouseEvent, uri: string, location: IViewportRange) => boolean | void;
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
}));
/**
* Allows intercepting links and handling them outside of the default link handler. When fired
* the listener has a set amount of time to handle the link or the default handler will fire.
* This was designed to only be handled by a single listener.
*/
public get onBeforeHandleLink(): Event<ITerminalBeforeHandleLinkEvent> { return this._onBeforeHandleLink.event; }
constructor(
private _xterm: Terminal,
@@ -83,8 +99,11 @@ export class TerminalLinkHandler {
@IEditorService private readonly _editorService: IEditorService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
@IFileService private readonly _fileService: IFileService
@IFileService private readonly _fileService: IFileService,
@ILogService private readonly _logService: ILogService
) {
super();
// Matches '--- a/src/file1', capturing 'src/file1' in group 1
this._gitDiffPreImagePattern = /^--- a\/(\S*)/;
// Matches '+++ b/src/file1', capturing 'src/file1' in group 1
@@ -211,19 +230,40 @@ export class TerminalLinkHandler {
this._xterm.registerLinkMatcher(this._gitDiffPostImagePattern, wrappedHandler, options);
}
public dispose(): void {
this._hoverDisposables.dispose();
}
private _wrapLinkHandler(handler: (uri: string) => boolean | void): XtermLinkMatcherHandler {
return (event: MouseEvent, uri: 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
if (!this._isLinkActivationModifierDown(event)) {
return false;
return;
}
return handler(uri);
// Allow the link to be intercepted if there are listeners
if (this._hasBeforeHandleLinkListeners) {
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);
}, TerminalLinkHandler.LINK_INTERCEPT_THRESHOLD);
let canceled = false;
const resolve = (handled: boolean) => {
if (!canceled) {
clearTimeout(timeoutId);
r(handled);
}
};
this._onBeforeHandleLink.fire({ link, resolve });
});
if (!wasHandled) {
handler(link);
}
return;
}
// Just call the handler if there is no before listener
handler(link);
};
}
@@ -244,18 +284,17 @@ export class TerminalLinkHandler {
return this._gitDiffPostImagePattern;
}
private _handleLocalLink(link: string): PromiseLike<any> {
return this._resolvePath(link).then(resolvedLink => {
if (!resolvedLink) {
return Promise.resolve(null);
}
const lineColumnInfo: LineColumnInfo = this.extractLineColumnInfo(link);
const selection: ITextEditorSelection = {
startLineNumber: lineColumnInfo.lineNumber,
startColumn: lineColumnInfo.columnNumber
};
return this._editorService.openEditor({ resource: resolvedLink, options: { pinned: true, selection } });
});
private async _handleLocalLink(link: string): Promise<void> {
const resolvedLink = await this._resolvePath(link);
if (!resolvedLink) {
return;
}
const lineColumnInfo: LineColumnInfo = this.extractLineColumnInfo(link);
const selection: ITextEditorSelection = {
startLineNumber: lineColumnInfo.lineNumber,
startColumn: lineColumnInfo.columnNumber
};
await this._editorService.openEditor({ resource: resolvedLink, options: { pinned: true, selection } });
}
private _validateLocalLink(link: string, callback: (isValid: boolean) => void): void {
@@ -270,7 +309,7 @@ export class TerminalLinkHandler {
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;
@@ -346,19 +385,19 @@ export class TerminalLinkHandler {
return link;
}
private _resolvePath(link: string): PromiseLike<URI | null> {
private async _resolvePath(link: string): Promise<URI | undefined> {
if (!this._processManager) {
throw new Error('Process manager is required');
}
const preprocessedLink = this._preprocessPath(link);
if (!preprocessedLink) {
return Promise.resolve(null);
return undefined;
}
const linkUrl = this.extractLinkUrl(preprocessedLink);
if (!linkUrl) {
return Promise.resolve(null);
return undefined;
}
try {
@@ -373,18 +412,20 @@ export class TerminalLinkHandler {
uri = URI.file(linkUrl);
}
return this._fileService.resolve(uri).then(stat => {
try {
const stat = await this._fileService.resolve(uri);
if (stat.isDirectory) {
return null;
return undefined;
}
return uri;
}).catch(() => {
}
catch (e) {
// Does not exist
return null;
});
return undefined;
}
} catch {
// Errors in parsing the path
return Promise.resolve(null);
return undefined;
}
}

View File

@@ -15,7 +15,7 @@ import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType, TerminalLinkHandlerCallback, LINK_INTERCEPT_THRESHOLD } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
@@ -30,6 +30,7 @@ import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
import { find } from 'vs/base/common/arrays';
import { timeout } from 'vs/base/common/async';
import { IViewsService } from 'vs/workbench/common/views';
import { IDisposable } from 'vs/base/common/lifecycle';
interface IExtHostReadyEntry {
promise: Promise<void>;
@@ -50,6 +51,7 @@ export class TerminalService implements ITerminalService {
private _findState: FindReplaceState;
private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {};
private _activeTabIndex: number;
private _linkHandlers: { [key: string]: TerminalLinkHandlerCallback } = {};
public get activeTabIndex(): number { return this._activeTabIndex; }
public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; }
@@ -411,6 +413,50 @@ export class TerminalService implements ITerminalService {
instance.addDisposable(instance.onDimensionsChanged(() => this._onInstanceDimensionsChanged.fire(instance)));
instance.addDisposable(instance.onMaximumDimensionsChanged(() => this._onInstanceMaximumDimensionsChanged.fire(instance)));
instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged));
instance.addDisposable(instance.onBeforeHandleLink(async e => {
// No link handlers have been registered
const keys = Object.keys(this._linkHandlers);
if (keys.length === 0) {
e.resolve(false);
return;
}
// Fire each link interceptor and wait for either a true, all false or the cancel time
let resolved = false;
const promises: Promise<boolean>[] = [];
const timeout = setTimeout(() => {
resolved = true;
e.resolve(false);
}, LINK_INTERCEPT_THRESHOLD);
for (let i = 0; i < keys.length; i++) {
const p = this._linkHandlers[keys[i]](e);
p.then(handled => {
if (!resolved && handled) {
resolved = true;
clearTimeout(timeout);
e.resolve(true);
}
});
promises.push(p);
}
await Promise.all(promises);
if (!resolved) {
resolved = true;
clearTimeout(timeout);
e.resolve(false);
}
}));
}
public addLinkHandler(key: string, callback: TerminalLinkHandlerCallback): IDisposable {
this._linkHandlers[key] = callback;
return {
dispose: () => {
if (this._linkHandlers[key] === callback) {
delete this._linkHandlers[key];
}
}
};
}
private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | undefined {

View File

@@ -107,7 +107,7 @@ export interface ITerminalConfiguration {
scrollback: number;
commandsToSkipShell: string[];
allowChords: boolean;
allowMenubarMnemonics: boolean;
allowMnemonics: boolean;
cwd: string;
confirmOnExit: boolean;
enableBell: boolean;

View File

@@ -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 {
@@ -81,7 +89,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Windows,
userHome: ''
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) {
assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl);
assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl);
@@ -157,7 +165,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) {
assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl);
assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl);
@@ -225,7 +233,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\Me'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
linkHandler.processCwd = 'C:\\base';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1');
@@ -238,7 +246,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\M e'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
linkHandler.processCwd = 'C:\\base dir';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1');
@@ -252,7 +260,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
linkHandler.processCwd = '/base';
assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1');
@@ -265,7 +273,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
assert.equal(linkHandler.preprocessPath('./src/file1'), null);
assert.equal(linkHandler.preprocessPath('src/file2'), null);
@@ -279,7 +287,7 @@ suite('Workbench - TerminalLinkHandler', () => {
const linkHandler = new TestTerminalLinkHandler(new TestXterm() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!);
} as any, testConfigHelper, null!, null!, null!, new MockTerminalInstanceService(), null!, null!);
function assertAreGoodMatches(matches: RegExpMatchArray | null) {
if (matches) {
@@ -302,4 +310,35 @@ suite('Workbench - TerminalLinkHandler', () => {
assert.equal(linkHandler.gitDiffLinkPostImageRegex.test('+++ /dev/null'), false);
assert.equal(linkHandler.gitDiffLinkPostImageRegex.test('+++ /dev/null '), false);
});
suite('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);
});
});
});

View File

@@ -21,8 +21,8 @@ function getMockTheme(type: ThemeType): IColorTheme {
getColor: (colorId: ColorIdentifier): Color | undefined => themingRegistry.resolveDefaultColor(colorId, theme),
defines: () => true,
getTokenStyleMetadata: () => undefined,
tokenColorMap: []
tokenColorMap: [],
semanticHighlighting: false
};
return theme;
}