Merge from vscode ad407028575a77ea387eb7cc219b323dc017b686

This commit is contained in:
ADS Merger
2020-08-22 06:06:52 +00:00
committed by Anthony Dresser
parent 404260b8a0
commit 4ad73d381c
480 changed files with 14360 additions and 14122 deletions

View File

@@ -21,10 +21,16 @@ export function convertLinkRangeToBuffer(lines: IBufferLine[], bufferWidth: numb
// Shift start range right for each wide character before the link
let startOffset = 0;
const startWrappedLineCount = Math.ceil(range.startColumn / bufferWidth);
for (let y = 0; y < startWrappedLineCount; y++) {
for (let y = 0; y < Math.min(startWrappedLineCount); y++) {
const lineLength = Math.min(bufferWidth, range.startColumn - y * bufferWidth);
let lineOffset = 0;
const line = lines[y];
// Sanity check for line, apparently this can happen but it's not clear under what
// circumstances this happens. Continue on, skipping the remainder of start offset if this
// happens to minimize impact.
if (!line) {
break;
}
for (let x = 0; x < Math.min(bufferWidth, lineLength + lineOffset); x++) {
const cell = line.getCell(x)!;
const width = cell.getWidth();

View File

@@ -16,11 +16,9 @@ import { IFileService } from 'vs/platform/files/common/files';
import { Terminal, IViewportRange, ILinkProvider } from 'xterm';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { posix, win32 } from 'vs/base/common/path';
import { ITerminalBeforeHandleLinkEvent, LINK_INTERCEPT_THRESHOLD, ITerminalExternalLinkProvider, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalExternalLinkProvider, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { OperatingSystem, isMacintosh, OS } 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';
import { TerminalProtocolLinkProvider } from 'vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider';
import { TerminalValidatedLocalLinkProvider, lineAndColumnClause, unixLocalLinkClause, winLocalLinkClause, winDrivePrefix, winLineAndColumnMatchIndex, unixLineAndColumnMatchIndex, lineAndColumnClauseGroupCount } from 'vs/workbench/contrib/terminal/browser/links/terminalValidatedLocalLinkProvider';
import { TerminalWordLinkProvider } from 'vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider';
@@ -44,24 +42,9 @@ interface IPath {
export class TerminalLinkManager extends DisposableStore {
private _widgetManager: TerminalWidgetManager | undefined;
private _processCwd: string | undefined;
private _hasBeforeHandleLinkListeners = false;
private _standardLinkProviders: ILinkProvider[] = [];
private _standardLinkProvidersDisposables: IDisposable[] = [];
protected static _LINK_INTERCEPT_THRESHOLD = LINK_INTERCEPT_THRESHOLD;
public static readonly LINK_INTERCEPT_THRESHOLD = TerminalLinkManager._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,
private readonly _processManager: ITerminalProcessManager,
@@ -69,14 +52,13 @@ export class TerminalLinkManager extends DisposableStore {
@IEditorService private readonly _editorService: IEditorService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IFileService private readonly _fileService: IFileService,
@ILogService private readonly _logService: ILogService,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
// Protocol links
const wrappedActivateCallback = this._wrapLinkHandler((_, link) => this._handleProtocolLink(link));
const protocolProvider = this._instantiationService.createInstance(TerminalProtocolLinkProvider, this._xterm, wrappedActivateCallback, this._tooltipCallback2.bind(this));
const protocolProvider = this._instantiationService.createInstance(TerminalProtocolLinkProvider, this._xterm, wrappedActivateCallback, this._tooltipCallback.bind(this));
this._standardLinkProviders.push(protocolProvider);
// Validated local links
@@ -87,19 +69,19 @@ export class TerminalLinkManager extends DisposableStore {
this._processManager.os || OS,
wrappedTextLinkActivateCallback,
this._wrapLinkHandler.bind(this),
this._tooltipCallback2.bind(this),
this._tooltipCallback.bind(this),
async (link, cb) => cb(await this._resolvePath(link)));
this._standardLinkProviders.push(validatedProvider);
}
// Word links
const wordProvider = this._instantiationService.createInstance(TerminalWordLinkProvider, this._xterm, this._wrapLinkHandler.bind(this), this._tooltipCallback2.bind(this));
const wordProvider = this._instantiationService.createInstance(TerminalWordLinkProvider, this._xterm, this._wrapLinkHandler.bind(this), this._tooltipCallback.bind(this));
this._standardLinkProviders.push(wordProvider);
this._registerStandardLinkProviders();
}
private _tooltipCallback2(link: TerminalLink, viewportRange: IViewportRange, modifierDownCallback?: () => void, modifierUpCallback?: () => void) {
private _tooltipCallback(link: TerminalLink, viewportRange: IViewportRange, modifierDownCallback?: () => void, modifierUpCallback?: () => void) {
if (!this._widgetManager) {
return;
}
@@ -156,7 +138,7 @@ export class TerminalLinkManager extends DisposableStore {
}
public registerExternalLinkProvider(instance: ITerminalInstance, linkProvider: ITerminalExternalLinkProvider): IDisposable {
const wrappedLinkProvider = this._instantiationService.createInstance(TerminalExternalLinkProviderAdapter, this._xterm, instance, linkProvider, this._wrapLinkHandler.bind(this), this._tooltipCallback2.bind(this));
const wrappedLinkProvider = this._instantiationService.createInstance(TerminalExternalLinkProviderAdapter, this._xterm, instance, linkProvider, this._wrapLinkHandler.bind(this), this._tooltipCallback.bind(this));
const newLinkProvider = this._xterm.registerLinkProvider(wrappedLinkProvider);
// Re-register the standard link providers so they are a lower priority that the new one
this._registerStandardLinkProviders();
@@ -173,38 +155,11 @@ export class TerminalLinkManager extends DisposableStore {
return;
}
// Allow the link to be intercepted if there are listeners
if (this._hasBeforeHandleLinkListeners) {
const wasHandled = await this._triggerBeforeHandleLinkListeners(link);
if (!wasHandled) {
handler(event, link);
}
return;
}
// Just call the handler if there is no before listener
handler(event, link);
};
}
private async _triggerBeforeHandleLinkListeners(link: string): Promise<boolean> {
return new Promise<boolean>(r => {
const timeoutId = setTimeout(() => {
canceled = true;
this._logService.error(`An extension intecepted a terminal link but it timed out after ${TerminalLinkManager.LINK_INTERCEPT_THRESHOLD / 1000} seconds`);
r(false);
}, TerminalLinkManager.LINK_INTERCEPT_THRESHOLD);
let canceled = false;
const resolve = (handled: boolean) => {
if (!canceled) {
clearTimeout(timeoutId);
r(handled);
}
};
this._onBeforeHandleLink.fire({ link, resolve });
});
}
protected get _localLinkRegex(): RegExp {
if (!this._processManager) {
throw new Error('Process manager is required');
@@ -369,7 +324,6 @@ export class TerminalLinkManager extends DisposableStore {
* @param link Url link which may contain line and column number.
*/
public extractLineColumnInfo(link: string): LineColumnInfo {
const matches: string[] | null = this._localLinkRegex.exec(link);
const lineColumnInfo: LineColumnInfo = {
lineNumber: 1,

View File

@@ -7,7 +7,7 @@ import { Terminal as XTermTerminal } from 'xterm';
import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
import { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11';
import { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl';
import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig, IDefaultShellAndArgsRequest, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, ITerminalProcessExtHostProxy, ICommandTracker, INavigationMode, TitleEventSource, ITerminalDimensions, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig, IDefaultShellAndArgsRequest, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, ITerminalProcessExtHostProxy, ICommandTracker, INavigationMode, TitleEventSource, ITerminalDimensions, ITerminalLaunchError, ITerminalNativeWindowsDelegate, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
import { Event } from 'vs/base/common/event';
@@ -136,14 +136,6 @@ 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;
/**
* Registers a link provider that enables integrators to add links to the terminal.
* @param linkProvider When registered, the link provider is asked whenever a cell is hovered
@@ -157,6 +149,12 @@ export interface ITerminalService {
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
manageWorkspaceShellPermissions(): void;
/**
* Injects native Windows functionality into the service.
*/
setNativeWindowsDelegate(delegate: ITerminalNativeWindowsDelegate): void;
setLinuxDistro(linuxDistro: LinuxDistro): void;
/**
* Takes a path and returns the properly escaped path to send to the terminal.
* On Windows, this included trying to prepare the path for WSL if needed.
@@ -215,8 +213,6 @@ export enum WindowsShellType {
}
export type TerminalShellType = WindowsShellType | undefined;
export const LINK_INTERCEPT_THRESHOLD = 3000;
export interface ITerminalBeforeHandleLinkEvent {
terminal?: ITerminalInstance;
/** The text of the link */
@@ -225,8 +221,6 @@ export interface ITerminalBeforeHandleLinkEvent {
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
@@ -289,15 +283,18 @@ 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;
readonly areLinksReady: boolean;
/**
* Returns an array of data events that have fired within the first 10 seconds. If this is
* called 10 seconds after the terminal has existed the result will be undefined. This is useful
* when objects that depend on the data events have delayed initialization, like extension
* hosts.
*/
readonly initialDataEvents: string[] | undefined;
/** A promise that resolves when the terminal's pty/process have been created. */
processReady: Promise<void>;

View File

@@ -35,13 +35,13 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
private _charMeasureElement: HTMLElement | undefined;
private _lastFontMeasurement: ITerminalFont | undefined;
private _linuxDistro: LinuxDistro = LinuxDistro.Unknown;
public config!: ITerminalConfiguration;
private readonly _onWorkspacePermissionsChanged = new Emitter<boolean>();
public get onWorkspacePermissionsChanged(): Event<boolean> { return this._onWorkspacePermissionsChanged.event; }
public constructor(
private readonly _linuxDistro: LinuxDistro,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService,
@INotificationService private readonly _notificationService: INotificationService,
@@ -62,6 +62,10 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
storageKeysSyncRegistryService.registerStorageKey({ key: 'terminalConfigHelper/launchRecommendationsIgnore', version: 1 });
}
public setLinuxDistro(linuxDistro: LinuxDistro) {
this._linuxDistro = linuxDistro;
}
private _updateConfig(): void {
this.config = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
}

View File

@@ -30,7 +30,7 @@ import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGR
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { ITerminalInstanceService, ITerminalInstance, TerminalShellType, WindowsShellType, ITerminalBeforeHandleLinkEvent, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstanceService, ITerminalInstance, TerminalShellType, WindowsShellType, ITerminalExternalLinkProvider } 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';
@@ -98,6 +98,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
private _titleReadyPromise: Promise<string>;
private _titleReadyComplete: ((title: string) => any) | undefined;
private _areLinksReady: boolean = false;
private _initialDataEvents: string[] | undefined = [];
private _messageTitleDisposable: IDisposable | undefined;
@@ -131,6 +132,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// TODO: Should this be an event as it can fire twice?
public get processReady(): Promise<void> { return this._processManager.ptyProcessReady; }
public get areLinksReady(): boolean { return this._areLinksReady; }
public get initialDataEvents(): string[] | undefined { return this._initialDataEvents; }
public get exitCode(): number | undefined { return this._exitCode; }
public get title(): string { return this._title; }
public get hadFocusOnExit(): boolean { return this._hadFocusOnExit; }
@@ -164,8 +166,6 @@ 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>,
@@ -233,6 +233,20 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this.updateAccessibilitySupport();
}
}));
// Clear out initial data events after 10 seconds, hopefully extension hosts are up and
// running at that point.
let initialDataEventsTimeout: number | undefined = window.setTimeout(() => {
initialDataEventsTimeout = undefined;
this._initialDataEvents = undefined;
}, 10000);
this._register({
dispose: () => {
if (initialDataEventsTimeout) {
window.clearTimeout(initialDataEventsTimeout);
}
}
});
}
public addDisposable(disposable: IDisposable): void {
@@ -419,10 +433,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
});
}
this._linkManager = this._instantiationService.createInstance(TerminalLinkManager, xterm, this._processManager!);
this._linkManager.onBeforeHandleLink(e => {
e.terminal = this;
this._onBeforeHandleLink.fire(e);
});
this._areLinksReady = true;
this._onLinksReady.fire(this);
});
@@ -868,11 +878,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
protected _createProcessManager(): void {
this._processManager = this._instantiationService.createInstance(TerminalProcessManager, this._id, this._configHelper);
this._processManager.onProcessReady(() => {
this._onProcessIdReady.fire(this);
});
this._processManager.onProcessReady(() => this._onProcessIdReady.fire(this));
this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode));
this._processManager.onProcessData(data => this._onData.fire(data));
this._processManager.onProcessData(data => {
this._initialDataEvents?.push(data);
this._onData.fire(data);
});
this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e));
this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e));
this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e));

View File

@@ -4,17 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { TERMINAL_VIEW_ID, IShellLaunchConfig, ITerminalConfigHelper, ITerminalNativeService, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalProcessExtHostProxy, IShellDefinition, LinuxDistro, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
import { TERMINAL_VIEW_ID, IShellLaunchConfig, ITerminalConfigHelper, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalProcessExtHostProxy, IShellDefinition, LinuxDistro, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE, ITerminalLaunchError, ITerminalNativeWindowsDelegate } from 'vs/workbench/contrib/terminal/common/terminal';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService } 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, TerminalLinkHandlerCallback, LINK_INTERCEPT_THRESHOLD, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType, ITerminalExternalLinkProvider } 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';
@@ -50,7 +50,6 @@ export class TerminalService implements ITerminalService {
private _findState: FindReplaceState;
private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {};
private _activeTabIndex: number;
private _linkHandlers: { [key: string]: TerminalLinkHandlerCallback } = {};
private _linkProviders: Set<ITerminalExternalLinkProvider> = new Set();
private _linkProviderDisposables: Map<ITerminalExternalLinkProvider, IDisposable[]> = new Map();
@@ -60,6 +59,7 @@ export class TerminalService implements ITerminalService {
private _configHelper: TerminalConfigHelper;
private _terminalContainer: HTMLElement | undefined;
private _nativeWindowsDelegate: ITerminalNativeWindowsDelegate | undefined;
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
@@ -92,8 +92,6 @@ export class TerminalService implements ITerminalService {
private readonly _onRequestAvailableShells = new Emitter<IAvailableShellsRequest>();
public get onRequestAvailableShells(): Event<IAvailableShellsRequest> { return this._onRequestAvailableShells.event; }
private readonly _terminalNativeService: ITerminalNativeService | undefined;
constructor(
@IContextKeyService private _contextKeyService: IContextKeyService,
@IWorkbenchLayoutService private _layoutService: IWorkbenchLayoutService,
@@ -105,34 +103,17 @@ export class TerminalService implements ITerminalService {
@IQuickInputService private _quickInputService: IQuickInputService,
@IConfigurationService private _configurationService: IConfigurationService,
@IViewsService private _viewsService: IViewsService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
// HACK: Ideally TerminalNativeService would depend on TerminalService and inject the
// additional native functionality into it.
@optional(ITerminalNativeService) terminalNativeService: ITerminalNativeService
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService
) {
// @optional could give undefined and properly typing it breaks service registration
this._terminalNativeService = terminalNativeService as ITerminalNativeService | undefined;
this._activeTabIndex = 0;
this._isShuttingDown = false;
this._findState = new FindReplaceState();
lifecycleService.onBeforeShutdown(async event => event.veto(this._onBeforeShutdown()));
lifecycleService.onShutdown(() => this._onShutdown());
if (this._terminalNativeService) {
this._terminalNativeService.onRequestFocusActiveInstance(() => {
if (this.terminalInstances.length > 0) {
const terminal = this.getActiveInstance();
if (terminal) {
terminal.focus();
}
}
});
this._terminalNativeService.onOsResume(() => this._onOsResume());
}
this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService);
this._terminalShellTypeContextKey = KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE.bindTo(this._contextKeyService);
this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_VISIBLE.bindTo(this._contextKeyService);
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this._terminalNativeService?.linuxDistro || LinuxDistro.Unknown);
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper);
this.onTabDisposed(tab => this._removeTab(tab));
this.onActiveTabChanged(() => {
const instance = this.getActiveInstance();
@@ -143,6 +124,14 @@ export class TerminalService implements ITerminalService {
this._handleContextKeys();
}
public setNativeWindowsDelegate(delegate: ITerminalNativeWindowsDelegate): void {
this._nativeWindowsDelegate = delegate;
}
public setLinuxDistro(linuxDistro: LinuxDistro): void {
this._configHelper.setLinuxDistro(linuxDistro);
}
private _handleContextKeys(): void {
const terminalIsOpenContext = KEYBINDING_CONTEXT_TERMINAL_IS_OPEN.bindTo(this._contextKeyService);
@@ -226,14 +215,6 @@ export class TerminalService implements ITerminalService {
this.terminalInstances.forEach(instance => instance.dispose(true));
}
private _onOsResume(): void {
const activeTab = this.getActiveTab();
if (!activeTab) {
return;
}
activeTab.terminalInstances.forEach(instance => instance.forceRedraw());
}
public getTabLabels(): string[] {
return this._terminalTabs.filter(tab => tab.terminalInstances.length > 0).map((tab, index) => `${index + 1}: ${tab.title ? tab.title : ''}`);
}
@@ -428,50 +409,6 @@ 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];
}
}
};
}
public registerLinkProvider(linkProvider: ITerminalExternalLinkProvider): IDisposable {
@@ -588,8 +525,8 @@ export class TerminalService implements ITerminalService {
return;
}
else if (shellType === WindowsShellType.Wsl) {
if (this._terminalNativeService && this._terminalNativeService.getWindowsBuildNumber() >= 17063) {
c(this._terminalNativeService.getWslPath(originalPath));
if (this._nativeWindowsDelegate && this._nativeWindowsDelegate.getWindowsBuildNumber() >= 17063) {
c(this._nativeWindowsDelegate.getWslPath(originalPath));
} else {
c(originalPath.replace(/\\/g, '/'));
}
@@ -603,9 +540,9 @@ export class TerminalService implements ITerminalService {
}
} else {
const lowerExecutable = executable.toLowerCase();
if (this._terminalNativeService && this._terminalNativeService.getWindowsBuildNumber() >= 17063 &&
if (this._nativeWindowsDelegate && this._nativeWindowsDelegate.getWindowsBuildNumber() >= 17063 &&
(lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) {
c(this._terminalNativeService.getWslPath(originalPath));
c(this._nativeWindowsDelegate.getWslPath(originalPath));
return;
} else if (hasSpace) {
c('"' + originalPath + '"');

View File

@@ -23,6 +23,7 @@ export class TerminalWidgetManager implements IDisposable {
}
dispose(): void {
this.hideHovers();
if (this._container && this._container.parentElement) {
this._container.parentElement.removeChild(this._container);
this._container = undefined;

View File

@@ -7,7 +7,6 @@ import * as nls from 'vs/nls';
import { Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { OperatingSystem } from 'vs/base/common/platform';
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
@@ -55,8 +54,6 @@ export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverM
// trying to create the corressponding object on the ext host.
export const EXT_HOST_CREATION_DELAY = 100;
export const ITerminalNativeService = createDecorator<ITerminalNativeService>('terminalNativeService');
export const TerminalCursorStyle = {
BLOCK: 'block',
LINE: 'line',
@@ -230,18 +227,17 @@ export interface IShellLaunchConfig {
}
/**
* Provides access to native or electron APIs to other terminal services.
* Provides access to native Windows calls that can be injected into non-native layers.
*/
export interface ITerminalNativeService {
readonly _serviceBrand: undefined;
readonly linuxDistro: LinuxDistro;
readonly onRequestFocusActiveInstance: Event<void>;
readonly onOsResume: Event<void>;
export interface ITerminalNativeWindowsDelegate {
/**
* Gets the Windows build number, eg. this would be `19041` for Windows 10 version 2004
*/
getWindowsBuildNumber(): number;
whenFileDeleted(path: URI): Promise<void>;
/**
* Converts a regular Windows path into the WSL path equivalent, eg. `C:\` -> `/mnt/c`
* @param path The Windows path.
*/
getWslPath(path: string): Promise<string>;
}

View File

@@ -3,22 +3,25 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService';
import { getSystemShell } from 'vs/workbench/contrib/terminal/node/terminal';
import { TerminalNativeService } from 'vs/workbench/contrib/terminal/electron-browser/terminalNativeService';
import { ITerminalNativeService } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalNativeContribution } from 'vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { getTerminalShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalConfiguration';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// This file contains additional desktop-only contributions on top of those in browser/
// Register services
registerSingleton(ITerminalNativeService, TerminalNativeService, true);
registerSingleton(ITerminalInstanceService, TerminalInstanceService, true);
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, LifecyclePhase.Ready);
// Register configurations
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
configurationRegistry.registerConfiguration(getTerminalShellConfiguration(getSystemShell));

View File

@@ -5,40 +5,40 @@
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
import { ITerminalNativeService, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { getWindowsBuildNumber, linuxDistro } from 'vs/workbench/contrib/terminal/node/terminal';
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { execFile } from 'child_process';
import { Emitter, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { registerRemoteContributions } from 'vs/workbench/contrib/terminal/electron-browser/terminalRemote';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
import { Disposable } from 'vs/base/common/lifecycle';
import { INativeOpenFileRequest } from 'vs/platform/windows/node/window';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
export class TerminalNativeService extends Disposable implements ITerminalNativeService {
export class TerminalNativeContribution extends Disposable implements IWorkbenchContribution {
public _serviceBrand: undefined;
public get linuxDistro(): LinuxDistro { return linuxDistro; }
private readonly _onRequestFocusActiveInstance = this._register(new Emitter<void>());
public get onRequestFocusActiveInstance(): Event<void> { return this._onRequestFocusActiveInstance.event; }
private readonly _onOsResume = this._register(new Emitter<void>());
public get onOsResume(): Event<void> { return this._onOsResume.event; }
constructor(
@IFileService private readonly _fileService: IFileService,
@ITerminalService private readonly _terminalService: ITerminalService,
@IInstantiationService readonly instantiationService: IInstantiationService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@IElectronService electronService: IElectronService
@IRemoteAgentService readonly remoteAgentService: IRemoteAgentService,
@IElectronService readonly electronService: IElectronService
) {
super();
ipcRenderer.on('vscode:openFiles', (event: unknown, request: IOpenFileRequest) => this._onOpenFileRequest(request));
this._register(electronService.onOSResume(() => this._onOsResume.fire()));
ipcRenderer.on('vscode:openFiles', (_: unknown, request: IOpenFileRequest) => this._onOpenFileRequest(request));
this._register(electronService.onOSResume(() => this._onOsResume()));
this._terminalService.setLinuxDistro(linuxDistro);
this._terminalService.setNativeWindowsDelegate({
getWslPath: this._getWslPath.bind(this),
getWindowsBuildNumber: this._getWindowsBuildNumber.bind(this)
});
const connection = remoteAgentService.getConnection();
if (connection && connection.remoteAuthority) {
@@ -46,18 +46,28 @@ export class TerminalNativeService extends Disposable implements ITerminalNative
}
}
private _onOsResume(): void {
const activeTab = this._terminalService.getActiveTab();
if (!activeTab) {
return;
}
activeTab.terminalInstances.forEach(instance => instance.forceRedraw());
}
private async _onOpenFileRequest(request: INativeOpenFileRequest): Promise<void> {
// if the request to open files is coming in from the integrated terminal (identified though
// the termProgram variable) and we are instructed to wait for editors close, wait for the
// marker file to get deleted and then focus back to the integrated terminal.
if (request.termProgram === 'vscode' && request.filesToWait) {
const waitMarkerFileUri = URI.revive(request.filesToWait.waitMarkerFileUri);
await this.whenFileDeleted(waitMarkerFileUri);
this._onRequestFocusActiveInstance.fire();
await this._whenFileDeleted(waitMarkerFileUri);
// Focus active terminal
this._terminalService.getActiveInstance()?.focus();
}
}
public whenFileDeleted(path: URI): Promise<void> {
private _whenFileDeleted(path: URI): Promise<void> {
// Complete when wait marker file is deleted
return new Promise<void>(resolve => {
let running = false;
@@ -80,7 +90,7 @@ export class TerminalNativeService extends Disposable implements ITerminalNative
* Converts a path to a path on WSL using the wslpath utility.
* @param path The original path.
*/
public getWslPath(path: string): Promise<string> {
private _getWslPath(path: string): Promise<string> {
if (getWindowsBuildNumber() < 17063) {
throw new Error('wslpath does not exist on Windows build < 17063');
}
@@ -92,7 +102,7 @@ export class TerminalNativeService extends Disposable implements ITerminalNative
});
}
public getWindowsBuildNumber(): number {
private _getWindowsBuildNumber(): number {
return getWindowsBuildNumber();
}
}

View File

@@ -18,6 +18,13 @@ import { findExecutable } from 'vs/workbench/contrib/terminal/node/terminalEnvir
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
// Writing large amounts of data can be corrupted for some reason, after looking into this is
// appears to be a race condition around writing to the FD which may be based on how powerful the
// hardware is. The workaround for this is to space out when large amounts of data is being written
// to the terminal. See https://github.com/microsoft/vscode/issues/38137
const WRITE_MAX_CHUNK_SIZE = 50;
const WRITE_INTERVAL_MS = 5;
export class TerminalProcess extends Disposable implements ITerminalChildProcess {
private _exitCode: number | undefined;
private _exitMessage: string | undefined;
@@ -27,6 +34,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
private _processStartupComplete: Promise<void> | undefined;
private _isDisposed: boolean = false;
private _titleInterval: NodeJS.Timer | null = null;
private _writeQueue: string[] = [];
private _writeTimeout: NodeJS.Timeout | undefined;
private readonly _initialCwd: string;
private readonly _ptyOptions: pty.IPtyForkOptions | pty.IWindowsPtyForkOptions;
@@ -232,8 +241,37 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
if (this._isDisposed || !this._ptyProcess) {
return;
}
for (let i = 0; i <= Math.floor(data.length / WRITE_MAX_CHUNK_SIZE); i++) {
this._writeQueue.push(data.substr(i * WRITE_MAX_CHUNK_SIZE, WRITE_MAX_CHUNK_SIZE));
}
this._startWrite();
}
private _startWrite(): void {
// Don't write if it's already queued of is there is nothing to write
if (this._writeTimeout !== undefined || this._writeQueue.length === 0) {
return;
}
this._doWrite();
// Don't queue more writes if the queue is empty
if (this._writeQueue.length === 0) {
this._writeTimeout = undefined;
return;
}
// Queue the next write
this._writeTimeout = setTimeout(() => {
this._writeTimeout = undefined;
this._startWrite();
}, WRITE_INTERVAL_MS);
}
private _doWrite(): void {
const data = this._writeQueue.shift()!;
this._logService.trace('IPty#write', `${data.length} characters`);
this._ptyProcess.write(data);
this._ptyProcess!.write(data);
}
public resize(cols: number, rows: number): void {

View File

@@ -1,163 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { OperatingSystem } from 'vs/base/common/platform';
import { TerminalLinkManager, XtermLinkMatcherHandler } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { Terminal as XtermTerminal } from 'xterm';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { Event } from 'vs/base/common/event';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { TestPathService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
class TestTerminalLinkManager extends TerminalLinkManager {
public get localLinkRegex(): RegExp {
return this._localLinkRegex;
}
public preprocessPath(link: string): string | null {
return this._preprocessPath(link);
}
protected _isLinkActivationModifierDown(event: MouseEvent): boolean {
return true;
}
public wrapLinkHandler(handler: (link: string) => void): XtermLinkMatcherHandler {
TerminalLinkManager._LINK_INTERCEPT_THRESHOLD = 0;
return this._wrapLinkHandler((_, link) => handler(link));
}
}
class MockTerminalInstanceService implements ITerminalInstanceService {
onRequestDefaultShellAndArgs?: Event<any> | undefined;
getDefaultShellAndArgs(): Promise<{ shell: string; args: string | string[] | undefined; }> {
throw new Error('Method not implemented.');
}
declare readonly _serviceBrand: undefined;
getXtermConstructor(): Promise<any> {
throw new Error('Method not implemented.');
}
getXtermSearchConstructor(): Promise<any> {
throw new Error('Method not implemented.');
}
getXtermUnicode11Constructor(): Promise<any> {
throw new Error('Method not implemented.');
}
getXtermWebglConstructor(): Promise<any> {
throw new Error('Method not implemented.');
}
createWindowsShellHelper(): any {
throw new Error('Method not implemented.');
}
createTerminalProcess(): any {
throw new Error('Method not implemented.');
}
getMainProcessParentEnv(): any {
throw new Error('Method not implemented.');
}
}
suite('Workbench - TerminalLinkManager', () => {
let instantiationService: TestInstantiationService;
setup(async () => {
const configurationService = new TestConfigurationService();
await configurationService.setUserConfiguration('terminal', { integrated: { enableFileLinks: true } });
instantiationService = new TestInstantiationService();
instantiationService.stub(IEnvironmentService, TestEnvironmentService);
instantiationService.stub(IPathService, new TestPathService());
instantiationService.stub(ITerminalInstanceService, new MockTerminalInstanceService());
instantiationService.stub(IConfigurationService, configurationService);
});
suite('preprocessPath', () => {
test('Windows', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\Me'
} as any);
linkHandler.processCwd = 'C:\\base';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1');
assert.equal(linkHandler.preprocessPath('src\\file2'), 'C:\\base\\src\\file2');
assert.equal(linkHandler.preprocessPath('~/src/file3'), 'C:\\Users\\Me\\src\\file3');
assert.equal(linkHandler.preprocessPath('~\\src\\file4'), 'C:\\Users\\Me\\src\\file4');
assert.equal(linkHandler.preprocessPath('C:\\absolute\\path\\file5'), 'C:\\absolute\\path\\file5');
assert.equal(linkHandler.preprocessPath('\\\\?\\C:\\absolute\\path\\extended\\file6'), 'C:\\absolute\\path\\extended\\file6');
});
test('Windows - spaces', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Windows,
userHome: 'C:\\Users\\M e'
} as any);
linkHandler.processCwd = 'C:\\base dir';
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1');
assert.equal(linkHandler.preprocessPath('src\\file2'), 'C:\\base dir\\src\\file2');
assert.equal(linkHandler.preprocessPath('~/src/file3'), 'C:\\Users\\M e\\src\\file3');
assert.equal(linkHandler.preprocessPath('~\\src\\file4'), 'C:\\Users\\M e\\src\\file4');
assert.equal(linkHandler.preprocessPath('C:\\abso lute\\path\\file5'), 'C:\\abso lute\\path\\file5');
});
test('Linux', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any);
linkHandler.processCwd = '/base';
assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1');
assert.equal(linkHandler.preprocessPath('src/file2'), '/base/src/file2');
assert.equal(linkHandler.preprocessPath('~/src/file3'), '/home/me/src/file3');
assert.equal(linkHandler.preprocessPath('/absolute/path/file4'), '/absolute/path/file4');
});
test('No Workspace', () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Linux,
userHome: '/home/me'
} as any);
assert.equal(linkHandler.preprocessPath('./src/file1'), null);
assert.equal(linkHandler.preprocessPath('src/file2'), null);
assert.equal(linkHandler.preprocessPath('~/src/file3'), '/home/me/src/file3');
assert.equal(linkHandler.preprocessPath('/absolute/path/file4'), '/absolute/path/file4');
});
});
suite('wrapLinkHandler', () => {
const nullMouseEvent: any = Object.freeze({ preventDefault: () => { } });
test('should allow intercepting of links with onBeforeHandleLink', async () => {
const linkHandler: TestTerminalLinkManager = instantiationService.createInstance(TestTerminalLinkManager, new XtermTerminal() as any, {
os: OperatingSystem.Linux,
userHome: ''
} as any);
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,7 +21,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
// const configurationService = new TestConfigurationService();
// configurationService.setUserConfiguration('editor', { fontFamily: 'foo' });
// configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: 'bar' } });
// const configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!);
// const configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!);
// configHelper.panelContainer = fixture;
// assert.equal(configHelper.getFont().fontFamily, 'bar', 'terminal.integrated.fontFamily should be selected over editor.fontFamily');
// });
@@ -30,7 +30,8 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
const configurationService = new TestConfigurationService();
configurationService.setUserConfiguration('editor', { fontFamily: 'foo' });
configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: null } });
const configHelper = new TerminalConfigHelper(LinuxDistro.Fedora, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
const configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.setLinuxDistro(LinuxDistro.Fedora);
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontFamily, '\'DejaVu Sans Mono\', monospace', 'Fedora should have its font overridden when terminal.integrated.fontFamily not set');
});
@@ -39,7 +40,8 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
const configurationService = new TestConfigurationService();
configurationService.setUserConfiguration('editor', { fontFamily: 'foo' });
configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: null } });
const configHelper = new TerminalConfigHelper(LinuxDistro.Ubuntu, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
const configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.setLinuxDistro(LinuxDistro.Ubuntu);
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontFamily, '\'Ubuntu Mono\', monospace', 'Ubuntu should have its font overridden when terminal.integrated.fontFamily not set');
});
@@ -48,7 +50,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
const configurationService = new TestConfigurationService();
configurationService.setUserConfiguration('editor', { fontFamily: 'foo' });
configurationService.setUserConfiguration('terminal', { integrated: { fontFamily: null } });
const configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
const configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set');
});
@@ -66,7 +68,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
fontSize: 10
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontSize, 10, 'terminal.integrated.fontSize should be selected over editor.fontSize');
@@ -79,11 +81,12 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
fontSize: 0
}
});
configHelper = new TerminalConfigHelper(LinuxDistro.Ubuntu, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.setLinuxDistro(LinuxDistro.Ubuntu);
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontSize, 8, 'The minimum terminal font size (with adjustment) should be used when terminal.integrated.fontSize less than it');
configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontSize, 6, 'The minimum terminal font size should be used when terminal.integrated.fontSize less than it');
@@ -96,7 +99,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
fontSize: 1500
}
});
configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontSize, 25, 'The maximum terminal font size should be used when terminal.integrated.fontSize more than it');
@@ -109,11 +112,12 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
fontSize: null
}
});
configHelper = new TerminalConfigHelper(LinuxDistro.Ubuntu, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.setLinuxDistro(LinuxDistro.Ubuntu);
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize + 2, 'The default editor font size (with adjustment) should be used when terminal.integrated.fontSize is not set');
configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().fontSize, EDITOR_FONT_DEFAULTS.fontSize, 'The default editor font size should be used when terminal.integrated.fontSize is not set');
});
@@ -131,7 +135,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
lineHeight: 2
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().lineHeight, 2, 'terminal.integrated.lineHeight should be selected over editor.lineHeight');
@@ -145,7 +149,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
lineHeight: 0
}
});
configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.getFont().lineHeight, 1, 'editor.lineHeight should be 1 when terminal.integrated.lineHeight not set');
});
@@ -158,7 +162,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.configFontIsMonospace(), true, 'monospace is monospaced');
});
@@ -170,7 +174,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
fontFamily: 'sans-serif'
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.configFontIsMonospace(), false, 'sans-serif is not monospaced');
});
@@ -182,7 +186,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
fontFamily: 'serif'
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.configFontIsMonospace(), false, 'serif is not monospaced');
});
@@ -198,7 +202,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.configFontIsMonospace(), true, 'monospace is monospaced');
});
@@ -214,7 +218,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.configFontIsMonospace(), false, 'sans-serif is not monospaced');
});
@@ -230,7 +234,7 @@ suite.skip('Workbench - TerminalConfigHelper', () => { // {{SQL CARBON EDIT}} sk
}
});
let configHelper = new TerminalConfigHelper(LinuxDistro.Unknown, configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
let configHelper = new TerminalConfigHelper(configurationService, null!, null!, null!, null!, null!, null!, new StorageKeysSyncRegistryService());
configHelper.panelContainer = fixture;
assert.equal(configHelper.configFontIsMonospace(), false, 'serif is not monospaced');
});